# Апрель 2019 — тройное ревью чернового пакета П14 «Валидация форм» Статус: **принят в публикационный слой 31 июля 2026 года**. Registry накладывает три ревизии по стабильным slug, не меняя дату и автора исходных публикаций: - editorial-2019-04-practice-forms-validation; - editorial-2019-04-mechanism-forms-validation; - editorial-2019-04-field-forms-validation. Созданы только: - web/scripts/upgrade-2019-04.mjs; - web/public/assets/editorial/2019/forms-validation-contract-2019.svg; - web/public/assets/editorial/2019/forms-validation-state-machine-2019.svg; - web/public/assets/editorial/2019/forms-validation-late-response-2019.svg; - этот файл. Все три ревизии намеренно не содержат date или author: эти поля остаются у исходных записей архива. Модуль экспортирует ровно три ревизии. При прямом вызове с --print-revisions он пишет только JSON; --run-fixture отдельно запускает учебную модель обратного порядка ответов. ## Проход 1. Факты и техника — пройдено | Утверждение или решение | Первичный источник | Проверенная граница | | --- | --- | --- | | Нативные ограничения формы и validity — ранняя проверка интерфейса | [HTML Standard: Constraint Validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) | Тексты не называют checkValidity() проверкой занятости, прав или защитой API; сервер остаётся источником бизнес-условия | | Нативная отправка формы — отдельный алгоритм браузера | [HTML Standard: form submission](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm) | Локальные правила не выдаются за замену серверной проверки и защиты от прямого запроса | | aria-describedby ссылается на описывающие элементы по ID | [WAI-ARIA 1.1: aria-describedby](https://www.w3.org/TR/wai-aria-1.1/#aria-describedby) | В примерах label остаётся нативным, а подсказка и ошибка имеют устойчивые ID; ARIA не используется вместо input/label | | aria-errormessage применяется вместе с aria-invalid, а релевантное сообщение не прячется | [WAI-ARIA 1.1: aria-errormessage](https://www.w3.org/TR/wai-aria-1.1/#aria-errormessage) | Примеры выставляют invalid только в ошибке и показывают видимый текст; они не обещают одинаковое озвучивание во всех браузерах и скринридерах | | AbortController создаёт signal и может сигнализировать abort | [DOM Standard: AbortController](https://dom.spec.whatwg.org/#abortcontroller) | Отмена названа оптимизацией транспорта. Корректность UI обеспечивается сравнением версии, даже если abort не дошёл до транспорта | | Fetch работает с моделью запроса/ответа и signal при поддержке клиента | [Fetch Standard](https://fetch.spec.whatwg.org/) | В статье нет обещания, что любой адаптер или legacy-клиент отменяется одинаково; запросы проверяются по актуальности после ответа | - Главная техническая гипотеза проверена автономным fixture, а не словами: запрос ivan с requestId: 1 отвечает позже запроса ivanka с requestId: 2. Результат прогона: ```json { "results": [ { "requestId": 1, "applied": false, "ignored": "stale-response" }, { "requestId": 2, "applied": true, "phase": "valid" } ], "finalState": { "value": "ivanka", "requestId": 2, "phase": "valid", "fieldError": "" } } ``` - Fixture проверяет только порядок и правило requestId. Он не подаётся как результат Network, браузерной трассы, screen reader или production API. Для настоящего экрана статьи оставляют честный маршрут: проверить клавиатуру и Accessibility tree после интеграции. - Контракт fields.email/fields.login явно назван локальным договором приложения, а не обязательным полем HTML или WAI-ARIA. Неизвестный ключ уходит в безопасный общий путь и требует согласования. - Асинхронная проверка не объявлена окончательным резервированием логина: сервер повторяет условие при сохранении, потому что между pre-check и POST другой запрос может занять значение. ## Проход 2. Редактура и голос М2 / 2019 — пройдено | Ревизия | Симптом и цена в начале | Главный технический вопрос | Артефакт и ограничение | | --- | --- | --- | --- | | Практика | Браузер сделал почту зелёной, API отказал; текст может потеряться в общем баннере | Как разделить HTML-ограничение, API-контракт и рендер поля | Карта ответственности, ответ fields, доступная разметка и маршрут внедрения; не обещается единый валидатор для всех форм | | Механизм | isValid и error не объясняют промежуточную фазу и старый ответ | Какие фазы и переходы принадлежат одному полю | Таблица автомата, version guard, fixture и ожидаемые a11y-инварианты; не заявляется универсальная поддержка всех transport-слоёв | | Полевой разбор | Медленный ответ «ivan занят» стирает корректное состояние ivanka | Где сохранять право ответа менять UI и куда ставить ошибку | Временная диаграмма, контрпример и requestId; Accessibility tree описано как план проверки, не как проведённый прогон | - Автор остаётся на правдоподобном уровне 2019 года: JavaScript-модули, форма, API-контракт, Fetch и базовая доступность. Нет поздних SLO, распределённой трассировки, feature flags, продуктовых метрик или позиции техлида крупной платформы. - Каждая статья держит цепочку «симптом → причина → проверка → действие → ожидаемый результат → ограничение». Вместо общих фраз названы объект, версия, ключ поля, видимый error-контейнер и условие сравнения. - Автоматический draft gate зафиксировал объём основного тела **11 707**, **12 082** и **10 685** знаков. Все значения находятся в требуемом диапазоне 5 000–15 000 без включения title, meta и раздела источников. - Во всех трёх статьях есть не менее пяти h2, доступная таблица с caption/thead/scope, собственная схема с содержательными alt и figcaption, воспроизводимый код, упорядоченный маршрут и не менее двух первичных источников. ## Проход 3. Визуал и выпуск — пройдено в пределах автономного пакета - forms-validation-contract-2019.svg отделяет HTML-ограничение, клиентское состояние и проверку API. Нижняя обратная стрелка явно называет правило: старый requestId не меняет новое поле. - forms-validation-state-machine-2019.svg показывает допустимые фазы одного input и две пунктирные ветви нового input, которые очищают старую remote-error. Отдельный зачёркнутый путь показывает устаревший ответ. - forms-validation-late-response-2019.svg фиксирует временной порядок t0–t3: быстрый requestId 2 применяется, а поздний requestId 1 отклоняется. Схема не подменяет fixture, а делает условие render читаемым. - В каждом SVG есть title, desc, role="img", единый вертикальный viewBox, нет JavaScript, внешних URL или растровых вложений. Подписи сокращены до действия, развёрнутое объяснение вынесено в figcaption статьи. - Этот проход не утверждает, что SVG открывали в конкретном браузере или что снимали фактический Accessibility tree. Он проверяет XML, структурную мобильную пригодность viewBox и связь каждой схемы с объяснением. Браузерный рендер и проверка на реальном экране остаются выпускными действиями после интеграции, а не придуманным доказательством черновика. ### Выполненные проверки ```text node --check web/scripts/upgrade-2019-04.mjs cd web && npm run audit:draft -- scripts/upgrade-2019-04.mjs node web/scripts/upgrade-2019-04.mjs --run-fixture xmllint --noout web/public/assets/editorial/2019/forms-validation-contract-2019.svg \ web/public/assets/editorial/2019/forms-validation-state-machine-2019.svg \ web/public/assets/editorial/2019/forms-validation-late-response-2019.svg ``` Результат: все автономные команды завершились с кодом 0; draft gate прошёл для трёх стабильных slug. После подключения registry основной редактор повторил strict audit: 11 707 / 12 082 / 10 685 знаков, figure, таблицы, код, маршруты и источники прошли. npm run build завершился с кодом 0 и сгенерировал 374 статические страницы. Выпусковой вердикт: **принят к публикации**. articles.json не менялся; registry заменяет только редакционные поля по стабильному slug.