На 31 июля 2026 года строгий аудит проходит 145 из 358 созданных материалов. Остальные 213 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
На 31 июля 2026 года строгий аудит проходит 148 из 358 созданных материалов. Остальные 210 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
<code>readingMinutes</code> и <code>contentHtml</code>. Полей
<code>date</code> и <code>author</code> нет: их сохраняет базовый архив.
<code>--print-revisions</code> печатает тот же JSON, что и import-safe export;
draft gate проверил это сравнением.
## Проход 1. Голос, структура и объём — пройдено
| Revision | Проблема и цена в первых двух абзацах | Главный вопрос | Body |
| --- | --- | --- | ---: |
| Практика | На пути оформления маленькие изменения проходят общий PASS, а часть пути постепенно съедает запас; цена — зелёный сигнал без владельца изменения | Как зафиксировать route, conditions, allocation и named component rule до сравнения candidate | **9 995** |
| Механизм | Total PASS принимают за доказательство здоровья пути; цена — budget превращается в таблицу, которая не запрещает частную регрессию | Почему contract, snapshot, component checks, aggregate и diagnosis имеют разные роли | **9 989** |
| Полевой разбор | Total остаётся зелёным, а один component красный; цена — накопление диагностического долга и широкие правки по одной строке | Как остановить несопоставимое сравнение и сузить следующий факт до одного component и одной boundary | **9 949** |
- Все тексты находятся в требуемом П48 коридоре **7–10 тыс.** и обязательном
диапазоне 5–15 тыс. знаков body.
-В каждом revision: девять или больше смысловых <code>h2</code>, accessible
table с <code>caption</code>/<code>thead</code>, свой figure с точным
<code>alt</code>/<code>figcaption</code>, несколько согласованных
JavaScript examples, нумерованный маршрут и раздел
«Проверяемые источники» с тремя official URLs.
- Голос соответствует М5 / февралю 2022: текст начинает с конкретного
пользовательского пути, говорит коротко «симптом → причина → проверка →
действие», а архитектурный вывод появляется только после описанного
наблюдения. Нигде не приписывается существующая production-команда, CI,
Chrome trace, LCP, real-user metric или SLA.
- В первой ручной вычитке draft gate обнаружил, что у практической статьи
формальное слово «проблема» находилось позже первых 800 знаков. Первый
абзац переписан как «Проблема начинается…»; повторный audit прошёл.
Вердикт прохода: **пройден**. Тексты не растягивают один вывод: каждый
переходит от contract к snapshot, compare, ограниченной диагностике и
проверке следующего изменения.
## Проход 2. Fixture и техническая согласованность — пройдено
<code>createTeachingBudget()</code> и
<code>runPerformanceBudgetFixture()</code> работают только с frozen plain
objects и arrays в памяти. Условный navigation workload имеет route
<code>/training/checkout/review</code>, scenario
<code>anonymous-cart-with-one-item</code> и четыре собственных поля:
11. diagnosis ведёт к focused action, а не global conclusion;
12. учебная арифметика totals согласована;
13. неизвестное или отрицательное поле не проходит validation;
14. fixture не выполняет external observation;
15. повторное сравнение детерминировано.
Проверены по два code fragments в каждом тексте: practice читает
<code>baselineComparison</code>/<code>candidateComparison</code> и guard для
first failure; mechanism создаёт baseline/candidate и отдельный condition
mismatch; field читает <code>diagnosis</code>/<code>measurementConditions</code>
и повторно проверяет границу scope. Ни один snippet не обращается к
несуществующему export или полю.
Вердикт прохода: **пройден**. Модель доказывает только собственный контракт:
component rule сильнее aggregate, tolerance и conditions видимы, а failure
создаёт ограниченную следующую проверку. Она не вычисляет реальную скорость.
## Проход 3. Исторические источники и визуал — пройдено
| Источник | Историческая рамка | Что разрешено использовать | Что текст не утверждает |
| --- | --- | --- | --- |
| [W3C Navigation Timing Level 2, 17 Jan 2022](https://www.w3.org/TR/2022/WD-navigation-timing-2-20220117/) | опубликован до всех дат февраля 2022 | существование <code>PerformanceNavigationTiming</code> и navigation timing information | что fixture fields являются platform timing fields |
| [W3C User Timing Level 3, 13 Sep 2021](https://www.w3.org/TR/2021/WD-user-timing-3-20210913/) | существовал до февраля 2022 | исторические mark/measure и metadata terminology | что package записывает mark, measure или browser timestamp |
| [W3C Performance Timeline Level 2, 19 Aug 2021](https://www.w3.org/TR/2021/WD-performance-timeline-2-20210819/) | существовал до февраля 2022 | historical meaning of performance entries and retrieval | что CI PASS, budget allocation или ticks определены W3C |
Все три источника — датированные W3C working drafts; в текстах это прямо
названо. Использованы только как историческая рамка официальных platform
interfaces. В пакете нет поздних interaction metrics, future INP, current-only
Lighthouse recommendations или придуманной метрики Chrome/пользователя.
SVG прошли mobile-first проверку:
- <code>performance-budget-allocation-2022.svg</code> показывает четыре
named checks, explicit limit+tolerance, aggregate PASS и overall FAIL в
одной вертикальной композиции;
- <code>performance-budget-trend-2022.svg</code> сравнивает baseline и
candidate для total и <code>scriptTicks</code>, не называя ticks
browser result;
- <code>performance-budget-diagnosis-2022.svg</code> показывает stop при
condition mismatch, порядок component → aggregate и focused action.
У каждого SVG есть <code>title</code>, <code>desc</code>,
<code>role="img"</code>, контрастные labels и viewBox для узкого экрана.
В XML нет <code>script</code>, <code>foreignObject</code>, external
<code>href</code>/<code>src</code> и raster data URI.
| <code>xmllint --noout</code> | PASS, все три SVG — корректный XML |
| SVG safety scan | PASS: совпадений нет; <code>rg</code> завершился с code 1, что для поиска означает ожидаемый пустой результат |
| Sharp 375 px | PASS: все три SVG отрендерены в PNG и вручную просмотрены; headings, cards, arrows, labels и нижние ограничения читаемы, clipping/overlap/horizontal overflow не обнаружены |
| Scope/self-review | PASS: созданы только пять разрешённых P48 файлов; shared registry, README, base archive, queue, Git и чужие mascot PNG не затронуты |
<code>npm run audit:draft</code> завершилась с code 0. npm вывел уже
существующие предупреждения о <code>store-dir</code>, <code>cache-dir</code>
и <code>public-hoist-pattern</code>; они не относятся к П48 и не менялись.
Не запускались strict audit после registry integration, production build,
browser or screen-reader test, Lighthouse, Chrome, реальный CI job, network
workload, trace, RUM, commit или публикация. Визуальная проверка относится к
локальному Sharp render 375 px, а не к фактическому browser layout. Это
намеренные ограничения автономной партии.
## Итог
Три прохода завершены. Один дефект формальной постановки проблемы найден и
исправлен до финального audit. П48 готова к независимой приёмке: следующие
шаги интегратора — отдельно проверить фактический mapping реального проекта,
подключить overlay и только затем запускать strict audit/build/publish.
## Независимое редакторское ревью и интеграция
Статус: **принято и подключено в editorial overlay 31 июля 2026 года**.
### 1. Факты и техника
- Источники закреплены на датированных W3C Working Draft: Navigation Timing
Level 2 от 17 января 2022, User Timing Level 3 от 13 сентября 2021 и
Performance Timeline Level 2 от 19 августа 2021. Они поддерживают только
исторический словарь platform timing interfaces; поля
<descid="desc">Вертикальная схема показывает четыре именованные части учебного маршрута checkout review. Baseline укладывается в каждый limit с tolerance. Candidate превышает allowed у scriptTicks, хотя его общий total остаётся в aggregate allowed. Значения подписаны как teaching ticks, а не как браузерная метрика.</desc>
<defs>
<style>
.bg { fill: #f8fafc; }
.title { fill: #102a43; font: 700 25px Arial, sans-serif; }
<titleid="title">Диагностический маршрут для budget comparison</title>
<descid="desc">Схема начинается с проверки route, scenario и declared conditions. При несовпадении comparison останавливается. При совпадении сначала проверяются именованные компоненты, затем aggregate. scriptTicks 34 при allowed 30 ведёт к focused action, хотя total 93 при allowed 98 остаётся aggregate pass.</desc>
<defs>
<style>
.bg { fill: #f8fafc; }
.title { fill: #102a43; font: 700 25px Arial, sans-serif; }
<titleid="title">Baseline и candidate в учебном сравнении бюджета</title>
<descid="desc">Диаграмма сравнивает baseline и candidate по total и scriptTicks. Total candidate 93 остаётся ниже aggregate allowed 98, а scriptTicks candidate 34 превышает component allowed 30. Поэтому итоговый verdict — named component fail, не глобальная оценка производительности.</desc>
<defs>
<style>
.bg { fill: #f8fafc; }
.title { fill: #102a43; font: 700 25px Arial, sans-serif; }
note:'исторический снимок W3C, существовавший до февральских дат публикации. Он описывает интерфейс PerformanceNavigationTiming и временную шкалу навигации; учебные поля fixture не являются его полями.',
};
constuserTimingDraft={
title:'W3C User Timing Level 3, Working Draft от 13 сентября 2021 года',
note:'исторический W3C draft о mark и measure. Он позволяет говорить о названных точках и измерениях, но не задаёт наш допуск и не превращает ticks fixture в данные браузера.',
};
constperformanceTimelineDraft={
title:'W3C Performance Timeline Level 2, Working Draft от 19 августа 2021 года',
note:'исторический W3C draft о хранении и получении performance entries. Он не определяет правило CI PASS, бюджет маршрута или интерпретацию учебных чисел.',
excerpt:'Практический маршрут: описать один пользовательский путь, зафиксировать условия и baseline, сравнить candidate по именованным частям и получить действие вместо общего PASS.',
readingMinutes:11,
},
[
paragraph('Проблема начинается на странице оформления: пользователь ждёт, пока станет доступен следующий шаг. Изменения приходят маленькими: новый код, стиль, виджет, правило рендера. Каждое по отдельности проходит общий check. Через несколько релизов путь стал тяжелее, но CI всё ещё отдаёт зелёный PASS. Цена такого сигнала проста: он говорит, что не пересечён порог, но не говорит, какая часть пути забрала запас и где искать изменение.'),
paragraph('Не надо отвечать на это обещанием «ускорить сайт». Сначала нужен один воспроизводимый контракт для конкретного пути: route, сценарий, условия наблюдения, snapshot и именные части бюджета. Тогда проверка отвечает на скромный вопрос: candidate остаётся внутри заранее названного допуска или нет. Она не выдаёт учебный расчёт за браузерный trace, реальную пользовательскую метрику, SLA или результат существующего CI.'),
heading('Начинаем с пути, а не с общей оценки'),
paragraph('Бюджет полезен только у входа, который можно назвать. В fixture это <code>/training/checkout/review</code> и сценарий <code>anonymous-cart-with-one-item</code>. Название намеренно длиннее слова «главная»: при другом товаре, авторизации, locale или feature flag это уже может быть другой вход. Если один job смешивает такие варианты, изменение в одном из них способно спрятаться за средним числом другого.'),
paragraph('Дальше фиксируются условия. В учебной модели это version workload, единица <code>teaching-ticks</code>, а browser observation, CI observation, сеть, CPU, cache и trace имеют значение <code>not-collected</code> или <code>not-modelled</code>. Эти поля не делают проверку слабой. Они запрещают дорисовать доказательство задним числом: пока нет trace, нельзя из суммы ticks сделать вывод о браузере; пока нет CI run, нельзя назвать fixture результатом pipeline.'),
dataTable(
'Контракт учебного бюджета одного пользовательского пути',
['Элемент','Что хранит fixture','Для чего нужен','Чего не доказывает'],
[
['Route и scenario','<code>/training/checkout/review</code>, одна корзина','не смешать разные входы','что путь уже прошёл в production'],
['Условия','version workload, ticks, <code>not-collected</code>','остановить сравнение при другой среде','свойства браузера или CI runner'],
['Компоненты','<code>documentTicks</code>, <code>styleTicks</code>, <code>scriptTicks</code>, <code>renderTicks</code>','увидеть вклад по частям','стандартные Web Vitals'],
['Допуск','limit плюс tolerance у каждого имени','сделать правило явным','универсальную норму для любого продукта'],
['Aggregate','вторичный total guard','увидеть суммарный запас','право скрыть failed component'],
],
),
heading('Разделите запас до того, как появится candidate'),
paragraph('Слово «бюджет» часто превращают в одну сумму. Для пользовательского пути это недостаточно. Один общий предел замечает только итог, а не перенос затрат между частями. В fixture у <code>scriptTicks</code> limit равен <code>28</code> и tolerance равен <code>2</code>; значит допустимо до <code>30</code>. У total limit <code>95</code> и tolerance <code>3</code>. Эти числа условны. Их смысл не в удачном размере, а в том, что limit и допуск существуют отдельно и печатаются в результате проверки.'),
paragraph('Почему допуск не стоит прятать в комментарии? Потому что без него нельзя понять, какой сдвиг команда заранее согласилась игнорировать и в каких условиях. Если tolerance нужен из-за нестабильности настоящего замера, эта нестабильность должна быть описана в measurement contract. В fixture она не измеряется: поэтому допуск — проектное правило учебного объекта, не статистическая модель и не утверждение о дисперсии браузера.'),
'Вертикальная схема учебного бюджета пути checkout review: четыре именованные части document, style, script и render имеют свои limit и tolerance. Baseline укладывается во все части, candidate превышает допустимый scriptTicks, хотя общий total остаётся в пределах вторичного порога.',
'Распределение показывает порядок проверки: сначала сравниваются именованные части с явным допуском, затем читается общий total. Зелёная сумма не отменяет красный component check.',
),
heading('Snapshot и candidate должны быть сопоставимы'),
paragraph('Snapshot — не «последний хороший отчёт». Это сохранённый объект с route, scenario, conditions и четырьмя учебными полями. Baseline в fixture содержит <code>24, 15, 26, 20</code>; candidate меняет только <code>scriptTicks</code> на <code>34</code>. Сумма candidate равна <code>93</code>, поэтому aggregate остаётся PASS до allowed <code>98</code>. Но component rule разрешает максимум <code>30</code>, и общий результат обязан быть FAIL. Именно это защищает от красивой, но бесполезной зелёной суммы.'),
codeBlock(practiceExample),
paragraph('Код не вызывает Lighthouse, Chrome, PerformanceObserver или сетевой запрос. Он не получает timestamps. Его роль — зафиксировать invariant модели: named component сильнее aggregate. В рабочем проекте аналогичный object можно заполнить данными выбранного теста, но только после того, как команда назвала источник, версию инструмента, контролируемые условия и смысл каждого поля. Подмена этих границ «примерным CI» создаёт ту же ложную уверенность, от которой пытаемся уйти.'),
codeBlock(practiceGuardExample),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> Общая проверка стабильно зелёная, но конкретный пользовательский путь постепенно меняется и становится труднее объяснить.',
'<strong>Причина.</strong> Aggregate объединяет части пути и не показывает, какая из них съела запас; baseline и candidate могут быть собраны при разных условиях.',
'<strong>Проверка контракта.</strong> Назовите route, сценарий, version workload, единицу, наличие или отсутствие browser/CI observation. Если conditions отличаются, не сравнивайте числа.',
'<strong>Проверка snapshot.</strong> Сохраните baseline с именованными полями. У каждого поля должны быть limit, tolerance и owner, а не только одна сумма в документации.',
'<strong>Проверка candidate.</strong> Сначала прочитайте <code>componentChecks</code>, затем aggregate. В fixture <code>scriptTicks</code> = 34 больше allowed 30, даже когда total 93 меньше aggregate allowed 98.',
'<strong>Действие.</strong> Откройте один input и одну границу, принадлежащую failed component. Для <code>scriptTicks</code> fixture возвращает <code>inspect-script-input-and-one-route-boundary</code>; не начинайте глобальную оптимизацию без дополнительного факта.',
]),
heading('Как превратить модель в проверку без ложного PASS'),
paragraph('В проекте порядок важнее выбора файла. Сначала profile route в контролируемых условиях: один вариант сценария, одна версия приложения, явно записанная конфигурация измерения. Затем сохранить snapshot вместе с conditions. Только после этого compare candidate. И уже после compare назначить focused action. Если начать с порога в CI, получится gate без смысла: он может зелёнеть, потому что route заменили, cache стал другим или в результаты попала другая часть опыта.'),
heading('Что происходит при несовпадении условий'),
paragraph('Fixture создаёт также candidate с изменённым условием cache. У него не появляется новый PASS или FAIL по компонентам: comparison останавливается как <code>measurement-contract-invalid</code>. Это сознательное поведение. Сравнение разных условий не становится корректным от того, что оба объекта содержат числа. Сначала восстановите один scenario и controlled conditions, затем снова снимите candidate. Так в отчёте остаётся отдельная категория «данных для вывода нет», а не случайный технический verdict.'),
paragraph('Эта ветка особенно полезна для CI. У pipeline может быть хороший сигнал о том, что script завершился успешно, но этот факт не тождественен сопоставимому performance observation. Не нужно обесценивать CI: ему следует отдать узкое правило, которое он действительно проверяет. Например, сравнение serialized snapshot с candidate по одному маршруту. Но browser trace, real-user data и service-level решение остаются другими артефактами и требуют собственных условий.'),
heading('Факт платформы и учебная модель'),
paragraph('Исторический W3C Navigation Timing Level 2 от 17 января 2022 года описывает <code>PerformanceNavigationTiming</code> и timing information navigation. User Timing Level 3 от сентября 2021 года описывает именованные marks и measures. Performance Timeline Level 2 от августа 2021 года описывает хранение и получение performance entries. Это официальные смыслы платформенных интерфейсов, а не источник наших <code>documentTicks</code> и <code>scriptTicks</code>.'),
paragraph('Модель пакета намеренно уже: она учит не считать скорость, а правильно оформлять сравнение. Ее output можно читать как «в этих условных входах named rule нарушен». Из него нельзя получить LCP, TTFB, браузерный waterfall, real-user result, количество пользователей или SLA. Для фактической интеграции сначала сопоставьте реальные поля с официальной документацией используемого инструмента и добавьте отдельный тест на mapping.'),
heading('Критерий готовности и ограничение'),
paragraph('Работа закончена не при первом зелёном total. Готовность для одного budget change выглядит так: route и scenario названы; conditions сохранены; baseline и candidate имеют один schema; каждый component имеет limit/tolerance; failed component даёт bounded diagnosis; следующий шаг ограничен одной границей. Затем выбранное изменение проверяется повторно в тех же условиях. Если conditions уже другие, это новая карточка сравнения, а не повод переписать baseline.'),
paragraph('Fixture проверяет пятнадцать собственных assertions, включая baseline PASS, named failure candidate, явные tolerances, невозможность aggregate скрыть component, остановку при condition mismatch и отсутствие внешнего наблюдения. Это регрессия контракта текста и кода. Она не заменяет профиль настоящего route, потому что настоящий профиль остаётся отдельной инженерной работой с отдельной средой и доказательством.'),
heading('Историческая граница февраля 2022'),
paragraph('Статья ограничена документами, опубликованными не позднее января 2022 года. W3C sources ниже — рабочие drafts, а не современная рекомендация и не набор новых показателей. Здесь нет поздних метрик взаимодействия, нет текущих советов Lighthouse и нет заявлений об измеренном продукте. Это сохраняет честную дистанцию между исторической рамкой, официальным API и нашей учебной схемой бюджета.'),
excerpt:'Причинная модель бюджета пути: от controlled conditions и snapshot к component checks, aggregate и ограниченной диагностике без подмены учебного расчёта browser trace.',
readingMinutes:12,
},
[
paragraph('Проблема появляется, когда общий PASS считают доказательством неизменности пути. Путь может получить лишнюю работу в одной части и сохранить приемлемую общую сумму. Цена — неверный выбор действия: команда смотрит на score или total, не видит сдвиг в компоненте и начинает менять всё подряд. Через несколько таких проверок бюджет превращается в табличку, которая ничего не запрещает.'),
paragraph('Причина не в том, что aggregate бесполезен. Он отвечает на другой вопрос: не вышла ли общая учебная сумма за свой предел. Бюджет пути отвечает сначала на вопрос о каждой именованной части и только потом о сумме. Чтобы ответ был воспроизводимым, рядом нужны controlled conditions, baseline snapshot, candidate и явный tolerance. Ни одно из этих слов не означает реальный browser observation: fixture строит только локальные objects с условными ticks.'),
heading('Четыре слоя одной проверки'),
paragraph('Первый слой — measurement contract. Он связывает route, user scenario, version workload и условия. Второй — snapshot baseline, который описывает известный вход именно в этом contract. Третий — component checks: каждый field сравнивается со своим limit плюс tolerance. Четвёртый — decision. Overall FAIL появляется, если хотя бы один named component не проходит; aggregate остаётся вторичным guard. Это простое правило убирает самую частую лазейку: «total зелёный, значит можно не смотреть красную строку». '),
paragraph('В fixture четыре поля называются <code>documentTicks</code>, <code>styleTicks</code>, <code>scriptTicks</code> и <code>renderTicks</code>. Они не названы <code>LCP</code>, <code>TTFB</code> или browser event, потому что не получены из браузера. Это project vocabulary учебной модели. Если настоящий проект берёт browser field, его официальное значение, supported browser и сбор нужно описать отдельно. Нельзя взять знакомое имя метрики и приклеить его к произвольному object только ради убедительного отчёта.'),
['Contract','route, scenario, declared conditions','comparable / invalid','любое несовпадение останавливает compare','«числа сами по себе сопоставимы»'],
['Snapshot','baseline timingFields','точка отсчёта','хранит тот же schema','«последний отчёт всегда baseline»'],
['Component','candidate field и limit+tolerance','pass/fail по имени','каждый field виден отдельно','«общая сумма лечит частный fail»'],
['Aggregate','сумма fields и total rule','вторичный pass/fail','читается после component','«PASS total доказывает путь»'],
['Diagnosis','failed named component','one bounded next action','не расширяет scope без факта','«найдена глобальная причина скорости»'],
],
),
heading('Допуск — часть контракта, а не скрытая скидка'),
paragraph('Если limit равен 28, а tolerance равен 2, то allowed равен 30. Такой расчёт должен быть виден в output, иначе reviewer не может отличить осознанный допуск от опечатки или смены правила. В fixture candidate имеет <code>scriptTicks: 34</code>. Он превышает allowed на четыре tick. Отдельное поле <code>deltaFromLimit</code> равно шести, потому что описывает расстояние до базового limit, а не до порога с допуском. Оба числа нужны, если заранее объяснить их смысл.'),
paragraph('Допуск нельзя переводить в процент без контекста. У одной части пути абсолютное изменение может быть осмысленным, у другой — нет. Настоящий способ выбрать tolerance зависит от источника наблюдения, повторов, среды и стоимости ложного FAIL. Учебная fixture не знает ни одной из этих вещей. Поэтому она не предлагает «правильные 2 ticks», а требует явного поля. Реальная команда добавляет обоснование рядом со своим mapping и не переносит учебные значения в конфигурацию молча.'),
heading('Почему линия aggregate может оставаться зелёной'),
paragraph('Baseline fixture суммируется до 85 ticks. Candidate суммируется до 93. Aggregate allowed равен 98, поэтому aggregate status — PASS. Однако рост находится в <code>scriptTicks</code>: baseline 26, candidate 34, allowed 30. Эта комбинация сделана специально. Если result позволил бы overall PASS, потому что 93 меньше 98, budget не защищал бы контракт пользователя: он прятал бы изменение в самой части, для которой владелец и limit были заведены.'),
'Сравнительная диаграмма baseline и candidate учебного маршрута: total растёт с 85 до 93 и остаётся ниже aggregate allowed 98, но scriptTicks растёт с 26 до 34 и превышает allowed 30. Итоговый verdict показан как fail по named component, а не как глобальная оценка скорости.',
'Линия aggregate нужна для контекста, а не для отмены component failure. На схеме значения подписаны как teaching ticks и отделены от браузерных метрик.',
),
heading('Механизм сравнения в одном объекте'),
codeBlock(mechanismExample),
paragraph('Функция <code>compareRouteWorkload</code> сначала вызывает validation для baseline и candidate. Она проверяет, что все четыре поля существуют, лишних нет, значения неотрицательные, route и scenario совпадают с contract, а conditions равны. Только после этого она строит component checks. Если conditions отличаются, component map пуст, aggregate становится <code>not-comparable</code>, а overall получает <code>measurement-contract-invalid</code>. Это предотвращает тихое смешение «до» и «после». '),
codeBlock(mechanismContractExample),
paragraph('Этот fragment не пытается «нормализовать» изменённый cache. Он оставляет compare недоступным, пока не восстановлен один declared contract. Так разница условий не превращается в число, которому дают performance-смысл.'),
heading('Сначала observation, потом архитектурный вывод'),
paragraph('M5-подход начинается с пользовательского сценария и заканчивается небольшим изменением, а не с тезиса «пакет тяжёлый». Candidate failure говорит только: в declared teaching model field <code>scriptTicks</code> больше allowed. Из этого нельзя вывести, что виновата конкретная библиотека, загрузчик, server response или пользовательское устройство. Чтобы назвать причину, нужно собрать следующий наблюдаемый артефакт на одной границе: dependency list, bundle diff, route trace или профиль — в зависимости от того, что реально доступно.'),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> В отчёте есть общий PASS, но изменения одной части пути продолжают накапливаться без понятного владельца.',
'<strong>Причина.</strong> Aggregate использовали как final verdict, хотя он не хранит распределение и может пройти при failed component.',
'<strong>Проверка contract.</strong> Сверьте route, scenario и все declared conditions baseline/candidate. Изменился хотя бы один обязательный элемент — верните <code>not-comparable</code>.',
'<strong>Проверка allocation.</strong> Для каждого component покажите actual, limit, tolerance, allowed и owner. Отдельно посчитайте total, но не смешивайте его с verdict component.',
'<strong>Проверка decision.</strong> Overall PASS допустим только когда все names PASS. Overall FAIL обязан перечислить failed component, даже если aggregate остаётся зелёным.',
'<strong>Действие.</strong> Возьмите первую failed name и сузьте следующую проверку до одного input и одной route boundary. Зафиксируйте, какой дополнительный факт нужен до архитектурного изменения.',
]),
heading('Откуда взять настоящие поля и где не подменять их'),
paragraph('Navigation Timing Level 2 уже к январю 2022 года описывал navigation timing information и <code>PerformanceNavigationTiming</code>. User Timing Level 3 описывал named marks/measures и их metadata. Performance Timeline Level 2 описывал получение entries. Эти документы полезны, когда проект выбирает platform source. Они не предлагают готовый budget для checkout, не говорят, что total должен быть 95, и не определяют связь наших четырех ticks с полями API.'),
paragraph('Поэтому корректная интеграция начинается с mapping-table. В ней для каждого production field указывают источник, version, значение, условия доступности, преобразование и owner. Затем отдельно документируют runner и repeatability. Пока этого нет, честнее оставить language учебным: <code>teaching-ticks</code>, <code>not-collected</code>, <code>not-modelled</code>. Это не уклонение от работы; это защита от визуально похожих, но невалидных цифр.'),
heading('Граница CI и browser observation'),
paragraph('CI может исполнить compare и упасть по возвратному коду. Но факт исполнения job не создаёт browser observation. Browser observation может быть полезным входом в budget, если его получали по определённому протоколу и сохранили вместе с conditions. У fixture оба значения прямо равны <code>not-collected</code>. Так output не позволяет сказать «CI замерил маршрут» или «Chrome подтвердил результат». '),
heading('Критерий корректной эволюции бюджета'),
paragraph('Budget change корректен, если меняется одна известная вещь: новый route scenario, новый component, limit/tolerance или способ получения поля. В каждом случае обновляется contract и baseline, а причина изменения остаётся рядом. Неправильно просто повысить общий total, когда <code>scriptTicks</code> красный: это снимает симптом, но не говорит, согласен ли владелец пути на более дорогую часть. Иногда повышение оправдано, но оно должно быть отдельным решением со стоимостью и ограничением.'),
paragraph('В fixture есть пятнадцать assertions: baseline проходит каждый named budget; candidate падает по <code>scriptTicks</code>; aggregate PASS не скрывает failure; tolerances явны; conditions несовместимы блокируют compare; diagnosis ограничена одним component; никаких browser, CI, trace или network observations не выполняется. Это техническая проверка нашей модели. Она не измеряет реальную страницу и не должна использоваться как её заменитель.'),
heading('Историческая граница февраля 2022'),
paragraph('Все ссылки ниже существовали до февраля 2022 года: Navigation Timing draft от 17 января 2022 года, User Timing draft от сентября 2021-го и Performance Timeline draft от августа 2021-го. Они процитированы как historical sources и сами обозначены W3C как working drafts. В статье нет поздних interaction metrics и нет современных рекомендаций, появившихся после этой рамки. Технический вывод относится только к структуре учебного comparison.'),
excerpt:'Полевой маршрут для случая, когда aggregate остаётся PASS, а named component превышает допуск: проверить contract, сохранить факт и выбрать одно ограниченное действие без глобального performance verdict.',
readingMinutes:11,
},
[
paragraph('На пользовательском пути есть неприятный случай: общий total остаётся зелёным, но одна именованная часть пересекает свой допуск. Его легко списать как «небольшое колебание», особенно если pipeline не упал. Цена такого решения — диагностический долг. Следующее изменение добавит ещё немного работы, а у команды останется только общий график и спор о том, когда именно путь начал меняться.'),
paragraph('Нужно не искать виноватого по одной строке, а правильно ограничить вывод. В учебной fixture candidate имеет total 93 при aggregate allowed 98, но <code>scriptTicks</code> равен 34 при allowed 30. Этот факт достаточен, чтобы заблокировать contract test, и недостаточен, чтобы объявить глобальную деградацию, проблему браузера, user metric или SLA. Хороший диагностический маршрут оставляет оба предложения рядом.'),
heading('Сначала отделите три разных состояния'),
paragraph('Первое состояние — comparable PASS: baseline и candidate имеют одинаковый contract, и все component checks проходят. Второе — comparable FAIL: contract тот же, но хотя бы один named component больше allowed. Третье — not comparable: scenario или conditions изменились, поэтому budget verdict не строится. Самая опасная ошибка — превратить третье состояние во второе. Тогда случайная смена cache, route data или config выглядит как performance regression, хотя данных для такого вывода нет.'),
paragraph('Fixture показывает все три ветки. Baseline сравнивается сам с собой и проходит. Candidate с теми же conditions падает по <code>scriptTicks</code>. Отдельный candidate меняет только <code>cache</code> с <code>not-modelled</code> на <code>changed-training-cache-state</code>; его comparison получает <code>measurement-contract-invalid</code>. В этой ветке нет component failure, потому что программа отказалась подменять различие условий числовым verdict.'),
dataTable(
'Три диагностических состояния budget comparison',
['Состояние','Что известно','Что не известно','Следующий шаг'],
[
['Comparable PASS','все names внутри allowed при одном contract','что путь быстрый для всех пользователей','сохранить snapshot и повторить только при том же contract'],
['Comparable FAIL','один named component превышает limit+tolerance','глобальная причина или browser effect','собрать один факт на границе failed component'],
['Not comparable','contract baseline/candidate различается','есть ли регрессия','восстановить scenario и conditions до нового compare'],
['Aggregate PASS + component FAIL','total в пределах, name не в пределах','что component можно игнорировать','считать overall FAIL и сузить действие'],
],
),
heading('Прочитайте output в правильном порядке'),
paragraph('Первой строкой читается validation: comparable ли объекты. Второй — список <code>failedComponents</code>. Третьей — diagnosis, где field и scope явно ограничены. Aggregate читается последним: он объясняет общий запас, но не принимает решение. Такой порядок помогает reviewer не споткнуться о знакомое зелёное слово PASS. В fixture aggregate находится в <code>candidateComparison.aggregate</code>, а final decision — в <code>candidateComparison.overall</code>.'),
codeBlock(fieldExample),
paragraph('Поле <code>diagnosis.nextAction</code> сознательно скупо: <code>inspect-script-input-and-one-route-boundary</code>. Оно не говорит «удалить библиотеку», «переписать приложение» или «ускорить сервер». По одному учебному числу нельзя выбрать такую архитектуру. Следующее действие должно породить проверяемый факт: например, список route inputs, diff зависимостей или отдельный профиль, если он действительно доступен и собран по понятному протоколу.'),
codeBlock(fieldRecheckExample),
heading('Диаграмма: зелёный total не отменяет красную ветку'),
'Диагностическая схема для budget comparison: сначала проверяются route, scenario и declared conditions; при несовпадении сравнение останавливается. При совпадении component checks идут раньше aggregate. Ветка scriptTicks 34 при allowed 30 ведёт к focused action, хотя total 93 при allowed 98 остаётся зелёным.',
'Схема показывает границы вывода: red component создаёт контрактный fail и ограниченную проверку, но не доказывает глобальную скорость, trace браузера или пользовательский результат.',
),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> Total budget зелёный, но на маршруте появляется новый красный component или его запас постепенно сокращается.',
'<strong>Причина.</strong> Итоговая сумма скрывает распределение. Либо baseline/candidate стали несопоставимыми, и цифры вообще нельзя читать вместе.',
'<strong>Проверка contract.</strong> Сверьте route, scenario, workloadVersion, unit и every declared condition. При любом различии получите <code>measurement-contract-invalid</code>, а не performance verdict.',
'<strong>Проверка component.</strong> Запишите actual, limit, tolerance и allowed. В этом case <code>scriptTicks</code> 34 против allowed 30; named fail остаётся виден независимо от total.',
'<strong>Проверка aggregate.</strong> Используйте 93 против allowed 98 только для контекста: total не вышел за вторичный guard, но он не может перевести overall в PASS.',
'<strong>Действие.</strong> Сохраните failed name и возьмите один input плюс одну boundary для следующего наблюдения. После изменения повторите тот же compare; если contract изменился, оформите новый snapshot.',
]),
heading('Как не сделать из диагностики глобальный performance verdict'),
paragraph('У diagnosis есть поле <code>notClaim</code>. Оно явно запрещает интерпретировать результат как global speed, browser trace, real-user result или SLA verdict. Такое ограничение кажется избыточным, пока в отчёте не появляется знакомое число. Именно тогда человек склонен достроить историю: «34 значит страница медленнее». Нет. В fixture 34 — значение одного условного property при локальном object comparison. Оно говорит ровно то, что проверено: rule именованной части не соблюдён.'),
paragraph('Нужен и обратный запрет. Aggregate PASS не даёт сказать «проблемы нет». Он лишь говорит, что учебный total не пересёк свой aggregate allowed. В реальном проекте этот total может быть полезен как guard против общего роста, но не как единственный gate. Если граница пользователя критична, ей нужен собственный named contract и owner. Если она не критична, тогда лучше не притворяться, что общий score защищает её.'),
heading('Выберите границу следующего наблюдения'),
paragraph('Для <code>scriptTicks</code> не стоит сразу открывать весь application. Начните с route boundary: entry, bundle boundary, dynamic input или другой реальный владелец, который выбран в mapping. Одного артефакта достаточно, чтобы сузить или отвергнуть гипотезу. Если видно, что changed input не относится к route, вернитесь к contract. Если input относится к route, тогда можно подготовить небольшое обратимое изменение и повторить compare. Оба пути лучше, чем широкая «оптимизация производительности». '),
paragraph('Подход сохраняет развитие автора 2022 года: сначала пользовательский опыт и наблюдаемый контракт, затем система границ, затем решение с ценой. Он не делает вид, что автор владеет production telemetry или знает реальную причину без trace. Любой более сильный вывод требует нового доказательства. Это не осторожность ради тона — это способ не закрепить неверную архитектуру после одной зелёной или красной строки.'),
heading('Источники помогают не перепутать поля'),
paragraph('W3C Navigation Timing Level 2 в историческом snapshot описывает platform interface для navigation data. User Timing Level 3 описывает marks/measures и metadata. Performance Timeline Level 2 описывает retrieval performance entries и observer mechanics. В каждом случае источник помогает понять, что значит фактическое поле платформы. Но он не говорит, что <code>scriptTicks</code> fixture равно одному из этих полей или что эти поля уже собраны в этом проекте.'),
paragraph('Перед переносом модели на настоящую страницу полезна маленькая таблица mapping: field учебного контракта, concrete source, data availability, transform, owner и known limitation. Если для одного поля mapping отсутствует, не подставляйте похожий термин. Либо оставьте field учебным, либо сначала соберите новый evidence. Такая дисциплина защищает не только от анахронизма, но и от обычной ошибки: неправильная метрика даёт очень точное число и очень плохое решение.'),
heading('Сигнал для CI и отдельный сигнал для исследования'),
paragraph('CI gate может работать как контрактный предохранитель: сравнить known snapshot и candidate, вывести failed components и завершиться с ошибкой. Но не стоит называть этот outcome «измерением браузерной производительности», если job не выполнял такое наблюдение. В fixture CI observation честно указано как <code>not-collected</code>. Так автоматизация остаётся полезной, но не получает чужой смысл.'),
paragraph('Исследование начинается после fail, а не до него. Для него нужны реальные артефакты, которые отсутствуют в fixture: выбранный browser profile, trace, resource list, application markers или другой источник. Их нельзя выводить из teaching ticks. Напротив, contract budget делает исследование дешевле: он уже назвал route, scenario, failed component, owner boundary и запретил смешать условия. Значит следующий сбор материала может быть меньше и точнее.'),
heading('Что проверить после focused action'),
paragraph('После небольшого изменения не повышайте limit первым движением. Сначала повторите same contract compare. Если <code>scriptTicks</code> вернулся в allowed, зафиксируйте, какой input изменился и что всё ещё не известно. Если не вернулся, следующий шаг должен быть ещё одним проверяемым узким экспериментом, а не каскадом правок. Если route or scenario изменились, не сравнивайте с исходным baseline: оформите новую версию workload и причину пересмотра.'),
heading('Историческая граница февраля 2022'),
paragraph('Материал не использует будущие показатели взаимодействия и не ссылается на актуальные страницы, которые могли поменять советы. Ссылки ниже ведут на dated W3C drafts: январь 2022 для Navigation Timing и 2021 для User Timing и Performance Timeline. Все три документа различают официальные platform interfaces и этап working draft. Учебная диагностика поверх них остаётся собственной моделью пакета.'),
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.