На 31 июля 2026 года строгий аудит проходит 163 из 358 созданных материалов. Остальные 195 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
На 31 июля 2026 года строгий аудит проходит 166 из 358 созданных материалов. Остальные 192 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
- Голос: М5, начало 2022 года. Прагматичная техническая речь: один media slot, отдельные владельцы state, проверяемая граница и обратимая правка вместо общего обещания «ускорить картинки».
- Граница: fixture не создаёт DOM, `img`, CSS layout, сеть, browser scheduler, `decode()`, `PerformanceObserver`, trace или product metric. `markup`, geometry, load/decode labels, priority intent и observation record — локальные данные модели. В частности, PASS не означает загрузку, декодирование, LCP или CLS.
- Источники: датированный W3C FPWD Largest Contentful Paint от 24.05.2022 и W3C HTML 5.2 Recommendation от 14.12.2017. Оба URL проверены на HTTP 200; не использованы плавающие editor drafts как доказательство состояния августа 2022 года.
## Проход 1 — факты и техника
- W3C LCP First Public Working Draft от 24 мая 2022 года назван именно Working Draft. Текст использует его только для границы: LCP — API наблюдения candidates с ограничениями, не синоним большой картинки и не результат unit fixture.
- HTML 5.2 Recommendation остаётся исторической первичной ссылкой для `img`; статья не приписывает ему product policy, responsive selection или конкретный scheduler priority.
- Учебный contract различает `markup`, `geometry`, `request.priorityIntent`, declared load, declared decode и caller-supplied observation. `priorityIntent` прямо маркирован как намерение приложения, не как приоритет браузера. `geometryReserved` прямо не называется отсутствием layout shift.
- Fixture намеренно отвергает decode до declared load и load без markup, принимает только положительную geometry, сохраняет deferred slot неготовым и всегда возвращает `realMetricMeasured: false`.
- После финальной правки пройдены: `node --check web/scripts/upgrade-2022-08.mjs`; `node web/scripts/upgrade-2022-08.mjs --verify-fixture`; `npm run audit:draft -- scripts/upgrade-2022-08.mjs`; import/CLI comparison без `date` и `author`.
## Проход 2 — редактура, голос и полнота
- Первые два абзаца каждой статьи называют ситуацию и цену: поздний контент, изменение layout, неподтверждённый priority, необъяснимый релиз и невозможность корректно откатить смешанную правку.
- Маршрут в каждой статье построен как «симптом → причина → проверка → действие», с отдельным rollback и списком того, чего модель не измеряет.
- У всех статей есть table, локальный SVG с alt/caption, исполнимый fixture command и нумерованный маршрут. Тон М5 не выдумывает production case, проценты, LCP/CLS trace, сроки или эффект; он отделяет contract от browser observation.
- Размер основного текста контролируется скриптом: все три статьи находятся в обязательном диапазоне 5 000–15 000 знаков без списка источников.
## Проход 3 — визуал и безопасность
- SVG отвечают на три разные задачи: contract slot, state boundary и diagnosis/rollback. Во всех есть `title`, `desc`, `role="img"`, а в статьях — развёрнутые alt и подписи.
-В SVG нет `script`, `foreignObject`, внешних URL и `data:image`. Проверка XML и safety scan не нашли запрещённых конструкций.
- Все три диаграммы открыты через Sharp-рендер на ширине 375 px: заголовки, состояния, подписи границы и ветка rollback остаются читаемыми; визуал не используется как доказательство браузерной метрики.
- Sidecar содержит ровно пять новых файлов. Registry, README, `articles.json`, очередь, Git, ранее созданные месяцы и чужие файлы не менялись; интеграция и публикация не выполнялись.
## Независимый редакторский приём
### Проход 1 — фактчек и модель
Проверены оба датированных W3C URL: LCP First Public Working Draft 24 мая
2022 года и раздел `img` HTML 5.2 Recommendation ответили `200`. Название
LCP сохранено как Working Draft, а не повышено до Recommendation. Фактчек
подтвердил ключевую границу текста: API описывает browser-side candidates и
ограничения, поэтому fixture не вправе объявлять свой `candidate-note`
измерением LCP или CLS.
Просмотрены все переходы `createMediaContract`: markup precedes plan,
declared load precedes declared decode, и supplied observation возможен только
после decode label. Geometry не названа результатом layout calculation;
`priorityIntent` возвращает `transport: not-performed`; readiness всегда
оставляет `realMetricMeasured: false`. Fixture прошла **14/14 assertions**.
### Проход 2 — текст и полнота
Проверены problem/cost в первых абзацах, tables, examples, ordered routes,
rollback и ограничения. Все три статьи различают component contract,
application intent, browser work и внешний observation record. Они не
заявляют загрузку, decode, LCP, CLS или скорость устройства. Draft audit
<titleid="title">Разбор медиа-проблемы и обратимая правка</title><descid="desc">Диаграмма делит жалобу на поздний hero, движение layout и спор о приоритете. Каждая ветка получает отдельные факты, после чего выполняется одна обратимая правка и повторяется тот же браузерный сценарий. Диаграмма не измеряет LCP и CLS.</desc>
<rectwidth="1200"height="720"fill="#111827"/><gfont-family="Arial, sans-serif"><textx="58"y="72"fill="#f9fafb"font-size="34"font-weight="700">Диагностика: одна гипотеза, одна обратимая правка</text>
<rectx="450"y="115"width="300"height="78"rx="14"fill="#7c2d12"stroke="#fdba74"stroke-width="2"/><textx="507"y="163"fill="#fff7ed"font-size="23"font-weight="700">Жалоба о media slot</text>
<rectx="385"y="495"width="430"height="86"rx="14"fill="#14532d"stroke="#86efac"stroke-width="2"/><textx="455"y="530"fill="#f0fdf4"font-size="22"font-weight="700">Одна узкая правка + rollback</text><textx="441"y="558"fill="#dcfce7"font-size="16">geometry ИЛИ source mapping ИЛИ composition</text>
<rectx="145"y="640"width="910"height="45"rx="9"fill="#3f1d2e"/><textx="262"y="669"fill="#fecdd3"font-size="19"font-weight="700">Наблюдение повторяют при тех же условиях; схема не измеряет реальный LCP или CLS</text></g>
<titleid="title">Контракт media slot: разметка, геометрия, load, decode и внешнее наблюдение</title><descid="desc">Пять последовательных слоёв отделены от браузерных метрик. Диаграмма указывает, что учебная модель не создаёт DOM, не выполняет сеть и не измеряет LCP или CLS.</desc>
<rectwidth="1200"height="700"fill="#0b1220"/><textx="70"y="78"fill="#f8fafc"font-family="Arial, sans-serif"font-size="34"font-weight="700">Один media slot: сначала факты contract</text>
<titleid="title">Состояния учебного media contract и граница браузерного наблюдения</title><descid="desc">Схема показывает, что разметка и геометрия являются независимыми входами, затем идут planned load, declared load и declared decode. Внешнее наблюдение находится за границей fixture и не делает её метрикой LCP или CLS.</desc>
<rectwidth="1200"height="700"fill="#101827"/><textx="60"y="72"fill="#f9fafb"font-family="Arial, sans-serif"font-size="33"font-weight="700">State machine без подмены браузера</text>
<rectx="90"y="615"width="1020"height="48"rx="10"fill="#3b1c2b"/><textx="183"y="646"fill="#fecdd3"font-size="19"font-weight="700">Fixture проверяет порядок labels; browser, layout, LCP и CLS остаются за её границей</text></g>
note:'датированный первичный документ. Он определяет API наблюдения candidate largest contentful paint и отдельно перечисляет его ограничения; fixture ниже этот API не вызывает и LCP не измеряет.',
};
consthtml52={
title:'HTML 5.2, W3C Recommendation от 14 декабря 2017 года',
note:'неизменяемая нормативная версия, доступная в августе 2022 года. Она задаёт элемент img и его атрибуты; проектные labels, операции модели и выводы о метриках в ней не определены.',
};
constcommonSources=[lcpDraft,html52];
/**
* Детерминированный учебный контракт для одного media slot.
excerpt:'Практический маршрут для медиа-слота: не путать declared geometry, load и decode, а проверку браузерной метрики вынести в отдельный наблюдаемый прогон.',
readingMinutes:12,
},[
paragraph('У большого изображения в первом экране обычно три видимых симптома: контент появляется поздно, блок прыгает после ответа или нужный ресурс оказывается в очереди не там, где его ожидали. Цена не сводится к цифре в отчёте: пользователь сначала видит пустое место или неверный порядок страницы, а команда начинает менять атрибуты вслепую. В следующем релизе та же ошибка возвращается другой картинкой.'),
paragraph('Причина часто в смешении четырёх фактов. Разметка говорит, какой ресурс описан. Геометрия говорит, какое место компонент резервирует по своему контракту. Load и decode относятся к платформенному пути, а LCP и layout shift появляются только в наблюдении конкретного документа и браузера. Ниже — учебная модель, где эти слова являются отдельными fields. Она не создаёт <code>img</code>, не запускает сеть и не измеряет LCP или CLS.'),
heading('Сначала назвать, что именно сломано'),
table('Матрица симптомов для одного media slot',['Симптом','Не делаем вывод','Первый проверяемый факт','Действие'],[
['Пустое место до изображения','«это точно LCP»','есть ли разметка и declared geometry для slot','зафиксировать dimensions рядом с источником layout'],
['Карточка сдвинулась после медиа','«width/height гарантируют нулевой CLS»','меняется ли место slot в выбранном DOM-сценарии','проверить правила контейнера и резервирование отдельно'],
['Hero приходит поздно','«один attribute задаёт реальный network priority»','какое намерение команда присвоила resource и где оно выражено','сверить разметку, ресурс и browser observation'],
['Декодирование заметно пользователю','«load равен готовому пикселю»','какой этап реально наблюдался и в каком браузере','собирать отдельный trace, не выводить его из unit fixture'],
]),
heading('Минимальный контракт до оптимизации'),
paragraph('Для одного slot достаточно записать четыре независимые вещи: <code>src</code> и alt как declared markup; <code>width</code>/<code>height</code> как declared geometry; намерение <code>critical-candidate</code> или <code>deferred-candidate</code>; и факт внешнего наблюдения. Последнее особенно важно. Даже когда ресурс важен для первого экрана, локальная модель не может узнать, стал ли он candidate LCP: у неё нет document, paint и ввода пользователя.'),
paragraph('Это не отказ от оптимизации. Это способ не сделать ложный rollback. Если slot не имеет геометрии, сначала безопасно добавить её в компонент и проверить выбранные варианты изображения. Если ожидание priority не совпало с trace, не надо сразу объявлять другой label «быстрее»: нужно сохранить условия прогона, браузер, viewport, cache state и список конкурирующих ресурсов. Тогда следующий шаг воспроизводим.'),
codeBlock(fixtureExample),
paragraph('Fixture принимает строку <code>teaching-load-ok</code> и затем <code>teaching-decode-ok</code>. Это нарочно не callback браузера. Она проверяет только порядок локального контракта: без markup нельзя plan load, decode не допускается до declared load, а observation записывается после declared decode. Результат PASS не говорит, что файл был загружен, декодирован, показан или стал LCP-кандидатом.'),
figure('/assets/editorial/2022/media-performance-2022-slot-contract.svg','Схема одного media slot: declared markup ведёт к отдельно declared geometry; затем application intent планирует load, учебный token отмечает load и decode, а внешний observation record хранится отдельной веткой. Внизу явно написано, что это не DOM, не CSS layout и не измерение LCP или CLS.','Контракт не заменяет browser trace: он делает явным, какие факты должен принести следующий слой проверки.'),
heading('Геометрия — часть компонента, а не последняя правка CSS'),
paragraph('Резервирование места полезно рассматривать как вход компонента. В модели <code>reserveGeometry(960, 540)</code> сохраняет ratio <code>960:540</code>; оно не вычисляет box, не знает <code>object-fit</code> и не видит CSS соседей. Поэтому такой unit test может защитить обязательность dimensions в данных, но не вправе утверждать, что layout shift исчез. Для этого нужен отдельный browser-сценарий с реальной разметкой.'),
paragraph('У одного источника может быть несколько отображений: hero, карточка, миниатюра. Не переносите размеры оригинала как универсальный ответ. Для каждого отображения команда должна назвать ожидаемую рамку, источник пропорции и поведение при неизвестной высоте. Если это невозможно сформулировать рядом с компонентом, optimisation пока не имеет стабильной границы, а не «нуждается в ещё одном CSS hack». '),
heading('Очередь ресурса: намерение не равно факту браузера'),
paragraph('В contract есть <code>priorityIntent</code>, но это только label решения: critical или deferred candidate. Он помогает reviewer спросить, почему этот ресурс должен конкурировать в ранней части загрузки. Он не обещает, что user agent назначит конкретный приоритет, начнёт скачивание первым или сохранит порядок при другом cache state. Такой запрет на сильный вывод дешевле последующего разбора «почему в лаборатории было иначе». '),
paragraph('Для non-critical media разумнее сначала убедиться, что оно действительно не требуется до действия пользователя или ниже первого сценария просмотра. Слово deferred не означает «можно потерять»: у slot остаются alt, geometry, error state и проверка возвращения на экран. Если продукту важен placeholder, он тоже становится отдельной разметкой и геометрией, а не тайным следствием неуспешной загрузки.'),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> Выберите один slot и один видимый дефект: поздний hero, скачок карточки или ошибочное раннее медиа. Не соединяйте их общим словом «производительность».',
'<strong>Причина.</strong> Разложите текущий компонент на markup, geometry, resource intent, load/decode и observation. Отметьте, какое поле отсутствует или меняется не там.',
'<strong>Проверка контракта.</strong> Запустите fixture. PASS проверяет только порядок учебных labels и отсутствие metric claim.',
'<strong>Проверка реализации.</strong> В выбранном браузере соберите отдельный сценарий: URL, viewport, cache state, список конкурирующих ресурсов и фактический layout. Это уже другой артефакт.',
'<strong>Действие.</strong> Добавьте geometry в component API, назовите resource intent и оставьте источник данных для responsive variant.',
'<strong>Откат.</strong> Если новый responsive источник показывает неверный кадр или ломает доступность, верните прежнее соответствие resource-to-slot. Не маскируйте проблему искусственным priority label без записи наблюдения.',
]),
heading('Что проверяет LCP-документ, а что остаётся за ним'),
paragraph('FPWD LCP от 24 мая 2022 года определяет наблюдение кандидатов и прямо называет ограничения эвристики. Это полезная граница: LCP — не синоним «любой большой картинки» и не обещание, что unit-модель может рассчитать пользовательское восприятие. HTML 5.2 фиксирует норму для <code>img</code>, но тоже не описывает продуктовую очередь и не выбирает за команду важный ресурс.'),
paragraph('Следующий проверяемый шаг — приложить к PR два артефакта. Первый: unit test данных slot, где отсутствующая или нулевая geometry отклоняется. Второй: короткий browser report с условиями и тем, что было реально замечено. Не заменяйте второй первым. Так изменение остаётся маленьким, но команда не делает вид, что локальный object уже является профилем браузера.'),
heading('Ограничение'),
paragraph('Модель не охватывает <code>srcset</code> selection, CSS background, video poster, CDN negotiation, cache, network error, EXIF orientation, accessibility tree, server rendering и реальные callbacks. Она не утверждает, что width/height сами по себе устраняют CLS, а priority intent — что-либо о scheduler. Для каждой из этих границ потребуется конкретная реализация и самостоятельная проверка.'),
excerpt:'Разбираем порядок состояний media slot и границу утверждений: разметка, геометрия, declared load/decode и внешний observation record не являются измерением браузерной метрики.',
readingMinutes:13,
},[
paragraph('После добавления оптимизации медиа часто возникает странный спор: один разработчик показывает unit test, другой — trace, а оба называют это «готовым LCP fix». Проблема такой подмены в том, что решение нельзя ни подтвердить, ни откатить: не ясно, что именно изменилось — markup, размеры, очередь, декодирование или условия запуска. При следующем изменении команда сравнит несравнимые результаты.'),
paragraph('Причина в том, что у этих фактов разные владельцы. Компонент владеет описанием slot и может требовать geometry. Приложение может назначить намерение важности. Браузер выполняет загрузку, decode и layout; измерительный код наблюдает его результат при конкретных условиях. Учебный контракт ниже не притворяется браузером: он хранит declared transitions и принимает внешний record только как supplied data.'),
heading('Пять слоёв вместо одного флага loaded'),
table('Состояния, которые нельзя заменить одним boolean',['Слой','Владелец','Наблюдаемый факт','Чего факт не доказывает'],[
['Markup','компонент','slot описан src и alt','ресурс запрошен или показан'],
['Geometry','component API и layout contract','есть положительные width и height','реальный box и отсутствие shift'],
['Load intent','приложение','slot помечен critical/deferred candidate','приоритет scheduler и время ответа'],
['Declared load/decode','учебная fixture','локальный порядок transitions','сетевой load или decode API'],
['External observation','отдельный browser прогон','в record есть значение и условия','причину изменения без анализа trace'],
]),
heading('Почему load и decode надо разделить даже в учебном коде'),
paragraph('Слово loaded удобно, но оно склеивает минимум два вопроса: ресурс уже доступен по пути загрузки и он готов для отображения в конкретном контексте. Настоящие платформенные алгоритмы сложнее этой заметки. Поэтому model не пытается их воспроизвести: <code>markLoad</code> принимает только teaching token, а <code>markDecode</code> требует ранее объявленный load. Их разделение полезно не для симуляции браузера, а чтобы review увидел неверный порядок переходов.'),
paragraph('В реальном коде граница будет другой: события, Promise или framework adapter. Нельзя заменить их вызовом fixture и сказать, что браузер прошёл decode. Но можно заранее договориться, что логика UI не покажет «готово» только потому, что создан descriptor. Это небольшой, проверяемый контракт: описание slot не равно завершённой работе платформы.'),
codeBlock(fixtureExample),
figure('/assets/editorial/2022/media-performance-2022-state-boundary.svg','Диаграмма состояний media slot: markup и geometry независимы; planned load с label critical/deferred не является транспортом; declared load ведёт к declared decode; лишь затем можно сохранить external observation record. Боковая область исключает DOM, scheduler, LCP и CLS из учебной модели.','Разделение переходов оставляет место для настоящего browser-слоя, не превращая fixture в его подделку.'),
heading('Геометрия: проверяем вход, не рисуем несуществующий layout'),
paragraph('Функция <code>reserveGeometry</code> допускает только положительные целые width и height. Это намеренно узкое правило. Оно помогает найти данные, где component API вообще не знает ожидаемый ratio. Но функция не вычисляет CSS box, не учитывает aspect-ratio, grid, container query и не знает, чем закончится рендер. Поэтому assertion называется <code>geometryReserved</code>, а не <code>noLayoutShift</code>.'),
paragraph('Такое именование снижает риск плохой аналитики. Если тест говорит «CLS fixed», его потом используют как аргумент против реального наблюдения. Если тест говорит «в contract есть declared geometry», он остаётся честным: дальше можно провести page-level проверку. В архитектуре это полезнее красивого флага, потому что граница ответственности указана прямо в имени.'),
heading('Наблюдение — вход другого контура'),
paragraph('В модели <code>recordExternalObservation</code> принимает record с kind и числом. Она не создаёт <code>PerformanceObserver</code> и не называет число LCP. Его source явно равен <code>external-observation-supplied-by-caller</code>. Это заставляет следующий слой указать происхождение: какой браузер, какой URL, какие условия кэша, какой viewport и какой trace или запись лежит рядом. Без этих условий число остаётся неподписанным сигналом.'),
paragraph('FPWD LCP полезен именно этим различием: API наблюдает кандидатов в документе, а не принимает обещание компонента. В документе есть input, viewport, paint и условия, которых нет в plain JavaScript object. Поэтому даже правильная component schema не равна измерению. Она лишь делает измерение проще интерпретировать: reviewer понимает, какой slot был объявлен critical и какая geometry ожидалась.'),
heading('Неверный priority: как искать, не придумывая scheduler'),
paragraph('Когда команда говорит «картинка грузится не с тем приоритетом», сначала нужно заменить оценку на вопрос. Какая разметка описывает ресурс? Почему продукт считает slot ранним или отложенным? Какие другие ресурсы конкурируют в конкретном прогоне? Что зафиксировано в trace? Три первых вопроса относятся к коду и contract, четвёртый — к браузерному наблюдению. Ни один label в object не является ответом на все четыре.'),
paragraph('Если наблюдение расходится с intent, rollback должен быть обратимым. Верните прежний mapping resource-to-slot или прежнюю стратегию выбора variant, сохраните report и сформулируйте новую гипотезу. Не меняйте одновременно source, CSS, CDN и priority hint: тогда следующий trace не позволит установить причину. Один осмысленный эксперимент важнее серии атрибутов, добавленных в надежде на быстрый эффект.'),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> Зафиксируйте один конфликт: slot объявлен ранним, но в browser report ресурс виден иначе; либо geometry есть в данных, но страница меняет место.',
'<strong>Причина.</strong> Проверьте, не заменены ли markup, geometry, load и observation флагом loaded или одной «performance» метрикой.',
'<strong>Проверка модели.</strong> Убедитесь, что переход decode до load отклоняется, а readiness никогда не утверждает real metric measured.',
'<strong>Проверка браузера.</strong> Отдельно сохраните среду запуска и trace. Укажите, какой вывод сделан из наблюдения, а какой остаётся гипотезой.',
'<strong>Откат.</strong> Откатывайте ровно один mapping или attribute-намерение, затем повторяйте тот же контролируемый сценарий. Не откатывайте «до хорошей цифры» без условия сравнения.',
]),
heading('Что можно использовать в production после модели'),
paragraph('Из fixture в production переносится не token и не число record. Переносится дисциплина: source media, geometry и intent должны иметь явную точку владения; browser observation должен быть подписан условиями; assertion должен называться ровно по тому факту, который проверяет. Это помогает и без Performance API: code review сразу видит, где component API допускает неизвестную высоту или где deferred slot неожиданно участвует в первом сценарии.'),
paragraph('HTML 5.2 описывает <code>img</code>, но не создаёт за продукт policy для всех вариантов изображений. LCP FPWD 2022 года — Working Draft, а не обещание одинакового результата для каждого документа. Эти статусы важнее рекламного языка: архитектурная заметка должна оставить место для браузерной разницы, версий и измерения, а не выдавать учебную схему за finished optimisation.'),
heading('Ограничение и следующий шаг'),
paragraph('Контракт не покрывает lazy loading, preload, responsive selection, background-image, animated formats, decoding errors, cross-origin timing, caching и ограничения устройств. Он также не строит accessibility tree и не проверяет alt в screen reader. Добавлять любое из этих свойств стоит только как новый layer со своим input и отрицательными assertions.'),
paragraph('Следующий шаг — выбрать один page-level media slot и оформить короткий evidence packet: скрин разметки/данных, ожидаемая geometry, rationale intent и протокол browser observation. Если после этого нужна правка, сделайте её одной: например, исправьте geometry contract или выбор source для этого slot. Затем повторите именно описанный сценарий. Так у оптимизации будет причина, проверка и безопасный путь назад.'),
],commonSources);
constfieldArticle=createRevision({
slug:'editorial-2022-08-field-media-performance',
title:'Медиа-слот в разборе: собрать доказательства до смены размера, источника и приоритета',
excerpt:'Полевой маршрут для позднего hero, скачущей карточки и спорного priority: какие факты записать, как сделать одну обратимую правку и где заканчивается учебная fixture.',
readingMinutes:13,
},[
paragraph('Фраза «картинка тормозит страницу» слишком широка, чтобы её исправить. Проблема может скрываться в лишнем исходнике для маленького slot, отсутствии зарезервированного места, неверной композиции первого экрана или предположении о browser priority без trace. Цена общей формулировки — опасный релиз: одновременно меняются CDN variant, CSS и атрибуты, а после этого никто не может объяснить, что помогло или что сломало доступный кадр.'),
paragraph('Начать нужно не с benchmark и не с обещания конкретной метрики. Возьмите один URL страницы, один viewport, один media slot и одно наблюдение пользователя. Затем отделите проверяемые поля component contract от того, что действительно увидел браузер. Учебная fixture этой партии проверяет только порядок локальных labels. Она не открывает страницу, не получает response и не выдаёт число за LCP или CLS.'),
heading('Карточка расследования до первой правки'),
table('Что приложить к задаче по медиа',['Поле','Пример записи','Почему нужно','Чего не утверждает'],[
['Slot','product-card/main-image','ограничивает область изменения','что все изображения страницы одинаковы'],
['Geometry contract','960×540, источник в данных карточки','даёт ожидаемую рамку review','реальный CSS box и отсутствие shift'],
['Intent','critical-candidate или deferred-candidate','объясняет ожидание команды','расписание browser scheduler'],
['Observation conditions','browser, viewport, cache state, route','делает повторный прогон сопоставимым','универсальный эффект во всех средах'],
['Rollback','вернуть прежний source mapping','ограничивает риск правки','отмену уже увиденного пользователем состояния'],
]),
heading('Три похожих симптома, три разные проверки'),
paragraph('Поздний hero проверяется не тем же способом, что и скачок layout. Для hero сначала посмотрите, какой slot продукт считает главным, какой source ему сопоставлен и какие конкуренты были в конкретном browser report. Для скачка сначала проверяется geometry contract и фактический DOM/layout выбранного сценария. Для «неверного priority» сначала уточняется, что означает это слово: product intent или факт, замеченный в trace. Одно измерение не закрывает все три вопроса.'),
paragraph('Полезно заранее записать и отрицательный результат. Например: «в component data dimensions есть, но при открытии фильтра slot меняет контейнер; вывод о причине не сделан». Такая запись лучше красивого диагноза, потому что она не превращает гипотезу в релизное решение. Сначала ограничивается неисправность, потом выбирается один эксперимент. Это особенно важно для изображений: они одновременно касаются content, CSS, доставки и доступности.'),
codeBlock(fixtureExample),
paragraph('Команда может добавить этот fixture рядом с данными или reducer, чтобы не потерять простую границу: нельзя declared decode до declared load; геометрия принимается отдельно; record внешнего наблюдения не делает <code>realMetricMeasured</code> истинным. Но fixture не заменяет полевой разбор. Если она PASS, это значит только, что локальный contract не назвал свою собственную строку браузерной метрикой.'),
figure('/assets/editorial/2022/media-performance-2022-diagnosis-rollback.svg','Диагностическая схема: жалоба делится на late hero, layout movement и priority dispute; для каждого собираются отдельные contract facts и browser observation conditions. Затем выполняется одна обратимая правка; если evidence не подтверждает гипотезу, возвращается прежний resource-to-slot mapping. Рамка снизу исключает из схемы измерение реального LCP и CLS.','В разборе медиа откат нужен для сохранения объяснимости: одна гипотеза, одна правка, тот же сценарий проверки.'),
heading('Проверка геометрии без ложного обещания CLS'),
paragraph('Зарезервированная geometry — хороший кандидат на маленькую правку, потому что у неё есть конкретный owner. В data contract можно отклонить нулевую ширину или высоту, показать fallback и не допустить, чтобы component молча получил неизвестную рамку. Но это не завершённый вывод о layout shift. Реальная страница содержит шрифты, контейнеры, соседние блоки и разные ветви состояния. Проверить их можно только через фактическую разметку и условия запуска.'),
paragraph('Если geometry добавляется в API впервые, rollback должен быть простым: вернуть прежнюю обработку конкретного slot и не удалять evidence packet. Не используйте откат как способ скрыть дефект: если прежний путь снова даёт скачок, он остаётся известным состоянием задачи. Следующая итерация меняет другую, явно названную причину — например контейнер или источник ratio, — а не все слои сразу.'),
heading('Проверка источника и priority без волшебного атрибута'),
paragraph('Для правильного источника недостаточно назвать меньший файл «лучшим». Slot может требовать другой crop, плотность, формат или доступный fallback. Сопоставьте resource-to-slot в одном месте и проверьте, что alt относится к содержанию, а не к имени файла. Если источник меняется, зафиксируйте, какой визуальный и content result ожидается; иначе откат будет невозможен, потому что новый файл окажется «оптимизацией» без критерия пригодности.'),
paragraph('Priority intent полезен как вопрос к архитектуре страницы: почему этот ресурс critical, а следующий deferred? Но ответ о фактическом порядке лежит в browser observation, а не в строке config. Даже датированный LCP draft не превращает product label в measurement. Поэтому report должен отделять: «мы задали такое намерение» и «в таких условиях увидели такой сигнал». Между ними остаётся место для других ресурсов, браузерной версии и cache state.'),
heading('Маршрут: симптом → причина → проверка → действие'),
orderedList([
'<strong>Симптом.</strong> Запишите одно воспроизводимое наблюдение и его условия. Не начинайте с общего «нужно улучшить скорость».',
'<strong>Причина.</strong> Составьте список возможных слоёв: source mapping, declared geometry, page composition, application intent или platform behaviour. Не выбирайте виновника по заголовку DevTools.',
'<strong>Проверка contract.</strong> Проверьте component data и fixture: есть ли markup, положительная geometry, явный intent и отсутствует ли ложный metric claim.',
'<strong>Проверка браузера.</strong> Зафиксируйте browser/version, route, viewport, cache state и trace. Назовите отдельно факт и интерпретацию.',
'<strong>Действие.</strong> Внесите одну обратимую правку: geometry, source mapping или page composition. Сохраните прежнее значение для rollback.',
'<strong>Повтор.</strong> Прогоните тот же сценарий. Если гипотеза не подтверждена, откатите одну правку и расширьте evidence, а не добавляйте следующую оптимизацию поверх неё.',
]),
heading('Пример границы для code review'),
paragraph('На review стоит задать несколько коротких вопросов. Где у slot живут dimensions? Откуда они берутся и что происходит, если их нет? Почему этот ресурс находится в early path? Каким наблюдением это проверялось и где лежат условия? Какой один mapping будет возвращён, если результат неверен? Эти вопросы не требуют сложной платформенной теории, но не дают превратить optional attribute в неподтверждённое performance обещание.'),
paragraph('Ответ «проверили локально» недостаточен, если не указан слой. Локально можно проверить object и component render; в браузере — конкретный page state; в аналитике — выбранный сбор событий. У каждого слоя своя ошибка и свой владелец. Эта статья сознательно не приводит выдуманный trace или изменение процентов: без реального артефакта такие цифры только мешают отличать рабочую гипотезу от удачного пересказа.'),
heading('Историческая граница августа 2022'),
paragraph('В источниках используется датированный W3C First Public Working Draft LCP от 24 мая 2022 года и HTML 5.2 Recommendation от 14 декабря 2017 года. Первый документ описывает API наблюдения и его ограничения; второй — platform-level разметку. Ни один из них не доказывает поведение конкретного CDN, браузера или продукта. Labels <code>critical-candidate</code>, <code>deferred-candidate</code> и teaching tokens принадлежат только этой модели.'),
heading('Ограничение и следующий шаг'),
paragraph('Пакет не покрывает video, audio, background images, preload, lazy loading, <code>srcset</code>, image decode errors, server components, CDN transformation, field telemetry и доступность реального UI. Он также не задаёт target LCP/CLS, потому что без продукта, аудитории и среды это были бы произвольные числа. Не добавляйте такую цифру в задачу, пока не определён метод и условия наблюдения.'),
paragraph('Следующий шаг — провести один разбор по таблице и сохранить короткий report рядом с изменением. Если slot действительно требует новой geometry или source, добавьте соответствующий unit test. Затем отдельно повторите browser-прогон. Если есть расхождение, это не повод переписать историю: обновите гипотезу, откатите узкую правку и оставьте trace как вход следующей итерации.'),
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.