# Автономное тройное ревью П38 · апрель 2021 · «Согласованность данных между сервисами» Статус: **авторское тройное ревью пройдено, затем пакет принят независимым редактором в выпусковой набор**. Пакет содержит три revision для стабильных slug: - editorial-2021-04-practice-data-consistency; - editorial-2021-04-mechanism-data-consistency; - editorial-2021-04-field-data-consistency. Созданы только пять разрешённых файлов: 1. web/scripts/upgrade-2021-04.mjs; 2. editorial/reviews/2021-04-draft.md; 3. web/public/assets/editorial/2021/data-consistency-state-machine-2021.svg; 4. web/public/assets/editorial/2021/data-consistency-compensation-2021.svg; 5. web/public/assets/editorial/2021/data-consistency-diagnosis-2021.svg. Revision-модуль экспортирует только изменяемые редакционные поля. В нём нет date, author или подключения registry. articles.json, README, очередь, стандарты, package config и Git не менялись. Команды --print-revisions и --verify-fixture предназначены только для import-safe проверки этого пакета. ## Проход 1. Факты, историческая рамка и техника — пройдено | Утверждение | Первичный или официальный источник | Проверенная граница | | --- | --- | --- | | Контекст события может включать id, source и type; version 1.0.1 CloudEvents уже существовала к апрелю 2021 года | [CloudEvents Specification v1.0.1: release record](https://github.com/cloudevents/spec/releases/tag/ce%40v1.0.1) | Учебный конверт заимствует только понятные поля. Он не является полной реализацией CloudEvents, transport binding или broker API. | | PostgreSQL 13 документирует локальную transaction isolation, serialization failure и необходимость retry в соответствующих случаях | [PostgreSQL 13: Transaction Isolation](https://www.postgresql.org/docs/13/transaction-iso.html) | Это граница одной базы owner-а. Она не делает атомарными две базы, event delivery и внешний reserve API. | | INSERT ... ON CONFLICT задаёт альтернативу для unique/exclusion constraint в одном PostgreSQL-хранилище | [PostgreSQL 13: INSERT](https://www.postgresql.org/docs/13/sql-insert.html) | compensation_key примера защищает повтор локального решения, а не доказывает cross-service consistency. | | Kafka 2.7 отделяет producer idempotence и ограничивает её одной session, отдельно предупреждая о application-level resend | [KafkaProducer 2.7.0 API](https://kafka.apache.org/27/javadoc/org/apache/kafka/clients/producer/KafkaProducer.html) | Set event id fixture подавляет один duplicate event только в памяти; статьи не обещают exactly-once business effect. | Технический сценарий намеренно ограничен одним учебным object id order-417. Owner сначала находится в paid v2. Проверенный учебный reason training-reservation-rejected даёт owner-у право создать cancelled v3 с единственным compensationKey. Consumer получает v3 раньше v2, сохраняет version gap, применяет v2 и затем replay-ит отложенную v3. Повтор v2/v3 не создаёт новый state transition. Инварианты fixture: - owner не создаёт вторую компенсацию для того же compensationKey; - consumer не меняет projection при gap и не двигает version назад; - duplicate event id не создаёт второй state transition; - cancelled v3 не разрешает следующий эффект readyToShip. Fixture использует только Array, Map и Set одного Node-процесса. Она не запускает database, broker, HTTP service, external reserve, real order, transaction manager или distributed delivery. Компенсирующее действие в статьях описано как паттерн решения owner-а, не как единый стандарт или готовая platform capability. Вердикт прохода: **пройден**. Источники существовали к апрелю 2021 года, а проверенные факты не расширены до обещания общей транзакции, готового distributed workflow или exactly-once business effect. ## Проход 2. Редактура, глубина и голос М4 — пройдено Final draft audit подтвердил объём 5–15 тыс. знаков. Тексты держат короткую прагматичную речь «симптом → причина → проверка → действие» и М4 апреля 2021 года: ownership, инвариант, evidence и ограниченная компетентность вместо claims о распределённой платформе. | Revision | Симптом и цена в первых двух абзацах | Главный вопрос | Итоговый объём | | --- | --- | --- | --- | | Практика | owner и fulfillment показывают разные versions; цена — совершить отгрузку или другой effect по отставшей проекции | Как назвать owner, инвариант следующего действия и границу eventual consistency | **10 294** знака body | | Механизм | v3 приходит до v2 и duplicate повторяется; цена — перепрыгнуть переход, откатить projection назад или создать вторую компенсацию | Почему event id, version и compensation key нельзя заменить одним идентификатором | **10 790** знаков body | | Полевой разбор | статусы расходятся, оператору хочется переписать их вручную; цена — потерять evidence и получить второй effect | Как собрать evidence packet и выбрать безопасное действие до replay | **11 728** знаков body | Редакторский проход подтвердил: - table с caption/thead, figure с содержательным alt/figcaption, не менее двух технических примеров и нумерованный маршрут в каждой revision; - явное различение owner state, consumer projection, version gap, duplicate event и compensation key; - отсутствие claims о реальных заказах, замеренном lag, exactly-once, production delivery и зрелой distributed platform; - отсутствие анахронизма: источники и версия Kafka/PostgreSQL/CloudEvents существовали к апрелю 2021 года, а паттерн не выдан за стандарт. Вердикт прохода: **пройден**. Все три материала начинают с наблюдаемого расхождения и цены, затем дают конкретный owner/инвариант/evidence/route. Риторическая формулировка про «магический rollback» была заменена до финального audit на точное описание ложной границы компенсации. ## Проход 3. Визуал, fixture и preflight — пройдено Три SVG подготовлены как вертикальные схемы для 375 px: - state machine отделяет owner v2/v3 от отложенной consumer projection; - compensation показывает проверенный reason, локальный key и новое owner решение; - diagnosis ведёт от блока рискованного effect к evidence packet, version branch и контролируемому действию. Во всех SVG предусмотрены title, desc и role="img"; отсутствуют JavaScript, foreignObject, external URL и raster data URI. В первой статической проверке нижняя подпись state machine оказалась слишком длинной для 375 px; она сокращена, SVG отрендерен и просмотрен повторно.
cd web && node --check scripts/upgrade-2021-04.mjs
cd web && npm run audit:draft -- scripts/upgrade-2021-04.mjs
cd web && node scripts/upgrade-2021-04.mjs --verify-fixture
cd web && xmllint --noout \
  public/assets/editorial/2021/data-consistency-state-machine-2021.svg \
  public/assets/editorial/2021/data-consistency-compensation-2021.svg \
  public/assets/editorial/2021/data-consistency-diagnosis-2021.svg
| Проверка | Реальный результат | | --- | --- | | node --check | PASS, code 0 | | Import-safe export и draft gate | PASS: итоговые **10 294 / 10 790 / 11 728** знаков body; для всех трёх slug найдены sections, table, figure, code, route, sources и локальные SVG | | In-memory fixture | PASS: итоговые десять assertions равны true; v3 сначала defer, затем v2 и replay v3; duplicate не меняет projection; другой event с занятой version отклоняется; компенсация записывается один раз; cancelled не разрешает effect | | xmllint --noout | PASS, все три SVG — корректный XML | | SVG safety scan | PASS: не найдены script, foreignObject, external URL или raster data URI | | Sharp mobile preflight | PASS: финальные PNG 375×656, 375×667 и 375×719 просмотрены вручную; clipping, overlap и horizontal overflow внутри схем не обнаружены | | Scope/self-review | PASS: созданы только пять разрешённых файлов; revision не меняют date/author; registry, archive, README, очередь, standard, package config, Git и чужие untracked files не редактировались | npm run audit:draft завершилась с code 0. npm вывел старые предупреждения о пользовательских store-dir, cache-dir и public-hoist-pattern; они не относятся к П38 и не менялись пакетом. До независимой интеграции автономный автор не заявлял strict registry audit, production build, browser, screen reader, database/broker/API checks, deployment, commit или push. ## Независимая интеграционная приёмка Основной редактор 31 июля 2026 года подключил три revision к web/data/editorial-revisions.mjs, сохранив базовый articles.json, даты и автора архивных записей. В registry стало 109 revision, строгий аудит проходит 118 из 358 материалов. В независимом техническом проходе найден один риск в учебном guard: новый event с уже занятой orderVersion, но с другим id, мог бы изменить projection. До выпуска guard был уточнён: сначала проверяется subject, затем такой event возвращает same-version-event-rejected; конфликт в отложенной версии также не перезаписывает evidence. Fixture получила десятый assertion, а механизм и полевой маршрут — явное правило не выбирать конфликт по времени получения. Это изменение не выдаётся за transport guarantee. CloudEvents release record подтверждает выпуск 1.0.1 в декабре 2020 года; версионная документация PostgreSQL 13 подтверждает границы локальной изоляции и retry при serialization failure; Kafka 2.7 отдельно ограничивает producer idempotence одной session и не дедуплицирует application-level re-send. Эти источники сверены независимо и использованы только в названных границах. | Проверка после интеграции | Реальный результат | | --- | --- | | Import-safe export | PASS: три revision, без date/author | | Строгий audit трёх slug | PASS: **10 294 / 10 790 / 11 728** знаков; у каждой статьи есть figure, table и code examples | | Fixture после редакторского исправления | PASS: все 10 assertions истинны, включая rejection другого event с той же version | | Независимый SVG review | PASS: XML и active/external asset scan прошли; три PNG 375 px просмотрены повторно, clipping, overlap и overflow не обнаружены | | Production build | PASS: Next.js собрал 374 статические страницы | Ни этот отчёт, ни интеграция не утверждают запуск broker, SDK, HTTP, базы, external API, browser или assistive technology. Выпусковой вердикт: **ACCEPT**. Commit и push выполняются отдельной публикационной операцией; Git остаётся источником её фактической записи.