chore(gates): убрать числовой храповик бюджета из #423

Проверка `assertSupportBundleOwnership` бросала при
`initialViewGzipBytes >= 291046` — «граф не стал больше, чем на момент
закрытия #423». Запас до порога: пятнадцать байт на бете 1.71.0, сто
четыре сейчас. Пятнадцать байт gzip меньше одной строки локали, поэтому
первый же посторонний коммит получил бы красный CI с сообщением про
копирайт формы поддержки — к которому не имеет отношения.

«Граф не вырос» — критерий приёмки на момент задачи, а не свойство
продукта. Свойство продукта охраняют `INITIAL_VIEW_GZIP_BUDGET` (300000)
и предупреждение о низком запасе: они судят размер целиком и не
привязаны к чужому номеру issue.

Долговечная половина того же контракта — владение графом (маркеры формы
отсутствуют в initial View, присутствуют в ленивом редакторе) — осталась
и по-прежнему падает в обе стороны. Новый тест закрепляет, что размер в
эту функцию вернуться не может: 0, 291046, 10 МБ и `undefined` проходят
одинаково, пока владение соблюдено.

Гейты: typecheck зелёный, npm test 1787/1786 pass 0 fail, npm run build
зелёный (dist побайтово не изменился — продуктовый код не тронут),
node scripts/bundle-budget.mjs зелёный: initial View 290942 Б, бюджет
300000 Б, запас 9058 Б плюс честное предупреждение о запасе.

Issue: #429
User-Visible: no
This commit is contained in:
Claude
2026-09-03 09:56:54 +03:00
parent cc09e8f827
commit 4cabcbe828
2 changed files with 59 additions and 14 deletions
+28 -8
View File
@@ -42,13 +42,39 @@ export const INITIAL_VIEW_GZIP_BUDGET = 300_000;
* средние фичи до стены, а не после неё.
*/
export const LOW_HEADROOM_WARNING_BYTES = 15_000;
export const SUPPORT_LAZY_INITIAL_BASELINE_BYTES = 291_046;
/**
* Числового храповика здесь больше нет, и это решение, а не упущение (#429).
*
* До #429 функция бросала при `initialViewGzipBytes >= 291 046` — «граф не стал
* больше, чем был на момент закрытия #423». На бете 1.71.0 запас до этого
* порога составлял пятнадцать байт, на момент правки — сто четыре. Пятнадцать
* байт gzip меньше одной строки локали: первый же посторонний коммит получил бы
* красный CI с сообщением про копирайт формы поддержки, к которому не имеет
* отношения.
*
* Гейт, обвиняющий не ту задачу, — худший вид гейта: его выключают, не
* разбираясь, и вместе с ним выключают проверку владения графом, которая как
* раз долговечна. Поэтому число снято, а проверка владения осталась.
*
* Что именно было снято по существу: «граф не вырос» — это критерий приёмки на
* момент задачи, а не свойство продукта. Свойство продукта охраняет общий
* бюджет (`INITIAL_VIEW_GZIP_BUDGET`) и предупреждение о запасе; они судят
* размер целиком и не привязаны к чужому issue.
*/
export const SUPPORT_LAZY_MARKERS = [
'Contact details (email/tg/WhatsApp), optional.',
'Контакт для связи (email/tg/WhatsApp), необязательно.',
];
/** Keep form-only support copy in the lazy editor graph (#423). */
/**
* Форма поддержки живёт только в ленивом графе редактора (#423).
*
* Функция судит ВЛАДЕНИЕ, а не размер: маркеры формы обязаны отсутствовать в
* `initialViewFiles` и присутствовать в `lazyEditorFiles`. Размер охраняют
* `assertBundleBudget` и `lowHeadroomWarning` — им для этого не нужен чужой
* номер issue (#429).
*/
export function assertSupportBundleOwnership(
manifest,
root = 'dist',
@@ -67,12 +93,6 @@ export function assertSupportBundleOwnership(
throw new Error(`support form copy missing from lazy editor graph: ${marker}`);
}
}
if (manifest.initialViewGzipBytes >= SUPPORT_LAZY_INITIAL_BASELINE_BYTES) {
throw new Error(
`initial View graph ${manifest.initialViewGzipBytes} B gzip did not improve on #423 baseline `
+ `${SUPPORT_LAZY_INITIAL_BASELINE_BYTES} B`,
);
}
}
/** Тревога о запасе: `null`, пока его хватает. */
+31 -6
View File
@@ -9,7 +9,6 @@ import {
} from '../scripts/bundle-manifest.mjs';
import {
INITIAL_VIEW_GZIP_BUDGET, LOW_HEADROOM_WARNING_BYTES,
SUPPORT_LAZY_INITIAL_BASELINE_BYTES,
assertBundleBudget, assertSupportBundleOwnership, lowHeadroomWarning,
} from '../scripts/bundle-budget.mjs';
import { compareBundleTrees, sha256Bytes, verifyBundleTree } from '../scripts/bundle-tree.mjs';
@@ -93,7 +92,6 @@ test('#423 support form copy belongs only to the lazy editor graph', () => {
const manifest = {
initialViewFiles: ['initial.js'],
lazyEditorFiles: ['editor.js'],
initialViewGzipBytes: SUPPORT_LAZY_INITIAL_BASELINE_BYTES - 1,
};
const markers = ['lazy English marker', 'lazy Russian marker'];
assert.doesNotThrow(() => assertSupportBundleOwnership(manifest, temp, markers));
@@ -105,11 +103,9 @@ test('#423 support form copy belongs only to the lazy editor graph', () => {
writeFileSync(join(temp, 'initial.js'), 'header only');
assert.throws(
() => assertSupportBundleOwnership(
{ ...manifest, initialViewGzipBytes: SUPPORT_LAZY_INITIAL_BASELINE_BYTES },
temp,
markers,
{ initialViewFiles: ['initial.js'], lazyEditorFiles: [] }, temp, markers,
),
/did not improve/,
/missing from lazy editor graph/,
);
} finally {
rmSync(temp, { recursive: true, force: true });
@@ -275,3 +271,32 @@ test('запас на момент рекалибровки выше порог
// Иначе рекалибровка была бы бессмысленной: гейт сразу же начал бы кричать.
assert.ok(INITIAL_VIEW_GZIP_BUDGET - 273_697 > LOW_HEADROOM_WARNING_BYTES);
});
test('#429 проверка владения не судит размер графа', () => {
// Числовой храповик #423 оставлял пятнадцать байт запаса и покрасил бы
// первый же посторонний коммит сообщением про копирайт формы поддержки.
// Гейт, обвиняющий не ту задачу, выключают не разбираясь — вместе с
// долговечной проверкой владения. Здесь закреплено, что размер вернуться в
// эту функцию не может: любое значение проходит, пока владение соблюдено.
const temp = mkdtempSync(join(tmpdir(), 'houseplan-support-size-'));
try {
writeFileSync(join(temp, 'initial.js'), 'header only');
writeFileSync(join(temp, 'editor.js'), 'lazy English marker · lazy Russian marker');
const markers = ['lazy English marker', 'lazy Russian marker'];
const base = { initialViewFiles: ['initial.js'], lazyEditorFiles: ['editor.js'] };
for (const initialViewGzipBytes of [0, 291_046, 10_000_000, undefined]) {
assert.doesNotThrow(
() => assertSupportBundleOwnership({ ...base, initialViewGzipBytes }, temp, markers),
`размер ${initialViewGzipBytes} не должен влиять на проверку владения`,
);
}
// Размер по-прежнему охраняется — но общим бюджетом, а не чужим номером.
assert.match(
lowHeadroomWarning(9058) || '',
/запас бюджета 9058 Б/,
'предупреждение о запасе остаётся единственным честным сигналом о размере',
);
} finally {
rmSync(temp, { recursive: true, force: true });
}
});