# Ноябрь 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 не подменяют ручную
проверку поведения в браузере.