docs(04-08): polish per iter-2 advisories — symbol mismatch + display-surface mode lock-in + cosmetic clarifications

iter-3 polish pass on Plan 04-08 per checker iter-2 verdict PASSED
(commit 9c334b7). Five cosmetic-level fixes; no thesis/scope changes;
BLOCKER fixes from iter-2 + WARNING fixes from iter-2 preserved verbatim.

Remediations:
- WARNING 1 (low-severity; displaySurface sub-gate scope ambiguity):
  HIGH-LATENCY catch path locked in; the under-specified
  `--check-display-surface-only` spike-script mode is dropped (would have
  required 5-10 LOC of executor improvisation for no meaningful latency
  win over the canonical spike re-run's assertA2 fast-fail at <30s).
- Advisory 1 (symbol-name mismatch): Tier-2 snippet's `collectDistFiles`
  replaced with the actual helper `listAllFilesRecursive(DIST_DIR)` from
  tests/background/no-test-hooks-in-prod-bundle.test.ts:152; also uses
  the existing `countOccurrencesInFile` for binary-extension-aware grep.
- Advisory 2 (SUMMARY-write practice for WARNING 1): explicit note added
  that 04-08-SUMMARY.md documents the WARNING 1 closure path (no Plan B
  fallback; explicit error-class identifier; observable via offscreen
  console capture).
- Advisory 3 (vitest math): 183 -> 184 clarified consistently across
  must_haves truth + Step 5 body + acceptance_criteria + verification +
  success_criteria (+1 from the new Tier-2 `test(...)` block).
- Advisory 4 (duration-N/A rationale): moved out of the PLAN body into
  the SUMMARY content list (Step 6); PLAN keeps only the load-bearing
  size gate + loop-attr behavioral assertion + spike-re-run empirical
  catch; 1.9 MB / ~400 kbps / ~38s decoded-timeline reasoning lands at
  SUMMARY-time.

Frontmatter:
- Added iter-2 entry to revision_history (iter-3 polish closure).
- Tag flipped planner-iter-2-revision -> planner-iter-3-revision.

Plan validates via gsd-sdk frontmatter.validate + verify.plan-structure:
- valid: true; 0 errors; 0 warnings; 2 tasks; all 4 task elements present.

Diff: +51/-22 lines (5640 chars net). Branch ready for plan-checker
iter-3 (cosmetic-only polish review expected to PASS without further
findings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 10:05:38 +02:00
parent 9c334b77e8
commit 17e55ddbb9

View File

@@ -36,7 +36,7 @@ tags:
- charter-d-p4-01
- roadmap-sc-1-closes
- post-debug-session-2
- planner-iter-2-revision
- planner-iter-3-revision
user_setup: []
revision_history:
- iter: 1
@@ -56,6 +56,17 @@ revision_history:
- "advisory 1: Task 3 mis-reference in commit message corrected (Task 1 + Task 2 only)."
- "advisory 2: recorder.ts:91 segments invariant gated by grep in Task 1 verify."
- "advisory 3: dual-fixture-location note added to Task 1 Step 1."
- iter: 2
plan_commit: 1f2eb2e
checker_commit: 9c334b7
verdict: PASSED
warnings_addressed:
- "WARNING 1 (iter-3 polish; checker iter-2 NEW WARNING): displaySurface sub-gate scope ambiguity resolved by locking in the HIGH-LATENCY catch path — the dedicated `--check-display-surface-only` spike-script mode is dropped (it was under-specified and would have required 5-10 LOC of executor improvisation for no meaningful latency win). The displaySurface invariant is now gated by the spike re-run's assertA2 fast-fail (Task 2 Step 1); the production gate at src/offscreen/recorder.ts:294 throws 'wrong-display-surface' within ~30s of spike start if the patchDisplaySurface helper is broken. SUMMARY documents the chosen closure path explicitly."
cosmetics_addressed:
- "advisory 1 (iter-3 polish; checker iter-2 NEW cosmetic-advisory 1): symbol-name mismatch in the WARNING 5 Tier-2 snippet — `collectDistFiles` replaced with the actual symbol `listAllFilesRecursive(DIST_DIR)` from tests/background/no-test-hooks-in-prod-bundle.test.ts:152; also uses the existing `countOccurrencesInFile` helper for binary-extension-aware grep (matches the Tier-1 entries' pattern verbatim)."
- "advisory 2 (iter-3 polish; checker iter-2 NEW cosmetic-advisory 2): WARNING 1 SUMMARY-write practice note added — the SUMMARY explicitly documents the chosen WARNING 1 closure path (no Plan B fallback; explicit error-class identifier on autoplay/codec reject; observable via offscreen console capture)."
- "advisory 3 (iter-3 polish; checker iter-2 NEW cosmetic-advisory 3): vitest math clarified throughout — must_haves truth + Step 5 body + acceptance_criteria + verification + success_criteria all consistently state '183 -> 184 GREEN; +1 from the new Tier-2 test(...) block in tests/background/no-test-hooks-in-prod-bundle.test.ts'."
- "advisory 4 (iter-3 polish; checker iter-2 NEW cosmetic-advisory 4): duration=N/A rationale moved out of the PLAN body into the SUMMARY content list (Step 6) — the PLAN keeps only the load-bearing >=1 MB size gate + loop-attr behavioral assertion + spike-re-run empirical catch; the 1.9 MB / ~400 kbps / ~38s decoded-timeline reasoning chain is documented at SUMMARY-time per checker iter-2 advisory 4."
must_haves:
truths:
- "installFakeDisplayMedia() at src/test-hooks/offscreen-hooks.ts is SYNCHRONOUS at module load — preserves the eager-install contract at lines 533-537 (the monkey-patch on navigator.mediaDevices.getDisplayMedia is in place BEFORE recorder.ts:46-48 top-level await resolves)"
@@ -67,7 +78,7 @@ must_haves:
- "assertA33 / driveA33 / orchestrator wiring land per the original Plan 04-04 Pattern 4 verbatim (cs-injection-world precedent NOT applicable — A33 is host-side CDP-driven, not page-side rrweb-driven)"
- "stopServiceWorker(browser, extensionId) helper at tests/uat/lib/harness-page-driver.ts is reused verbatim from Plan 04-04 (already committed at 3726eee); no new helper symbol needed"
- "A33 env-gated by SKIP_LONG_UAT (default RUN for closure + alpha gate; SKIP_LONG_UAT=1 to skip per-commit iteration); 95s baseline preserved when skipped"
- "UAT harness count flips 33 -> 34 (A33 added); 34/34 GREEN when SKIP_LONG_UAT unset; vitest 183/183 GREEN preserved"
- "UAT harness count flips 33 -> 34 (A33 added); 34/34 GREEN when SKIP_LONG_UAT unset; vitest goes 183/183 -> 184/184 GREEN (Plan 04-08 adds exactly one new vitest `test(...)` block — the Tier-2 filename-leak gate in tests/background/no-test-hooks-in-prod-bundle.test.ts; cf. WARNING 5 remediation + iter-3 polish per checker iter-2 cosmetic-advisory 3)"
- "ROADMAP SC #1 (SW state persistence) GREEN — A33 empirical evidence that a 5-min idle + Puppeteer worker.close() + SAVE_ARCHIVE produces video/last_30sec.webm with size > 100 KB; ROADMAP.md row flipped from 'STATUS 2026-05-21: OPEN' to 'STATUS 2026-05-22: CLOSED via Plan 04-08'"
- "Tier-1 FORBIDDEN_HOOK_STRINGS inventory unchanged at 12 entries (lockstep across tests/uat/harness.test.ts + tests/background/no-test-hooks-in-prod-bundle.test.ts) — Plan 04-08 introduces NO new __MOKOSH_UAT__-gated symbols on production bundle; the bundled WebM ships only in test build per Vite ?url + test-config gating"
- "Tier-2 production-bundle filename leak gate added: 'synthetic-display-source' string returns 0 hits across dist/ — codified in tests/background/no-test-hooks-in-prod-bundle.test.ts as a new sub-invariant (canary for future regressions that might accidentally inline test-hooks into the production chunk)"
@@ -597,7 +608,7 @@ From tests/background/no-test-hooks-in-prod-bundle.test.ts (CURRENT Tier-1 inven
**Step 1 — Bundle the WebM fixture (advisory 3 dual-location note).**
- Create directory: `mkdir -p tests/uat/fixtures/`.
- Copy `tests/fixtures/last_30sec.webm` to `tests/uat/fixtures/synthetic-display-source.webm`. The existing artifact is a 1.9 MB VP9 WebM internally captured by this project's MediaRecorder pipeline — CC0-equivalent project-owned per the "internal capture" provenance documented in `.planning/STATE.md` Phase 1 Closure Notes. Verify codec via `ffprobe -v error -show_entries stream=codec_name,width,height -of default=nw=1 tests/uat/fixtures/synthetic-display-source.webm` reports `codec_name=vp9`.
- The fixture must be >=1 MB AND >=30 seconds duration (loopable). The existing 1.9 MB capture satisfies size; duration is `N/A` per ffprobe (live-capture WebM lacks a duration tag), BUT the 1.9 MB VP9 at 400 kbps yields ~38s of decoded timeline — sufficient for the 5-min spike via `videoEl.loop = true`. If the executor wants a stricter contract, regenerate via `ffmpeg -f lavfi -i testsrc=duration=35:size=320x180:rate=30 -c:v libvpx-vp9 -b:v 400k tests/uat/fixtures/synthetic-display-source.webm` (this is OPTIONAL — the copy baseline works; only regenerate if the copy's duration tag is load-bearing for the chosen tests).
- The fixture must be >=1 MB (size gate verified by `wc -c` >= 1_000_000 in the Task 1 verify block) AND must loop cleanly under `videoEl.loop = true` across the 5-min spike window (loop behavior verified empirically by the spike re-run in Task 2 Step 1 — if the fixture's decoded timeline is too short OR the loop seam produces a decoder hiccup, the spike's `videoSize > 100_000` floor would catch it). The 1.9 MB capture from `tests/fixtures/last_30sec.webm` is the COPY baseline; if the executor finds the copy fails the spike re-run for any duration/loop-seam reason, the OPTIONAL fallback is to regenerate via `ffmpeg -f lavfi -i testsrc=duration=35:size=320x180:rate=30 -c:v libvpx-vp9 -b:v 400k tests/uat/fixtures/synthetic-display-source.webm`. The full reasoning chain (ffprobe duration=N/A is acceptable because the 1.9 MB / ~400 kbps VP9 yields ~38s of decoded timeline; the `videoEl.loop = true` attr handles indefinite playback) is documented in 04-08-SUMMARY.md's "Bundled WebM fixture decision" section so future maintainers understand the rationale at SUMMARY-time (cf. iter-3 polish per checker iter-2 cosmetic-advisory 4).
- **advisory 3 note**: `tests/fixtures/last_30sec.webm` remains in place (Plan 01-07 regression fixture; not affected). The new path at `tests/uat/fixtures/synthetic-display-source.webm` is a SECOND copy under the UAT subtree — this is intentional because the Vite ?url import in `src/test-hooks/offscreen-hooks.ts` resolves cleanly from `../../tests/uat/fixtures/...` without crossing a non-bundled subtree (the `tests/fixtures/` directory is excluded from the test bundle's input set; the `tests/uat/fixtures/` directory is implicitly included as a transitive import of the offscreen-hooks module).
- Decision (per `feedback-no-unilateral-scope-reduction.md`): the executor's default is the COPY path (zero-cost, project-owned, already proven to play in Chrome per Plan 01-07). Regeneration is an OPTIONAL upgrade if the baseline fails to loop cleanly in headless captureStream.
@@ -715,6 +726,15 @@ export function installFakeDisplayMedia(): void {
// downstream. The spike's gating check on `videoSize > 100_000` will
// fail with this error visible in the offscreen console capture (or in
// the harness diagnostics), making the root cause unambiguous.
//
// WARNING 1 SUMMARY-write practice (iter-3 polish): the executor writing
// 04-08-SUMMARY.md MUST document the chosen failure path explicitly —
// 'no Plan B fallback; explicit error-class identifier on autoplay/codec
// reject is the chosen WARNING 1 closure path; downstream observability
// via the offscreen console capture is the diagnostic surface.' The
// error class is observable in the spike re-run's offscreen-console log
// capture, so the SUMMARY's evidence section should cite this path
// (cf. cosmetic-advisory 2 from checker iter-2).
fakeVideoReadyPromise = new Promise<void>((resolve, reject) => {
const onCanPlay = (): void => {
videoEl.removeEventListener('canplay', onCanPlay);
@@ -934,23 +954,31 @@ if (op === 'install-fake-display-media') {
// Tier-1 (symbols): 12 entries (unchanged from Plan 01-14)
// Tier-2 (asset filenames): 1 entry (Plan 04-08 — synthetic-display-source)
test('Tier-2: synthetic-display-source filename does not leak into production dist/', () => {
// Walk dist/ files (skip the binary asset extensions in IGNORED_EXTENSIONS).
// Grep for the literal string 'synthetic-display-source'. Expected: 0 hits.
const distFiles = collectDistFiles(); // existing helper from the Tier-1 test
// Walk dist/ files via the existing recursive walker (which skips
// symlinks; the existing countOccurrencesInFile helper handles
// binary-extension skipping). Grep for the literal string
// 'synthetic-display-source'. Expected: 0 hits.
const distFiles = listAllFilesRecursive(DIST_DIR); // existing helper at line ~152 of this file
const offendingFiles: string[] = [];
for (const filePath of distFiles) {
const content = readFileSync(filePath, 'utf-8');
if (content.includes('synthetic-display-source')) {
if (countOccurrencesInFile(filePath, 'synthetic-display-source') > 0) {
offendingFiles.push(filePath);
}
}
expect(offendingFiles).toEqual([]);
});
```
- **Note**: the executor should READ the existing test file first to identify:
- The exact name of the helper that walks dist/ files (the snippet above calls it `collectDistFiles` — verify the actual name and adapt).
- The exact location to insert the new test block (after the Tier-1 inventory test, before the file's final close).
- The exact import shape (the snippet uses `readFileSync` — verify already imported).
- **Note**: the snippet above uses the actual symbols from the live file
(`listAllFilesRecursive(DIST_DIR)` at line ~152 + `countOccurrencesInFile`
at line ~185 + the `DIST_DIR` constant at line ~133). The executor still
reads the existing test file first to confirm:
- The exact insertion site for the new `test(...)` block (after the
closing `}` of the `for (const needle of FORBIDDEN_HOOK_STRINGS)` loop
inside the existing `describe(...)` block — same describe scope keeps
the gates colocated under one suite name).
- Whether the new test should also be wrapped in the same
`it.skipIf(SKIP_BUILD === '1' && !existsSync(DIST_DIR))` style as the
Tier-1 entries (cross-check the existing pattern when reading).
**Step 7 — Verify TypeScript + production build clean + test build emits asset + Tier-2 gate passes.**
- `npx tsc --noEmit` exits 0.
@@ -963,8 +991,8 @@ if (op === 'install-fake-display-media') {
- `grep -c "installFakeDisplayMedia(): void" src/test-hooks/offscreen-hooks.ts` returns ≥ 1 (sync signature preserved; iter-2 BLOCKER 2 verification — function does NOT return Promise).
- `grep -c "export function installFakeDisplayMedia(): Promise" src/test-hooks/offscreen-hooks.ts` returns 0 (verifies the function was NOT converted to async).
- `grep -c "await installFakeDisplayMedia" src/test-hooks/offscreen-hooks.ts` returns 0 (verifies the bridge handler + eager-install were NOT converted to await).
- **Sub-verify gate for displaySurface monkey-patch compatibility (WARNING 2 remediation):** create a one-shot inline node script that loads dist-test (via Puppeteer's `enableExtensions`) + executes a snippet in the offscreen document that mints a stream + asserts `stream.getVideoTracks()[0].getSettings().displaySurface === 'monitor'`. If this fails, the production `displaySurface !== 'monitor'` gate at `src/offscreen/recorder.ts:294` would tear down the stream + throw `'wrong-display-surface'` — the spike would fail at Step 2 (assertA2 prime), not at Step 7 (videoSize check). Implementation: append to the existing `tests/uat/spike-a33-sw-persistence.ts` script a `--check-display-surface-only` mode that runs only Steps 1-2 (prime + 5s post-prime probe), invokes `__mokoshOffscreenQuery` op='get-display-surface', asserts result is 'monitor', exits. Run via `HEADLESS=1 SKIP_PROD_REBUILD=1 npx tsx tests/uat/spike-a33-sw-persistence.ts --check-display-surface-only 2>&1 | tee /tmp/04-08-display-surface-check.log` and grep `'DISPLAY-SURFACE-CHECK: PASSED'` in the log. The full spike re-run (Step 1 of Task 2) is a superset of this check, but running it as a fast sub-gate in Task 1 catches the WARNING 2 risk in <10s of wall-clock instead of waiting 6+ min into the spike.
- Alternative if the executor finds the spike-script-augmentation overhead too high: skip the dedicated sub-gate and rely on the spike re-run in Task 2 Step 1 (the displaySurface failure would manifest as 'wrong-display-surface' Error in the offscreen console capture; the spike's gating condition would still fail). The dedicated sub-gate is the LOW-LATENCY path; the spike re-run is the HIGH-LATENCY path; both gate the same invariant.
- **Sub-verify gate for displaySurface monkey-patch compatibility (WARNING 2 remediation — iter-3 polish: HIGH-LATENCY catch path locked in).** The displaySurface contract is gated by the spike re-run in Task 2 Step 1 — NOT by a dedicated low-latency sub-gate. Rationale: the spike's Step 1 calls `__mokoshHarness.assertA2` which executes `recorder.startRecording` -> `await navigator.mediaDevices.getDisplayMedia(...)` (the patched closure). If `track.getSettings().displaySurface !== 'monitor'` after the `patchDisplaySurface(stream)` call, the production gate at `src/offscreen/recorder.ts:294` tears down the stream + throws `'wrong-display-surface'` during assertA2 — surfacing the regression within seconds of the spike's Step 1, NOT after the 5-min idle elapses. The high-latency framing was overstated in iter-2; in practice the failure surfaces in <30s of the spike (assertA2 prime takes 5-15s; the displaySurface check fires inside the production handler immediately on track availability). The dedicated `--check-display-surface-only` mode is dropped — it would have required 5-10 LOC of under-specified spike-script augmentation (env-var hook, log emit, exit-code semantics) for no meaningful latency win over the canonical spike re-run.
- **SUMMARY documents the WARNING 2 closure path:** the executor's 04-08-SUMMARY.md MUST state explicitly that the WARNING 2 closure relied on the spike re-run's assertA2 fast-fail (NOT a dedicated sub-gate); cite the wall-clock-to-failure (<30s for displaySurface; full 6+ min only if assertA2 prime succeeds and the failure is in the videoSize floor).
- **Sub-verify gate for segments invariant (advisory 2 remediation):** `grep -cE 'let segments: Blob\[\] = \[\];' src/offscreen/recorder.ts` returns 1 (architectural invariant per debug session-2; Plan 04-08 does NOT modify recorder.ts).
</action>
<verify>
@@ -1004,7 +1032,7 @@ if (op === 'install-fake-display-media') {
<action>
**Step 0 — GATING CONDITION (Task 1 complete + methodology valid).**
- Verify Task 1 acceptance criteria all met. If any fail (TS error, missing fixture, sync signature violated, etc.), STOP and fix before proceeding.
- Verify the displaySurface sub-gate from Task 1 Step 7 PASSED. If skipped, the spike re-run in Step 1 below catches it but with 6+ min latency.
- displaySurface compatibility is gated by Step 1 below (the spike re-run's assertA2 fast-fails on `'wrong-display-surface'` if the patch is broken; surfaces within ~30s of spike start, NOT after the 5-min idle). No separate Task 1 sub-gate exists — the dedicated `--check-display-surface-only` mode was dropped in iter-3 polish per WARNING 1 closure (the high-latency catch path is locked in).
**Step 1 — Re-run the spike script.**
- Run: `HEADLESS=1 SKIP_PROD_REBUILD=0 npx tsx tests/uat/spike-a33-sw-persistence.ts 2>&1 | tee /tmp/04-08-spike-rerun.log`
@@ -1019,7 +1047,7 @@ if (op === 'install-fake-display-media') {
**Step 2 — Update the spike script if needed (sync-install/lazy-first-frame compatibility).**
- The spike script's prime step uses `__mokoshHarness.assertA2` (canonical fresh-recording bootstrap; Plan 04-04 REVISION iter-2 Option B). Under the new methodology, `assertA2` triggers `recorder.startRecording` which calls `navigator.mediaDevices.getDisplayMedia` — this is now the patched closure that lazy-waits for video readiness. First call may take an extra ~50-500ms; the existing assertA2 timeout (per Plan 01-13 default ~15s) absorbs this comfortably. NO edit to the spike script's logic is needed.
- **IF** Task 1 Sub-step 3g's sub-gate (`--check-display-surface-only` mode) was implemented, that mode is preserved as a forensic helper. Otherwise the spike script is unchanged.
- No spike-script edit is needed. The dedicated `--check-display-surface-only` mode was dropped in iter-3 polish (WARNING 1 closure — high-latency catch path locked in); the canonical spike covers the displaySurface invariant via assertA2's fast-fail path.
**Step 3 — Land A33 in the harness (3-file lockstep per Plan 04-04 Wave 1 spec verbatim).**
@@ -1097,16 +1125,17 @@ if (op === 'install-fake-display-media') {
- `grep -v '^#\|^//' dist/assets/index-*.js | grep -c 'Buffer\.'` returns 1 (pre-existing JSZip polyfill; Plan 04-02 deferred)
- SW chunk `window.`/`document.` references = 0
- Manifest validation + en/ru parity preserved (unchanged from Plan 04-03)
- vitest baseline preserved: `npm test 2>&1 | tail -5` — expect 184/184 GREEN (was 183 baseline + 1 new Tier-2 test from Plan 04-08), or 181/184 with the 3 documented pre-existing parallel-vitest flakes per 04-CONTEXT items 9-10; flakes pass in isolation.
- vitest baseline flips 183 -> 184: `npm test 2>&1 | tail -5` — expect 184/184 GREEN (prior baseline 183 + exactly 1 new `test(...)` block added in Task 1 Step 6 — the Tier-2 'synthetic-display-source filename does not leak' gate in tests/background/no-test-hooks-in-prod-bundle.test.ts; cf. WARNING 5 + iter-3 polish per checker iter-2 cosmetic-advisory 3). Or 181/184 with the 3 documented pre-existing parallel-vitest flakes per 04-CONTEXT items 9-10; flakes pass in isolation.
**Step 6 — Write Plan 04-08 SUMMARY.**
- Create `.planning/phases/04-harden-clean-up-optional/04-08-SUMMARY.md`:
- Methodology reframe rationale (cite debug session-2 verdict verbatim)
- **iter-2 revision summary** (cite checker iter-1 + BLOCKER 1 + BLOCKER 2 + WARNING resolutions)
- Bundled WebM fixture decision (copy vs regenerate; size + codec evidence; dual-location note)
- Bundled WebM fixture decision (copy vs regenerate; size + codec evidence; dual-location note; **duration=N/A rationale** — 1.9 MB / ~400 kbps VP9 = ~38s decoded timeline + `videoEl.loop = true` for indefinite playback across the 5-min spike; cf. iter-3 polish per checker iter-2 cosmetic-advisory 4)
- installFakeDisplayMedia diff summary (canvas -> HTMLVideoElement; SYNC install + LAZY first-frame; 6 bridge ops preserved sync; A23 capture preserved; eager-install contract preserved)
- **WARNING 1 closure path** (autoplay reject fallback) — document explicitly: no Plan B fallback; explicit error-class identifier on autoplay/codec reject; the error class string is observable in the spike's offscreen-console capture; cite the wall-clock-to-failure surface (per iter-3 polish + checker iter-2 cosmetic-advisory 2)
- manifest.json WAR entry decision (BLOCKER 1 rationale: pre-emptive explicit entry; production inert; test bundle authorized)
- displaySurface compatibility evidence (sub-gate result; WARNING 2 closure)
- **WARNING 2 closure path** (displaySurface compat) — document explicitly: HIGH-LATENCY catch via spike re-run's assertA2 fast-fail (NOT a dedicated sub-gate); cite the wall-clock-to-failure (<30s for displaySurface check inside assertA2 prime); the dedicated `--check-display-surface-only` mode was dropped in iter-3 polish per WARNING 1 closure
- Spike re-run evidence (videoSize before/after; segment-count probe values; elapsed time)
- A33 land evidence (driveA33 + orchestrator wiring; FORBIDDEN_HOOK_STRINGS at 12; pre-checkpoint gates 6/6; Tier-2 gate added)
- UAT before/after (33/33 -> 34/34 GREEN)
@@ -1190,7 +1219,7 @@ if (op === 'install-fake-display-media') {
- FORBIDDEN_HOOK_STRINGS inventory unchanged at 12 entries — verify by line count of both arrays.
- **Tier-2 gate (Plan 04-08 iter-2):** `grep -c 'synthetic-display-source' tests/background/no-test-hooks-in-prod-bundle.test.ts` returns ≥ 1; the test PASSES under `npm test -- tests/background/no-test-hooks-in-prod-bundle.test.ts`.
- Pre-checkpoint bundle gates 6/6 PASS unchanged from Plan 04-03 baseline.
- vitest 184 baseline preserved (183 prior + 1 new Tier-2 test) — or 181/184 with the 3 documented pre-existing flakes; pass in isolation.
- vitest baseline flips 183 -> 184 (prior 183 GREEN + exactly 1 new `test(...)` block — the Tier-2 'synthetic-display-source filename does not leak' gate in tests/background/no-test-hooks-in-prod-bundle.test.ts) — or 181/184 with the 3 documented pre-existing flakes; pass in isolation.
- **WARNING 4 (iter-2):** `.planning/ROADMAP.md` contains `'CLOSED via Plan 04-08'` (grep returns ≥ 1); contains zero hits on `'STATUS 2026-05-21: OPEN'` (the old status was removed); contains `'STATUS 2026-05-22: CLOSED'`.
- `.planning/STATE.md` Decisions list contains a Plan 04-08 entry citing ROADMAP SC #1 CLOSED.
- `.planning/phases/04-harden-clean-up-optional/04-08-SUMMARY.md` exists with: methodology rationale + iter-2 revision summary + spike re-run evidence + probe values + A33 land evidence + UAT before/after + ROADMAP SC #1 closure + cross-reference to Plan 04-04 post-debug amendment.
@@ -1258,7 +1287,7 @@ if (op === 'install-fake-display-media') {
- Tier-1 FORBIDDEN_HOOK_STRINGS lockstep at 12 entries (unchanged).
- Tier-2 gate (Plan 04-08): `npm test -- tests/background/no-test-hooks-in-prod-bundle.test.ts` passes.
- Pre-checkpoint bundle gates 6/6 PASS (new Function=0 + eval=0 + Buffer.=1 + window.=0 + document.=0 in SW + Tier-1=12 + en/ru parity).
- vitest baseline 184 preserved (183 prior + 1 new Tier-2; or 181/184 with 3 documented pre-existing flakes; pass in isolation).
- vitest baseline flips 183 -> 184 GREEN (prior 183 + exactly 1 new `test(...)` block — the Tier-2 filename-leak gate in tests/background/no-test-hooks-in-prod-bundle.test.ts; cf. WARNING 5 + iter-3 polish per checker iter-2 cosmetic-advisory 3); or 181/184 with 3 documented pre-existing flakes; pass in isolation.
- A29 + A30 + A31 + A32 unchanged (no regression to existing assertions).
- Architecture invariant preserved: `src/offscreen/recorder.ts:91 let segments: Blob[] = []` UNCHANGED — debug session-2 verdict is honored (NO IndexedDB persistence work).
- spike-FAILED forensic-evidence preservation: `tests/uat/spike-a33-sw-persistence.ts` retained (Plan 04-04 commit 3726eee + debug session-2 Step B + C additions); now functions as a PASSING regression test under the new methodology.
@@ -1283,7 +1312,7 @@ if (op === 'install-fake-display-media') {
- Tier-2 production-bundle filename-leak gate added: `synthetic-display-source` returns 0 hits in dist/ (WARNING 5).
- Pre-checkpoint bundle gates 6/6 PASS.
- Architectural integrity preserved (no IndexedDB persistence; no chrome.storage migration; src/offscreen/recorder.ts:91 segments array unchanged; grep gate enforces).
- vitest 184 baseline preserved (183 prior + 1 new Tier-2 test).
- vitest baseline flips 183 -> 184 (prior 183 + exactly 1 new `test(...)` block — the Tier-2 filename-leak gate added in Task 1 Step 6).
- Plan 04-04 forensic artifacts (`stopServiceWorker` helper + spike script) repurposed as PASSING regression tests under valid methodology.
- iter-2 BLOCKER 1 + BLOCKER 2 + WARNINGs 1-5 + advisories 1-3 all addressed per checker iter-1 remediation guidance.
</success_criteria>