fix: close performance evidence and budget gates

This commit is contained in:
2026-09-02 08:27:21 +03:00
parent 1734003172
commit 5525557c3a
13 changed files with 541 additions and 39 deletions

View File

@@ -4,7 +4,9 @@ This runbook separates executable developer evidence from the two physical relea
## Automated build and transfer gate
Run `npm run build:preview`. The build ends with `npm run check:budgets`, which classifies every shipped file exactly once, measures Brotli transfer bytes (or raw bytes for already-compressed formats), verifies that the live Three.js scene remains behind a dynamic import, and applies the exact section 14 thresholds. Unknown files fail closed.
Run `npm run build:preview`. The build ends with `npm run check:budgets`, which classifies every shipped file exactly once, measures Brotli transfer bytes (or raw bytes for already-compressed formats), verifies that the live Three.js scene remains behind a dynamic import, and applies the exact section 14 thresholds. Unknown files fail closed. Every non-empty manifest media file is hash-checked and deterministically decoded: Sharp verifies image dimensions and `ffprobe` verifies video dimensions and duration against the manifest. Missing probe evidence, disagreement, or an unprobeable asset fails the gate.
`config/performance-budget-evidence.json` is the auditable allocation declaration. The checker derives texture bytes as `width × height × bytes-per-pixel × layers × 4/3` for mipmaps, render-target bytes as `width × height × bytes-per-pixel × attachments × samples`, adds declared geometry buffer bytes and the fixed 32 MB allowance, and enforces the Low/High GPU caps. It also enforces peak request concurrency and the 2048-pixel mobile texture bound. High-tier-only chunks use the `high-tier-*`/`environment-high-*` bucket and are capped separately. Any scene allocation or request-scheduling change must update this declaration in the same change; incomplete allocations fail closed.
The current empty-media preview measures approximately 7.8 KB for HTML plus critical CSS, 61.8 KB for initial application JavaScript, and 114.2 KB for the deferred first live scene. These values are build observations, not permanent allowances.
@@ -32,7 +34,19 @@ They prove that the harness and interactions execute. They do not make a release
Use only the Pixel 6 8 GB / Chromium Mobile Low and M1 MacBook Air 8 GB / Chromium Desktop High reference classes, or hardware with the same CPU/GPU and RAM. Fix both displays at 60 Hz; require battery above 50%, power saving off, a cool start, no foreground competition, page zoom 100%, full motion, Save-Data off, and the exact network shaping from section 14. Record OS/browser/display versions in the private lab evidence, not in shipped artifacts.
For each profile, run five fresh temporary profiles from `about:blank`. Clear service workers, Cache Storage, HTTP cache, cookies, local/session storage, and IndexedDB before every run. Set `PORTFOLIO_REFERENCE_LAB=1` so cadence and all per-run budgets become assertions. A warm-up median outside 16.667 ±1 ms invalidates the run.
For each profile, run five fresh temporary profiles from `about:blank`. Clear service workers, Cache Storage, HTTP cache, cookies, local/session storage, and IndexedDB before every run.
Reference mode is fail-closed. Create one private `portfolio-reference-run-attestation/v1` JSON file per run with the exact pinned device, Chromium/OS/display, viewport, network, run index/ID, and every environmental assertion recorded. Keep device metadata outside the public repository. Compute the SHA-256 of the exact file bytes, then run one trace with all three variables set:
```bash
PORTFOLIO_REFERENCE_LAB=1 \
PORTFOLIO_REFERENCE_ATTESTATION_PATH=/private/evidence/desktop-run-1.json \
PORTFOLIO_REFERENCE_ATTESTATION_SHA256=<64-lowercase-hex-digest> \
npx playwright test tests/performance/drive-trace.spec.ts \
--project=performance-desktop --workers=1
```
Reference mode rejects missing or extra fields, digest mismatch, wrong hardware/network/profile, failed setup assertions, or disagreement with the browser-observed viewport, visibility, reduced-motion, Save-Data, zoom, and Chromium version. Only a validated attestation can produce `gatingReferenceResult: true`; ordinary developer runs always remain false. A warm-up median outside 16.667 ±1 ms or any per-run budget failure invalidates the run.
Aggregate exactly five reviewed JSON paths:
@@ -40,7 +54,9 @@ Aggregate exactly five reviewed JSON paths:
npm run aggregate:performance -- run-1.json run-2.json run-3.json run-4.json run-5.json
```
Aggregation fails unless all five are marked reference evidence, every per-run gate passes, worst/median LCP are at most 3.0/2.5 seconds, and worst/median TBT are at most 300/200 ms. Do not commit result files until their metadata has passed privacy review.
Aggregation fails unless the set contains unique authenticated run IDs, digests, and indexes 1–5 for one profile, all five are marked reference evidence, every per-run gate passes, worst/median LCP are at most 3.0/2.5 seconds, and worst/median TBT are at most 300/200 ms. Run and aggregate the other profile separately. Do not commit result files until their metadata has passed privacy review.
The former High DPR cap of 2 produced a conservative 242 MB estimate at 1440×900 once the antialiased framebuffer, post target, route-sign texture, geometry, and fixed allowance were counted. High is therefore capped at DPR 1.5. The executable declaration now derives 153,078,016 bytes (about 146 MB) for High and 39,508,160 bytes (about 37.7 MB) for Low, below the exact 192/96 MB limits.
## Physical ten-minute protocol