` and ``; planner-side confirms the head + tokens.css link remain untouched. |
+| A6 | Phase 3 plans can stay at FORBIDDEN_HOOK_STRINGS = 12 entries (no new __MOKOSH_UAT__ symbol required) | Pitfall 5 / Standard Stack | MEDIUM — most likely true (rrweb + chrome.tabs + chrome.downloads are already production surfaces), but if Plan 03-04 scaffolding requires a new bridge op (e.g., `get-page-metrics` from offscreen → harness), that would add 1-2 entries. Surface in plan-checker pass. |
+| A7 | `chrome://memory-internals` is available on Chrome stable 124+ (operator-facing path) | RAM operator instructions / D-P3-04 | LOW — chrome://memory-internals is a stable internal URL since Chrome 80+. The `chrome://extensions/` service-worker memory display (Inspect views > service worker > Memory) is the canonical alternative. |
+| A8 | The harness host can read the assembled zip's `rrweb/session.json` and `logs/events.json` via existing `findLatestZip` + JSZip pattern (Plan 02-04 precedent) | Don't Hand-Roll / Pattern 1 | VERIFIED — Plan 02-04 driveA26 + driveA28 already do exactly this for meta.json + zip-layout; rrweb/session.json + logs/events.json are sibling entries in the canonical 5-entry layout. |
+
+**If the table is mostly LOW risk:** confirmed. The only MEDIUM is A6; planner-side flag.
+
+## Open Questions
+
+1. **Wave structure: parallel or sequential for Plans 03-01..04?**
+ - What we know: Plan 02-04 ran A24-A28 sequentially within a single plan (one author). Phase 3's 5-plan structure is finer-grained per D-P3-01.
+ - What's unclear: Do Plans 03-01, 03-02, 03-03 modify the SAME `tests/uat/extension-page-harness.ts` + `tests/uat/lib/harness-page-driver.ts` files in ways that would conflict on parallel execution? CONTEXT.md "Claude's Discretion" defers to plan-time `files_modified` overlap audit.
+ - Recommendation: Default sequential (03-01 → 03-02 → 03-03 → 03-04 → 03-05) unless plan-checker confirms zero overlap. Phase 2 lesson cited in CONTEXT.md is "plan-checker should catch overlaps"; honor it.
+
+2. **A29 chaining: own SAVE vs. chain off A28?**
+ - What we know: A26 + A28 chain off A25's already-completed SAVE per Plan 02-04 (no new SAVE). A27 owns its SAVE because the tab tracker needs the multi-tab onActivated events to fire BEFORE dispatch.
+ - What's unclear: Does the probe-page DOM injection happen before the existing harness page's recorded session, or before a separate session? rrweb starts on `start()` (content-script init) — by the time the harness page is loaded, rrweb is already recording.
+ - Recommendation: A29 chains off A28's already-completed SAVE if the DOM mutations happen during the rolling 30s recording window before A25's SAVE. If timing-fragile, A29 owns its SAVE with `setupFreshRecording` + segment-settle, mirroring A27. Plan 03-01 planner picks based on smoke-test.
+
+3. **Plan 03-04 Page.metrics scaffolding: include or skip?**
+ - What we know: D-P3-04 says "if practical without research budget". This research budget is exhausted; Page.metrics IS practical (single API call); scaffolding is ~30 lines.
+ - What's unclear: Is the resulting page-realm-only measurement value worth the diagnostic copy overhead? Operator-facing chrome://memory-internals is unaffected.
+ - Recommendation: SHIP the scaffolding (low cost). Output is informational only; explicit diagnostic copy ("page-realm only; SW context excluded") avoids over-interpretation. Tier-1 inventory unaffected (Page.metrics is host-side; not bundled).
+
+## Environment Availability
+
+| Dependency | Required By | Available | Version | Fallback |
+|------------|------------|-----------|---------|----------|
+| Node.js + npm | All harness tooling | ✓ | (project pin) | — |
+| Puppeteer ^25 | UAT harness driver | ✓ | 25.0.2 (package.json) | — |
+| Chrome / Chromium (Puppeteer-bundled) | Real-Chrome target for harness | ✓ | Puppeteer-bundled stable | — |
+| rrweb 2.0.0-alpha.4 + @rrweb/types | DOM event verification (Plan 03-01) | ✓ | Pinned (package.json:11) | — |
+| JSZip | Archive parsing in driveA29+ | ✓ | 3.10.1 | — |
+| tsx | TS runner | ✓ | 4.22.1 | — |
+| vitest | Unit-test layer (Tier-1 grep gate) | ✓ | ^4 | — |
+| chrome://memory-internals (operator) | §10 #9 RAM check | ✓ (Chrome stable 80+) | — | chrome://extensions service-worker Memory tab |
+| ffprobe / ffmpeg | §10 #7 video playback re-verification (already covered in Phase 1 VERIFICATION) | Already verified Phase 1 closure | — | — |
+
+**Missing dependencies with no fallback:** None. Phase 3 introduces zero new dependencies.
+
+**Missing dependencies with fallback:** None.
+
+## Validation Architecture
+
+> Required per `.planning/config.json:workflow.tdd_mode = true` (workflow.nyquist_validation absent — treat as enabled).
+
+### Test Framework
+
+| Property | Value |
+|----------|-------|
+| Framework | vitest ^4 (171/171 GREEN post Phase 2) + Puppeteer ^25 UAT harness (29/29 GREEN) |
+| Config file | `vite.config.ts` + `vite.test.config.ts` (defines `__MOKOSH_UAT__`); `vitest.config.ts` if present (project pins via package.json scripts) |
+| Quick run command | `npm test` (vitest) for unit tier; `SKIP_PROD_REBUILD=1 HEADLESS=1 npm run test:uat` for harness tier |
+| Full suite command | `npm test && npm run test:uat` (sequential — UAT depends on `npm run build:test` artifact) |
+
+### Phase Requirements → Test Map
+
+| Req ID | Behavior | Test Type | Automated Command | File Exists? |
+|--------|----------|-----------|-------------------|-------------|
+| REQ-install-clean | §10 #1 fresh build loads unpacked w/o errors | aggregator (existing tests) | `npm test` covers manifest + i18n + no-remote-fonts | ✅ tests/i18n/manifest-i18n.test.ts + tests/build/no-remote-fonts.test.ts |
+| REQ-rrweb-dom-buffer | §10 #4 rrweb records meta+full+incremental on probe page | UAT harness (Plan 03-01 A29) | `npm run test:uat` (post-Plan 03-01) | ❌ Wave 0 (A29 to be created) |
+| REQ-user-event-log | §10 #5 events.json contains 5 UserEvent types | UAT harness (Plan 03-02 A30) | `npm run test:uat` (post-Plan 03-02) | ❌ Wave 0 (A30 to be created) |
+| (§10 #8 PARTIAL per D-P3-02) | Password sentinel absent from events.json | UAT harness (Plan 03-03 A31 negative-assert) | `npm run test:uat` (post-Plan 03-03) | ❌ Wave 0 (A31 to be created) |
+| (§10 #9 best-effort per D-P3-04) | RAM scaffolding via Page.metrics OR operator chrome://memory-internals | UAT harness (Plan 03-04 A3X, optional) + manual-only operator step | `npm run test:uat` (post-Plan 03-04) + operator | Optional Wave 0 (A3X may or may not be created) |
+
+### Sampling Rate
+- **Per task commit:** `npm test` (~30s for full vitest suite)
+- **Per wave merge:** `npm run test:uat` (~95s; Plan 02-04 baseline)
+- **Phase gate:** `npm test && npm run test:uat` both GREEN before `/gsd-verify-work 3`
+
+### Wave 0 Gaps
+- [ ] `tests/uat/extension-page-harness.ts` — append probe HTML injection helper + assertA29..A31 (+ optional A3X) — Plan 03-01..04
+- [ ] `tests/uat/lib/harness-page-driver.ts` — append driveA29..A31 (+ optional A3X) + EventType import — Plan 03-01..04
+- [ ] `tests/uat/harness.test.ts` — import + drivers[] push + banner — Plan 03-01..04
+- [ ] `tests/uat/extension-page-harness.html` — append probe HTML below existing `` + ``; preserve tokens.css link — Plan 03-01
+
+*(No new test framework install required. No new vitest test files anticipated — all new assertions live in the UAT harness tier.)*
+
+## Security Domain
+
+> `security_enforcement` is not explicitly set in `.planning/config.json` — treating as default-enabled.
+
+### Applicable ASVS Categories
+
+| ASVS Category | Applies | Standard Control |
+|---------------|---------|-----------------|
+| V2 Authentication | no | Extension is local-only; no auth surface |
+| V3 Session Management | no | Local-only; no remote sessions |
+| V4 Access Control | partial | MV3 permissions baseline (DEC-011 + Amendment 1) — verified via existing `manifest-i18n.test.ts` |
+| V5 Input Validation | yes | `URL_SCHEME_ALLOW` regex at `src/background/tab-url-tracker.ts:79` validates URL schemes; probe page inputs are not user input from a security boundary perspective |
+| V6 Cryptography | no | No cryptography in Phase 1 v1 surface |
+| V7 Error Handling and Logging | partial | Logging via `ContentLogger`; no PII expected (passwords filtered) |
+| V8 Data Protection | partial | Password filter at `src/content/index.ts:82` is the v1 minimum per D-P3-02; full masking deferred to Phase 4+ if charter reverses |
+
+### Known Threat Patterns for Phase 3
+
+| Pattern | STRIDE | Standard Mitigation |
+|---------|--------|---------------------|
+| Test-only hook surface leaking to production bundle | Information Disclosure | Tier-1 FORBIDDEN_HOOK_STRINGS gate (12 entries; unit-mirror + UAT A0 mirror); `__MOKOSH_UAT__` Vite define-token tree-shake; verified per Plan 02-04 SUMMARY |
+| Probe page sentinel value (e.g., "secret-do-not-log-123") leaking via grep mismatch | Information Disclosure | Sentinel is a fixed test constant, not a real secret; absence-assertion proves filter fires; logged to event log triggers explicit RED |
+| New chrome.* permission grant for probe-page composition | Elevation of Privilege | Phase 3 plans explicitly stay at DEC-011 + Amendment 1 baseline (8 permissions); no new manifest changes |
+| rrweb data buffer growth past 5000 events / 10min cap during probe | Denial of Service | `cleanupOldEvents` at `src/content/index.ts:27-50` already enforces (oldest-dropped); Plan 03-01 probe HTML interaction is brief (~500ms) and far below the cap |
+
+## Sources
+
+### Primary (HIGH confidence)
+- npm registry verified 2026-05-20 via `npm view rrweb dist-tags`: `latest=2.0.0-alpha.4, alpha=2.0.0-alpha.20, beta=1.0.0-beta.2`
+- @rrweb/types EventType enum verified via `node_modules/@rrweb/types/dist/index.d.ts`: `{DomContentLoaded:0, Load:1, FullSnapshot:2, IncrementalSnapshot:3, Meta:4, Custom:5, Plugin:6}`
+- Plan 02-04 SUMMARY (`.planning/phases/02-stabilize-export-pipeline/02-04-SUMMARY.md`) — most recent Approach B harness precedent; 29/29 UAT GREEN
+- Plan 01-13 SUMMARY — Approach B foundation; FORBIDDEN_HOOK_STRINGS pattern
+- Plan 01-14 SUMMARY — single-assertion plan precedent (A23); 7-file atomic-commit shape
+- `src/content/index.ts` — production wiring being verified (read-only for Phase 3)
+- `src/shared/types.ts:124-131` — UserEvent type contract
+- `tests/uat/extension-page-harness.ts:2851-3413` — assertA24-A28 implementations (latest pattern)
+- `tests/uat/lib/harness-page-driver.ts` — driveA* + findLatestZip + JSZip pattern
+- `tests/background/no-test-hooks-in-prod-bundle.test.ts:108-126` — Tier-1 inventory (12 entries)
+- 03-CONTEXT.md (D-P3-01..04 locked decisions + canonical_refs)
+- 03-UI-SPEC.md (null-spec; probe-page conventions; FORBIDDEN_HOOK_STRINGS lockstep guidance)
+
+### Secondary (MEDIUM confidence)
+- Puppeteer official docs: https://pptr.dev/api/puppeteer.page.metrics (Page.metrics + JSHeapUsedSize semantics)
+- Puppeteer official docs: https://pptr.dev/guides/chrome-extensions (MV3 SW target acquisition pattern)
+- MDN: https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory (SW memory measurement requires COOP+COEP — not viable for MV3 extensions)
+- rrweb master/test/utils.ts (reference for assertDomSnapshot pattern — explicitly rejected for charter mismatch)
+- W3C Screen Capture spec §6.1 (already cited in Plan 01-14; relevant for §10 #9 if RAM scaffolding research expands)
+
+### Tertiary (LOW confidence — flagged for plan-time validation)
+- chrome://memory-internals stability across Chrome stable channel (cited at A7 in Assumptions Log; common operator path but not formally guaranteed)
+- WebSearch findings on rrweb 2.0 stable release status — cross-verified with npm registry (HIGH); separate WebSearch hit on "rrweb 2.0 production ready" returned an unrelated commercial-fork article, not the canonical rrweb-io repo
+
+## Metadata
+
+**Confidence breakdown:**
+- Standard stack: HIGH — all dependencies present in package.json; versions verified via `npm view`
+- Architecture: HIGH — Approach B template from Plan 02-04 is direct precedent; 3 chained-assertion patterns proven
+- Pitfalls: HIGH for Pitfalls 1-3 (verified against existing harness + rrweb registry); MEDIUM for Pitfalls 4-6 (research-derived; not yet exercised in this codebase)
+- RAM ceiling (§10 #9): MEDIUM — Page.metrics scope verified; SW heap measurement caveat verified; chrome://memory-internals operator instructions are standard but not version-stamped
+- rrweb v2 upgrade safety: HIGH — alpha.4 pin status verified directly via npm dist-tags
+
+**Research date:** 2026-05-20
+**Valid until:** 2026-06-20 (30 days; stable dependencies; if rrweb 2.0 stable ships in the interim, re-check D-P3-03 deferral)
+
+## RESEARCH COMPLETE