fix: bind performance evidence to production resources
This commit is contained in:
@@ -6,7 +6,11 @@ This runbook separates executable developer evidence from the two physical relea
|
||||
|
||||
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.
|
||||
Runtime budgets are not read from a hand-edited estimate. The authenticated test build records the actual production `SceneResourceBag`: owned texture dimensions/pixel layout/mipmap state, the byte lengths of unique geometry buffers, live render-target dimensions/attachments/samples, and the production framebuffer. A dedicated production-path capture derives peak image/scene and video concurrency from completed browser Resource Timing intervals. The evaluator recomputes decoded bytes, adds the fixed 32 MB allowance, and enforces the Low/High GPU, concurrency, and 2048-pixel mobile texture caps. Adding a production resource or eager request therefore changes the measured ledger.
|
||||
|
||||
Run `npm run capture:runtime-budgets`. It loads the real High scene at a device DPR of 2, verifies that the renderer actually reaches its 1.5 DPR cap, and writes `runtime-budget-trace.v1.json` beneath the ignored Playwright result directory. Then verify that exact capture with `npm run check:budgets -- --runtime-trace <runtime-budget-trace.v1.json>`. The checker rejects the former standalone evidence schema, a tier/profile mismatch, a missing DPR-cap observation, or framebuffer dimensions that do not match the observed viewport. Supplied totals are ignored and recomputed from raw allocations.
|
||||
|
||||
High-tier-only chunks use the `high-tier-*`/`environment-high-*` bucket and are capped separately.
|
||||
|
||||
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.
|
||||
|
||||
@@ -46,17 +50,30 @@ 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.
|
||||
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. The trace still emits an unsigned `validated-reference-candidate-unsigned` with `gatingReferenceResult: false`; ordinary developer runs are also unsigned and false. A warm-up median outside 16.667 ±1 ms or any per-run budget failure invalidates the candidate.
|
||||
|
||||
After independent device/evidence review, an authorized lab signer uses an Ed25519 private key held outside the repository to sign the exact candidate. Never copy the private key into the repository, result directory, command output, or trust policy:
|
||||
|
||||
```bash
|
||||
npm run sign:performance -- \
|
||||
--key-id lab-release-2026 \
|
||||
--private-key /private/keys/reference-ed25519.pem \
|
||||
candidate.json signed-run-1.json
|
||||
```
|
||||
|
||||
Signing binds the complete measurements, budget booleans, runtime/request ledgers, profile, attestation digest, run ID, and run index to a result digest. It is the only operation that changes `gatingReferenceResult` to true. The external release trust policy contains only the approved key ID and Ed25519 public key; it is selected by the release controller, never from a result file.
|
||||
|
||||
Aggregate exactly five reviewed JSON paths:
|
||||
|
||||
```bash
|
||||
npm run aggregate:performance -- run-1.json run-2.json run-3.json run-4.json run-5.json
|
||||
npm run aggregate:performance -- \
|
||||
--trust-policy /approved/policy/reference-trust-policy.json \
|
||||
signed-run-1.json signed-run-2.json signed-run-3.json signed-run-4.json signed-run-5.json
|
||||
```
|
||||
|
||||
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.
|
||||
Aggregation verifies every result digest and Ed25519 signature against that explicit trusted policy. It rejects unsigned or tampered reports, a result-supplied/self-selected key, duplicate/replayed identities or digests, incomplete indexes, mixed profiles, and failed gates. Five unique indexes 1–5 are required; worst/median LCP remain at most 3.0/2.5 seconds and worst/median TBT 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.
|
||||
The former High DPR cap of 2 produced a conservative estimate above the 192 MB cap once the antialiased framebuffer, post target, route-sign texture, geometry, and fixed allowance were counted. High is therefore capped at DPR 1.5. The browser-produced ledger is now the release evidence rather than that former declaration.
|
||||
|
||||
## Physical ten-minute protocol
|
||||
|
||||
|
||||
Reference in New Issue
Block a user