ci: рекалибровать бюджет initial view и предупреждать до стены, а не после

Запас ушёл с 26 КБ до 8.3 КБ за сутки. По документам код-ревью видно, что это не
диффузное расползание, а один шаг плюс обычная работа:

  #317 256127 · #318 256091 · #341 256046 · #354 257212 · #159 256828
  #357 271143  <- +14 КБ за один заход
  #20 271455 · #361 272848 · #359 272469 · #360 273697  <- текущий факт

Шаг на #357 — plan-art мебели: 44 top-view символа в eager-графе, которые платит
каждый план, включая планы без единого предмета мебели.

Потолок 282000 -> 300000. Правило #352 сохранено: 273697 x 1.10 = 301067, то
есть 300000 остаётся внутри надбавки ~10% над измеренным фактом. Запас
возвращается к 26.3 КБ — примерно к тому, что было до #357.

Запись честная и в комментарии сказана прямо: рекалибровка ничего не ускоряет и
ничего не чинит. Она фиксирует новую норму и возвращает гейту способность красить
того, кто вырастил бандл, а не того, кто пушнул последним. Настоящий рычаг —
ленивый граф, варианты 1 и 2 из #367.

Добавлено предупреждение: пока запас меньше 15000 Б, гейт печатает ::warning:: и
строку в summary. Прежняя редакция полагалась на то, что человек заметит тренд в
выводе; за сутки его не заметил никто, потому что каждая отдельная строка
выглядела нормально. Текст предупреждения называет лечение — иначе следующий
читатель поднимет потолок ещё раз и назовёт это решением.

Тест закрепляет обе стороны: надбавка не больше 10% и не меньше 5% (меньше —
возврат лотереи «красит последний коммит»), тревога срабатывает строго ниже
порога, превышение описывается как превышение. Три мутанта проверены руками,
один добавлен в реестр.

Issue: #367
User-Visible: no
This commit is contained in:
Claude
2026-08-29 12:32:01 +03:00
parent 5a285a6a4b
commit 0935a4d099
4 changed files with 104 additions and 5 deletions
+45 -2
View File
@@ -11,8 +11,48 @@ import { pathToFileURL } from 'node:url';
// the bundle (5740324b was exactly that). The ceiling therefore keeps a
// deliberate ~10% allowance over the measured fact; the fact and headroom
// are printed on every run so the trend is visible long before the wall.
// Measured fact at calibration (v1.69.0-beta.1): 255 993 B gzip.
export const INITIAL_VIEW_GZIP_BUDGET = 282_000;
//
// #367, рекалибровка 29.08. Запас съеден с 26 КБ до 8.3 КБ, и это не диффузное
// расползание, а один шаг плюс обычная работа. Факт по документам код-ревью:
//
// #317 256 127 · #318 256 091 · #341 256 046 · #354 257 212 · #159 256 828
// #357 271 143 ← +14 КБ за один заход
// #20 271 455 · #361 272 848 · #359 272 469 · #360 273 697 ← текущий факт
//
// Шаг на #357 — plan-art мебели: 44 top-view символа в eager-графе, которые
// платит КАЖДЫЙ план, включая планы без единого предмета мебели. Остальные
// приросты по килобайту и относятся к обычным фичам.
//
// Поэтому запись честная: рекалибровка НИЧЕГО не ускоряет и ничего не чинит.
// Она фиксирует, что 273 697 Б — новая норма, и возвращает рабочий запас, чтобы
// гейт снова красил того, кто вырастил бандл, а не того, кто пушнул последним.
// Настоящий рычаг остаётся прежним и описан в #367: вынести plan-art мебели в
// ленивый чанк (−13.6 КБ, вариант 1) либо русский словарь (вариант 2).
//
// Measured fact at recalibration (dev @ 360, 29.08.2026): 273 697 B gzip.
// 273 697 × 1.10 = 301 067 — потолок 300 000 держится внутри правила ~10%.
export const INITIAL_VIEW_GZIP_BUDGET = 300_000;
/**
* Порог, ниже которого запас перестаёт быть запасом (#367).
*
* Прежняя редакция полагалась на то, что человек заметит тренд в выводе. За
* сутки запас ушёл с 26 КБ до 8.3 КБ, и не заметил никто — потому что каждая
* отдельная строка выглядела нормально. Предупреждение срабатывает за две
* средние фичи до стены, а не после неё.
*/
export const LOW_HEADROOM_WARNING_BYTES = 15_000;
/** Тревога о запасе: `null`, пока его хватает. */
export function lowHeadroomWarning(headroom, threshold = LOW_HEADROOM_WARNING_BYTES) {
if (!Number.isFinite(headroom) || headroom >= threshold) return null;
if (headroom < 0) {
return `бюджет превышен на ${-headroom} Б — гейт уже красный`;
}
return `запас бюджета ${headroom} Б, меньше порога ${threshold} Б:`
+ ' следующая средняя фича упрётся в стену. Рекалибровка это не лечит —'
+ ' смотрите ленивые графы (#367)';
}
export function assertBundleBudget(manifest, budget = INITIAL_VIEW_GZIP_BUDGET) {
if (manifest?.schema !== 1 || !Array.isArray(manifest.files)) {
@@ -58,6 +98,8 @@ if (import.meta.url === pathToFileURL(process.argv[1] || '').href) {
`lazy locale: ${result.lazyLocaleGzipBytes} B gzip`,
];
for (const line of lines) console.log(line);
const warning = lowHeadroomWarning(headroom);
if (warning) console.log(`::warning::${warning}`);
// #352: the trend belongs where humans look — the run summary.
if (process.env.GITHUB_STEP_SUMMARY) {
const { appendFileSync } = await import('node:fs');
@@ -66,6 +108,7 @@ if (import.meta.url === pathToFileURL(process.argv[1] || '').href) {
`| граф | gzip | бюджет | запас |`,
`|---|---|---|---|`,
`| initial View | ${result.initialViewGzipBytes} B | ${INITIAL_VIEW_GZIP_BUDGET} B | ${headroom} B |`,
...(warning ? ['', `> ${warning}`] : []),
'',
].join('\n'));
}
+12
View File
@@ -1308,6 +1308,18 @@ const MUTANT_DEFINITIONS = [
replace: ' if (false) {',
}],
},
{
id: 'budget-warning-never-fires',
guard: 'node --test --test-name-pattern="срабатывает до стены" test/bundle-assets.test.mjs',
because: 'прежняя редакция полагалась на то, что человек заметит тренд в выводе: за сутки '
+ 'запас ушёл с 26 КБ до 8.3 КБ, и не заметил никто — каждая отдельная строка выглядела '
+ 'нормально (#367)',
patches: [{
file: 'scripts/bundle-budget.mjs',
find: ' if (!Number.isFinite(headroom) || headroom >= threshold) return null;',
replace: ' if (true) return null;',
}],
},
{
id: 'review-doc-guard-matches-by-substring',
guard: 'node --test --test-name-pattern="соседний каталог" test/review-doc-guard.test.mjs',