# Автономное тройное ревью П39 · май 2021 · «Блокировки и конкуренция» Статус: **авторское тройное ревью пройдено, затем пакет принят независимым редактором в выпусковой набор**. Revision-модуль содержит ровно три стабильных slug: - editorial-2021-05-practice-distributed-locks; - editorial-2021-05-mechanism-distributed-locks; - editorial-2021-05-field-distributed-locks. В revisions нет date, author или подключения registry. Эта авторская партия не меняла articles.json, README, очередь, стандарт, package config или Git. Созданы только пять разрешённых файлов, перечисленных внизу документа. ## Проход 1. Факты, историческая рамка и техника — пройдено | Утверждение или решение | Первичный / официальный источник | Зафиксированная граница | | --- | --- | --- | | Для исторической точки мая 2021 выбрана линия etcd v3.4: её Lock возвращает key на время владения; unlock или expiry/revoke связанного lease освобождает lock | [etcd v3.4 Concurrency API Reference](https://etcd.io/docs/v3.4/dev-guide/api_concurrency_reference_v3/) | Документация описывает lock внутри etcd. Она не объявляет возвращённый key универсальным числовым fencing token для внешней базы, файла или API. | | LeaseGrant получает advisory TTL, а ответ возвращает TTL, выбранный server; без keepalive lease истекает, attached keys удаляются | [etcd v3.4 API Reference](https://etcd.io/docs/v3.4/dev-guide/api_reference_v3/) | Учебные 5000 мс не являются значением TTL для etcd, не проверяют keepalive, clock drift или clock correctness. | | Lock сам по себе advisory; sequencer передаётся получателю операции, а получатель проверяет его актуальность и может отвергнуть request | [Mike Burrows, The Chubby lock service for loosely-coupled distributed systems, OSDI 2006](https://research.google/pubs/the-chubby-lock-service-for-loosely-coupled-distributed-systems/) | Chubby — исторический первичный пример boundary, не скрытая реализация fixture и не рекомендация установить этот сервис. | | Выбор v3.4 не заносит будущую версию в текст мая: официальный анонс v3.5 датирован 15 июня 2021 года и ретроспективно называет запуск v3.4 августом 2019 года | [Announcing etcd 3.5](https://etcd.io/blog/2021/announcing-etcd-3.5/) | Эта ссылка служит редакторской проверкой датировки; сама статья не ссылается на будущий для мая анонс и не использует API v3.5. | runDistributedLockFixture() — детерминированная state machine только на Map и ручном счётчике времени. В ней нет системных часов, сети или provider client: 1. worker-A получает training-lease-1 и token 1 на 5000 мс; 2. учебный clock переходит к 6000 мс, lease-1 помечается истёкшим, но worker-A не считается остановленным; 3. worker-B получает training-lease-2 и token 2; 4. защищаемый ресурс принимает write worker-B, сохраняет v2 и highest token 2; 5. поздний write worker-A с token 1 получает rejected-stale-fence; 6. старый release worker-A не снимает текущий lease worker-B; 7. отдельный намеренно unsafe ресурс без fencing показывает, что token 1 перезаписал бы v2. Проверены девять assertions: выдача первого lease/token, pause после expiry, выдача второго lease/token, принятие v2, отказ stale v1, защита release нового lease, сохранение v2, небезопасный контраст без fencing и работа только в памяти. Главный технический вывод узкий: **fence помогает только когда защищаемый ресурс сам хранит и монотонно проверяет token в своей операции записи**. Generic lock не выдан за доказательство безопасности. Не проверялись реальный etcd/Redis/ZooKeeper, provider SDK, cluster, keepalive, сеть, clock synchronization, база, файловый storage, HTTP, внешний API, нагрузка или provider SLA. Fixture не заявляет exactly-once, отмену старого request и корректность реальных часов. Вердикт прохода: **пройден**. Историческая версия и ограничения названы рядом с механизмом, а модель не переносит свойства учебной Map на настоящий провайдер. ## Проход 2. Редактура, глубина и голос М4 — пройдено | Revision | Симптом и цена в первых двух абзацах | Главный вопрос | Объём основного текста | | --- | --- | --- | ---: | | Практика | worker-A останавливается дольше lease, B уже обновляет отчёт, A может поздно перезаписать v2 | Как до критической секции разделить lifecycle lease, owner, handle и resource-side fence | **10 939** знаков body | | Механизм | поздний request получает успешный ответ после нового владельца, поэтому команда ошибочно обвиняет lock provider | Почему token обязан проверять защищаемый ресурс, а не только authority перед началом работы | **10 293** знака body | | Полевой разбор | после v2 в лог попадает «успех» старого A; цена — ложный диагноз и повтор той же гонки | Как собрать evidence и отделить stale generation от duplicate, bad release и безусловного write | **9 857** знаков body | - Все статьи начинают с наблюдаемого симптома и цены, затем держат маршрут «симптом → причина → проверка → действие → ограничение». - В каждой revision есть table с caption/thead, figure с самостоятельными alt/figcaption, не менее двух технических примеров, нумерованный путь, три первичных или официальных источника и явный тестовый interleaving. - Голос М4 / мая 2021 продолжает пакеты о транзакции, кешировании и очередях: автор называет owner, handle, ресурсную границу и инвариант, но не изображает себя владельцем большой distributed platform. Речь короткая и предметная: token 1 ≤ highest token 2 → reject, а не «блокировка магически защищает данные». - Убраны опасные подмены: expiry не назван остановкой процесса; token не назван clock; lease key не объявлен готовым fence для внешнего ресурса; fencing не отождествлён с idempotency или exactly-once. - Заголовки и excerpts обещают ограниченный результат: понять boundary и проверить stale write, а не получить универсальный рецепт distributed lock. Вердикт прохода: **пройден**. Тексты лежат в диапазоне 5 000–15 000 знаков и развивают T-shape автора от delivery/данных к одному проверяемому контракту конкуренции без анахронизмов и техлидской позы 2027 года. ## Проход 3. Визуал, fixture и preflight — пройдено в границах пакета - distributed-lock-lease-timeline-2021.svg показывает полный interleaving от lease-1/token 1 до reject позднего token 1. После первого Sharp-рендера длинная нижняя подпись была разбита на две строки. - distributed-lock-fence-boundary-2021.svg отделяет authority от ресурса и показывает, где именно хранится highest token. После первого рендера нижняя карточка получила две короткие строки и большую высоту. - distributed-lock-diagnosis-2021.svg ведёт от evidence packet к stale generation, duplicate, resource without compare и bad release. После первого рендера перенесены длинная итоговая подпись и строка atomic compare. - У всех трёх SVG есть title, desc, role="img" и вертикальный viewBox. В исходниках нет JavaScript, foreignObject, external URL или data URI; обычный XML namespace не является внешним asset. ### Фактически выполненные проверки Команды запускались из web/ после финальных правок:
node --check scripts/upgrade-2021-05.mjs
npm run audit:draft -- scripts/upgrade-2021-05.mjs
node scripts/upgrade-2021-05.mjs --verify-fixture
xmllint --noout \
  public/assets/editorial/2021/distributed-lock-lease-timeline-2021.svg \
  public/assets/editorial/2021/distributed-lock-fence-boundary-2021.svg \
  public/assets/editorial/2021/distributed-lock-diagnosis-2021.svg
| Проверка | Реальный результат | | --- | --- | | node --check | PASS, code 0 | | Import-safe export и draft gate | PASS: итоговые **10 939 / 10 293 / 9 857** знаков body; найдены три slug, sections, tables, figures, code, routes, sources и локальные visual assets | | In-memory fixture | PASS: все девять assertions истинны; worker-B получил token 2 после expiry A, ресурс принял v2 и отверг поздний token 1, старый release не удалил lease-B | | xmllint --noout | PASS, все три SVG — корректный XML | | SVG safety scan | PASS: нет script, foreignObject, external asset URL или raster data URI | | Sharp mobile preflight | PASS после корректировки длинных подписей: вручную просмотрены финальные PNG **375×740**, **375×781** и **375×844**; clipping, overlap и horizontal overflow внутри схем не обнаружены | | Scope/self-review | PASS: созданы только пять разрешённых файлов; registry, articles.json, README, очередь, стандарт, package config, Git и чужие untracked files не менялись | npm run audit:draft завершилась с code 0. npm вывел уже существующие предупреждения о пользовательских store-dir, cache-dir и public-hoist-pattern; эти настройки не относятся к П39 и не менялись. Не запускались strict audit после подключения registry, production build, browser, screen reader, CI, deployment или публикация. Static SVG preflight не заменяет browser review, accessibility audit и integration test выбранной инфраструктуры. ## Итог Статус автономного этапа: **тройное авторское ревью пройдено; П39 была готова к отдельной интеграционной приёмке**. Commit и push на этом этапе намеренно не выполнялись. Созданы ровно пять файлов: 1. web/scripts/upgrade-2021-05.mjs; 2. editorial/reviews/2021-05-draft.md; 3. web/public/assets/editorial/2021/distributed-lock-lease-timeline-2021.svg; 4. web/public/assets/editorial/2021/distributed-lock-fence-boundary-2021.svg; 5. web/public/assets/editorial/2021/distributed-lock-diagnosis-2021.svg. ## Независимая интеграционная приёмка Основной редактор 31 июля 2026 года подключил три revision к web/data/editorial-revisions.mjs, сохранив базовый articles.json, даты и автора архивных записей. В registry стало 112 revision, строгий аудит проходит 121 из 358 материалов. Независимый факт-чек уточнил одну формулировку до выпуска: в etcd v3.4 LeaseGrantRequest.TTL назван advisory, а LeaseGrantResponse.TTL — выбранным server значением. Поэтому слова «запрошенный TTL — минимум» заменены на точную границу API. Учебные 5000 мс не стали claim о настройке etcd. Отдельно перепроверены: lifecycle lock key при expiry/revoke lease и Chubby-подход с advisory lock/acquisition count, который защищаемый server сравнивает от delayed write. | Проверка после интеграции | Реальный результат | | --- | --- | | Import-safe export | PASS: три revision, без date/author | | Строгий audit трёх slug | PASS: **10 939 / 10 293 / 9 857** знаков; у каждой статьи есть figure, table и code examples | | In-memory fixture | PASS: все 9 assertions истинны; token 2 принят, token 1 после него отклонён, старый release не снял lease-B | | Независимый SVG review | PASS: XML и active/external asset scan прошли; три PNG 375 px просмотрены повторно, clipping, overlap и overflow не обнаружены | | Production build | PASS: Next.js собрал 374 статические страницы | Ни этот отчёт, ни интеграция не утверждают запуск etcd, другого provider, cluster, базы, HTTP, browser, SDK или внешнего API. Выпусковой вердикт: **ACCEPT**. Commit и push выполняются отдельной публикационной операцией; Git остаётся источником её фактической записи.