Uh oh!
There was an error while loading. Please reload this page.
test(scripts): add per-chunk gzipped ceilings to the eager-closure budget - #6210
Conversation
…dget Per-chunk ceilings for vendor-objectstack, framework and ui-components on top of the aggregate closure ceiling, keyed on the chunk names the report carries so a renamed or vanished chunk fails loudly instead of passing by measuring nothing. Report v2 publishes each eager chunk's own rolldown name. Part of #5490
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
yinlianghui-tw
commented
Aug 25, 2026
PM review — verified against the repository, not against the reportReviewed at head Checked independentlyThe three budgeted names are real Both constraints hold arithmetically, per chunk. Ceiling above measured (a ratchet, not an aspiration) and headroom under the 89 KiB the gate exists to catch:
These are checked in the test as well as satisfied in the constant, which is the right split — the assertion is what survives the next edit. Exit 2 reaches CI as a failure. The v1→v2 bump has no other consumer. Grepped every file on
What makes this worth landingControl [A] is the argument, and it is a single run rather than a claim: +89 KiB onto The vacuity discipline is the other half and it is unusually complete — four separate ways the per-chunk half could measure nothing (chunk absent, zero named chunks, empty ceiling map, unnamed member) and all four are Two judgements I'd have made the same way:
Control [B] coming back with seven failures against a predicted one is reported as wider-than-predicted rather than smoothed over, and the seven share one cause. Restore proven by anchored counts and an empty The stale-card correction is material and was surfaced rather than buried: ⛔ Not arming yet
Generated by Claude Code |
yinlianghui-tw
commented
Aug 25, 2026
Armed — all 25 checks concluded, ready + auto-merge (SQUASH)Re-read the full check set on
⭐ Worth recording alongside the arm: Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
…t, and re-baseline the ceiling The gate stated a binding constraint on its own sensitivity — the headroom above the measured payload must stay SMALLER than the 89 KiB regression the gate exists to catch — and then checked it between two constants frozen in the same module. That assertion is an arithmetic fact about the file, true whatever the console weighs. The closure shrank 706,013 gzipped bytes below the pinned baseline without the ceiling following it down; the live headroom reached 8.6x the regression size, and the check meant to notice stayed green. `evaluateHeadroomSensitivity` derives the headroom from the report the gate just read — for the aggregate ceiling and each of the three per-chunk ceilings added by #6210 — and calls a ceiling more than one regression above its own measurement an ERROR (exit 2, a verdict about the gauge), never a size failure. `error` still outranks `fail`, now across three halves. The aggregate ceiling is re-baselined downward as the decision this records: MAX_EAGER_CLOSURE_GZIP_BYTES 4,086,000 -> 3,345,000 over a BASELINE moving 4,005,911 (4c1623c) -> 3,299,898 (48e5381). Headroom 8.63x -> 0.49x the regression size. Lowering a ceiling toward reality is a tightening; the floor is unchanged — never below a measured figure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Fixes#5490
Per-chunk gzipped ceilings on top of the aggregate eager-closure ceiling, delivering option C of the #5468 ruling (option A stays as shipped in PR #5466; option B — a comparison against
main— is rejected and is not reintroduced here: nothing in this change readsmain, builds twice, or compares against another ref).Sequencing caveat: which state I found
The ruling's caveat says to set the lines after the cleave work if it has landed. It has not landed. Both cards are closed, and neither changed chunking:
/metafoldadvancedChunksinapps/console/vite.config.tsis untouched by both, so the measurement below is against a pre-cleave closure by fact, not by choice. It is measured on the current tip ofmain(2c8474c04), which is the only honest option available today; when a cleave does land, these lines must be re-measured with it.Re-measured, and the card's figures were stale
Every number was re-measured with
vite buildonapps/console, read out of the gauge's own report. Three consecutive builds produced byte-identical totals (3,298,620 gzipped, 52/508 chunks), so these are measurements and not build noise.vendor-objectstackframeworkui-componentsvendor-objectstackhas more than halved since the card was written; the closure as a whole is 3,298,620 B against the 4,005,911 B baseline frozen in the file. Truthful current state plus ~2%, and no ceiling is set below what was measured — this is a ratchet, not an optimisation target.Each headroom is far narrower than
REGRESSION_THIS_GATE_MUST_CATCH_BYTES(89 KiB), which is the property that makes the lines worth having: a repeat of the #5266 incident cannot fit inside any of them. A unit test asserts exactly that, per budgeted chunk.The part that decides whether the gate is worth anything
Chunk names come from the gauge's own measurement.
emitEagerClosureReportnow publishes each eager chunk's rolldownchunk.nameasfiles[].name(report v2); the checker looks names up in that report. It does not re-derive a name by stripping the hash-and-extension suffix off a file name, and it carries no list of chunks it merely expects to exist.A budgeted name that is absent from the report is an error (exit 2), never a skip — a ceiling with no subject weighs nothing and is green forever. The failure prints the missing name, says a vanished chunk must be re-pinned deliberately rather than inferred, and lists every chunk the report does carry, largest first, so a rename is diagnosable from the failure alone.
Three further vacuity holes are closed the same way: a report with zero named chunks is an error; an empty ceiling map is an error ("a disabled check, not a passing one"); and a member carrying no name fails report validation, so a build from before v2 is refused as version drift rather than read as "all budgeted chunks are missing".
The mapping is pinned twice — once at runtime against the report, and once in a unit test asserting each budgeted name is a real
advancedChunksgroup inapps/console/vite.config.ts, so a rename reds without needing a build.Controls, each predicted before running
Positive control 1 — a chunk grows. The #5266 incident replayed byte-for-byte: +89 KiB onto
vendor-objectstackin a report kept internally consistent. Predicted exit 1, aggregate green, per-chunk red naming the chunk and both numbers.The aggregate half is green in that run with 679.9 KB to spare. That contrast is the whole reason this half exists.
Positive control 2 — a ceiling lowered below measured (
framework: 502_000→450_000, anchored counts 1→0 and 0→1 on disk). Predicted red namingframework: observed exit 1,480.9 KB / 439.5 KB ceiling (OVER by 41.4 KB). Predicted at least the ceiling-vs-baseline unit test to red as well; observed 7 failures, all of them the same cause (the baseline now exceeds the lowered ceiling) — a wider blast radius than predicted, same direction. Restored withgit checkout HEAD -- scripts/check-eager-closure-budget.mjs; anchored counts back to 1/0 andgit diff HEADempty (0 bytes).Negative control — a budgeted chunk renamed in the report (the
vendor-objectstackname value replaced withvendor-objectstack-core, anchored counts 1→0 and 0→1). Predicted exit 2 naming the absent chunk, not a pass:What happens on an unbuilt tree
It fails loudly, and it always did — this change keeps that and extends it to the new half. With no
apps/console/dist/eager-closure.jsonthe checker exits 2, both halves saying so in their own words:.github/workflows/performance-budget.ymlmaps exit 2 tobudget_status=errorand fails the step, and it builds the packages and the console before running the checker. Thepnpm check:eager-closurealias is the only other caller, and run against an unbuilt tree it produces the output above rather than a green tick. No path through this gate exits 0 having measured nothing.Verification — all at
32f162a77(the final commit)npx vite build(apps/console)node scripts/check-eager-closure-budget.mjsnpx vitest run scripts/__tests__ --maxWorkers=2(root vitest)npx tsc --noEmit -p tsconfig.scripts.json--listFiles)npx tsc -b apps/console/tsconfig.node.json --forcevite.config.tspnpm lint:rootnpx eslinton the three changed filespnpm check:control-bytes/check:phantom-deps/check:esm-specifiersExit codes captured by redirect before any pipe. The whole
scripts/__tests__directory was run rather than one file because eight tests in it readapps/console/vite.config.tsas their subject.Scope
Chunking is unchanged, the aggregate ceiling and its baseline are unchanged, and no cleave was attempted. Two of the existing
maintests had to move: their fixtures did not carry the budgeted chunk names, and a report missing those is now an error — which is the new half working, not a fixture detail.One thing worth flagging rather than fixing here: the per-chunk headroom assertion compares two frozen constants, the same shape #5924 records for the aggregate one. The per-chunk band is ~2% rather than ~24%, so the exposure is much smaller, but the systemic fix (deriving the headroom check from the report the gate just read) belongs to that card, which is also where the aggregate ceiling's now-very-wide live headroom is already recorded. Nothing here lowers or raises that ceiling.
Generated by Claude Code