Performance budget and ratchet (targets aspire, ceilings hold)
Generated from
pattern-library/registry.json— do not edit by hand; change the registry and runbun run patterns:build.
Category: Velocity Measurement · Tier: deep · Maturity: proven (verified 2026-10-10 @ 149f43a7-dirty) · Risk: low — measurement and gating only; no runtime behaviour
Two thresholds with different jobs: targets are where we want to be and never fail a build, ceilings are the measured value at the moment it was accepted and only ever move down. A gate wired to a target gets muted the afternoon it is added.
When to use: Use for any deterministic metric worth defending — shared JS, route JS, prerendered document weight, known expensive queries.
Avoid when
- The metric is not deterministic run to run, like cold-start time or field latency — report it, don't gate it
- No production build runs before shipping, so there is no lab measurement the gate can trust
Alternatives
- a target scored on a dashboard that never fails the build — prefer when the metric is noisy or field-measured and only needs to stay visible
Docs
- docs/blueprint/velocity/measurement.md#performance-budget-and-ratchet — Targets vs ratchets, and the field/lab/dev split (GitHub · GitLab)
- docs/stack/quality/performance.md — The measurement contexts in full (GitHub · GitLab)
Code
src/lib/server/perf/budgets.json— The single source of truth for both kinds of threshold (GitHub · GitLab)src/lib/server/perf/budgets.ts— Scoring, and why lab and field budgets cannot be shared (GitHub · GitLab)scripts/perf/snapshot.ts— routeNodes(): each route's layout chain from the generated client app (GitHub · GitLab)
Tests
src/lib/server/perf/snapshot.gate.test.ts(GitHub · GitLab)src/lib/server/perf/budgets.test.ts(GitHub · GitLab)
Proof
Invariants
- Targets and regression gates stay distinct — a target may be red today, and saying so is the point.
- Ratchets move down, not up, except through explicit architectural review. Lowering a ceiling is how an improvement gets banked.
- Development measurements are never mixed with lab or production ones.
- A metric is only ratcheted when it is deterministic enough to be reproducible — which is why cold-start time is reported and not gated.
- A lab snapshot from a non-production build is refused rather than scored.
- A per-route budget scores what a visitor downloads: the shared baseline, every layout on the route's chain, and the page — never the page node alone.
Emulation notes
- Give ceilings a few percent of headroom over the measurement. Set exactly at the measured value, one ordinary feature trips the gate — and a gate that fails on ordinary work is a gate that gets muted. The headroom absorbs a feature and deliberately not a heavy dependency.
- Keep the thresholds in ONE file that both the application and the shell probes read. Two copies drift, and the copy that drifts is always the one the gate uses.
- Field and lab budgets for the same metric name are different numbers. Scoring a real-user p75 against a warm-preview budget reports a failure on every healthy deployment.
- Derive the chain from the build, not from file paths: v10r parses the route dictionary in the generated client app.js. Scoring page nodes only had under-reported the median route by 81 KB gz, because the public shell layout alone was ~160 KB.
Machine-readable record: performance-budget-ratchet in pattern-library/registry.json.