Files

20 KiB

Phase 4: Harden + clean up (optional) - Context

Gathered: 2026-05-20 Status: Ready for planning

## Phase Boundary

Final v1 milestone phase: eliminate accumulated P1/P2 follow-ups, audit residuals, flake instability, and operator-perceptible polish so the v1 release is not just spec-conformant but maintainable + operator-friendly. Per ROADMAP, this phase has NO new v1 requirements — all functional REQs are covered by Phases 1-3.

Charter: User explicitly chose "Full Phase 4" (most rigorous option). All 4 ROADMAP success criteria + meaningful subset of 12 deferred items from 03-VERIFICATION.md are IN scope.

In scope:

ROADMAP success criteria (4 originally defined):

  1. SW state persistence across 30s idle unload/reload (5+ min idle export test produces non-empty video buffer)
  2. fetch + XHR network_error capture in events.json (response code >= 400 verification)
  3. generate-icons.js ESM/CJS compatibility (npm run build + node generate-icons.js both succeed under "type": "module")
  4. Dead-code grep returns no live references for permissions.request + duplicate offscreen inline string

Audit P1 polish (all three — D-P4-02): 5. P1 #11: fetch interception URL extraction fix — args[0]?.toString() becomes [object Request] when args[0] is a Request object; replace with args[0] instanceof Request ? args[0].url : String(args[0]) at src/content/index.ts:147 6. P1 #14: navigation URL tracking — replace history.state?.url (always "unknown" in apps that don't populate it) with module-level previousUrl tracking; src/content/index.ts:99-109 7. 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; src/content/index.ts:36-42

Flake stabilization: 8. A29 zip-mtime race fix via cs-injection-world re-target (Plan 03-02 introduced the pattern; ~1/3 runs flake) 9. Pre-existing parallel-vitest Tier-1-build-step race (~1/5 full-suite runs) 10. 2 pre-existing ffprobe/ffmpeg vitest flakes (pre-date Phase 3)

Visual / operator-perceptible polish (D-P4-03): 11. getDisplayMedia cursor visibility constraint video: { cursor: 'always' } — operator-perceptible UX win (Plan 01-07 obs 2026-05-15); enables pointer-driven bug reproduction 12. Dark-surface logo contrast — Plan 01-10 obs 2026-05-20

CSP / build hygiene: 13. setimmediate polyfill new Function in SW chunk via vite-plugin-node-polyfills — pre-existing CSP-question; replace with manual polyfill or strip dependency

Harness extension polish: 14. A31 extended: grep rrweb/session.json for sentinel absence (one-line ext.) — folds into existing driveA31

Docs hygiene (D-P4-05): 15. ROADMAP backfill for Plans 01-08..01-13 (5 plans inline-tracked but not row-added per Plan 01-13 plan-checker flag #4)

Closure: 16. 04-VERIFICATION.md aggregator + alpha re-distribution + milestone v1 close prep

Out of scope (deferred to v2 / v1.1 follow-up milestone):

  • rrweb 2.0.0-alpha.4 → stable v2 upgrade research + implementation (D-P3-03 + D-P4-01 charter): alpha-pin stable across 13 plans + 33/33 UAT GREEN; risk vs reward favors v1.1+ deferral
  • Programmatic SW-realm RAM measurement via chrome.devtools Memory API (D-P3-04 + D-P4-01): research-heavy; A32 best-effort scaffolding + chrome://memory-internals operator path + alpha distribution coverage already accepted for §10 #9
  • REQ-password-confidentiality v2 candidate (full rrweb v2 maskInputFn + data-sensitive HTML attribute guards): out of scope per charter shift "we don't care about privacy hardening" 2026-05-20; only revisit if charter reverses
## Implementation Decisions

Phase 4 scope (D-P4-01 — full Phase 4)

  • D-P4-01: Full Phase 4 scope — all 4 ROADMAP success criteria + meaningful subset of 12 deferred items from 03-VERIFICATION.md. Exclusions per user choice: rrweb v2 upgrade + programmatic SW-RAM measurement. Estimated plan count: 6-8 plans across 2-3 waves.
    • Rationale: User picked "Full Phase 4 (Recommended for v1 quality)" 2026-05-20. Honors no-unilateral-scope-reduction memory + canonical ceremony preference. Phase 4 is the last chance to harden before v1 release; the audit P1/P2 items are real correctness issues (P1 #11 fetch URL is wrong; P1 #14 nav URL always "unknown"; P1 #15 rrweb timestamps wrong unit). Visual polish (cursor + dark-logo) is operator-perceptible quality.

Audit P1 polish (D-P4-02 — all three)

  • D-P4-02: Address all three audit P1 correctness items (#11 + #14 + #15) in a single dedicated plan or two cohesive plans.
    • Rationale: All three are correctness fixes in src/content/index.ts; surgical scopes per item; high ratio of fix-value to fix-cost. User chose "All three (Recommended)" 2026-05-20.

Visual / operator-perceptible polish (D-P4-03 — both items)

  • D-P4-03: Include both cursor visibility + dark-surface logo contrast.
    • Rationale: Cursor visibility is functional (pointer-driven bug reproduction is the highest-signal cue when operator reproduces a click-based bug; current captures lack the cursor entirely per Plan 01-07 obs 2026-05-15). Dark-logo is brand polish (Plan 01-10 obs 2026-05-20). Both are small surgical fixes that improve operator-facing quality before alpha re-distribution. User chose "Both (Recommended)" 2026-05-20.

Alpha tester feedback integration (D-P4-04 — user-handled out-of-band)

  • D-P4-04: Phase 4 execution proceeds independently of alpha tester feedback. User explicitly: "no no, if something i'll tell you" 2026-05-20 — alpha tester findings, if any, are user-routed via separate channels. Phase 4 does NOT wait for alpha confirmation. After Phase 4 closes, fresh build is re-packaged for testers as the v1-final candidate.
    • Rationale: Faster to v1 close. Honors user's operating mode (they curate operator-side signal themselves). Alpha distribution becomes a post-v1 quality validator + maintenance-window input, not a v1 gate.

Docs hygiene (D-P4-05 — ROADMAP backfill in)

  • D-P4-05: Include ROADMAP backfill for Plans 01-08..01-13 (5 plans inline-tracked but not row-added per Plan 01-13 plan-checker flag #4). Small surgical docs polish; ~15 min.
    • Rationale: ROADMAP rows are the canonical reference document; keeping it accurate is hygiene. User chose "Include" 2026-05-20.

Claude's Discretion

  • Plan organization: Planner picks 6-8 plan split. Suggested grouping:
    • 04-01: Bug / flake stabilization wave (A29 race + parallel-vitest race + 2 ffprobe flakes — 4 atomic tasks)
    • 04-02: Audit P1 polish (#11 fetch + #14 nav URL + #15 rrweb timestamps — cohesive content-script polish)
    • 04-03: SW state persistence (5min idle test — ROADMAP SC #1; harness extension)
    • 04-04: fetch + XHR network_error harness extension (ROADMAP SC #2; extends driveA30 or new driveA33)
    • 04-05: generate-icons ESM/CJS + dead-code grep + setimmediate polyfill (ROADMAP SC #3+#4 + CSP hygiene — build-side hardening)
    • 04-06: Visual polish — cursor visibility constraint + dark-logo contrast (operator-perceptible)
    • 04-07: A31 extension (one-line rrweb session.json sentinel grep) — could fold into 04-02
    • 04-08: VERIFICATION.md aggregator + ROADMAP backfill + alpha re-distribution + milestone v1 close prep Planner may consolidate (e.g., fold 04-07 into 04-02; merge 04-05 + 04-06 if cohesive) for 6-7 plans target.
  • Wave structure: Likely 3-4 waves; sequential where files_modified overlap (Phase 2 + Phase 3 lessons cited).
  • Harness assertion numbering: A33+ for new Phase 4 harness assertions (continues A29-A32 sequence from Phase 3).
  • Pre-checkpoint bundle gates: Same 6/6 inventory per saved memory feedback-pre-checkpoint-bundle-gates.md (Tier-1 grep + SW CSP-safety + Node-globals + DOM-globals + manifest + en↔ru parity).
  • Tier-1 FORBIDDEN_HOOK_STRINGS: stays at 12 unless A33+ needs new MOKOSH_UAT-gated symbols (audit at plan time; flag if increment needed).
  • CSP-safety mitigation for setimmediate polyfill: options include (a) strip vite-plugin-node-polyfills and provide manual setimmediate=queueMicrotask polyfill, (b) configure plugin to use polyfills.builtins.setimmediate manually, (c) document acceptance with explicit CSP-allow rationale. Planner / researcher picks based on impact.
  • CSV / data file modifications: none expected; Phase 4 is mostly src/* tweaks + tests/* additions + docs.

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Phase scope + acceptance source

  • .planning/ROADMAP.md §"Phase 4: Harden + clean up (optional)" — 4 ROADMAP success criteria verbatim + originally-framed P1/P2 list
  • .planning/REQUIREMENTS.md (no new REQs in Phase 4; Phase 4 verifies tech-debt cleanup against already-shipped REQs)
  • .planning/PROJECT.md — Validated section (all v1 REQs from Phase 1+2+3) + DEC-* table + Active section showing Phase 4 backlog
  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-VERIFICATION.md "Forward-Looking Deferred Items" table — 12 items inventory; Phase 4 cherry-picks ~10

Audit residuals + bug-fix targets (read for P1 polish per D-P4-02)

  • .planning/intel/audit-residuals.md or original audit document — P1 #11, P1 #14, P1 #15 source descriptions (if absent, retrieve from prior session intel)
  • src/content/index.ts:147 — fetch interception (P1 #11 target)
  • src/content/index.ts:99-109 — navigation URL tracking (P1 #14 target; module-level previousUrl needed)
  • src/content/index.ts:36-42 — rrweb buffer cleanup timestamps (P1 #15 target; epoch vs page-load-relative)

Flake stabilization targets

  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-02-SUMMARY.md "Issues Encountered" — A29 zip-mtime race documented; cs-injection-world is natural fix candidate
  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-03-SUMMARY.md — A29 race confirmed pre-existing; not Plan 03-03 introduced
  • tests/uat/lib/harness-page-driver.ts — findLatestZip at ~line 1395; A29 race-condition origin
  • tests/uat/extension-page-harness.ts — assertA29 + assertA30 + assertA31 + (assertA32 absent — A32 is host-side only)
  • tests/uat/harness.test.ts — orchestrator; driveA29Wrapped + driveA30Wrapped + driveA31Wrapped + driveA32 entries

ROADMAP SC targets

  • ROADMAP SC #1 — SW state persistence: src/background/index.ts (initialize + keepalivePort + chrome.runtime.onStartup); needs new harness for 5-min idle test
  • ROADMAP SC #2 — fetch + XHR network_error: src/content/index.ts (setupFetchInterception + setupXHRInterception if exists); existing A30 covers click+input+navigation+js_error+network_error from synthetic triggers — Phase 4 SC #2 verifies the real-page failing-fetch path empirically
  • ROADMAP SC #3 — generate-icons ESM/CJS: generate-icons.js at repo root; package.json "type": "module" setting
  • ROADMAP SC #4 — dead-code grep: ripgrep for permissions.request + duplicate offscreen inline string in src/

Visual polish targets

  • src/offscreen/recorder.ts getDisplayMedia call site — add video: { cursor: 'always' } per Chrome CursorCaptureConstraint enum (per Plan 01-07 obs 2026-05-15)
  • src/shared/brand/mokosh-mark.svg + src/welcome/welcome.css (or wherever logo renders on dark surfaces) — Plan 01-10 obs 2026-05-20

CSP / build hygiene

  • vite.config.ts — vite-plugin-node-polyfills config (setimmediate polyfill source)
  • dist/assets/index.ts-*.js (SW chunk) — new Function source confirmation
  • .planning/phases/01-stabilize-video-pipeline/deferred-items.md — pre-existing acceptance log

Prior-phase pattern + closure precedents

  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-PATTERNS.md — Approach B harness extension pattern (still canonical for new harness work in Phase 4)
  • .planning/phases/02-stabilize-export-pipeline/02-VERIFICATION.md — T5 override template structure
  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-VERIFICATION.md — 4-override template structure
  • .planning/phases/01-stabilize-video-pipeline/01-13-SUMMARY.md — Approach B harness ESTABLISHED
  • .planning/phases/02-stabilize-export-pipeline/02-04-SUMMARY.md — A24-A28 extension precedent
  • .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-02-SUMMARY.md — cs-injection-world pattern (chrome.tabs.create + chrome.scripting.executeScript world:'ISOLATED'); content-script realm access pattern

Decision / operating-principle references

  • /home/parf/.claude/projects/-home-parf-projects-work-repremium/memory/feedback-trust-harness-over-manual-uat.md — harness coverage canonical; operator empirical reserved for genuinely non-automatable cases (A32 RAM is the canonical example)
  • /home/parf/.claude/projects/-home-parf-projects-work-repremium/memory/feedback-pre-checkpoint-bundle-gates.md — 6/6 standard inventory before checkpoint
  • /home/parf/.claude/projects/-home-parf-projects-work-repremium/memory/feedback-gsd-ceremony-for-fixes.md — debug discoveries route through /gsd-debug; no hot-edits
  • /home/parf/.claude/projects/-home-parf-projects-work-repremium/memory/feedback-no-unilateral-scope-reduction.md — user validates every scope decision

Charter / v1 closure

  • 2026-05-20 charter shift: "we don't care about privacy hardening" → REQ-password-confidentiality Out of Scope v1
  • v1 close target: after Phase 4, fresh alpha re-distribution → tester confirmation → v1.0 tag + release notes (separate workstream; not Phase 4 plan)

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • Approach B harness pattern: any new Phase 4 harness assertions (A33+) follow the established assertA*/driveA*/orchestrator-wiring pattern. cs-injection-world adaptation (Plan 03-02) is canonical for content-script realm access.
  • findLatestZip helper (tests/uat/lib/harness-page-driver.ts:~1395): mtime-sort archive selection; A29 race fix target.
  • JSZip + jszip helpers (tests/uat/lib/zip.ts): archive parsing for harness assertions.
  • __MOKOSH_UAT__ Vite-define-token: gates test-only surfaces from production bundle (only needed if new FORBIDDEN_HOOK_STRINGS entries introduced).
  • Pre-checkpoint bundle gates pattern (Plan 03-05 Task 1): 6/7 gate run before VERIFICATION.md write; Plan 04-08 (or equivalent closure plan) follows this.

Established Patterns

  • Sequential wave decomposition for file-overlap (Phase 2 lesson + Phase 3 lesson): plan-checker should catch files_modified overlap within a wave; if detected, decompose into sequential waves.
  • VERIFICATION.md override pattern: documented in Phase 2 (T5) + Phase 3 (4 overrides incl. §10 #9). For Phase 4, success-criteria verification may use overrides for items already-verified-in-Phase-3 (e.g., dead-code grep is mostly checking work already done).
  • CON-event-log-schema (REQUIREMENTS.md): 5 event types; Phase 4 P1 #11/#14/#15 fixes affect navigation + fetch fields without changing schema shape.
  • STATE.md CLI bug: state.record-session flips status to "completed" when total/completed plan counts match — recurring bug fixed via manual STATE.md edit each phase (Phase 2 + Phase 3 + Phase 3-discuss + Phase 3-UI). Phase 4 will hit this 1-2 more times.

Integration Points

  • src/content/index.ts: locus of P1 #11/#14/#15 fixes; existing event-log emit + fetch interception + navigation tracking
  • src/background/index.ts: locus of SW state persistence work (initialize + chrome.runtime.onStartup + keepalivePort)
  • src/offscreen/recorder.ts: locus of getDisplayMedia cursor:'always' constraint
  • vite.config.ts + dist/ build output: locus of setimmediate polyfill replacement
  • generate-icons.js + package.json "type": "module": locus of ESM/CJS compat fix

</code_context>

## Specific Ideas
  • A29 cs-injection-world fix: the proven Plan 03-02 pattern — chrome.tabs.create({url: 'https://example.com'}) + chrome.scripting.executeScript({world: 'ISOLATED', target: {tabId}, func: probeDOMMutation}) — re-target the rrweb probe surface so the tab being captured is the harness probe page (eliminates iana.org leftover read race).
  • P1 #11 fetch fix specific code change: args[0]?.toString()args[0] instanceof Request ? args[0].url : String(args[0]). Add unit test for both string-arg and Request-arg cases.
  • P1 #14 nav URL fix: add module-level let previousUrl = location.href; in src/content/index.ts; update before each navigation event capture; use previousUrl in the emit instead of history.state?.url.
  • P1 #15 rrweb timestamps: use Date.now() at emit time as the canonical epoch source; rrweb's internal page-load-relative timestamps stay rrweb-internal but the wrapper writes Unix epoch for events.json.
  • 5min idle test pattern (ROADMAP SC #1): Puppeteer await new Promise(r => setTimeout(r, 5 * 60 * 1000)) after recorder start; then SAVE; assert video/last_30sec.webm exists in archive + size > 0 bytes. Long-running test; consider parallel skip + dedicated CI lane.
  • fetch+XHR network_error verification (ROADMAP SC #2): harness fires fetch('https://example.com/does-not-exist-404') + xhr.open('GET', '/404-also'); xhr.send(); from probe HTML; SAVE; assert events.json contains 2 network_error entries with response code >= 400 (extends driveA30 or adds A33).
  • generate-icons ESM/CJS fix (SC #3): package.json "type": "module" means .js files are ESM; generate-icons.js uses require('fs') (CJS); rename to generate-icons.cjs OR rewrite to ESM (import fs from 'node:fs'). Either works.
  • Dead-code grep (SC #4): rg 'permissions\.request' src/ should return 0 hits (was removed in Phase 1 Plan 01-05); rg '<inline-offscreen-string>' src/ vite.config.ts should return 0 hits (offscreen duality removed in Phase 1 Plan 01-06).
  • Cursor visibility implementation: getDisplayMedia({video: {cursor: 'always'}, audio: ...}) at the getDisplayMedia call site in src/offscreen/recorder.ts (or wherever the constraint is built per D-13 restart-segments architecture).
  • Dark-logo contrast: options — (a) add prefers-color-scheme: dark media query in welcome.css with alt-color SVG, (b) swap to a contrast-tested neutral palette, (c) wrap logo in white-circle background. Designer-leaning; planner-side choice.
  • setimmediate polyfill replacement: globalThis.setImmediate = globalThis.setImmediate || ((fn, ...args) => queueMicrotask(() => fn(...args))); inline in SW entry — bypasses vite-plugin-node-polyfills entirely.
## Deferred Ideas

To v1.1 / v2 maintenance milestone (post-v1 close)

  • rrweb 2.0.0-alpha.4 → stable v2 upgrade (D-P3-03 deferral; alpha-pin proven stable through 13 plans + 33/33 UAT GREEN; reaffirmed Phase 4 D-P4-01)
  • Programmatic SW-realm RAM measurement via chrome.devtools Memory API (D-P3-04 deferral; reaffirmed Phase 4 D-P4-01; A32 best-effort + chrome://memory-internals + alpha distribution coverage accepted as v1 closure)
  • REQ-password-confidentiality v2 candidate: full rrweb v2 maskInputFn + data-sensitive HTML attribute guards (D-P3-02 deferral; only revisit if charter reverses on "we don't care about privacy hardening")
  • Per-plan ROADMAP rows for any Phase 2/3 plans inline-tracked but not row-added (if any beyond Plans 01-08..01-13 catch-up)
  • Alpha-tester findings integration: any cycle-1-style debugs from current alpha (mokosh-build-2026-05-20-6dbed91.zip) or Phase 4 re-distributed build route through separate maintenance window — user explicitly handles operator-side signal out-of-band per D-P4-04

To v2 / SRV milestone (per SPEC §9 Out of Scope)

  • Server upload of captured archives (SRV-01)
  • AI-driven diagnostics (SRV-02)
  • Automatic ticket creation (SRV-03)
  • Analytics dashboard (SRV-04)
  • Audio recording (CAP-01)
  • DOM-event masking + privacy hardening reactivation (if v2 charter reverses)

Phase: 04-harden-clean-up-optional Context gathered: 2026-05-20