revise late 2018 editorial articles
Build and deploy / deploy (push) Successful in 14s

This commit is contained in:
2026-07-31 10:09:53 +03:00
parent 2c7f9d37d7
commit c72a72b8f3
18 changed files with 2281 additions and 6 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Производство редакционных партий
На 31 июля 2026 года строгий аудит проходит 27 из 358 созданных материалов. Остальные 331 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
На 31 июля 2026 года строгий аудит проходит 36 из 358 созданных материалов. Остальные 322 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
## Одна партия
+152
View File
@@ -0,0 +1,152 @@
# П09 · 2018-10 → 2019-01 · тройное ревью и выпускной gate
Статус: **принят в публикационный слой 31 июля 2026 года**. Ревизии
накладываются только по стабильному slug: дата и автор остаются данными
базового архива, поэтому выпуск не подменяет хронологию.
Пакет сохраняет два существующих slug октября 2018 года и один slug января
2019 года. В нём нет выдуманной третьей октябрьской статьи.
| Slug | Дата и голос | Главный вопрос | Основной текст |
| --- | --- | --- | ---: |
| editorial-2018-10-mechanism-image-workflow | 2018, М1 | Кто владеет файлом на пути от preview до PREVIEW_PICTURE | 7 535 |
| editorial-2018-10-field-image-workflow | 2018, М1 | Как договорить legacy-форму, FileInput и серверное сохранение | 8 297 |
| editorial-2019-01-mechanism-jquery-webpack | 2019, М2 | Почему старый jQuery-плагин ломается только в production | 8 585 |
Все значения выше получены тем же правилом, что использует редакционный
аудит: без раздела «Проверяемые источники», с видимым текстом таблиц и
примеров.
## 1. Факты и техника
### Проверены источники
- **Bitrix.** Официальные страницы FileInput, CFile::SaveFile,
CFile::MakeFileArray и CIBlockElement::Update подтверждают используемые
методы, файловый массив, ID файла, булев результат Update() и LAST_ERROR.
Отдельно сверено, что MakeFileArray принимает ID файла.
- **PHP.** Официальные страницы $_FILES и move_uploaded_file задают границу
HTTP POST upload. В статьях не заявляется, что browser preview является
сохранённым файлом.
- **jQuery.** Официальная документация .on() подтверждает делегирование к
существующему контейнеру и event namespace; .ready() — запуск работы после
готовности DOM.
- **Webpack.** Официальные документы Shimming, ProvidePlugin, migration to v4
и SplitChunksPlugin подтверждают различие свободного идентификатора и
глобальной зависимости, а также переход к optimization.splitChunks в
Webpack 4.
### Проверен механизм
- У 2018-статей отделены UI-контрол, файловый массив запроса, запись b_file и
поле элемента. Код не считает успехом один только preview или один только ID
файла.
- В field-статье конфликт «новый файл + удаление» завершает запрос понятной
ошибкой; ветка «без файла» не удаляет картинку по состоянию DOM.
- В статье 2019 года ProvidePlugin не выдан за универсальную настройку window.
Bootstrap сначала назначает window.jQuery, затем делает runtime require
legacy-плагина.
- Минимальный ESM-прогон подтвердил предпосылку о порядке: зависимость
исполняется до тела импортирующего модуля. Результат:
["dependency","module body"].
### Команды и результаты
node --check web/scripts/upgrade-2018-10-2019-01.mjs
# exit 0
node --input-type=module -e '<минимальный data: ESM сценарий>'
# ["dependency","module body"]
node web/scripts/audit-editorial-draft.mjs web/scripts/upgrade-2018-10-2019-01.mjs
# PASS editorial-2018-10-mechanism-image-workflow: 7535 body chars
# PASS editorial-2018-10-field-image-workflow: 8297 body chars
# PASS editorial-2019-01-mechanism-jquery-webpack: 8585 body chars
Вердикт: **пройдено**. Все три материала имеют 2+ первичных источника,
воспроизводимые примеры и явные версионные/проектные оговорки. Размеры и
лимиты в коде названы проектными, а не универсальными.
## 2. Редактура и голос
### Проверены начало, плотность и язык
- В первых двух предложениях каждой статьи есть симптом и цена ошибки:
старая обложка каталога, лишние не связанные файлы, неработающая production
форма.
- Все статьи используют маршрут «симптом → причина → проверка → действие».
Каждый раздел заканчивается проверяемым следствием или ограничением.
- В 2018 году сохраняется М1: короткие шаги, «я бы проверил», локальная
граница PHP/Bitrix и осторожный вывод. Нет ретроспективных SLO, Kubernetes,
incident command или модной терминологии вместо действия.
- Январь 2019 года делает только следующий правдоподобный шаг к М2: модуль,
entry, chunk, production-артефакт, stats.json и граница между глобалом и
compiled source. Это развитие из предыдущих статей о jQuery/Webpack, а не
скачок к архитектурной декларации.
- Проверка черновика не нашла шаблонных оборотов из quality gate, следов
генерации, пустых alt, короткого тела, нецелевых slug или изменения даты и
автора.
### Редакторские решения
1. В первой 2018-статье отказался от обещания «правильно настроить загрузку
вообще»: текст отвечает только на вопрос о владельце состояния.
2. Во второй 2018-статье не смешал обработчик .on() с серверной логикой:
jQuery отвечает за статус, сервер — за файл и карточку.
3. В январской статье не приписал Webpack фиксированные имена chunks и не
назвал отключение splitChunks решением. Вместо этого оставлен путь к
фактическому stats.json и production HTML.
Вердикт: **пройдено**. Плотность текста соответствует диапазону 5–15 тыс.
знаков, стиль движется от М1 к М2 без анахронизма.
## 3. Визуал и выпуск
### Проверка схем
Созданы три самостоятельные SVG с role="img", title, desc, осмысленными alt
в статье и подписью figure:
- bitrix-file-state-ownership-2018.svg — четыре состояния файла;
- legacy-photo-form-contract-2018.svg — договор DOM, multipart POST и
серверной ветки;
- webpack-jquery-order-2019.svg — порядок bootstrap/require и плохая ветка
static import.
xmllint --noout \
web/public/assets/editorial/2018/bitrix-file-state-ownership-2018.svg \
web/public/assets/editorial/2018/legacy-photo-form-contract-2018.svg \
web/public/assets/editorial/2019/webpack-jquery-order-2019.svg
# exit 0
Сначала схемы были широкими и на viewport 375 px текст становился слишком
мелким. Визуальная проверка это выявила до выпуска. Схемы переделаны в
вертикальные: на 375×812 все карточки, стрелки и подписи читаются без
горизонтального скролла. На desktop ширина страницы не превышает viewport:
scrollWidth = 1280, clientWidth = 1280 у каждого SVG.
### Выпусковой контракт
- CLI вызов скрипта вернул exit 0, пустой stderr и ровно три JSON-ревизии.
- Import скрипта безопасен: не пишет файлы и не выводит текст; его массив
совпал с массивом, полученным через CLI.
- audit-editorial-draft.mjs подтвердил exact slug, длины, 5+ разделов,
figure/alt/figcaption, table/thead, код, ol, источники и отсутствие
изменения date/author.
- При просмотре raw SVG браузер повторял внутреннюю ошибку
Cannot use 'in' operator to search for 'animation' in undefined. Та же
ошибка воспроизвелась на старом
/assets/illustrations/jquery-webpack.svg; у новых SVG нет скриптов, поэтому
ошибка не отнесена к черновику.
После интеграции основной редактор повторно прогнал оба уровня проверки:
- `npm run audit:draft -- scripts/upgrade-2018-10-2019-01.mjs` подтвердил
три ревизии: 7 535 / 8 297 / 8 585 знаков тела;
- строгий аудит опубликованного слоя подтвердил для каждой статьи figure,
table, code, маршрут действий, источники и требования к голосу;
- `xmllint --noout` принял все три SVG;
- `npm run build` завершился с кодом 0 и сгенерировал 374 статические страницы.
Вердикт: **принят к публикации**. Изменения `articles.json` не требуются:
revisions registry подменяет только редакционные поля по стабильному slug.
+114
View File
@@ -0,0 +1,114 @@
# Ноябрь 2018 — тройное ревью и выпускной gate «Интеграционные проверки PHP»
Статус: **принят в публикационный слой 31 июля 2026 года**. Пакет П10
сохраняет стабильные slug, дату и автора базового архива:
- <code>editorial-2018-11-practice-php-integration-tests</code>;
- <code>editorial-2018-11-mechanism-php-integration-tests</code>;
- <code>editorial-2018-11-field-php-integration-tests</code>.
Артефакты П10:
- <code>web/scripts/upgrade-2018-11.mjs</code>;
- <code>web/public/assets/editorial/2018/php-integration-contract-2018.svg</code>;
- <code>web/public/assets/editorial/2018/php-test-boundary-2018.svg</code>;
- <code>web/public/assets/editorial/2018/php-false-green-trace-2018.svg</code>;
- этот файл.
Сам скрипт П10 не меняет <code>web/data/articles.json</code>: публикационный
слой подключает его отдельным registry только по slug. В общем checkout во
время работы могли появляться параллельные артефакты других пакетов; они не
входят в этот список и П10 их не редактирует. Дата ревью: 31 июля 2026 года.
## 1. Факты и техника — пройдено
### Карта утверждений и первичных источников
| Утверждение | Первичный источник | Оговорка в материале |
| --- | --- | --- |
| PHPUnit 7 запускает классы, наследующие <code>PHPUnit\Framework\TestCase</code>, и тесты из файлов <code>*Test.php</code> | [Getting Started with PHPUnit 7](https://phpunit.de/getting-started/phpunit-7.html) | Пример помечен как PHP 7.2 / PHPUnit 7.5; версия закрепляется проектом, а не статьёй |
| <code>setUp()</code> и <code>tearDown()</code> создают и очищают fixture вокруг теста | [PHPUnit 7.5 Fixtures](https://docs.phpunit.de/en/7.5/fixtures.html) | Статья не выдаёт fixture за изоляцию всей системы: отдельно названы вторые соединения и HTTP |
| Mock/test double позволяет контролировать соседа класса, но не является доказательством SQL, PDO или сети | [PHPUnit 7.5 Test Doubles](https://docs.phpunit.de/en/7.5/test-doubles.html) | Unit- и integration-тесты отвечают на разные вопросы и оба остаются нужны |
| <code>PDO::beginTransaction()</code> выключает autocommit; <code>rollBack()</code> откатывает изменения и возвращает его, но MySQL может сделать неявный commit для DDL | [PDO::beginTransaction](https://www.php.net/manual/en/pdo.begintransaction.php), [PDO::rollBack](https://www.php.net/manual/en/pdo.rollback.php) | Миграции и DDL не запускаются внутри транзакции теста; показан только путь данных |
| <code>getenv()</code> читает конфигурацию, а <code>curl_exec()</code> и <code>curl_getinfo()</code> позволяют различить transport error и HTTP-статус | [getenv](https://www.php.net/manual/en/function.getenv.php), [curl_exec](https://www.php.net/manual/en/function.curl-exec.php), [curl_getinfo](https://www.php.net/manual/en/function.curl-getinfo.php) | Пример допускает только локальный учебный callback; внешние URL, production-секреты и результаты вызова не выдумываются |
### Технический проход
- Во всех трёх ревизиях ровно один главный вопрос: контракт PDO-репозитория; граница unit/integration; фальшивая зелень в связке БД/HTTP/конфигурации.
- Код вручную сверён с синтаксисом PHP 7.2: типы параметров и возврата, <code>array()</code>, методы PHPUnit 7; в тексте нет claim о запущенном контейнере, рабочем пароле или зелёном результате PHP-теста.
- В коде HTTP учебный endpoint ограничен локальным адресом. Это не выдано за универсальную политику безопасности: для тестовой сети отдельно названы allowlist и отдельные credentials.
- SQL, окружение, PDO и cURL не смешиваются в один диагноз. Каждой точке соответствует наблюдаемый факт и следующее действие.
- DDL, второй PDO-коннект и HTTP не объявлены автоматически откатываемыми. Граница уборки показана явно.
## 2. Редактура и голос М1 — пройдено
| Ревизия | Симптом и цена в первых двух абзацах | Один вопрос | Артефакт | Голос и ограничение |
| --- | --- | --- | --- | --- |
| Практика | Unit зелёный, но запись/чтение ломается; цена — неделя правок не той логики | Какой договор должен проверить PDO integration test | Тест <code>INSERT → SELECT → rollback</code>, таблица контракта, схема | Короткие шаги 2018 года; тестовая БД и контейнер не выдаются за запущенные |
| Механизм | Mock зелёный, но SQL/конфигурация не работают; цена — ложная уверенность при рефакторинге | Где граница unit и integration | Соседние unit- и integration-примеры, таблица вопросов | Нет поздних SLO/observability-терминов; история ограничена PHP 7.2/PHPUnit 7.5 |
| Поле | Регистрация 500 после записи или не уведомляет; цена — потеря следа и подмена реального клиента | Как увидеть разрыв БД/HTTP/config | Локальный callback, request ID, cURL-адаптер, трассировочная таблица | Учебная трасса не названа инцидентом; production endpoint запрещён |
- М1 сохранён: текст идёт по формуле «симптом → причина → проверка → действие → результат → ограничение», использует короткие предметные абзацы и допускает «разберём», «сначала проверяем» только рядом с конкретным действием.
- Не используются вводные о «современном мире», обещания универсального решения, SLO, Kubernetes, feature flags, продуктовые метрики или нераскрытый зрелый жаргон.
- В каждой статье есть не менее пяти смысловых разделов, таблица с <code>thead</code> и <code>scope</code>, код, упорядоченный маршрут, один собственный SVG с содержательным <code>alt</code>/<code>figcaption</code>, ограничения и точный заголовок <code>&lt;h2&gt;Проверяемые источники&lt;/h2&gt;</code>.
## 3. Визуал и выпуск — пройдено после локальных проверок
- <code>php-integration-contract-2018.svg</code> объясняет узкий контракт <code>PHPUnit → PDO → test DB → rollback</code>; данные и DDL не показаны как часть одного обратимого действия.
- <code>php-test-boundary-2018.svg</code> контрастно разделяет подменённый репозиторий в unit-тесте и настоящий PDO/cURL-адаптер в integration-тесте. Пунктир отмечает именно границу подмены.
- <code>php-false-green-trace-2018.svg</code> показывает порядок <code>config → PDO → cURL → 202</code> и нижний integration-маршрут с request ID; смысл не зависит только от цвета.
- Все SVG имеют собственные <code>title</code>/<code>desc</code>, вертикальный viewBox <code>720 × 900</code>, контрастный текст и без скриптов, внешних ресурсов или raster-вложений.
### Фактически выполненные команды и доказательства
Выполнены следующие проверки:
node --check web/scripts/upgrade-2018-11.mjs
node web/scripts/upgrade-2018-11.mjs --print-revisions | <JSON parser>
node --input-type=module -e "import('./web/scripts/upgrade-2018-11.mjs').then(...)"
xmllint --noout web/public/assets/editorial/2018/php-*-2018.svg
<standalone structural audit of revisions>
<whitespace audit of the five P10 files>
Результаты:
- <code>node --check</code> завершился с кодом 0.
- Прямой <code>--print-revisions</code> выдал валидный JSON ровно с тремя slug: <code>practice</code>, <code>mechanism</code> и <code>field</code> П10. Import модуля не печатал побочных данных и вернул <code>revisions.length === 3</code>.
- <code>xmllint</code> принял все три SVG. Проверка пяти файлов не нашла строк с хвостовыми пробелами.
- Структурный аудит прошёл: практика — 8 753 знака основного тела и 7 541 знак без кода/источников; механизм — 9 044 и 7 578; поле — 10 956 и 7 900. У каждой ревизии 9 <code>h2</code>, одна схема, таблица, код, упорядоченный маршрут, два или более источника и явный симптом в первых 800 знаках.
- SVG открыты через локальную статическую выдачу на viewport <code>375 × 812</code>. Для каждого <code>clientWidth === scrollWidth === 375</code>; после переделки вертикальная компоновка сохранила читаемые подписи. DOM каждой схемы содержит SVG, но не содержит <code>script</code> или inline event handler.
- В окружении нет PHP CLI: <code>php --version</code> вернул <code>command not found</code>. Поэтому PHP-фрагменты прошли фактологический и ручной синтаксический проход, но не выдаются за запущенные тесты. Для реального прогона нужны отдельные test-only DSN и локальный callback.
После интеграции в registry строгий аудит опубликованного слоя прошёл для
всех трёх slug. Он подтвердил сохранность date/author базового архива,
диапазон 8 753 / 9 044 / 10 956 знаков тела, обязательные figure, таблицы,
код, маршруты и источники. `npm run build` завершился с кодом 0 и
сгенерировал 374 статические страницы.
## 4. Дополнительный выпускной проход — пройдено
Независимый draft-gate выявил, что автономные ревизии не должны переопределять
<code>date</code> и <code>author</code>: эти поля принадлежат базовому архиву и
защищают хронологию и авторство публикации. Из всех трёх exported objects эти
ключи удалены. Сохранены только поля ревизии: <code>slug</code>,
<code>title</code>, <code>categories</code>, <code>cover</code>,
<code>excerpt</code>, <code>contentHtml</code> и <code>readingMinutes</code>.
Повторные результаты:
- <code>npm run audit:draft -- scripts/upgrade-2018-11.mjs</code> завершился с
кодом 0: 8 753 / 9 044 / 10 956 знаков тела и три <code>PASS</code>.
- <code>node --check scripts/upgrade-2018-11.mjs</code> завершился с кодом 0.
- <code>xmllint --noout</code> принял все три SVG.
<code>npm</code> вывел только не блокирующие предупреждения о пользовательских
настройках <code>store-dir</code>, <code>cache-dir</code> и
<code>public-hoist-pattern</code>; сам draft-gate прошёл.
## 5. Выпусковой вердикт
Пакет принят к публикации. У связанного файла ревизий нет права менять
<code>date</code> или <code>author</code>; registry накладывает только
редакционные поля по стабильному slug. PHP-примеры не выдаются за реально
запущенные тесты: ограничение окружения и требование отдельного test-only DSN
остаются явно зафиксированными выше.
+77
View File
@@ -0,0 +1,77 @@
# Декабрь 2018 — тройное ревью и выпускной gate «Рефакторинг Bitrix без большого переписывания»
Статус: **принят в публикационный слой 31 июля 2026 года**. Пакет П11
сохраняет стабильные slug, дату и автора базового архива:
- <code>editorial-2018-12-practice-legacy-refactoring</code>;
- <code>editorial-2018-12-mechanism-legacy-refactoring</code>;
- <code>editorial-2018-12-field-legacy-refactoring</code>.
Созданы только:
- <code>web/scripts/upgrade-2018-12.mjs</code>;
- <code>web/public/assets/editorial/2018/bitrix-legacy-safe-seam-2018.svg</code>;
- <code>web/public/assets/editorial/2018/bitrix-mixed-responsibility-2018.svg</code>;
- <code>web/public/assets/editorial/2018/bitrix-legacy-replacement-rollback-2018.svg</code>;
- этот файл.
Сам П11 не меняет <code>web/data/articles.json</code>: публикационный слой
подключает его отдельным registry только по slug. В рабочем дереве могут
находиться независимые изменения других партий. Дата ревью: 31 июля 2026 года.
## Проход 1. Факты и техника — пройдено
| Утверждение или фрагмент | Первичный источник | Проверенная граница |
| --- | --- | --- |
| <code>CModule::IncludeModule('iblock')</code> возвращает булев результат подключения модуля | [CModule::IncludeModule](https://dev.1c-bitrix.ru/api_help/main/reference/cmodule/includemodule.php) | Во всех примерах это явная проверка перед использованием legacy API; она не выдаётся за настройку прав или окружения |
| <code>CIBlockElement::GetList</code> возвращает выборку по фильтру и допускает выбор полей <code>ID</code>, <code>IBLOCK_ID</code>, <code>CODE</code> | [CIBlockElement::GetList](https://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php) | Повторная выборка проверяет один элемент по ID, а не все ссылки каталога или импорт |
| <code>CIBlockElement::Update</code> возвращает <code>true</code>/<code>false</code>; текст ошибки доступен через <code>LAST_ERROR</code> | [CIBlockElement::Update](https://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/update.php?print=Y) | В примерах передаётся только <code>CODE</code> или <code>NAME</code>; ни один текст не обещает атомарность с HTML, кешем или интеграцией |
| Обработчик <code>OnBeforeIBlockElementUpdate</code> запускается до обновления и может изменить поля либо отменить действие | [OnBeforeIBlockElementUpdate](https://dev.1c-bitrix.ru/api_help/iblock/events/onbeforeiblockelementupdate.php) | Статьи требуют проверить зарегистрированные обработчики на конкретном контуре, а не объявляют результат <code>Update</code> окончательным состоянием всего сайта |
| <code>CUtil::translit</code> принимает язык и параметры регистра, замен и длины | [CUtil::translit](https://dev.1c-bitrix.ru/api_help/main/reference/cutil/translit.php) | Параметры приведены как учебные. Уникальность, старые URL и SEO-правила оставлены за пределами примера |
| Исключение прекращает обычный путь функции до обработчика формы | [PHP Manual — Exceptions](https://www.php.net/exceptions) | Исключение используется только для разделения ошибки входа/Bitrix API и сообщения формы; оно не названо транзакцией нескольких систем |
- Проверены три разных вопроса: защищённый шов одного <code>Update</code>; причина опасного смешения формы, инфоблока и следующего эффекта; контролируемая замена одного legacy-участка с отдельным откатом маршрута и данных.
- PHP-фрагменты написаны в синтаксисе, доступном PHP 7.2. Они являются учебными и воспроизводимыми при наличии Bitrix-окружения, но не выдаются за выполненные в этом workspace: здесь нет ядра Bitrix, test-only данных и доступа к конкретному проекту.
- Удалён не относящийся к тексту источник <code>filter_var</code>; в финальном списке остались только источники, на которые опирается соответствующий материал.
- Массив <code>PROPERTY_VALUES</code> в примеры не добавлен: документация <code>Update</code> требует полного набора свойств при его передаче, а пакет намеренно демонстрирует изменение одного поля.
- Модуль экспортирует ровно три ревизии без файлового ввода-вывода. CLI печатает только JSON при <code>--print-revisions</code>, поэтому импорт скрипта безопасен для будущей интеграции.
## Проход 2. Редактура и голос М1 — пройдено
| Ревизия | Симптом и цена в первых двух абзацах | Один главный вопрос | Артефакт и ограничение |
| --- | --- | --- | --- |
| Практика | После правки карточка теряет привычный URL; цена — 404 и неясный след для шаблона/выгрузки | Как вынести защищённый шов вокруг изменения <code>CODE</code> | <code>ProductCodeWriter</code>, таблица контракта и повторная выборка; не обещаются уникальность, SEO и безопасность всех связей |
| Механизм | Форма показывает ошибку после уже выполненной записи; цена — повтор побочного эффекта и потеря причины | Почему смешение POST, API, HTML и интеграции опасно | Упрощённый <code>save.php</code>, отделённая функция записи и таблица следов; не заявляется транзакция между системами |
| Поле | Вызовы формирования <code>CODE</code> разбросаны; цена — сломанный URL и риск затереть чужое изменение откатом | Как заменить один legacy-участок с проверкой и откатом | Снимок до изменения, явный маршрут writer и сравнение после записи; один элемент не выдаётся за миграцию импорта |
- Автоматический аудит зафиксировал основной объём: **8 837**, **9 492** и **9 445** знаков. Все значения находятся в диапазоне 5 000–15 000; тема П11 также выдерживает плановые 7–9 тыс. близко к середине диапазона без искусственного наполнения.
- В каждой статье есть не менее пяти смысловых <code>h2</code>, таблица с <code>thead</code> и <code>scope</code>, собственный рисунок с содержательными <code>alt</code>/<code>figcaption</code>, код, упорядоченный маршрут, ограничения и точный заголовок <code>&lt;h2&gt;Проверяемые источники&lt;/h2&gt;</code>.
- Тон сохранён для М1 / 2018: короткая цепочка «симптом → причина → проверка → действие», локальные PHP/Bitrix-термины, осторожные выводы. Нет SLO, Kubernetes, feature flags, продуктовых метрик, обещаний «переписать всё» и выдуманных результатов запуска.
- Мобильный проход нашёл слишком мелкие подписи в исходных SVG. Подписи были сокращены до действий и увеличены; развёрнутое объяснение осталось в <code>figcaption</code>, где оно читается без масштабирования схемы.
## Проход 3. Визуал и выпуск — пройдено после исправления подписей
- <code>bitrix-legacy-safe-seam-2018.svg</code> объясняет границу формы, writer, <code>Update(CODE)</code> и повторной выборки; шаблон и интеграция явно остаются снаружи.
- <code>bitrix-mixed-responsibility-2018.svg</code> показывает четыре разных следа <code>save.php</code> и то, что поздний сбой не отменяет раннюю запись автоматически.
- <code>bitrix-legacy-replacement-rollback-2018.svg</code> разделяет откат маршрута и восстановление поля, поэтому диаграмма не предлагает опасное автоматическое перезаписывание данных.
- SVG открыты в браузере на ширине 1 280px и 375px: у всех трёх есть <code>title</code>, <code>desc</code>, <code>role="img"</code>, корректный <code>viewBox</code> и нет горизонтального переполнения. Дополнительно отрендерены в PNG на ширине 375px; после исправления видны заголовки, действия и предупреждение, без обрезанных строк.
- У всех рисунков валидный XML, нет JavaScript, внешних ресурсов и растровых вложений.
### Выполненные проверки
```text
node --check web/scripts/upgrade-2018-12.mjs
node --input-type=module -e "import('./web/scripts/upgrade-2018-12.mjs') ..."
cd web && npm run audit:draft -- scripts/upgrade-2018-12.mjs
xmllint --noout web/public/assets/editorial/2018/bitrix-legacy-safe-seam-2018.svg \
web/public/assets/editorial/2018/bitrix-mixed-responsibility-2018.svg \
web/public/assets/editorial/2018/bitrix-legacy-replacement-rollback-2018.svg
```
После интеграции основной редактор повторно выполнил strict audit: все три
slug прошли требования к структуре, визуалу, таблицам, коду, источникам и
объёму 8 837 / 9 492 / 9 445 знаков тела. <code>npm run build</code>
завершился с кодом 0 и сгенерировал 374 статические страницы.
Выпусковой вердикт: **принят к публикации**. <code>articles.json</code> не
менялся; registry накладывает только редакционные поля по стабильному slug.