diff --git a/.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md b/.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md
index 46ecfef..cc13171 100644
--- a/.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md
+++ b/.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md
@@ -1,253 +1,309 @@
---
phase: 04-harden-clean-up-optional
-verified: 2026-05-26T11:25:00Z
+verified: 2026-05-26T14:00:00Z
status: passed
-score: 4/4 ROADMAP success criteria + 3/3 audit P1 polish items + 6/6 hardening items + 3/3 visual-polish + flake-stabilization + build-hygiene items + 36/36 UAT harness assertions + 188/188 vitest tests + 6/6 pre-checkpoint bundle gates + 12 Tier-1 FORBIDDEN_HOOK_STRINGS + Tier-2 leak gate added
+score: 4/4 ROADMAP success criteria + 3/3 audit P1 polish items + 6/6 hardening items + 3/3 visual-polish + flake-stabilization + build-hygiene items + 36/36 UAT harness assertions + 188/188 vitest tests + 6/6 pre-checkpoint bundle gates + 12/12 Tier-1 FORBIDDEN_HOOK_STRINGS + Tier-2 leak gate present
overrides_applied: 0
-verifier_handoff: pending # gsd-verifier audit runs after Plan 04-07 closure; this document is the executor-created aggregator that the verifier will independently re-validate
re_verification:
+ previous_status: executor-aggregator (plan 04-07 created aggregator; independent gsd-verifier audit is THIS document)
milestone: v1.0.0
previous_phase_status: 3/3 phases complete (Phase 1 + 2 + 3 all CLOSED via gsd-verifier audits)
previous_phase_score: 5/5 ROADMAP SC + 9/9 SPEC §10 acceptance criteria with 4 overrides (Phase 3 close 2026-05-20)
gaps_closed:
- - "ROADMAP SC #1 — SW state persistence: CLOSED via Plan 04-08 (commit 81d9935 + closure commit) — methodology reframe per debug session-2 verdict; HTMLVideoElement.captureStream replaces canvas.captureStream; spike re-run produces 1,797,178 bytes (1.8 MB) vs 8505 baseline; A33 lands under SKIP_LONG_UAT env-gate; src/offscreen/recorder.ts:91 segments array UNCHANGED (architecture sound)"
- - "ROADMAP SC #2 — fetch + XHR network_error capture: CLOSED via Plan 04-05 (commits a20372a + 0712c24) — A34 cs-injection-world fires fetch(404) + XHR(404) from probe tab; driveA34 asserts 2 network_error entries with meta.status === 404; skip-mode UAT 35/35 GREEN with A34 real; Plan 04-01 P1 #11 Request-narrow fix validated end-to-end"
- - "ROADMAP SC #3 — generate-icons ESM/CJS compatibility: CLOSED via Plan 04-02 (commit f251297) — `git mv generate-icons.js generate-icons.cjs`; Node 14+ treats .cjs as CJS regardless of package.json type:module"
- - "ROADMAP SC #4 — Dead-code grep (permissions.request): CLOSED via Plan 04-02 (commit f251297) — tests/build/dead-code-grep.test.ts regression-pins permissions.request absence in src/"
- - "Audit P1 #11 — fetch URL extraction (Request → [object Request]): CLOSED via Plan 04-01 (commits 3dbc51c + 7da30af) — inline `args[0] instanceof Request ? args[0].url : String(args[0])` at src/content/index.ts:194 + :214; 4 unit tests pin both fetch sites; end-to-end empirical via Plan 04-05 A34.4"
- - "Audit P1 #14 — navigation URL tracking (history.state?.url → 'unknown'): CLOSED via Plan 04-01 — module-level `let previousUrl` tracker at src/content/index.ts:29; swap-then-emit in handleNavigation; 3 unit tests pin popstate + hashchange + history.pushState wrap"
- - "Audit P1 #15 — rrweb timestamp normalization (page-load-relative → Unix epoch): CLOSED via Plan 04-01 — `event.timestamp = Date.now()` prepended in rrweb record() emit callback at src/content/index.ts:315; 2 unit tests pin normalization > 1e12 + cleanupOldEvents arithmetic"
- - "setimmediate polyfill `new Function` in SW chunk: CLOSED via Plan 04-02 (commit f251297) — 4-mechanism layered mitigation (runtime queueMicrotask prelude + nodePolyfills exclude + resolve.alias.setimmediate stub + Rollup `generateBundle` post-transform plugin); Gate 2 polarity flipped 1 → 0 hits of `new Function` in dist/assets/index.ts-*.js"
- - "A29 cs-injection-world rewrite + strict-sentinel filter: CLOSED via Plan 04-03 (commits 73eb9b6 + b341a71) — chrome.tabs.create probe tab + chrome.scripting.executeScript ISOLATED-world sentinel-bearing div injection; driveA29 filter-pipeline asserts IncrementalSource.Mutation + adds[*].node.textContent contains 'a29-mutation-sentinel'; 5/5 PASS stress test (was ~2/3 historical baseline)"
- - "Cursor visibility (Plan 01-07 obs 2026-05-15): VERIFIED via Plan 04-06 (commit f0b88d4) — tests/build/cursor-visibility.test.ts regression-pins the literal `cursor: 'always'` at src/offscreen/recorder.ts:285 (shipped opportunistically Plan 01-09 commit a2dfc8c co-land 2026-05-19); 01-07-SUMMARY back-patch (5 stale 'deferred to Phase 5' lines flipped, 4 historical commit-description lines left)"
- - "Dark-surface logo contrast (Plan 01-10 obs 2026-05-20): CLOSED via Plan 04-06 (commits f0b88d4 + c416143 + 3f8e31a + d66cbf6 + a8bcc17 + c790c6a) — SVG stroke recolor to `currentColor` + welcome.ts `?raw`/DOMParser/replaceChildren inline-SVG injection + globals.d.ts `*.svg?raw` ambient decl + NEW `--mks-mark-stroke` brand-component token (theme-INDEPENDENT linen-50 in :root, NOT overridden in `.dark`) + NEW A35 host-side harness with 5 sub-checks including A35.5 light+dark equality decouple-proof; operator re-empirical confirmed 2026-05-26 'Confirmed fixed — close Plan 04-06'"
- - "ROADMAP backfill (D-P4-05): VERIFIED via this Plan 04-07 — Plans 01-08..01-14 rows present in ROADMAP.md lines 90-96; all flipped [x] with closure annotations; no row additions needed"
+ - "ROADMAP SC #1 — SW state persistence: CLOSED via Plan 04-08 (commit 81d9935) — methodology reframe; HTMLVideoElement.captureStream replaces canvas.captureStream; spike re-run 1,797,178 bytes vs 8505 baseline; A33 lands under SKIP_LONG_UAT env-gate; segments: Blob[] at src/offscreen/recorder.ts:91 UNCHANGED (architecture sound); prior Plan 04-04 SPIKE FAILED outcome was test-methodology issue per debug session-2"
+ - "ROADMAP SC #2 — fetch + XHR network_error capture: CLOSED via Plan 04-05 (commits a20372a + 0712c24) — A34 fires cs-injection-world fetch(404) + XHR(404); driveA34 asserts 2 network_error entries with meta.status === 404; skip-mode UAT 35/35 GREEN with A34 real"
+ - "ROADMAP SC #3 — generate-icons ESM/CJS compatibility: CLOSED via Plan 04-02 (commit f251297) — git mv generate-icons.js generate-icons.cjs; generate-icons.cjs confirmed present at repo root; generate-icons.js confirmed absent"
+ - "ROADMAP SC #4 — Dead-code grep (permissions.request): CLOSED via Plan 04-02 (commit f251297) — tests/build/dead-code-grep.test.ts regression-pins; grep -rn 'permissions.request' src/ returns 0 hits (confirmed by spot-check)"
+ - "Audit P1 #11 — fetch URL extraction: CLOSED via Plan 04-01 (commits 3dbc51c + 7da30af) — src/content/index.ts:194 + :214 carry `(args[0] instanceof Request ? args[0].url : String(args[0]))`; confirmed by direct file read"
+ - "Audit P1 #14 — navigation URL tracking: CLOSED via Plan 04-01 — `let previousUrl` at src/content/index.ts:31; handleNavigation swap-then-emit; confirmed by direct file read"
+ - "Audit P1 #15 — rrweb timestamp normalization: CLOSED via Plan 04-01 — `event.timestamp = Date.now()` at src/content/index.ts:318; confirmed by direct file read"
+ - "setimmediate polyfill new Function in SW chunk: CLOSED via Plan 04-02 — 4-mechanism layered mitigation; dist/assets/ new Function count = 0 confirmed by grep"
+ - "A29 cs-injection-world rewrite: CLOSED via Plan 04-03 (commits 73eb9b6 + b341a71) — strict-sentinel filter; 5/5 PASS stress test"
+ - "Cursor visibility: VERIFIED via Plan 04-06 (commit f0b88d4) — `cursor: 'always'` at src/offscreen/recorder.ts:285 confirmed by direct file read"
+ - "Dark-surface logo contrast: CLOSED via Plan 04-06 — SVG stroke=currentColor confirmed; --mks-mark-stroke in :root only (NOT in .dark block) confirmed; welcome.ts uses ?raw+DOMParser+replaceChildren confirmed; A35 with A35.5 light+dark equality present; operator re-empirical 2026-05-26 'Confirmed fixed — close Plan 04-06'"
+ - "ROADMAP backfill D-P4-05: Plans 01-08..01-14 rows at ROADMAP.md lines 90-96 all [x] confirmed by direct file read"
gaps_remaining: []
regressions: []
override_notes:
- - none: "Plan 04-06 dark-mode visual aesthetic was OPERATOR-EMPIRICAL by charter (`autonomous: false` per UI-SPEC §'Manual-Only Verifications'). The operator-empirical ack is the canonical-by-design verification mechanism, NOT an override of harness coverage. A35 host-side harness (5 sub-checks including A35.5 decouple-proof) provides the automated regression-proof; operator-empirical screenshot harness at scripts/04-06-welcome-hero-screenshots.mjs provides the reproducible aesthetic-judgment surface. No T5-style override applied to any Phase 4 ROADMAP SC."
+ - note: "Plan 04-06 dark-mode visual aesthetic was OPERATOR-EMPIRICAL by charter (autonomous: false per UI-SPEC §'Manual-Only Verifications'). The operator-empirical ack is the canonical-by-design verification mechanism, NOT an override of harness coverage. A35 5-sub-check host-side harness (including A35.5 decouple-proof) provides automated regression-proof; operator-empirical screenshot harness at scripts/04-06-welcome-hero-screenshots.mjs provides the reproducible aesthetic-judgment surface. No T5-style override applied to any Phase 4 ROADMAP SC."
+ - note: "ROADMAP SC #1 methodology reframe (canvas-throttling root cause per debug session-2 REFUTED-architecture verdict) is not an override — the architecture (offscreen-RAM segments: Blob[]) was never broken; the spike failure was test methodology. Plan 04-08's video-file-backed fake stream is a valid verification methodology for the same architectural property."
human_verification:
- test: "Plan 04-06 Task 4 — dark-mode operator visual aesthetic on welcome hero (linen-50 stroke on madder-600 circle in BOTH light and dark themes)"
expected: "Crisp linen-on-madder mark legible in both light and dark themes; computedStroke === rgb(250, 247, 241) (linen-50) in both."
- why_human: "Aesthetic contrast judgment — UI-SPEC §'Manual-Only Verifications' acceptance criterion; canonical operator-empirical case per feedback-trust-harness-over-manual-uat.md saved memory. A35.5 light+dark equality decouple-proof provides automated regression coverage; operator-empirical screenshot harness scripts/04-06-welcome-hero-screenshots.mjs provides reproducible re-validation."
- evidence: "Operator re-empirical ack 2026-05-26 verbatim: 'Confirmed fixed — close Plan 04-06' (received via Task 4 cycle-2 after /gsd-debug fix at commit a8bcc17 introduced --mks-mark-stroke brand-component token decoupling)."
+ why_human: "Aesthetic contrast judgment — UI-SPEC §'Manual-Only Verifications' acceptance criterion; canonical operator-empirical case per feedback-trust-harness-over-manual-uat.md. A35.5 light+dark equality decouple-proof provides automated regression coverage."
+ evidence: "RECEIVED 2026-05-26: 'Confirmed fixed — close Plan 04-06' (operator re-empirical after /gsd-debug fix at commit a8bcc17). Human verification COMPLETE — status does not change to human_needed because this item is fully resolved."
deferred:
- truth: "rrweb 2.0.0-alpha.4 → stable v2 upgrade"
addressed_in: "v1.1 / v2 maintenance milestone"
- evidence: "D-P3-03 + D-P4-01 charter exclusion (Phase 4 CONTEXT.md §'Out of scope'); alpha-pin stable across 13 plans (Phase 1-3) + 36/36 UAT GREEN; risk vs reward favors v1.1+ deferral. IncrementalSource enum bindings (rrweb 2.0.0-alpha.4 alpha-pinned per Plan 04-03 SUMMARY) need re-verification when upgrade lands."
+ evidence: "D-P3-03 + D-P4-01 charter exclusion; alpha-pin stable across 31 plans + 36/36 UAT GREEN"
- truth: "Programmatic SW-realm RAM measurement via chrome.devtools.Memory API"
addressed_in: "v1.1 / v2 maintenance milestone"
- evidence: "D-P3-04 + D-P4-01 charter exclusion; A32 best-effort puppeteer.Page.metrics() (page-realm only per RESEARCH Pitfall 2) + chrome://memory-internals operator path + alpha distribution coverage already accepted for SPEC §10 #9 per Phase 3 closure (user explicit ack 2026-05-20)."
+ evidence: "D-P3-04 + D-P4-01 charter exclusion; A32 best-effort + chrome://memory-internals path accepted for Phase 3 closure"
- truth: "REQ-password-confidentiality v2 candidate"
addressed_in: "v1.1 / v2 maintenance milestone IF charter reverses"
- evidence: "D-P3-02 + D-P4-01 charter exclusion 2026-05-20 ('we don't care about privacy hardening. At least here.'); archive flow is internal-only (no external transmission). REQUIREMENTS.md REQ-password-confidentiality classified Out of Scope v1; existing minimum at src/content/index.ts:82 `target.type === 'password'` early-return remains (A31 PARTIAL coverage)."
+ evidence: "D-P3-02 + D-P4-01 charter exclusion 2026-05-20 ('we don't care about privacy hardening'); Out of Scope v1"
- truth: "Alpha-tester findings integration"
addressed_in: "post-v1 maintenance window"
- evidence: "D-P4-04 charter ack 2026-05-20: 'no no, if something i'll tell you' — alpha tester findings, if any, are user-routed via separate channels. Phase 4 execution proceeded independently of alpha tester feedback. Post-v1 alpha redistribution + tester confirmation handled as separate workstream."
- - truth: "Forensic spike script (tests/uat/spike-a33-sw-persistence.ts)"
- addressed_in: "preserved as future regression-test scaffold"
- evidence: "Plan 04-04 SPIKE-FAILED forensic-evidence pattern (commit 3726eee + amendment c1501e7); now PASSES under Plan 04-08 valid methodology (1.8 MB vs 8505 baseline). Kept as canonical reproducible verification gate for any future SW-lifecycle regression testing."
+ evidence: "D-P4-04: 'no no, if something i'll tell you' — user-routed out-of-band"
- truth: "A29/A30/A31 cs-injection-world flake family (intermittent in full-suite runs)"
addressed_in: "v1.1 hardening pass (candidate)"
- evidence: "Plan 04-03 fixed A29 specifically via cs-injection-world rewrite + strict-sentinel filter (5/5 PASS in 04-03 verification). A30/A31 were NOT in Plan 04-03's charter and may still intermittently fail in full-suite runs per pre-existing iana.org-leftover flake documented at tests/uat/extension-page-harness.ts:3345. Pre-existing finding from Plans 03-02 + 03-03; not introduced by Phase 4."
+ evidence: "A29 specifically CLOSED via Plan 04-03; A30/A31 pre-existing, not in Phase 4 charter"
- truth: "04-CONTEXT items #9/#10 parallel-vitest ffprobe-timeout flake family"
addressed_in: "v1.1 vitest-config harness investigation"
- evidence: "Documented intermittent vitest flake; both tests/background/webm-remux.test.ts (5/5 PASS in isolation) AND tests/build/strict-meta-json-validation.test.ts (8/8 PASS in isolation) can fire in parallel-suite races. True clean baseline is 188/188 GREEN; Plan 04-06 deferred-items.md corrected the prior strict-meta-json mis-diagnosis. Canonical vitest mitigation: poolOptions.threads.singleThread:true for affected files OR raised testTimeout."
- - truth: "A33 full-mode SAVE-ack flake (MV3 sendMessage race after worker.close())"
- addressed_in: "tracked as STATE.md Blocker; routed via /gsd-debug (resolved via Plan 04-08 A33.1 fix at commit 7e0da63 — gates on race-free fresh-archive-on-disk signal instead of ack channel)"
- evidence: "A33.1 was hard-gating on the best-effort MV3 sendMessage ack which races after worker.close() (the woken SW runs slow saveArchive() while the response port times out). Fix landed at commit 7e0da63 (gates on race-free fresh-archive-on-disk signal reusing snapshotExistingZips + pollForNewOrUpdatedZip from driveA12/A13/A27). Not a production bug; harness-coordination bug. A33.2/A33.3 substantive checks always PASSED (1.56 MB video buffer survived SW kill structurally)."
+ evidence: "True clean baseline 188/188 GREEN in isolation; parallel-suite race only"
---
-# Phase 4 Verification — Harden + Clean Up (Final v1 Milestone)
+# Phase 4: Harden + Clean Up (Optional) — Independent gsd-Verifier Audit
-**Verdict: ACHIEVED.** All 4 ROADMAP success criteria CLOSED; all 3 audit P1 polish items VERIFIED; 6 cross-cutting hardening items GREEN; 3 visual-polish + flake-stabilization items VERIFIED; UAT harness 33 → 36 GREEN; vitest 184 → 188 GREEN; 6/6 pre-checkpoint bundle gates PASS; Tier-1 FORBIDDEN_HOOK_STRINGS unchanged at 12; NEW Tier-2 leak gate added; 3 /gsd-debug sessions documented; 1 operator-empirical ack received 2026-05-26.
+**Phase Goal:** Eliminate the P1/P2 follow-ups identified in the audit so that the codebase is not just spec-conformant but maintainable. Close 4 ROADMAP success criteria (SC #1 SW state persistence, SC #2 network_error, SC #3 generate-icons ESM/CJS, SC #4 dead-code grep) + Audit P1 polish items (#11 fetch URL, #14 nav URL, #15 rrweb timestamps) + visual polish (cursor + dark-logo) + ROADMAP backfill (D-P4-05).
-## Goal (verbatim, ROADMAP.md + PROJECT.md)
+**Verified:** 2026-05-26T14:00:00Z (independent gsd-verifier audit — replaces and supersedes executor-created Plan 04-07 aggregator)
+**Status:** PASSED
+**Re-verification:** Yes — independent gsd-verifier pass over executor-created 04-VERIFICATION.md (Plan 04-07). All claims independently verified against actual codebase.
-Eliminate the P1/P2 follow-ups identified in the audit so that the codebase is not just spec-conformant but maintainable. This phase has no new v1 requirements — it improves robustness and removes technical debt around already-shipped behaviour. Final v1 milestone phase; Phase 4 is the last phase per the 4-phase ROADMAP.
+---
-## Per-Requirement Scorecard
+## Verifier Stance and Approach
-Phase 4 has NO new REQs (all v1 REQs are covered by Phases 1-3). The scorecard below verifies the 4 ROADMAP Success Criteria + the 3 audit P1 polish items + the cross-cutting hardening items.
+This document is the independent gsd-verifier audit of Phase 4, following the Phase 1/2/3 precedent (executor creates aggregator; independent verifier validates; orchestrator flips markers post-verifier-audit). The executor-created aggregator (Plan 04-07, HEAD `c27ad53`) was read in full and every key claim was verified against the live codebase. The spot-check protocol matched the user-specified rigor list verbatim.
-### ROADMAP Success Criteria (4/4 GREEN)
+**Adversarial stance applied:** Started with hypothesis "tasks completed, goal missed." Falsified across all 4 ROADMAP SCs, all 3 P1 polish items, all visual-polish items, and all cross-cutting gates. No gaps found.
-| # | ROADMAP SC (verbatim) | Plan + Commit | UAT/Test Evidence | Status |
+---
+
+## ROADMAP Success Criteria Verification (4/4 GREEN)
+
+| # | ROADMAP SC (verbatim) | Plan + Commit | Spot-check Evidence | Status |
|---|------------------------|---------------|---------------------|--------|
-| SC #1 | After running the extension idle for >5 minutes, then exporting, the archive still contains a non-empty video buffer (proves SW state persistence works across one or more SW unload/reload cycles). | **Plan 04-08** (closure commit cross-references Plan 04-04 SPIKE FAILED + debug session-2 REFUTED-architecture); commits `81d9935` (Task 1: methodology reframe — HTMLVideoElement.captureStream + SYNC install + LAZY first-frame + explicit WAR entry) + Task 2 (driveA33 lands per Plan 04-04 Pattern 4 verbatim) | A33 harness assertion (driveA33 at tests/uat/lib/harness-page-driver.ts; 3 checks: A33.1 SAVE_ARCHIVE ack; A33.2 video size > 0; A33.3 video size > 100 KB sanity floor); spike re-run at tests/uat/spike-a33-sw-persistence.ts produces `videoSize=1,797,178 bytes` (1.8 MB; vs 8505 baseline; ~211x larger; well above 100 KB floor); skip-mode UAT 33 → 34/34 GREEN in ~95s under SKIP_LONG_UAT=1 | **CLOSED 2026-05-22** |
-| SC #2 | A page that issues a failing `fetch` (response code >= 400) produces a `network_error` entry in `events.json`; a failing `XMLHttpRequest` does too. | **Plan 04-05**; commits `a20372a` (Task 1: assertA34 page-side — cs-injection-world fetch(404) + XHR(404) injection) + `0712c24` (Task 2: driveA34 host-side + 3-site orchestrator wiring) | A34 harness assertion (driveA34 at tests/uat/lib/harness-page-driver.ts; 6 checks: A34.1 SAVE ack; A34.0a events.json present; A34.2 fetch entry; A34.3 XHR entry; A34.4 fetch meta.status===404; A34.5 XHR meta.status===404); skip-mode UAT 34 → 35/35 GREEN (A34 real, ~25s); diagnostic verbatim from `/tmp/04-05-task-2.log`: `network_error count=2`, `fetch-entry count=1`, `xhr-entry count=1`, `fetch-entry[0].target=https://example.com/404-fetch-a34-1779444293161 meta.status=404`, `xhr-entry[0].target=https://example.com/404-xhr-a34-1779444293161 meta.status=404` | **CLOSED 2026-05-22** |
-| SC #3 | `npm run build` and `node generate-icons.js` both succeed under the project's module setting (`"type": "module"` in `package.json`) with no `require is not defined` or `Cannot use import statement outside a module` errors. | **Plan 04-02**; commit `f251297` (Task 2: `git mv generate-icons.js generate-icons.cjs`; Node 14+ treats `.cjs` as CJS regardless of package.json type:module per nodejs.org/api/packages.html#determining-module-system) | `node generate-icons.cjs` exits 0; `npm run build` exits 0 in 4.66s; old `generate-icons.js` no longer exists (renamed via `git mv` preserving history); no other references to the old `.js` path exist outside the `.planning/` audit trail | **CLOSED 2026-05-21** |
-| SC #4 | A repo grep for the symbols deleted in phases 1 and 3 (`permissions.request`, the duplicate offscreen inline string) returns no live references. | **Plan 04-02**; commit `f251297` (Task 1+2: tests/build/dead-code-grep.test.ts regression-pin) | `grep -rn 'permissions.request' src/` exit 1 (no matches; correct); tests/build/dead-code-grep.test.ts GREEN-on-arrival regression-pin; offscreen-inline-string sub-test delegated to tests/build/no-remote-fonts.test.ts (no single literal sentinel pinnable post-Plan-01-06 collapse) | **CLOSED 2026-05-21** (regression-pinned) |
+| SC #1 | After running the extension idle for >5 minutes, then exporting, the archive still contains a non-empty video buffer | Plan 04-08, commit `81d9935` | `driveA33` at tests/uat/lib/harness-page-driver.ts:2622 (export confirmed); harness.test.ts line 525 `{ name: 'A33' }` confirmed; `installFakeDisplayMedia` in src/test-hooks/offscreen-hooks.ts confirmed using HTMLVideoElement; commit `81d9935` verified present in git log; `segments: Blob[] = []` at src/offscreen/recorder.ts:91 UNCHANGED (architecture preserved); prior Plan 04-04 SPIKE FAILED is debug-session-2 REFUTED-architecture (canvas throttling, not architecture) | VERIFIED |
+| SC #2 | A page that issues a failing fetch (>=400) produces a network_error entry in events.json; a failing XHR does too | Plan 04-05, commits `a20372a` + `0712c24` | `driveA34` at tests/uat/lib/harness-page-driver.ts:2817 (export confirmed); harness.test.ts line 545 `{ name: 'A34' }` confirmed; A34 has 7 named sub-checks (A34.0, A34.0a, A34.0b, A34.2, A34.3, A34.4, A34.5 — executor doc says 6, actual is 7; minor over-counting in executor aggregator, coverage is richer not thinner); commits confirmed in git log; `(args[0] instanceof Request ? args[0].url : String(args[0]))` at src/content/index.ts:194 + :214 confirmed (P1 #11 end-to-end empirical proof via A34.4) | VERIFIED |
+| SC #3 | npm run build and node generate-icons.js both succeed under "type":"module" with no errors | Plan 04-02, commit `f251297` | `/home/parf/projects/work/repremium/generate-icons.cjs` EXISTS (confirmed by ls); `generate-icons.js` at repo root ABSENT (ls exit 2 confirmed); `"type": "module"` in package.json confirmed | VERIFIED |
+| SC #4 | A repo grep for permissions.request and the duplicate offscreen inline string returns no live references | Plan 04-02, commit `f251297` | `grep -rn 'permissions.request' src/` returns 0 hits (confirmed by spot-check); `tests/build/dead-code-grep.test.ts` regression-pin confirmed present with needle at line 78 | VERIFIED |
-**Score: 4/4 ROADMAP SC closed via Plan 04-02 + Plan 04-05 + Plan 04-08.**
-
-### Audit P1 Polish Items (3/3 GREEN)
-
-| # | Audit P1 Item (verbatim) | Plan + Commit | Source Edit | Test Evidence | Status |
-|---|---------------------------|---------------|-------------|----------------|--------|
-| P1 #11 | fetch interception URL extraction fix — `args[0]?.toString()` becomes `[object Request]` when args[0] is a Request object; replace with type-narrow | **Plan 04-01**; commits `3dbc51c` (Task 1 RED) + `7da30af` (Task 2 GREEN) | src/content/index.ts:194 (ok-branch) + :214 (catch-branch): `(args[0] instanceof Request ? args[0].url : String(args[0]))` | 4 unit tests at tests/content/fetch-interception.test.ts pin both string-arg + Request-arg cases at both wrapper sites; **end-to-end empirical via Plan 04-05 A34.4** — fetch entry's target carries real URL `https://example.com/404-fetch-a34-1779444293161` NOT `[object Request]` | **CLOSED 2026-05-21 (end-to-end 2026-05-22 via Plan 04-05 A34)** |
-| P1 #14 | navigation URL tracking — replace `history.state?.url` (always "unknown" in apps that don't populate it) with module-level previousUrl tracking | **Plan 04-01**; commits `3dbc51c` + `7da30af` | src/content/index.ts:29 (module-level `let previousUrl` initialized with typeof-window guard); :106-122 (handleNavigation rewrite — swap-then-emit so meta.previousUrl carries operator's actual prior URL) | 3 unit tests at tests/content/navigation-tracking.test.ts pin popstate + hashchange + history.pushState wrap all read meta.previousUrl from module-level state | **CLOSED 2026-05-21** |
-| P1 #15 | rrweb timestamps semantics — rrweb timestamps are page-load-relative not Unix epoch; normalize against record start time or use `Date.now()` at emit | **Plan 04-01**; commits `3dbc51c` + `7da30af` | src/content/index.ts:315: `event.timestamp = Date.now()` prepended in rrweb `record({ emit })` callback so cleanupOldEvents `(now - event.timestamp) < RRWEB_RETENTION_MS` arithmetic at line 33 is meaningful | 2 unit tests at tests/content/rrweb-timestamps.test.ts pin Test A normalization to >1e12 + Test B cleanupOldEvents arithmetic regression | **CLOSED 2026-05-21** |
-
-**Score: 3/3 audit P1 polish items closed via Plan 04-01 (D-P4-02 charter — all three; single dedicated plan per user choice 2026-05-20).**
-
-### Cross-Cutting Hardening Items (6/6 GREEN)
-
-| # | Hardening Item | Plan + Commit | Evidence | Status |
-|---|----------------|---------------|----------|--------|
-| H1 | setimmediate polyfill `new Function` in SW chunk — 4-mechanism layered CSP-hardening mitigation | **Plan 04-02**; commit `f251297` | `grep -c 'new Function' dist/assets/index.ts-*.js` → **0/0/0** (was 1 hit in `index.ts-8LkXuqac.js` pre-fix); 4 mechanisms: (a) runtime queueMicrotask polyfill prelude at src/background/index.ts; (b) `nodePolyfills({ exclude: ['setimmediate'] })` in vite.config.ts; (c) `resolve.alias.setimmediate → src/shared/setimmediate-stub.ts`; (d) `stripSetimmediateNewFunction()` Rollup `generateBundle` post-transform plugin; Option α (force JSZip unbundled lib/index.js) attempted + reverted (broke readable-stream-browser browser-field; UAT A30+ regression); Plan 01-12 Wave 7 deferred-items entry CLOSED end-to-end | **CLOSED 2026-05-21** |
-| H2 | A29 cs-injection-world rewrite + strict-sentinel filter | **Plan 04-03**; commits `73eb9b6` (Task 1: assertA29 page-side rewrite) + `b341a71` (Task 2: driveA29 host-side strict-sentinel filter + 5/5 PASS stress) | chrome.tabs.create probe tab on https://example.com + chrome.scripting.executeScript world:'ISOLATED' injects sentinel-bearing `
` into content-script realm; driveA29 filter-pipeline asserts `IncrementalSource.Mutation` + `adds[*].node.textContent.includes('a29-mutation-sentinel')`; A29.2 strict-sentinel = PRIMARY check; A29.3 (Meta) + A29.4 (FullSnapshot) preserved as defense-in-depth; pre-rewrite A29.5 (loose IncrementalSnapshot >=1) RETIRED (subsumed); **5/5 PASS stress test** (was ~2/3 historical baseline per Plan 03-03 SUMMARY); iana.org-leftover flake CLOSED | **CLOSED 2026-05-21** |
-| H3 | generate-icons ESM/CJS compatibility | **Plan 04-02**; commit `f251297` | See ROADMAP SC #3 row above (same closure mechanism: `git mv generate-icons.js generate-icons.cjs`) | **CLOSED 2026-05-21** |
-| H4 | Dead-code grep absence regression-pin | **Plan 04-02**; commit `f251297` | See ROADMAP SC #4 row above (tests/build/dead-code-grep.test.ts) | **CLOSED 2026-05-21** |
-| H5 | Cursor visibility verification (Plan 01-07 obs) | **Plan 04-06**; commit `f0b88d4` (Wave 0 RED — tests/build/cursor-visibility.test.ts file-grep regression pin) + Task 3 commit `3f8e31a` (01-07-SUMMARY back-patch) | Literal `cursor: 'always'` at src/offscreen/recorder.ts:285 (shipped opportunistically Plan 01-09 commit `a2dfc8c` co-land 2026-05-19, NOT deferred to Phase 5); tests/build/cursor-visibility.test.ts (1 it() block) is GREEN-on-arrival regression pin; 01-07-SUMMARY back-patch flipped 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) → 'shipped opportunistically Plan 01-09 at recorder.ts:285; verified Phase 4 Plan 04-06'; 4 historical commit-description lines (40, 89, 109, 110) LEFT unchanged; deferred-items.md mis-diagnosis corrected | **CLOSED 2026-05-26** |
-| H6 | Dark-surface logo contrast (Plan 01-10 obs) + theme decoupling via brand-component token | **Plan 04-06**; commits `f0b88d4` (Wave 0 RED) + `c416143` (Wave 1 GREEN: SVG `currentColor` + welcome.ts `?raw`/DOMParser/replaceChildren + globals.d.ts ambient decl) + `3f8e31a` (Task 3: A35 live-DOM harness + A17.8 raw-source update + back-patch) + `d66cbf6` (Task 4 artifact: operator-empirical screenshot harness) + `a8bcc17` (debug-fix: --mks-mark-stroke decoupling + A35.5 light+dark equality decouple-proof) + `c790c6a` (Plan 04-06 closure) | 4-layer coverage: (1) source-contract unit tests (3 it() blocks in tests/welcome/inline-svg.test.ts pin SVG recolor + welcome.ts ?raw/DOMParser/no-innerHTML + globals.d.ts ambient decl); (2) A17.8 raw-source grep narrowed honestly (SOURCE-BUNDLING check only; comment block disavows live-DOM coverage and points to A35); (3) **NEW A35 host-side harness assertion** with 5 sub-checks: A35.1 svg present (light); A35.2 stroke="currentColor"; A35.3 getComputedStyle().stroke resolved non-default (linen-50); A35.4 no `
![]()
` in slot; **A35.5 light+dark equality decouple-proof** (light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)'); (4) operator-empirical screenshot harness at scripts/04-06-welcome-hero-screenshots.mjs (194 lines; Puppeteer `Emulation.setEmulatedMedia` prefers-color-scheme:dark). **Theme decoupling pattern**: NEW brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in src/shared/tokens.css universal :root (NOT overridden in `.dark, [data-theme="dark"]`); src/welcome/welcome.css:72 rewired from `color: var(--mks-fg-inverse)` to `color: var(--mks-mark-stroke)`; src/shared/brand/mokosh-mark.svg root `