| name | perf-verify |
| description | Verify a performance change with before/after evidence — baseline runs, labeled diffs, then the asserting layer. Use when optimizing API or web performance, investigating a perf regression, comparing latency, DOM nodes, or script time across a change, or asked "did this make it faster". |
perf-verify — the optimization loop
Report tools produce labeled artifacts (.perf/<label>/); the asserting
layer gates. Never conclude from a single run — variance rule: 3 runs
per side, compare medians.
Preconditions
docker info first if anything hangs, then docker compose up -d.
- Rebuild HEAD (core is CJS — api/web consume its dist):
pnpm --filter core build && pnpm --filter api build && pnpm --filter web build
- Kill stale listeners on 3001/4173, then start both in the background:
- API:
RATE_LIMIT_PER_MIN=10000000 node dist/main.js from apps/api/
(a full stress run is ~600k requests — 100k/min silently measured
the limiter once; stress now fails such a run)
- Web:
pnpm --filter web preview --port 4173 (never the dev server)
- Confirm the port serves a HEAD build:
curl -s localhost:3001/metrics
answers (stale-dist runs have burned two milestones).
The loop
- Baseline before touching code — 3 runs per relevant surface:
- backend:
node scripts/api-bench.mjs --label baseline-<n> (n = 1..3)
- frontend (only when the change touches web):
node scripts/perf-profile.mjs --label baseline-<n> and one
node scripts/snapshot.mjs --label baseline for screenshots.
- Apply the change; rebuild; restart the API/preview from the new dist.
- Rerun the same tools 3× with
--label after-<slug>-<n>.
- Diff medians from
.perf/<label>/api.json / profile.json. If the
delta of medians is within the baseline's own run-to-run spread, the
honest verdict is "no measurable change" — report exactly that.
- The asserting layer must stay green:
pnpm ui-spec — frontend budgets (DOM scaling, script time)
node scripts/stress.mjs --label after-<slug> — backend budgets,
exits 1 on breach.
Verdict
Report a table: metric | baseline median | after median | delta | budget.
Budgets live in perf/budgets.json — ratcheted, never loosened silently.
A real improvement may tighten one: one-line DECISIONS.md entry + ratchet
in the same commit.
Cleanup
bench/stress print their own psql cleanup line — run it. After any load
run, restart the API before probing error paths (a hot process skews them).