# Ноябрь 2019 — тройное ревью автономного пакета P21 «Воспроизводимые сборки» Статус: **принят в publication registry 31 июля 2026 года**. Три revision накладываются только по stable slug и сохраняют даты и авторов базового архива: - editorial-2019-11-practice-reproducible-builds; - editorial-2019-11-mechanism-reproducible-builds; - editorial-2019-11-field-reproducible-builds. Модуль экспортирует ровно три revision. В объектах нет date и author: эти поля принадлежат исходным записям архива. При прямом запуске с --print-revisions stdout содержит только JSON; отдельный --run-fixture печатает JSON учебной hash-проверки. ## Проход 1. Факты и техника — пройдено | Утверждение или решение | Первичный источник | Проверенная граница | | --- | --- | --- | | Lockfile фиксирует конкретное дерево, включая транзитивные зависимости | [npm 6: package-locks](https://docs.npmjs.com/cli/v6/configuring-npm/package-locks/) и [package-lock.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-lock-json/) | Текст не утверждает, что lockfile фиксирует OS, время, webpack config или внешний генератор. Он фиксирует разрешение пакетов, когда используется в контролируемом install. | | npm ci — чистая установка с отказом при рассинхронизации lockfile и package.json | [npm 6: npm ci](https://docs.npmjs.com/cli/v6/commands/npm-ci/) | Статьи не подменяют им рабочий npm install и не обещают, что npm ci устраняет drift плагина или даты в asset. | | npm config может прийти из CLI, окружения, npmrc и package.json | [npm 6: npm config](https://docs.npmjs.com/cli/v6/commands/npm-config/) | В журнал предлагается whitelist безопасных значений, а не полный env, токены или auth headers. | | [contenthash] связан с содержимым asset, но runtime и module IDs способны расширить diff chunks | [webpack: Caching](https://webpack.js.org/guides/caching/) | Имя одного файла названо сигналом, а не доказательством равенства всего dist. Проверяется manifest всех deployable files. | | SHA-256 нужен для сравнения выбранных bytes | [Node.js: Crypto](https://nodejs.org/api/crypto.html) | Hash не объявлен подписью релиза, доказательством работы приложения или результатом production-сборки. | Автономная fixture не скачивает зависимости и не запускает webpack. Она проверяет только алгоритм сравнения: перестановка одинаковых entries даёт тот же hash manifest, изменение одного bytes даёт другой. Фактический вывод:
{
  "fixtureOnly": true,
  "lockfileSha256": "d2976c1b0ca05326497d2b8157ee39b3ffc6f5ad6481c119e2fd769d3e6c8204",
  "firstManifestSha256": "adc6fefae98f7874289579da4efcf252217989cbc9caf32fc8bb830f6eeac75e",
  "secondManifestSha256": "adc6fefae98f7874289579da4efcf252217989cbc9caf32fc8bb830f6eeac75e",
  "changedManifestSha256": "a521a4c7df02a402a2ab7e71ff690554cdf686faf831aaefe7d171079d15e8fe",
  "checks": {
    "sameEntriesDifferentOrder": true,
    "changedFileChangesManifest": true
  }
}
Следовательно, fixture подтверждает только канонизацию sample manifest. В пакете нет заявления о CI, registry install, браузерном релизе или production output. Для настоящего проекта статьи требуют записать собственные commit, lockfile digest, Node/npm, команду, журнал и manifest после реального запуска. ## Проход 2. Редактура и голос М2 / 2019 — пройдено | Ревизия | Симптом и стоимость в начале | Главный технический вопрос | Проверяемый результат и ограничение | | --- | --- | --- | --- | | Практика | Один commit создаёт два dist; review и rollback не знают, какой набор assets был проверен | Как получить два чистых прогона, не смешав установку зависимостей и проверку output | Lockfile/log/manifest route, Node hash script и список входов; нет заявления о запуске этого проекта | | Механизм | Одинаковый Git hash скрывает разные runtime, config или generated data | Где проходит граница функции build и что доказывает manifest SHA-256 | Карта входов, таблица владельцев, контрпримеры contenthash; hash не выдан за подпись или тест приложения | | Полевой разбор | Коллеги получили разные release-файлы и хотят начать с очистки cache | Как по первому differing file отличить dependency, config и generated output | Карточка двух прогонов, дерево диагностики и обратимый путь исправления; CI и production не заявлены | - Тон соответствует уровню М2 / 2019: npm 6, webpack 4, Node, проектный npmrc, чистая установка, manifest и diff. В текст не добавлены поздние практики вроде supply-chain attestations, SLO, распределённой трассировки или риторика платформенного техлида. - Во всех трёх текстах держится маршрут «симптом → причина → проверка → действие → ожидаемый результат → ограничение». Конкретные объекты названы: package-lock.json, npm ci, dist, first.manifest, NODE_ENV, runtime chunk и generated banner. - Нет шаблонных призывов «очистить кэш», «закрепить всё» или «сделать CI» без диагностического условия. Каждый такой шаг имеет место в маршруте, владельца и границу вывода. - Draft gate подтвердил основной текст в диапазоне 5 000–15 000 символов: **10 061** для практики, **9 115** для механизма и **8 650** для полевого разбора. В значение не включены title, meta и раздел источников. - В каждой статье есть не менее пяти h2, доступная таблица с caption, thead и scope, оригинальная схема с содержательными alt/figcaption, код, упорядоченный маршрут и не менее двух официальных источников. ## Проход 3. Визуал и выпуск автономного пакета — пройдено - reproducible-build-input-contract-2019.svg ведёт от исходников, зависимостей и среды/команды к чистой установке, build и manifest. Диаграмма подчёркивает, что hash приходит после явного контракта, а не заменяет его. - reproducible-build-hash-boundary-2019.svg отделяет зафиксированные commit/lockfile от runtime, config и generated data. Нижняя развилка не называет расхождение ошибкой сборщика: она ведёт к первому отличающемуся файлу. - reproducible-build-diagnosis-2019.svg показывает две чистые сборки, сравнение входов и явное условие: при расхождении входов маршрут останавливается, при совпадении сравнивается output manifest. Это визуальный маршрут, а не скриншот несуществующего прогона. - В каждом SVG есть title, desc, role="img", вертикальный viewBox, контрастные карточки и подписи внутри заданной ширины. Нет JavaScript, внешних URL, растровых вложений или анимации. XML-валидатор принял все три файла. - Независимый mobile preflight отрисовал каждый SVG через Sharp в PNG шириной 375 px. Первый raster показал мелкие подписи в горизонтальных панелях и обрезание диагностической схемы. Все три визуала пересобраны вертикально; повторный рендер не показал обрезания, наложения или горизонтального выхода. Это проверка статичных изображений, а не browser screenshot или Accessibility tree. - После подключения registry strict audit и production build пройдены. Ручной browser-review поведения страницы остаётся отдельной выпускной проверкой и не заявлен как выполненный. ## Выполненные команды
cd web
node --check scripts/upgrade-2019-11.mjs
npm run audit:draft -- scripts/upgrade-2019-11.mjs
node scripts/upgrade-2019-11.mjs --run-fixture
xmllint --noout \
  public/assets/editorial/2019/reproducible-build-input-contract-2019.svg \
  public/assets/editorial/2019/reproducible-build-hash-boundary-2019.svg \
  public/assets/editorial/2019/reproducible-build-diagnosis-2019.svg
Все четыре команды завершились с кодом 0. Draft gate вывел:
PASS editorial-2019-11-practice-reproducible-builds: 10061 body chars
PASS editorial-2019-11-mechanism-reproducible-builds: 9115 body chars
PASS editorial-2019-11-field-reproducible-builds: 8650 body chars
После интеграции strict audit подтвердил: 10 061 / 9 115 / 8 650 знаков, по одному figure и table, 3 / 1 / 1 code example. npm run build завершился с кодом 0 и сгенерировал 374 статические страницы. Выпусковой вердикт: **тройное ревью пройдено, пакет принят к публикации**. articles.json не менялся; registry заменяет только редакционные поля по stable slug. Production build и raster preflight не подменяют ручную проверку поведения в браузере.