diff --git a/editorial/production/README.md b/editorial/production/README.md
index c32aae5..e8d1394 100644
--- a/editorial/production/README.md
+++ b/editorial/production/README.md
@@ -1,6 +1,6 @@
# Производство редакционных партий
-На 31 июля 2026 года строгий аудит проходит 3 из 358 созданных материалов. Остальные 355 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
+На 31 июля 2026 года строгий аудит проходит 18 из 358 созданных материалов. Остальные 340 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
## Одна партия
diff --git a/editorial/reviews/2018-06-draft.md b/editorial/reviews/2018-06-draft.md
index a09771a..0a6cee0 100644
--- a/editorial/reviews/2018-06-draft.md
+++ b/editorial/reviews/2018-06-draft.md
@@ -29,7 +29,7 @@
- Поля `assets`, `chunks`, `modules` и entrypoint-данные сверены с [Stats Data](https://v4.webpack.js.org/api/stats/) Webpack 4; команда и формат CLI — с [документацией CLI](https://v4.webpack.js.org/api/cli/).
- Диагностический фрагмент не трактует присутствие модуля в нескольких chunks как готовое доказательство скачивания. Статья требует проверить HTML и Network отдельно.
- Размер ассета в stats не выдан за сетевой transfer size: явно названы влияние сжатия, кеша, режима сборки и source map. В текст не добавлены вымышленные замеры, пользователи или результаты.
-- Третий редакторский проход после независимого quality-gate: первое предложение теперь начинается с явного маркера «Симптом» и называет наблюдаемые `site.…js` и `admin.…js` в Network; цена ошибки сохранена — пользователь скачивает код панели, которой не откроет.
+- Третий редакторский проход после независимого quality-gate: первое предложение теперь начинается с явного маркера «Симптом» и называет наблюдаемые `site.[contenthash].js` и `admin.[contenthash].js` в Network; цена ошибки сохранена — пользователь скачивает код панели, которой не откроет.
## 2. Редактура и голос — пройдено
diff --git a/web/scripts/upgrade-2018-06.mjs b/web/scripts/upgrade-2018-06.mjs
index 81e4709..91f0186 100644
--- a/web/scripts/upgrade-2018-06.mjs
+++ b/web/scripts/upgrade-2018-06.mjs
@@ -158,7 +158,7 @@ module.exports = {
paragraph('У правил выделения тоже есть граница. vendors смотрит только на путь внутри node_modules; пакет, который нужен одному checkout, не обязан переезжать в общий файл. common смотрит на повторное достижение модуля из двух chunks. Поэтому я не называю папку shared гарантией оптимизации: имя папки помогает человеку, а решение принимает правило сборки по графу и его условиям.'),
paragraph('Перед тем как менять пороги, полезно сохранить список ассетов первого build. После изменения я сравниваю не общую сумму каталога, а роли файлов: появился ли vendors, попал ли money.js в common, остался ли код каталога в catalog. Так видно, какое именно правило сработало, и не приходится угадывать по одному числу в терминале.'),
heading('Проверка не заканчивается на появлении файлов'),
- paragraph('После сборки должны появиться файлы с именами, зависящими от хеша: runtime.…js, vendors.…js, при нашем маленьком примере common.…js, а также catalog.…js и checkout.…js. Хеши нельзя вшивать в шаблон HTML вручную. Шаблонизатор, плагин или серверный код должен получить актуальный список ассетов из сборки.'),
+ paragraph('После сборки должны появиться файлы с именами, зависящими от хеша: runtime.[contenthash].js, vendors.[contenthash].js, при нашем маленьком примере common.[contenthash].js, а также catalog.[contenthash].js и checkout.[contenthash].js. Хеши нельзя вшивать в шаблон HTML вручную. Шаблонизатор, плагин или серверный код должен получить актуальный список ассетов из сборки.'),
codeBlock(String.raw`
@@ -286,7 +286,7 @@ const fieldArticle = {
excerpt: 'Пошаговая диагностика Webpack 4: отделяем новые ассеты от реального дублирования, читаем stats.json и проверяем, что браузер действительно скачивает.',
readingMinutes: 10,
contentHtml: [
- paragraph('Симптом: после добавления admin-entry вырос site.…js, а Network обычной страницы показывает запрос к admin.…js. Пользователь получает код панели, которой не откроет; если править только сумму файлов в dist, легко оставить этот лишний запрос или сломать подключение нужного entry.'),
+ paragraph('Симптом: после добавления admin-entry вырос site.[contenthash].js, а Network обычной страницы показывает запрос к admin.[contenthash].js. Пользователь получает код панели, которой не откроет; если править только сумму файлов в dist, легко оставить этот лишний запрос или сломать подключение нужного entry.'),
paragraph('Главный вопрос статьи: как по данным Webpack 4 доказать, почему bundle вырос после добавления entry, прежде чем менять конфигурацию? Для ответа нужны три вещи: список emitted-ассетов, связь модуля с chunks и фактические script-теги в HTML. Одной цифры из файловой системы недостаточно.'),
heading('Сначала фиксирую условия сравнения'),
paragraph('Сравнивать development-результат с production-результатом бессмысленно: режим, минификация, source map и плагины меняют картину сильнее, чем новый entry. Я делаю два production-build на одном коммите: до изменения и после него. Для каждого сохраняю JSON статистики отдельно, например stats-before.json и stats-after.json.'),
@@ -343,7 +343,7 @@ for (const module of repeated.slice(0, 30)) {
dataTable(
['Наблюдение', 'Что это может означать', 'Следующее действие'],
[
- ['Появился новый admin.…js, старый site.…js почти не изменился', 'В dist лежит ещё одна страница, но старая не стала тяжелее', 'Проверить, что старый HTML не подключает admin'],
+ ['Появился новый admin.[contenthash].js, старый site.[contenthash].js почти не изменился', 'В dist лежит ещё одна страница, но старая не стала тяжелее', 'Проверить, что старый HTML не подключает admin'],
['Один пакет из node_modules виден у двух initial chunks', 'Внешняя зависимость достигнута из двух entry и не вынесена', 'Проверить splitChunks и условия cache group'],
['Оба entry подключены в одном HTML', 'Шаблон страницы получает чужой сценарий', 'Исправить генерацию script-тегов до настройки оптимизации'],
['Рост только в development', 'Сравнение сделано в разных режимах или с source map', 'Повторить замер одинаковой production-командой'],