From 898713585beaf051d947034af77ababb2946e375 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 5 Oct 2026 23:50:57 -0700 Subject: [PATCH 1/4] chore(size): measure the minified allowance against the minified recorded with each cap Each cap records the minified size measured when it was set (capMinified inline, { cap, minified } in floor-caps.json). Over the brotli cap, a scenario fails when head minified exceeds the recorded size + 20 B, so growth cannot creep across PRs; the base comparison stays as the fail-safe for a cap without one. The warning states the headroom left. The ratchet pairs the recorded minified with each lowered cap and otherwise only lowers it (--minified-only records missing ones); check-floor-caps freezes a floor's recorded minified like its cap. Co-authored-by: Claude via Cursor --- scripts/size/README.md | 93 ++++++++++++------ scripts/size/check-floor-caps.mjs | 17 +++- scripts/size/gate.mjs | 96 ++++++++++++++----- scripts/size/gate.test.mjs | 92 ++++++++++++++---- scripts/size/ratchet.mjs | 152 ++++++++++++++++++++++-------- scripts/size/report.mjs | 22 +++-- scripts/size/scenarios.js | 27 +++++- scripts/size/size.mjs | 1 + 8 files changed, 376 insertions(+), 124 deletions(-) diff --git a/scripts/size/README.md b/scripts/size/README.md index a20b2746a..c598b0115 100644 --- a/scripts/size/README.md +++ b/scripts/size/README.md @@ -20,28 +20,43 @@ monotonic in the input: a change of a few minified bytes moves a scenario's brotli by ±50–90 B, so a brotli-only gate failed PRs for noise and every "fix" either raised a cap (permanently) or golfed the code until the layout came out lucky. Minified bytes are deterministic, so the gate (`gate.mjs`) -uses them to tell noise from growth. Per scenario: - -| brotli vs cap | minified vs base | verdict | -| ------------- | ------------------------------------- | ------------------------------ | -| at or under | anything | **pass** | -| over | grew by ≤ `MINIFIED_ALLOWANCE` (20 B) | **pass with a warning** | -| over | grew by more | **fail** | -| over | no base measurement | **fail** (the cap is absolute) | - -"Base" is the PR's base commit (`pull_request.base.sha`, the first parent -of the merge commit CI measures as the head), measured in the same run -with the head's harness; on a push to `next` it is the commit before the -push. The warning — in the job summary, the PR size comment and as an -annotation — reads _over brotli cap by N B, minified +M B — layout noise; -cap will be re-based at the next ratchet_. The allowance is one constant, -`MINIFIED_ALLOWANCE` in `gate.mjs`; a scenario may set its own with -`minifiedAllowance` in `scenarios.js` (none does). +uses them to tell noise from growth. + +Every cap records the **minified size measured when it was set**: +`capMinified` beside an inline `limit` in `scenarios.js`, and +`{ "cap", "minified" }` entries in `floor-caps.json`. Per scenario: + +| brotli vs cap | head minified | verdict | +| ------------- | ---------------------------------------------------- | ----------------------- | +| at or under | anything | **pass** | +| over | ≤ recorded minified + `MINIFIED_ALLOWANCE` (20 B) | **pass with a warning** | +| over | more | **fail** | +| over | no recorded minified: grew ≤ 20 B over the PR's base | pass with a warning | +| over | no recorded minified: grew more, or no base | **fail** | + +The allowance is measured against the recorded size, not per PR, so growth +cannot creep across PRs: on an over-cap scenario, two successive +15 B PRs +do not both pass — the second is +30 B over the recorded size. The warning +(job summary, PR size comment, annotation) states the headroom left: +_over brotli cap by N B; minified M B vs R B recorded with the cap (+D B) — +H B of the 20 B minified allowance left; +P B minified over this PR's base_. +A failure carries the same numbers, so a PR whose own change is small can +see that earlier growth used the allowance up. + +The last two rows are the fail-safe for a cap without a recorded minified (a +new scenario that did not record one): the gate compares with the PR's base +(`pull_request.base.sha`, the first parent of the merge commit CI measures +as the head; on a push to `next`, the commit before the push), measured in +the same run with the head's harness, and the summary says so. The +allowance is one constant, `MINIFIED_ALLOWANCE` in `gate.mjs`; a scenario +may set its own with `minifiedAllowance` in `scenarios.js` (none does). Real growth is still a decision made in the PR: lower the bytes, or raise -the scenario's cap in the same PR with a dated reason in its ledger. Raising -a frozen floor cap (below) additionally needs a `Size-Exception:` line in -the PR body — the override for growth the maintainer has accepted. +the scenario's cap **and its recorded minified** in the same PR, measured +together by CI, with a dated reason in its ledger. A new scenario records +both. Raising a frozen floor's cap or its recorded minified (below) +additionally needs a `Size-Exception:` line in the PR body — the override +for growth the maintainer has accepted. Locally, `npm run size` is the absolute gate (any scenario over its cap fails); `node gate.mjs head.json base.json` applies the PR rule to two @@ -49,14 +64,22 @@ fails); `node gate.mjs head.json base.json` applies the PR rule to two ## The ratchet -Noise that passed with a warning leaves a scenario over its cap; savings -leave caps loose. `npm run ratchet` re-bases every cap on what the tree -measures now — measured + 10 B rounded up to 0.01 KB — and **only ever -lowers** a cap. It rewrites the inline caps in `scenarios.js` and the frozen -floors in `floor-caps.json`, adds a dated ledger line above each lowered -cap, and prints the lowered inline caps and the lowered **frozen floors** as -separate tables, so a floor change is seen as one. A scenario still over its -cap is listed and left alone: the ratchet does not raise. +Savings leave caps loose. `npm run ratchet` re-bases every cap on what the +tree measures now — measured + 10 B rounded up to 0.01 KB — and **only ever +lowers** a cap. A lowered cap records the minified measured with it (one +measurement; if that minified is higher, brotli still shrank, and the +ratchet lists it). A cap it does not lower only ever has its recorded +minified **lowered**, or recorded for the first time; it is never raised — +that loosens the gate like a cap raise, so it takes a PR (and, on a floor, +a `Size-Exception:`). The ratchet rewrites `scenarios.js` and +`floor-caps.json`, adds a dated ledger line above each cap it changes, and +prints the inline caps and the **frozen floors** as separate tables, so a +floor change is seen as one. Scenarios still over their cap, or above their +recorded minified, are listed and left alone: the ratchet does not raise, +so a scenario that landed over its cap on noise stays over it, held to its +recorded minified + 20 B, until code shrinks or a PR re-bases it. +`--minified-only` leaves every cap alone and only records or lowers +minified sizes. Run it once per RC, on `next`, from CI's numbers — local and CI artifacts differ by tens of brotli bytes: @@ -124,8 +147,9 @@ maintainer accepted the cost (read from the PR body when the run starts — edit the body, then re-run). Ten weeks of individually justified 10–300 B bumps took the signals floor from 7.1 to 9.9 KB; the freeze makes the next one a decision, not a paragraph. See -`documentation/plans/size-reduction-audit.md`. The ratchet may lower a -frozen floor like any cap. +`documentation/plans/size-reduction-audit.md`. Each floor's recorded +minified is frozen the same way (raising it, or removing it, needs the +exception). The ratchet may lower a frozen floor like any cap. ## Attribution @@ -176,3 +200,12 @@ breaks. `compare` job (which ran after `check`) into a parallel `base` job that `check` waits on, and pushes to `next` now compare against the previous commit instead of the absolute cap. No cap changed. +- **2026-10-05 — recorded minified (#SEED_PR).** Measured per PR, the + allowance let an over-cap scenario creep: each +15 B PR passed against its + own base. Every cap now records the minified size measured when it was + set, and the allowance is measured against that. The warning states the + headroom left instead of promising a re-base (the lower-only ratchet + cannot re-base an over-cap scenario). Seeded by the ratchet's + `--minified-only` mode from CI's measurement of `next` @ SEED_SHA (Size + run SEED_RUN); every cap unchanged. The base comparison remains the fail-safe + for a cap without a recorded minified. diff --git a/scripts/size/check-floor-caps.mjs b/scripts/size/check-floor-caps.mjs index 416036bb2..f39383b50 100644 --- a/scripts/size/check-floor-caps.mjs +++ b/scripts/size/check-floor-caps.mjs @@ -12,7 +12,11 @@ // Compares floor-caps.json at HEAD with the same file at . Exits // non-zero if any cap increased, unless SIZE_EXCEPTION (the PR body, in CI) // contains a line starting with "Size-Exception:" that names the reason. -// A cap absent at the base (a new floor scenario) is allowed. +// A cap absent at the base (a new floor scenario) is allowed. The minified +// size recorded with each cap (`{ cap, minified }` entries; the gate +// measures minified growth against it) is frozen the same way: raising it +// loosens the gate exactly as raising the cap does. A recorded minified +// absent at the base (an entry still in the old string form) is allowed. import { readFileSync } from "node:fs"; import { execFileSync } from "node:child_process"; @@ -54,12 +58,15 @@ try { } const exception = /^\s*Size-Exception:\s*\S/m.test(process.env.SIZE_EXCEPTION ?? ""); +const entry = e => (typeof e === "string" ? { cap: e } : e); let raised = []; -for (const [name, cap] of Object.entries(head)) { +for (const [name, value] of Object.entries(head)) { if (!(name in baseCaps)) continue; - const before = toBytes(baseCaps[name]); - const after = toBytes(cap); - if (after > before) raised.push(` ${name}: ${baseCaps[name]} -> ${cap}`); + const was = entry(baseCaps[name]); + const now = entry(value); + if (toBytes(now.cap) > toBytes(was.cap)) raised.push(` ${name}: ${was.cap} -> ${now.cap}`); + if (typeof was.minified === "number" && !(now.minified <= was.minified)) + raised.push(` ${name}: recorded minified ${was.minified} B -> ${now.minified ?? "removed"}`); } if (raised.length === 0) { diff --git a/scripts/size/gate.mjs b/scripts/size/gate.mjs index 61bf5cc7e..d75105fee 100644 --- a/scripts/size/gate.mjs +++ b/scripts/size/gate.mjs @@ -3,14 +3,19 @@ // // Caps are brotli bytes, and brotli is what ships, so a scenario under its // cap passes whatever its minified size did. Over the cap is not enough to -// fail: brotli's layout moves ±50–90 B on minified changes of a few bytes, so -// a PR fails a scenario only when it is over its brotli cap AND its minified -// growth over the PR's base exceeds MINIFIED_ALLOWANCE (or the scenario's -// `minifiedAllowance`). Over the cap within the allowance passes with a -// warning — layout noise, left for the next ratchet (ratchet.mjs) to re-base. -// The base is the PR's base commit, or on a push to next the commit before -// it. Without a base measurement (a new scenario, a base the head's harness -// could not measure, a local run) the cap is absolute, as it always was. +// fail: brotli's layout moves ±50–90 B on minified changes of a few bytes. +// Each cap records the minified size measured when it was set +// (`capMinified`), and a scenario fails only when it is over its brotli cap +// AND its minified size exceeds that recorded size by more than +// MINIFIED_ALLOWANCE (or the scenario's `minifiedAllowance`). Over the cap +// within the allowance passes with a warning stating the headroom left. +// Measuring against the recorded size, not the PR's base, bounds growth +// across PRs: two +15 B PRs on an over-cap scenario cannot both pass. +// +// Fail-safe: a cap with no recorded minified falls back to the minified +// growth over the PR's base (the PR's base commit, or on a push to next the +// commit before it). Without that either (a new scenario, a base the head's +// harness could not measure, a local run) the cap is absolute. // // Usage: node gate.mjs [base.json] // Exits non-zero when any scenario fails. In GitHub Actions each warning @@ -23,10 +28,17 @@ import { fileURLToPath } from "node:url"; // counts as real. Minified is the deterministic unit; brotli is not. export const MINIFIED_ALLOWANCE = 20; +const signed = d => `${d >= 0 ? "+" : "−"}${Math.abs(d)} B`; +const bytes = n => `${n.toLocaleString("en-US")} B`; +const REAL_GROWTH = + "real growth: reduce it, or raise the cap and its recorded minified in this PR with a reason (frozen floors need `Size-Exception:`)"; + /** - * One scenario's verdict. - * @returns {{ name: string, verdict: "pass" | "warn" | "fail", overBy?: number, - * minDelta?: number, allowance?: number, message: string }} + * One scenario's verdict. `against` says what the minified size was judged + * against: the minified recorded with the cap, or (fail-safe) the base. + * @returns {{ name: string, verdict: "pass" | "warn" | "fail", + * against?: "recorded" | "base" | "none", overBy?: number, minDelta?: number, + * baseDelta?: number, headroom?: number, allowance?: number, message: string }} */ export function decide(head, base) { const { name } = head; @@ -34,32 +46,58 @@ export function decide(head, base) { if (head.size <= head.limit) return { name, verdict: "pass", message: "within its cap" }; const overBy = head.size - head.limit; const allowance = head.minifiedAllowance ?? MINIFIED_ALLOWANCE; - if (!base || base.error || typeof base.minified !== "number") + const hasBase = base && !base.error && typeof base.minified === "number"; + const baseDelta = hasBase ? head.minified - base.minified : undefined; + const thisPR = hasBase ? `; ${signed(baseDelta)} minified over this PR's base` : ""; + + if (typeof head.capMinified === "number") { + const minDelta = head.minified - head.capMinified; + const headroom = allowance - minDelta; + const vs = `minified ${bytes(head.minified)} vs ${bytes(head.capMinified)} recorded with the cap (${signed(minDelta)})`; + const common = { name, against: "recorded", overBy, minDelta, baseDelta, headroom, allowance }; + if (headroom >= 0) + return { + ...common, + verdict: "warn", + message: `over brotli cap by ${overBy} B; ${vs} — ${headroom} B of the ${allowance} B minified allowance left${thisPR}` + }; + return { + ...common, + verdict: "fail", + message: `over brotli cap by ${overBy} B; ${vs} — ${-headroom} B past the ${allowance} B minified allowance${thisPR}. ${REAL_GROWTH}` + }; + } + + if (!hasBase) return { name, verdict: "fail", + against: "none", overBy, allowance, - message: `over brotli cap by ${overBy} B, no base measurement to compare minified growth against` + message: `over brotli cap by ${overBy} B; no minified recorded with the cap and no base measurement to compare against` }; - const minDelta = head.minified - base.minified; - const signed = `${minDelta >= 0 ? "+" : "−"}${Math.abs(minDelta)} B`; - if (minDelta <= allowance) + const headroom = allowance - baseDelta; + const common = { + name, + against: "base", + overBy, + minDelta: baseDelta, + baseDelta, + headroom, + allowance + }; + const vs = `no minified recorded with the cap, so judged against this PR's base: minified ${signed(baseDelta)}`; + if (headroom >= 0) return { - name, + ...common, verdict: "warn", - overBy, - minDelta, - allowance, - message: `over brotli cap by ${overBy} B, minified ${signed} — layout noise; cap will be re-based at the next ratchet` + message: `over brotli cap by ${overBy} B; ${vs} — ${headroom} B of the ${allowance} B minified allowance left` }; return { - name, + ...common, verdict: "fail", - overBy, - minDelta, - allowance, - message: `over brotli cap by ${overBy} B, minified ${signed} (allowance ${allowance} B) — real growth: reduce it, or raise the cap in this PR with a reason (frozen floors need \`Size-Exception:\`)` + message: `over brotli cap by ${overBy} B; ${vs} — ${-headroom} B past the ${allowance} B minified allowance. ${REAL_GROWTH}` }; } @@ -101,6 +139,12 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) { `::${v.verdict === "warn" ? "warning" : "error"} title=${prop(`size: ${v.name}`)}::${data(v.message)}` ); } + const fallback = verdicts.filter(v => v.against === "base" || v.against === "none"); + if (fallback.length) + console.log( + `\ngate: ${fallback.length} over-cap scenario(s) have no minified recorded with the cap; ` + + "judged against the base instead (fail-safe)." + ); const failed = verdicts.some(v => v.verdict === "fail"); const warned = verdicts.filter(v => v.verdict === "warn").length; console.log( diff --git a/scripts/size/gate.test.mjs b/scripts/size/gate.test.mjs index 301bd88b0..e3f3b7ad9 100644 --- a/scripts/size/gate.test.mjs +++ b/scripts/size/gate.test.mjs @@ -3,46 +3,100 @@ import { test } from "node:test"; import assert from "node:assert/strict"; import { decide, decideAll, MINIFIED_ALLOWANCE } from "./gate.mjs"; -const head = (size, minified, extra = {}) => ({ name: "s", size, minified, limit: 1000, ...extra }); +// A scenario capped at 1000 B brotli, with 4000 B minified recorded with the cap. +const head = (size, minified, extra = {}) => ({ + name: "s", + size, + minified, + limit: 1000, + capMinified: 4000, + ...extra +}); +const unrecorded = (size, minified, extra = {}) => { + const h = head(size, minified, extra); + delete h.capMinified; + return h; +}; const base = minified => ({ name: "s", size: 990, minified }); test("under the cap passes whatever minified did", () => { assert.equal(decide(head(1000, 5000), base(4000)).verdict, "pass"); - assert.equal(decide(head(990, 5000)).verdict, "pass"); + assert.equal(decide(unrecorded(990, 5000)).verdict, "pass"); }); -test("over the cap with minified growth within the allowance warns", () => { - const v = decide(head(1050, 4000 + MINIFIED_ALLOWANCE), base(4000)); +test("over the cap within the allowance of the recorded minified warns with the headroom left", () => { + const v = decide(head(1050, 4012), base(4000)); assert.equal(v.verdict, "warn"); + assert.equal(v.against, "recorded"); assert.equal(v.overBy, 50); - assert.equal(v.minDelta, MINIFIED_ALLOWANCE); + assert.equal(v.minDelta, 12); + assert.equal(v.headroom, MINIFIED_ALLOWANCE - 12); assert.equal( v.message, - `over brotli cap by 50 B, minified +${MINIFIED_ALLOWANCE} B — layout noise; cap will be re-based at the next ratchet` + `over brotli cap by 50 B; minified 4,012 B vs 4,000 B recorded with the cap (+12 B) — ${MINIFIED_ALLOWANCE - 12} B of the ${MINIFIED_ALLOWANCE} B minified allowance left; +12 B minified over this PR's base` ); + assert.doesNotMatch(v.message, /re-base/); +}); + +test("exactly at the allowance warns; one byte past fails", () => { + assert.equal(decide(head(1001, 4000 + MINIFIED_ALLOWANCE)).verdict, "warn"); + const v = decide(head(1001, 4000 + MINIFIED_ALLOWANCE + 1), base(4000)); + assert.equal(v.verdict, "fail"); + assert.equal(v.headroom, -1); + assert.match(v.message, /1 B past the 20 B minified allowance/); +}); + +test("creep: two successive +15 B PRs on an over-cap scenario — the second fails", () => { + // PR 1 on a base at the recorded size: +15 B, over the cap on layout noise. + const pr1 = decide(head(1030, 4015), base(4000)); + assert.equal(pr1.verdict, "warn"); + assert.equal(pr1.headroom, 5); + // PR 1 merged; PR 2 adds another +15 B on top of it. Against its own base + // that is +15 B again, but against the recorded minified it is +30 B. + const pr2 = decide(head(1030, 4030), base(4015)); + assert.equal(pr2.verdict, "fail"); + assert.equal(pr2.baseDelta, 15); + assert.equal(pr2.minDelta, 30); + assert.match(pr2.message, /\+15 B minified over this PR's base/); + // The per-PR comparison alone (no recorded minified) would have let it through. + assert.equal(decide(unrecorded(1030, 4030), base(4015)).verdict, "warn"); }); -test("over the cap after shrinking minified warns", () => { +test("under the cap again after creep passes; the recorded minified does not move", () => { + assert.equal(decide(head(995, 4030), base(4015)).verdict, "pass"); +}); + +test("shrinking minified over the cap warns with more headroom", () => { const v = decide(head(1003, 3946), base(4000)); assert.equal(v.verdict, "warn"); - assert.match(v.message, /minified −54 B/); + assert.equal(v.headroom, MINIFIED_ALLOWANCE + 54); + assert.match(v.message, /\(−54 B\)/); }); -test("over the cap with minified growth past the allowance fails", () => { - const v = decide(head(1001, 4000 + MINIFIED_ALLOWANCE + 1), base(4000)); - assert.equal(v.verdict, "fail"); - assert.equal(v.minDelta, MINIFIED_ALLOWANCE + 1); +test("a scenario's minifiedAllowance overrides the default", () => { + assert.equal(decide(head(1001, 4030, { minifiedAllowance: 40 })).verdict, "warn"); + assert.equal(decide(head(1001, 4010, { minifiedAllowance: 0 })).verdict, "fail"); }); -test("a scenario's minifiedAllowance overrides the default", () => { - assert.equal(decide(head(1001, 4030, { minifiedAllowance: 40 }), base(4000)).verdict, "warn"); - assert.equal(decide(head(1001, 4010, { minifiedAllowance: 0 }), base(4000)).verdict, "fail"); +test("fail-safe: no recorded minified falls back to the base and says so", () => { + const warn = decide(unrecorded(1050, 4020), base(4000)); + assert.equal(warn.verdict, "warn"); + assert.equal(warn.against, "base"); + assert.match(warn.message, /no minified recorded with the cap, so judged against this PR's base/); + const fail = decide(unrecorded(1050, 4021), base(4000)); + assert.equal(fail.verdict, "fail"); + assert.equal(fail.against, "base"); +}); + +test("no recorded minified and no usable base: the cap is absolute", () => { + assert.equal(decide(unrecorded(1001, 4000)).verdict, "fail"); + assert.equal(decide(unrecorded(1001, 4000), { name: "s", error: "boom" }).verdict, "fail"); + assert.equal(decide(unrecorded(1000, 4000)).verdict, "pass"); }); -test("without a usable base the cap is absolute", () => { - assert.equal(decide(head(1001, 4000)).verdict, "fail"); - assert.equal(decide(head(1001, 4000), { name: "s", error: "boom" }).verdict, "fail"); - assert.equal(decide(head(1000, 4000)).verdict, "pass"); +test("a recorded minified does not need a base", () => { + assert.equal(decide(head(1001, 4010)).verdict, "warn"); + assert.equal(decide(head(1001, 4021)).verdict, "fail"); }); test("a scenario that failed to bundle fails", () => { diff --git a/scripts/size/ratchet.mjs b/scripts/size/ratchet.mjs index 9f0c20494..d1dcce5d1 100644 --- a/scripts/size/ratchet.mjs +++ b/scripts/size/ratchet.mjs @@ -5,18 +5,28 @@ // Run per RC, on the release candidate's next, from CI's measurement // (`--from`): local and CI artifacts differ by tens of brotli bytes. // +// Each cap carries the minified size recorded when it was set +// (`capMinified`; gate.mjs measures minified growth against it). A lowered +// cap records the minified measured with it — the two are one measurement. +// A cap that is not lowered only ever has its recorded minified LOWERED (or +// recorded for the first time when it has none): raising it would loosen the +// gate exactly as raising the cap would, so that stays a PR decision too. +// // Inline caps are rewritten in scenarios.js with a dated ledger line above // each; the frozen floors in floor-caps.json are rewritten too, with their // ledger line on the scenario in scenarios.js, and are listed in their own -// table so a floor change is seen as one. Scenarios still over their cap -// after re-measuring are listed and left alone: the ratchet does not raise. +// tables so a floor change is seen as one. Scenarios still over their cap, +// or above their recorded minified, are listed and left alone. // -// Usage: node ratchet.mjs [--from ] [--note ] [--dry-run] -// --from ratchet from a size.mjs --json measurement (CI's -// size-head artifact of a push to next) instead of -// measuring this checkout -// --note recorded in each ledger line (e.g. "RC.7, next @ abc1234") -// --dry-run print the tables, write nothing +// Usage: node ratchet.mjs [--from ] [--note ] +// [--minified-only] [--dry-run] +// --from ratchet from a size.mjs --json measurement (CI's +// size-head artifact of a push to next) instead of +// measuring this checkout +// --note recorded in each ledger line (e.g. "RC.7, next @ abc1234") +// --minified-only leave every cap alone; only record missing minified +// sizes and lower recorded ones +// --dry-run print the tables, write nothing import { readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; @@ -27,6 +37,7 @@ const HEADROOM = 10; /** Measured brotli + headroom, rounded up to the next 10 B (0.01 KB). */ const capFor = br => Math.ceil((br + HEADROOM) / 10) * 10; const formatCap = bytes => `${(bytes / 1000).toFixed(2)} KB`; +const fmt = n => n.toLocaleString("en-US"); const args = process.argv.slice(2); const flag = name => { @@ -36,6 +47,7 @@ const flag = name => { const fromFile = flag("--from"); const note = flag("--note"); const dryRun = args.includes("--dry-run"); +const minifiedOnly = args.includes("--minified-only"); let measured; if (fromFile) { @@ -54,7 +66,12 @@ if (fromFile) { const floorFile = join(here, "floor-caps.json"); const scenariosFile = join(here, "scenarios.js"); -const floorCaps = JSON.parse(readFileSync(floorFile, "utf8")); +const floorCaps = Object.fromEntries( + Object.entries(JSON.parse(readFileSync(floorFile, "utf8"))).map(([name, e]) => [ + name, + typeof e === "string" ? { cap: e } : e + ]) +); let source = readFileSync(scenariosFile, "utf8"); const errors = measured.filter(m => m.error); @@ -67,28 +84,41 @@ if (errors.length) { const date = new Date().toLocaleDateString("en-CA"); const origin = fromFile ? "CI-measured" : `measured locally (${process.platform})`; -const lowered = { inline: [], floor: [] }; +const changed = { inline: [], floor: [] }; const stillOver = []; +const aboveRecorded = []; for (const scenario of scenarios) { const m = measured.find(x => x.name === scenario.name); if (!m) { console.error(`ratchet: no measurement for "${scenario.name}"; nothing written.`); process.exit(1); } - const cap = toBytes(scenario.limit); - const next = capFor(m.size); - if (m.size > cap) - stillOver.push({ name: scenario.name, cap, size: m.size, minified: m.minified }); - if (next >= cap) continue; const floor = scenario.name in floorCaps; + const cap = toBytes(scenario.limit); + const recorded = scenario.capMinified; + if (m.size > cap) stillOver.push({ name: scenario.name, cap, size: m.size }); + + let newCap = cap; + let newRecorded = recorded; + if (!minifiedOnly && capFor(m.size) < cap) { + newCap = capFor(m.size); + newRecorded = m.minified; + } else if (typeof recorded !== "number" || m.minified < recorded) { + newRecorded = m.minified; + } else if (m.minified > recorded) { + aboveRecorded.push({ name: scenario.name, recorded, minified: m.minified }); + } + if (newCap === cap && newRecorded === recorded) continue; + const row = { name: scenario.name, from: formatCap(cap), - to: formatCap(next), + to: formatCap(newCap), size: m.size, - minified: m.minified + recFrom: recorded, + recTo: newRecorded }; - (floor ? lowered.floor : lowered.inline).push(row); + (floor ? changed.floor : changed.inline).push(row); // The scenario's block runs from its `name:` to the next scenario's. const start = source.indexOf(`name: ${JSON.stringify(scenario.name)},`); @@ -99,41 +129,89 @@ for (const scenario of scenarios) { const at = block.indexOf(limitText); if (at < 0) throw new Error(`ratchet: no \`${limitText}\` line for "${scenario.name}"`); const lineStart = block.lastIndexOf("\n", at) + 1; + const lineEnd = block.indexOf("\n", at); const indent = block.slice(lineStart, at); + const recordedText = + typeof recorded === "number" + ? `recorded minified ${fmt(recorded)} -> ${fmt(newRecorded)} B` + : `recorded minified ${fmt(newRecorded)} B (first record)`; + const what = + newCap !== cap + ? `${row.from} -> ${row.to}, ${recordedText}` + : `cap unchanged at ${row.from}, ${recordedText}`; const ledger = - `${indent}// Ratchet (${date}${note ? `, ${note}` : ""}): ${row.from} -> ${row.to}, ${origin} at\n` + - `${indent}// ${m.size.toLocaleString("en-US")} B (${m.minified.toLocaleString("en-US")} B minified). ` + - `Lower only: measured + ${HEADROOM} B rounded up to 0.01 KB.\n`; - const rest = floor - ? block.slice(lineStart) - : block.slice(lineStart).replace(limitText, `limit: ${JSON.stringify(row.to)},`); - if (floor) floorCaps[scenario.name] = row.to; - source = source.slice(0, start) + block.slice(0, lineStart) + ledger + rest + source.slice(end); + `${indent}// Ratchet (${date}${note ? `, ${note}` : ""}): ${what}; ${origin} at\n` + + `${indent}// ${fmt(m.size)} B (${fmt(m.minified)} B minified). Lower only: cap at measured\n` + + `${indent}// + ${HEADROOM} B rounded up to 0.01 KB; recorded minified never raised.\n`; + + let limitLine = block.slice(lineStart, lineEnd); + let after = block.slice(lineEnd); + if (floor) { + floorCaps[scenario.name] = { cap: row.to, minified: newRecorded }; + } else { + if (newCap !== cap) + limitLine = limitLine.replace(limitText, `limit: ${JSON.stringify(row.to)},`); + const recordedLine = /\n *capMinified: \d+,/; + after = recordedLine.test(after) + ? after.replace(recordedLine, `\n${indent}capMinified: ${newRecorded},`) + : `\n${indent}capMinified: ${newRecorded},` + after; + } + source = + source.slice(0, start) + + block.slice(0, lineStart) + + ledger + + limitLine + + after + + source.slice(end); } const table = rows => - ["| scenario | cap | measured | new cap |", "| --- | ---: | ---: | ---: |"] - .concat(rows.map(r => `| ${r.name} | ${r.from} | ${r.size} B | ${r.to} |`)) + [ + "| scenario | cap | new cap | measured | recorded minified | new recorded |", + "| --- | ---: | ---: | ---: | ---: | ---: |" + ] + .concat( + rows.map( + r => + `| ${r.name} | ${r.from} | ${r.to === r.from ? "—" : r.to} | ${r.size} B | ${r.recFrom ?? "none"} | ${r.recTo} |` + ) + ) .join("\n"); -console.log(`ratchet: ${origin}${note ? `, ${note}` : ""}${dryRun ? " (dry run)" : ""}\n`); -console.log(`Inline caps lowered (scenarios.js): ${lowered.inline.length}`); -if (lowered.inline.length) console.log(table(lowered.inline)); -console.log(`\nFROZEN FLOOR caps lowered (floor-caps.json): ${lowered.floor.length}`); -if (lowered.floor.length) console.log(table(lowered.floor)); -if (stillOver.length) { +console.log( + `ratchet: ${origin}${note ? `, ${note}` : ""}${minifiedOnly ? " (minified only)" : ""}${dryRun ? " (dry run)" : ""}\n` +); +console.log(`Inline caps changed (scenarios.js): ${changed.inline.length}`); +if (changed.inline.length) console.log(table(changed.inline)); +console.log(`\nFROZEN FLOOR caps changed (floor-caps.json): ${changed.floor.length}`); +if (changed.floor.length) console.log(table(changed.floor)); +const pairedUp = [...changed.inline, ...changed.floor].filter( + r => r.to !== r.from && typeof r.recFrom === "number" && r.recTo > r.recFrom +); +if (pairedUp.length) + console.log( + `\nRecorded minified went UP with a lowered cap (one measurement, brotli shrank): ${pairedUp.length}\n` + + pairedUp.map(r => ` ${r.name}: ${r.recFrom} -> ${r.recTo} B`).join("\n") + ); +if (stillOver.length) console.log( `\nStill over their cap (not raised — the ratchet only lowers): ${stillOver.length}\n` + stillOver .map(s => ` ${s.name}: ${s.size} B > ${formatCap(s.cap)} (+${s.size - s.cap} B)`) .join("\n") ); -} +if (aboveRecorded.length) + console.log( + `\nAbove their recorded minified (not raised): ${aboveRecorded.length}\n` + + aboveRecorded + .map(s => ` ${s.name}: ${s.minified} B > ${s.recorded} B (+${s.minified - s.recorded} B)`) + .join("\n") + ); -if (!dryRun && (lowered.inline.length || lowered.floor.length)) { +if (!dryRun && (changed.inline.length || changed.floor.length)) { writeFileSync(scenariosFile, source); writeFileSync(floorFile, JSON.stringify(floorCaps, null, 2) + "\n"); console.log("\nratchet: scenarios.js and floor-caps.json rewritten."); } else if (!dryRun) { - console.log("\nratchet: no cap to lower."); + console.log("\nratchet: nothing to change."); } diff --git a/scripts/size/report.mjs b/scripts/size/report.mjs index fdc879942..0429f02df 100644 --- a/scripts/size/report.mjs +++ b/scripts/size/report.mjs @@ -1,7 +1,7 @@ // Renders the PR size comment: head vs base per scenario, from two size.mjs // --json files, with gate.mjs's verdict for each. Base entries may be missing // (a new scenario, or a base checkout the head's scenarios cannot bundle); -// those rows show "—" and their cap is absolute. +// those rows show "—". // // Usage: node report.mjs [base.json] > comment.md @@ -31,24 +31,34 @@ const rows = head.map((h, i) => { const comparable = !h.error && b && !b.error; const change = comparable ? delta(h.size, b.size) : "—"; const minChange = comparable ? signed(h.minified - b.minified) : "—"; + const minRecorded = + !h.error && typeof h.capMinified === "number" ? signed(h.minified - h.capMinified) : "—"; const cap = toKB(h.limit); const status = h.error ? "❌ error" : v.verdict === "pass" ? "✅" : v.verdict === "warn" - ? `⚠️ over by ${v.overBy} B, noise` + ? `⚠️ over by ${v.overBy} B, ${v.headroom} B minified headroom` : `❌ over by ${v.overBy} B`; const lazy = h.lazy?.length ? h.lazy.map(c => `${c.name} ${toKB(c.br)}`).join(", ") : ""; - return `| ${h.name} | ${size} | ${change} | ${minChange} | ${cap} | ${status} | ${lazy} |`; + return `| ${h.name} | ${size} | ${change} | ${minChange} | ${minRecorded} | ${cap} | ${status} | ${lazy} |`; }); console.log(""); console.log("## Size (brotli, eager entry chunk)\n"); -console.log("| scenario | head | vs base | minified vs base | cap | | lazy chunks (not counted) |"); -console.log("| --- | ---: | ---: | ---: | ---: | --- | --- |"); +console.log( + "| scenario | head | vs base | minified vs base | minified vs recorded | cap | | lazy chunks (not counted) |" +); +console.log("| --- | ---: | ---: | ---: | ---: | ---: | --- | --- |"); console.log(rows.join("\n")); +const fallback = verdicts.filter(v => v.against === "base" || v.against === "none"); +if (fallback.length) + console.log( + `\n> **Fail-safe:** ${fallback.length} over-cap scenario(s) have no minified recorded with the cap and were judged against this PR's base instead: ${fallback.map(v => v.name).join("; ")}.` + ); + const warned = verdicts.filter(v => v.verdict === "warn"); const failed = verdicts.filter(v => v.verdict === "fail"); if (warned.length) { @@ -60,5 +70,5 @@ if (failed.length) { for (const v of failed) console.log(`- **${v.name}**: ${v.message}`); } console.log( - `\nBundled with Rolldown (what Vite ships), brotli q11, decimal KB. A scenario fails only when it is over its brotli cap **and** grew more than ${MINIFIED_ALLOWANCE} B minified over the base; over the cap within that allowance is brotli layout noise and passes with a warning. Caps in \`scripts/size/scenarios.js\`; the floor and page caps in \`floor-caps.json\` are frozen (lower only, or \`Size-Exception:\` in the PR body). Caps are re-based downward by \`npm run ratchet\` (scripts/size/README.md).` + `\nBundled with Rolldown (what Vite ships), brotli q11, decimal KB. A scenario fails only when it is over its brotli cap **and** its minified size is more than ${MINIFIED_ALLOWANCE} B over the minified recorded with the cap; over the cap within that allowance is brotli layout noise and passes with a warning. Caps and their recorded minified in \`scripts/size/scenarios.js\`; the floor and page caps in \`floor-caps.json\` are frozen (lower only, or \`Size-Exception:\` in the PR body). \`npm run ratchet\` lowers caps per RC; it never raises one (scripts/size/README.md).` ); diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index 45fab4d25..336122e53 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -18,6 +18,14 @@ // overrides it per scenario. Limits are lowered (never raised) per RC by // ratchet.mjs, which writes a dated `Ratchet` line above each one it moves. // +// Recorded minified (2026-10-05): `capMinified` (floor-caps.json's +// `minified` for the floors) is the minified size measured when the limit +// was set; the allowance is measured against it rather than per PR, so +// growth cannot creep across PRs. Set it with the limit, from the same CI +// measurement. Seeded for every scenario from CI on next @ SEED_SHA (Size run +// SEED_RUN), limits unchanged; the base comparison is the fail-safe for a +// limit without one. +// // Bundler switch (2026-09-26): the harness measured with esbuild through // size-limit until this date; it now measures with Rolldown, the bundler Vite // ships, pinned exactly in package.json. Every cap was re-based on that day @@ -44,7 +52,15 @@ const alias = { // without a `Size-Exception:` line in its body. Lowering is always allowed. // The dated notes on each scenario below remain the ledger of how the // floor got here. -const floorCaps = require("./floor-caps.json"); +// Each entry is { cap, minified }: the brotli cap and the minified size +// measured when it was set (the gate measures minified growth against it). +const floorFile = require("./floor-caps.json"); +const floorCaps = Object.fromEntries( + Object.entries(floorFile).map(([name, e]) => [name, typeof e === "string" ? e : e.cap]) +); +const floorMinified = Object.fromEntries( + Object.entries(floorFile).map(([name, e]) => [name, e.minified]) +); // Server-component PAGES (audit §1): everything such a page ships eagerly, // nothing external — the frames client and the server-function transport @@ -477,6 +493,7 @@ module.exports = [ // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 7.35 KB. limit: floorCaps["signals: core floor (createSignal/Memo/Effect/Root/flush)"], + capMinified: floorMinified["signals: core floor (createSignal/Memo/Effect/Root/flush)"], alias }, { @@ -1326,6 +1343,7 @@ module.exports = [ // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 9.86 KB. limit: floorCaps["app: render + one signal (the simple-app floor)"], + capMinified: floorMinified["app: render + one signal (the simple-app floor)"], alias }, { @@ -1647,6 +1665,7 @@ module.exports = [ // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 17.71 KB. limit: floorCaps["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], + capMinified: floorMinified["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], alias }, { @@ -3423,6 +3442,8 @@ module.exports = [ // measured + 10 B rounded up to 0.01 KB. Accepted by the maintainer // (2026-10-05). The cap is frozen again at 44.84 KB. limit: floorCaps["page: base server components (hydrating + dynamic + frames + sf reference)"], + capMinified: + floorMinified["page: base server components (hydrating + dynamic + frames + sf reference)"], alias: pageAlias }, { @@ -3530,6 +3551,8 @@ module.exports = [ // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 48.51 KB. limit: floorCaps["page: live server components (base + live/GET + action + isPending/latest)"], + capMinified: + floorMinified["page: live server components (base + live/GET + action + isPending/latest)"], alias: pageAlias }, { @@ -3553,6 +3576,7 @@ module.exports = [ path: "../../packages/web/dist/server.js", import: "{ getRequestEvent, isServer }", limit: floorCaps["server: floor (getRequestEvent + isServer)"], + capMinified: floorMinified["server: floor (getRequestEvent + isServer)"], alias: serverAlias, platform: "node", conditions: serverConditions @@ -3585,6 +3609,7 @@ module.exports = [ path: "../../packages/web/dist/server.js", import: "{ renderToString }", limit: floorCaps["server: renderToString (the server-render floor)"], + capMinified: floorMinified["server: renderToString (the server-render floor)"], alias: serverAlias, platform: "node", conditions: serverConditions diff --git a/scripts/size/size.mjs b/scripts/size/size.mjs index eb21957e8..a6feaa86c 100644 --- a/scripts/size/size.mjs +++ b/scripts/size/size.mjs @@ -65,6 +65,7 @@ for (const scenario of scenarios) { minified: r.min, limit: cap, passed: !over, + ...(typeof scenario.capMinified === "number" && { capMinified: scenario.capMinified }), ...(scenario.minifiedAllowance !== undefined && { minifiedAllowance: scenario.minifiedAllowance }), From 481de8f9ac612541416c182d82975b9ed440ea54 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 5 Oct 2026 23:51:53 -0700 Subject: [PATCH 2/4] chore(size): wrap the ratchet's ledger lines at 80 columns Co-authored-by: Claude via Cursor Co-authored-by: Cursor --- scripts/size/ratchet.mjs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/size/ratchet.mjs b/scripts/size/ratchet.mjs index d1dcce5d1..79299e223 100644 --- a/scripts/size/ratchet.mjs +++ b/scripts/size/ratchet.mjs @@ -39,6 +39,20 @@ const capFor = br => Math.ceil((br + HEADROOM) / 10) * 10; const formatCap = bytes => `${(bytes / 1000).toFixed(2)} KB`; const fmt = n => n.toLocaleString("en-US"); +/** `text` as `//` comment lines of at most 80 columns at `indent`. */ +const comment = (text, indent) => { + const lines = []; + let line = ""; + for (const word of text.split(" ")) { + if (line && indent.length + 3 + line.length + 1 + word.length > 80) { + lines.push(line); + line = word; + } else line = line ? `${line} ${word}` : word; + } + lines.push(line); + return lines.map(l => `${indent}// ${l}\n`).join(""); +}; + const args = process.argv.slice(2); const flag = name => { const i = args.indexOf(name); @@ -139,10 +153,12 @@ for (const scenario of scenarios) { newCap !== cap ? `${row.from} -> ${row.to}, ${recordedText}` : `cap unchanged at ${row.from}, ${recordedText}`; - const ledger = - `${indent}// Ratchet (${date}${note ? `, ${note}` : ""}): ${what}; ${origin} at\n` + - `${indent}// ${fmt(m.size)} B (${fmt(m.minified)} B minified). Lower only: cap at measured\n` + - `${indent}// + ${HEADROOM} B rounded up to 0.01 KB; recorded minified never raised.\n`; + const ledger = comment( + `Ratchet (${date}${note ? `, ${note}` : ""}): ${what}; ${origin} at ${fmt(m.size)} B ` + + `(${fmt(m.minified)} B minified). Lower only: cap at measured + ${HEADROOM} B rounded up ` + + `to 0.01 KB; recorded minified never raised.`, + indent + ); let limitLine = block.slice(lineStart, lineEnd); let after = block.slice(lineEnd); From b00ef86e032a980a50062014be8ad42fdcdbb65f Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 5 Oct 2026 23:52:32 -0700 Subject: [PATCH 3/4] chore(size): seed recorded minified from CI on next @ c54fb10eb Co-authored-by: Claude via Cursor Co-authored-by: Cursor --- scripts/size/README.md | 6 +-- scripts/size/floor-caps.json | 35 ++++++++++++--- scripts/size/scenarios.js | 82 +++++++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/scripts/size/README.md b/scripts/size/README.md index c598b0115..35187016c 100644 --- a/scripts/size/README.md +++ b/scripts/size/README.md @@ -200,12 +200,12 @@ breaks. `compare` job (which ran after `check`) into a parallel `base` job that `check` waits on, and pushes to `next` now compare against the previous commit instead of the absolute cap. No cap changed. -- **2026-10-05 — recorded minified (#SEED_PR).** Measured per PR, the +- **2026-10-05 — recorded minified (#3822).** Measured per PR, the allowance let an over-cap scenario creep: each +15 B PR passed against its own base. Every cap now records the minified size measured when it was set, and the allowance is measured against that. The warning states the headroom left instead of promising a re-base (the lower-only ratchet cannot re-base an over-cap scenario). Seeded by the ratchet's - `--minified-only` mode from CI's measurement of `next` @ SEED_SHA (Size - run SEED_RUN); every cap unchanged. The base comparison remains the fail-safe + `--minified-only` mode from CI's measurement of `next` @ c54fb10eb (Size + run 37424485735); every cap unchanged. The base comparison remains the fail-safe for a cap without a recorded minified. diff --git a/scripts/size/floor-caps.json b/scripts/size/floor-caps.json index 0fb36068d..8b4ce64bb 100644 --- a/scripts/size/floor-caps.json +++ b/scripts/size/floor-caps.json @@ -1,9 +1,30 @@ { - "signals: core floor (createSignal/Memo/Effect/Root/flush)": "7.35 KB", - "app: render + one signal (the simple-app floor)": "9.86 KB", - "app: hydrating (no stores) with Show/For/Loading/Errored/lazy": "17.71 KB", - "page: base server components (hydrating + dynamic + frames + sf reference)": "44.84 KB", - "page: live server components (base + live/GET + action + isPending/latest)": "48.51 KB", - "server: floor (getRequestEvent + isServer)": "1.34 KB", - "server: renderToString (the server-render floor)": "20.42 KB" + "signals: core floor (createSignal/Memo/Effect/Root/flush)": { + "cap": "7.35 KB", + "minified": 20103 + }, + "app: render + one signal (the simple-app floor)": { + "cap": "9.86 KB", + "minified": 27657 + }, + "app: hydrating (no stores) with Show/For/Loading/Errored/lazy": { + "cap": "17.71 KB", + "minified": 52537 + }, + "page: base server components (hydrating + dynamic + frames + sf reference)": { + "cap": "44.84 KB", + "minified": 145569 + }, + "page: live server components (base + live/GET + action + isPending/latest)": { + "cap": "48.51 KB", + "minified": 157517 + }, + "server: floor (getRequestEvent + isServer)": { + "cap": "1.34 KB", + "minified": 3324 + }, + "server: renderToString (the server-render floor)": { + "cap": "20.42 KB", + "minified": 71813 + } } diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index 336122e53..d950692d0 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -22,8 +22,8 @@ // `minified` for the floors) is the minified size measured when the limit // was set; the allowance is measured against it rather than per PR, so // growth cannot creep across PRs. Set it with the limit, from the same CI -// measurement. Seeded for every scenario from CI on next @ SEED_SHA (Size run -// SEED_RUN), limits unchanged; the base comparison is the fail-safe for a +// measurement. Seeded for every scenario from CI on next @ c54fb10eb (Size run +// 37424485735), limits unchanged; the base comparison is the fail-safe for a // limit without one. // // Bundler switch (2026-09-26): the harness measured with esbuild through @@ -492,6 +492,10 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 7.35 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 7.35 KB, recorded minified 20,103 B (first record); + // CI-measured at 7,349 B (20,103 B minified). Lower only: cap at measured + + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["signals: core floor (createSignal/Memo/Effect/Root/flush)"], capMinified: floorMinified["signals: core floor (createSignal/Memo/Effect/Root/flush)"], alias @@ -911,7 +915,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 14.56 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 14.56 KB, recorded minified 44,366 B (first record); + // CI-measured at 14,529 B (44,366 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "14.56 KB", + capMinified: 44366, alias }, { @@ -1152,7 +1161,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 9.49 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 9.49 KB, recorded minified 26,785 B (first record); + // CI-measured at 9,486 B (26,785 B minified). Lower only: cap at measured + + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "9.49 KB", + capMinified: 26785, alias }, { @@ -1342,6 +1356,10 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 9.86 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 9.86 KB, recorded minified 27,657 B (first record); + // CI-measured at 9,846 B (27,657 B minified). Lower only: cap at measured + + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["app: render + one signal (the simple-app floor)"], capMinified: floorMinified["app: render + one signal (the simple-app floor)"], alias @@ -1664,6 +1682,10 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 17.71 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 17.71 KB, recorded minified 52,537 B (first record); + // CI-measured at 17,687 B (52,537 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], capMinified: floorMinified["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], alias @@ -2089,7 +2111,12 @@ module.exports = [ // render-effect mark in laneDirty (+4). Cap set at measured + 10 B // rounded up to 0.01 KB. Accepted by the maintainer (2026-10-05). The // cap is frozen again at 28.87 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 28.87 KB, recorded minified 91,556 B (first record); + // CI-measured at 28,818 B (91,556 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "28.87 KB", + capMinified: 91556, alias }, { @@ -2311,7 +2338,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 12.86 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 12.86 KB, recorded minified 36,538 B (first record); + // CI-measured at 12,830 B (36,538 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "12.86 KB", + capMinified: 36538, alias }, { @@ -2583,7 +2615,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 14.46 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 14.46 KB, recorded minified 41,061 B (first record); + // CI-measured at 14,388 B (41,061 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "14.46 KB", + capMinified: 41061, alias: observeAlias }, { @@ -2974,7 +3011,12 @@ module.exports = [ // core only; brotli layout over the engine's bundle. Cap set at // measured + 10 B rounded up to 0.01 KB. Accepted by the maintainer // (2026-10-05). The cap is frozen again at 28.66 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 28.66 KB, recorded minified 86,389 B (first record); + // CI-measured at 28,642 B (86,389 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "28.66 KB", + capMinified: 86389, alias: observeAlias }, // Compiled-template scenarios (2026-10-05): the four `app:` fixtures above @@ -3007,7 +3049,12 @@ module.exports = [ // CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/floor.jsx", compile: { hydratable: false }, + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 10.05 KB, recorded minified 28,188 B (first record); + // CI-measured at 10,033 B (28,188 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "10.05 KB", + capMinified: 28188, alias }, { @@ -3043,7 +3090,12 @@ module.exports = [ // Cap at CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/csr.jsx", compile: { hydratable: false }, + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 25.13 KB, recorded minified 78,868 B (first record); + // CI-measured at 25,114 B (78,868 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "25.13 KB", + capMinified: 78868, alias }, { @@ -3074,7 +3126,12 @@ module.exports = [ // web=16,591 app=3,058). Cap at CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/hydrating.jsx", compile: { hydratable: true }, + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 30.93 KB, recorded minified 99,168 B (first record); + // CI-measured at 30,921 B (99,168 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "30.93 KB", + capMinified: 99168, alias }, { @@ -3282,7 +3339,12 @@ module.exports = [ // reads the new response's refs before the commit. Accepted by the // maintainer (2026-10-04). The cap is frozen again at 13.78 KB (head + // 10 B). + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 13.78 KB, recorded minified 43,310 B (first record); + // CI-measured at 13,770 B (43,310 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "13.78 KB", + capMinified: 43310, alias: framesAlias, external: framesExternal }, @@ -3441,6 +3503,10 @@ module.exports = [ // +16, observeFlight first-observer hold +17); brotli layout. Cap set at // measured + 10 B rounded up to 0.01 KB. Accepted by the maintainer // (2026-10-05). The cap is frozen again at 44.84 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 44.84 KB, recorded minified 145,569 B (first record); + // CI-measured at 44,819 B (145,569 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["page: base server components (hydrating + dynamic + frames + sf reference)"], capMinified: floorMinified["page: base server components (hydrating + dynamic + frames + sf reference)"], @@ -3550,6 +3616,10 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 48.51 KB. + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 48.51 KB, recorded minified 157,517 B (first record); + // CI-measured at 48,489 B (157,517 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["page: live server components (base + live/GET + action + isPending/latest)"], capMinified: floorMinified["page: live server components (base + live/GET + action + isPending/latest)"], @@ -3575,6 +3645,10 @@ module.exports = [ // shaking. path: "../../packages/web/dist/server.js", import: "{ getRequestEvent, isServer }", + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 1.34 KB, recorded minified 3,324 B (first record); + // CI-measured at 1,331 B (3,324 B minified). Lower only: cap at measured + + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["server: floor (getRequestEvent + isServer)"], capMinified: floorMinified["server: floor (getRequestEvent + isServer)"], alias: serverAlias, @@ -3608,6 +3682,10 @@ module.exports = [ // maintainer. The cap is frozen again at 20.42 KB. path: "../../packages/web/dist/server.js", import: "{ renderToString }", + // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // unchanged at 20.42 KB, recorded minified 71,813 B (first record); + // CI-measured at 20,412 B (71,813 B minified). Lower only: cap at measured + // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["server: renderToString (the server-render floor)"], capMinified: floorMinified["server: renderToString (the server-render floor)"], alias: serverAlias, From 18939cc9901daa529579e37e0864777cca211ead Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Tue, 6 Oct 2026 02:31:09 -0700 Subject: [PATCH 4/4] chore(size): re-seed recorded minified from CI on next @ fff1615ee #3812, #3814 and #3811 moved minified +30 to +69 B after the first seed (c54fb10eb); re-seeded from scratch at the tip, every cap unchanged. Co-authored-by: Claude via Cursor Co-authored-by: Cursor --- scripts/size/README.md | 6 +- scripts/size/floor-caps.json | 10 +-- scripts/size/scenarios.js | 114 +++++++++++++++++------------------ 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/scripts/size/README.md b/scripts/size/README.md index 35187016c..b39e216a3 100644 --- a/scripts/size/README.md +++ b/scripts/size/README.md @@ -200,12 +200,12 @@ breaks. `compare` job (which ran after `check`) into a parallel `base` job that `check` waits on, and pushes to `next` now compare against the previous commit instead of the absolute cap. No cap changed. -- **2026-10-05 — recorded minified (#3822).** Measured per PR, the +- **2026-10-06 — recorded minified (#3822).** Measured per PR, the allowance let an over-cap scenario creep: each +15 B PR passed against its own base. Every cap now records the minified size measured when it was set, and the allowance is measured against that. The warning states the headroom left instead of promising a re-base (the lower-only ratchet cannot re-base an over-cap scenario). Seeded by the ratchet's - `--minified-only` mode from CI's measurement of `next` @ c54fb10eb (Size - run 37424485735); every cap unchanged. The base comparison remains the fail-safe + `--minified-only` mode from CI's measurement of `next` @ fff1615ee (Size + run 37443080193); every cap unchanged. The base comparison remains the fail-safe for a cap without a recorded minified. diff --git a/scripts/size/floor-caps.json b/scripts/size/floor-caps.json index 8b4ce64bb..acb9d32b8 100644 --- a/scripts/size/floor-caps.json +++ b/scripts/size/floor-caps.json @@ -1,23 +1,23 @@ { "signals: core floor (createSignal/Memo/Effect/Root/flush)": { "cap": "7.35 KB", - "minified": 20103 + "minified": 20133 }, "app: render + one signal (the simple-app floor)": { "cap": "9.86 KB", - "minified": 27657 + "minified": 27687 }, "app: hydrating (no stores) with Show/For/Loading/Errored/lazy": { "cap": "17.71 KB", - "minified": 52537 + "minified": 52567 }, "page: base server components (hydrating + dynamic + frames + sf reference)": { "cap": "44.84 KB", - "minified": 145569 + "minified": 145599 }, "page: live server components (base + live/GET + action + isPending/latest)": { "cap": "48.51 KB", - "minified": 157517 + "minified": 157562 }, "server: floor (getRequestEvent + isServer)": { "cap": "1.34 KB", diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index d950692d0..f5e503529 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -18,12 +18,12 @@ // overrides it per scenario. Limits are lowered (never raised) per RC by // ratchet.mjs, which writes a dated `Ratchet` line above each one it moves. // -// Recorded minified (2026-10-05): `capMinified` (floor-caps.json's +// Recorded minified (2026-10-06): `capMinified` (floor-caps.json's // `minified` for the floors) is the minified size measured when the limit // was set; the allowance is measured against it rather than per PR, so // growth cannot creep across PRs. Set it with the limit, from the same CI -// measurement. Seeded for every scenario from CI on next @ c54fb10eb (Size run -// 37424485735), limits unchanged; the base comparison is the fail-safe for a +// measurement. Seeded for every scenario from CI on next @ fff1615ee (Size run +// 37443080193), limits unchanged; the base comparison is the fail-safe for a // limit without one. // // Bundler switch (2026-09-26): the harness measured with esbuild through @@ -492,9 +492,9 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 7.35 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 7.35 KB, recorded minified 20,103 B (first record); - // CI-measured at 7,349 B (20,103 B minified). Lower only: cap at measured + + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 7.35 KB, recorded minified 20,133 B (first record); + // CI-measured at 7,361 B (20,133 B minified). Lower only: cap at measured + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["signals: core floor (createSignal/Memo/Effect/Root/flush)"], capMinified: floorMinified["signals: core floor (createSignal/Memo/Effect/Root/flush)"], @@ -915,12 +915,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 14.56 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 14.56 KB, recorded minified 44,366 B (first record); - // CI-measured at 14,529 B (44,366 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 14.56 KB, recorded minified 44,396 B (first record); + // CI-measured at 14,540 B (44,396 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "14.56 KB", - capMinified: 44366, + capMinified: 44396, alias }, { @@ -1161,12 +1161,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 9.49 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 9.49 KB, recorded minified 26,785 B (first record); - // CI-measured at 9,486 B (26,785 B minified). Lower only: cap at measured + + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 9.49 KB, recorded minified 26,828 B (first record); + // CI-measured at 9,513 B (26,828 B minified). Lower only: cap at measured + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "9.49 KB", - capMinified: 26785, + capMinified: 26828, alias }, { @@ -1356,9 +1356,9 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 9.86 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 9.86 KB, recorded minified 27,657 B (first record); - // CI-measured at 9,846 B (27,657 B minified). Lower only: cap at measured + + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 9.86 KB, recorded minified 27,687 B (first record); + // CI-measured at 9,856 B (27,687 B minified). Lower only: cap at measured + // 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["app: render + one signal (the simple-app floor)"], capMinified: floorMinified["app: render + one signal (the simple-app floor)"], @@ -1682,9 +1682,9 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 17.71 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 17.71 KB, recorded minified 52,537 B (first record); - // CI-measured at 17,687 B (52,537 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 17.71 KB, recorded minified 52,567 B (first record); + // CI-measured at 17,672 B (52,567 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], capMinified: floorMinified["app: hydrating (no stores) with Show/For/Loading/Errored/lazy"], @@ -2111,12 +2111,12 @@ module.exports = [ // render-effect mark in laneDirty (+4). Cap set at measured + 10 B // rounded up to 0.01 KB. Accepted by the maintainer (2026-10-05). The // cap is frozen again at 28.87 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 28.87 KB, recorded minified 91,556 B (first record); - // CI-measured at 28,818 B (91,556 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 28.87 KB, recorded minified 91,625 B (first record); + // CI-measured at 28,888 B (91,625 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "28.87 KB", - capMinified: 91556, + capMinified: 91625, alias }, { @@ -2338,12 +2338,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 12.86 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 12.86 KB, recorded minified 36,538 B (first record); - // CI-measured at 12,830 B (36,538 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 12.86 KB, recorded minified 36,568 B (first record); + // CI-measured at 12,905 B (36,568 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "12.86 KB", - capMinified: 36538, + capMinified: 36568, alias }, { @@ -2615,12 +2615,12 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 14.46 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 14.46 KB, recorded minified 41,061 B (first record); - // CI-measured at 14,388 B (41,061 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 14.46 KB, recorded minified 41,091 B (first record); + // CI-measured at 14,449 B (41,091 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "14.46 KB", - capMinified: 41061, + capMinified: 41091, alias: observeAlias }, { @@ -3011,12 +3011,12 @@ module.exports = [ // core only; brotli layout over the engine's bundle. Cap set at // measured + 10 B rounded up to 0.01 KB. Accepted by the maintainer // (2026-10-05). The cap is frozen again at 28.66 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 28.66 KB, recorded minified 86,389 B (first record); - // CI-measured at 28,642 B (86,389 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 28.66 KB, recorded minified 86,419 B (first record); + // CI-measured at 28,639 B (86,419 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "28.66 KB", - capMinified: 86389, + capMinified: 86419, alias: observeAlias }, // Compiled-template scenarios (2026-10-05): the four `app:` fixtures above @@ -3049,12 +3049,12 @@ module.exports = [ // CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/floor.jsx", compile: { hydratable: false }, - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 10.05 KB, recorded minified 28,188 B (first record); - // CI-measured at 10,033 B (28,188 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 10.05 KB, recorded minified 28,218 B (first record); + // CI-measured at 10,031 B (28,218 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "10.05 KB", - capMinified: 28188, + capMinified: 28218, alias }, { @@ -3090,12 +3090,12 @@ module.exports = [ // Cap at CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/csr.jsx", compile: { hydratable: false }, - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 25.13 KB, recorded minified 78,868 B (first record); - // CI-measured at 25,114 B (78,868 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 25.13 KB, recorded minified 78,898 B (first record); + // CI-measured at 25,129 B (78,898 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "25.13 KB", - capMinified: 78868, + capMinified: 78898, alias }, { @@ -3126,12 +3126,12 @@ module.exports = [ // web=16,591 app=3,058). Cap at CI-measured + 10 B rounded up to 0.01 KB. path: "fixtures/compiled/hydrating.jsx", compile: { hydratable: true }, - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 30.93 KB, recorded minified 99,168 B (first record); - // CI-measured at 30,921 B (99,168 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 30.93 KB, recorded minified 99,198 B (first record); + // CI-measured at 30,957 B (99,198 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: "30.93 KB", - capMinified: 99168, + capMinified: 99198, alias }, { @@ -3339,7 +3339,7 @@ module.exports = [ // reads the new response's refs before the commit. Accepted by the // maintainer (2026-10-04). The cap is frozen again at 13.78 KB (head + // 10 B). - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap // unchanged at 13.78 KB, recorded minified 43,310 B (first record); // CI-measured at 13,770 B (43,310 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. @@ -3503,9 +3503,9 @@ module.exports = [ // +16, observeFlight first-observer hold +17); brotli layout. Cap set at // measured + 10 B rounded up to 0.01 KB. Accepted by the maintainer // (2026-10-05). The cap is frozen again at 44.84 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 44.84 KB, recorded minified 145,569 B (first record); - // CI-measured at 44,819 B (145,569 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 44.84 KB, recorded minified 145,599 B (first record); + // CI-measured at 44,864 B (145,599 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["page: base server components (hydrating + dynamic + frames + sf reference)"], capMinified: @@ -3616,9 +3616,9 @@ module.exports = [ // lane re-stage +13, verdict pull +1). Cap set at measured + 10 B rounded // up to 0.01 KB. Accepted by the maintainer (2026-10-05). The cap is // frozen again at 48.51 KB. - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap - // unchanged at 48.51 KB, recorded minified 157,517 B (first record); - // CI-measured at 48,489 B (157,517 B minified). Lower only: cap at measured + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap + // unchanged at 48.51 KB, recorded minified 157,562 B (first record); + // CI-measured at 48,527 B (157,562 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised. limit: floorCaps["page: live server components (base + live/GET + action + isPending/latest)"], capMinified: @@ -3645,7 +3645,7 @@ module.exports = [ // shaking. path: "../../packages/web/dist/server.js", import: "{ getRequestEvent, isServer }", - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap // unchanged at 1.34 KB, recorded minified 3,324 B (first record); // CI-measured at 1,331 B (3,324 B minified). Lower only: cap at measured + // 10 B rounded up to 0.01 KB; recorded minified never raised. @@ -3682,7 +3682,7 @@ module.exports = [ // maintainer. The cap is frozen again at 20.42 KB. path: "../../packages/web/dist/server.js", import: "{ renderToString }", - // Ratchet (2026-10-05, seed, next @ c54fb10eb, Size run 37424485735): cap + // Ratchet (2026-10-06, seed, next @ fff1615ee, Size run 37443080193): cap // unchanged at 20.42 KB, recorded minified 71,813 B (first record); // CI-measured at 20,412 B (71,813 B minified). Lower only: cap at measured // + 10 B rounded up to 0.01 KB; recorded minified never raised.