ZEROlobby
22/22 strict⌘Kvisitor
skip to main
ADR-022
skin
——:——:——zcovenant · audit
perf + attestation· chapter 28 · 4 gates · 106 pages graded

budgets are declared, not assumed

four gates run in ci:all immediately after the build. bundle weight, prerendered HTML weight, web-vitals contract runtime parity, build attestation + SBOM. every budget lives in a single contract; tightening it requires an ADR. the report you are reading is regenerated on every build.

00 · liveLCP · INP · CLS · FCP · TTFB · graded against the budget the moment the browser reports them

this page reports its own vitals · live

web vitals · live· five core metrics · graded against the budget contract · 0 samples since mount0 / 5 arrived
  • lcplargest contentful paint— · pending sample
  • inpinteraction to next paint— · pending sample
  • clscumulative layout shift— · pending sample
  • fcpfirst contentful paint— · pending sample
  • ttfbtime to first byte— · pending sample

sampled on this page · pageId · · the same registrar is mounted at app/layout.tsx for telemetry-spare console reporting · CI gate scripts/check-web-vitals.mjs enforces parity between this runtime and the budget contract.

01 · budgetssingle source of truth

every budget is declared in one file

plate · A · budgets.contract.jsonv2026-05-14.1
metric
perf
unit
kB
window
static
agg
identity
source
budgets.contract.json
fresh
last build
categoryfieldvalue
bundleperRouteFirstLoadKb1450 kB
bundlelargestChunkKb 490 kB
ssr perRouteHtmlKb 840 kB
ssr perRouteChunkCount 24
web-vitalsLCP 2500 ms
web-vitalsINP 200 ms
web-vitalsCLS 0.1
web-vitalsFCP 1800 ms
web-vitalsTTFB 800 ms
why budgets, not benchmarks
a benchmark is a number you publish. a budget is a number you defend. these four gates defend the budget on every PR; the build hard-fails if the system regresses past the line. tightening a budget is an ADR; loosening one needs brand-veto sign-off. the audit identified "deleted in cleanup, no replacement" as the failure mode this ADR corrects.
02 · bundletop 5 of 106

per-route first-load JS · ranked

plate · B · heaviest routespeak 1421.5 kB
metric
perf
unit
kB
window
static
agg
identity
source
bundle-report.json
fresh
last build
routechunksfirst-load JSlargest chunk
/charts141421.5 kB481.1 kB
/theme141420.6 kB481.1 kB
/components121380.9 kB481.1 kB
/receipts121354.7 kB481.1 kB
/motion121354.4 kB481.1 kB
03 · ssrtop 5 of 91

per-route prerendered HTML · ranked

plate · C · heaviest pagespeak 812.9 kB
metric
perf
unit
kB
window
static
agg
identity
source
ssr-report.json
fresh
last build
routeHTMLchunks
/charts812.9 kB19
/components703.1 kB17
/v1577.5 kB16
/tokens387.3 kB17
/changelog236.4 kB17
04 · web vitalscontract ↔ runtime

three-way parity check, no browser needed

stepartefactverified by
1 · contractgovernance/perf/budgets.contract.jsonschema=zero.perf.budgets.v1
2 · runtimebrand-runtime/src/web-vitals.ts · WEB_VITALS_BUDGETfield-for-field parse + compare
3 · mount book/app/layout.tsx mounts <WebVitalsBoot />regex on the layout file
how the runtime ships
registerWebVitals() dynamically imports web-vitals only in the browser; SSR is a no-op. each sample is graded against the contract; failing samples surface via console.warn by default so the discipline is visible in DevTools without a backend. consumers can pass a sink to forward samples to a real telemetry pipeline.
05 · attestation6 inputs · 353 sbom components

every primary build output · hashed and committed

plate · D · build-attestation2026-05-14T14:36:30.914Z
metric
perf
unit
kB
window
static
agg
identity
source
build-attestation.json
fresh
last build
inputbytessha256
packages/tokens/tokens.json11,989179052bd8369
packages/tokens/tokens.css8,2884d296c29222b
packages/icons/src/icons.json7,157527f67368194
packages/ui/dist/index.js56,638b7a87e512087
brand-runtime/dist/index.js2,8093e20ed23f9b6
book/.next/BUILD_ID21fe0ade8e165c
reproducibility now, deterministic build later
v1 commits the attestation so PR diffs reveal what the build changed. it does not yet enforce equality across runs (Next's BUILD_ID is timestamp-derived). a future ADR may promote the gate to require deterministic hashes once the build pipeline supports it.