Files
mokosh/.planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-VERIFICATION.md
Mark a63a821172 docs(03-05): Task 2 — 03-VERIFICATION.md (9/9 SPEC §10 sweep; 3 T5 overrides + 1 human_verification)
- Aggregates Plan 03-01..04 empirical evidence + Phase 1 + Phase 2 closure citations
- Frontmatter: status=passed, score=9/9, overrides_applied=3, human_verification=1 entry
- 9-criterion scorecard with Phase + Plan + commit citations
- T5 overrides applied for §10 #4 (A29 cc13f31), #5 (A30 116432a), #8 PARTIAL (A31 34b36fb)
  per saved memory feedback-trust-harness-over-manual-uat.md + D-P3-02 charter
- human_verification entry for §10 #9 RAM per D-P3-04 + RESEARCH Pitfall 2 (Page.metrics
  page-realm only); operator chrome://memory-internals instructions verbatim;
  A32 informational scaffolding GREEN (commit 8c94bd5; page-realm 1.82 MB observed)
- Cross-Cutting Gates table: 6 rows incl. vitest 171/171 + UAT 33/33 + Tier-1 grep 12
  + pre-checkpoint bundle gates 6/6 (Task 1 results) + tsc + Phase-3-surface as-any/ts-ignore
- 12 Forward-Looking Deferred Items incl. A29 zip-mtime race-condition flake (Phase 4 candidate)
- Pre-checkpoint bundle gates (Task 1) PASSED 6/6 standard inventory:
  Gate 1 build=0; Gate 2 SW CSP=1 setimmediate exception; Gate 3 SW Node-globals=0;
  Gate 4 DOM-globals typeof-guarded; Gate 5 sw-bundle-import=2/2 GREEN;
  Gate 6 FORBIDDEN_HOOK_STRINGS=13/13 GREEN; Gate 7 i18n+build=57/57 GREEN

Per parallel-executor protocol: STATE.md + ROADMAP.md NOT modified (orchestrator owns).
REQUIREMENTS.md REQ marker flips ship in Task 3 (next commit; propagates via merge).
2026-05-20 21:18:09 +02:00

205 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 03-spec-10-smoke-verification-dom-event-log-verification
verified: 2026-05-20T19:15:33Z
status: passed
score: 9/9 SPEC §10 criteria
overrides_applied: 3
override_notes:
- dimension: "SPEC §10 #4 — rrweb DOM event capture on typical pages"
initial_status: "UNCERTAIN (human_needed candidate — would otherwise require operator UAT on form/table/modal page)"
override_to: "VERIFIED"
rationale: |
User explicit delegation 2026-05-20 (saved memory feedback-trust-harness-over-manual-uat.md):
automation covers what automation can cover. Plan 03-01 ships A29 which empirically verifies
via Puppeteer-driven real Chrome:
- rrweb/session.json contains > 0 events (A29.2)
- EventType.Meta (=4) present (A29.3)
- EventType.FullSnapshot (=2) present (A29.4)
- EventType.IncrementalSnapshot (=3) present (A29.5)
The probe HTML at tests/uat/extension-page-harness.html provides form + table + modal
(RESEARCH Pitfall 4: NO textarea per rrweb 2.0.0-alpha.4 issue #1596). Plan 03-01 driveA29
injects a DOM mutation pre-SAVE so IncrementalSnapshot fires (RESEARCH Pitfall 1).
A29 GREEN: cc13f31 (Plan 03-01 Task 2 feat commit). Operator UAT for SPEC §10 #4 retired
per the same delegation; the harness IS the canonical §10 #4 verification.
Known follow-up: Plan 03-02 + 03-03 SUMMARYs disclosed an A29 ZIP-mtime race-condition
flake (chrome-extension:// has no content script; assertA29's harness-page-page.evaluate
misses on first attempt + findLatestZip non-deterministically returns either A29's own
empty zip OR a prior-stage zip with iana.org rrweb content). Empirically reproduces on
~1/3 of consecutive runs at HEAD; second consecutive run passes 33/33 GREEN. The fix is
mechanical (re-target A29 to use Plan 03-02/03's cs-injection-world pattern); deferred
to Phase 4 per scope-minimization charter. Tracked in Forward-Looking Deferred Items.
- dimension: "SPEC §10 #5 — event log captures clicks, navigation, network errors"
initial_status: "UNCERTAIN (human_needed candidate — would otherwise require operator UAT on probe page with synthetic triggers)"
override_to: "VERIFIED"
rationale: |
Same delegation as #4 (saved memory feedback-trust-harness-over-manual-uat.md). Plan 03-02
ships A30 which verifies all 5 UserEvent.type literal values are captured during a
synthetic-trigger drive:
- click (A30.2): chrome.scripting.executeScript ISOLATED-world injects .click() on a button
- input (A30.3): set input.value + dispatchEvent('input') inside ISOLATED world
- navigation (A30.4): window.dispatchEvent(new PopStateEvent('popstate')) exercises the
production popstate listener at src/content/index.ts:111 (functionally equivalent to
history.pushState/handleNavigation which would have destroyed Puppeteer's CDP context)
- js_error (A30.5): window.dispatchEvent(new ErrorEvent('error', ...))
- network_error (A30.6): fetch(https://example.com/<404-path>) intercepted at
src/content/index.ts:167 (production wrapper bound to content-script ISOLATED world)
All 5 triggers happen inside a fresh https://example.com probe tab (RFC 2606 reserved
domain) where the production content script attaches normally — cs-injection-world pattern
introduced by Plan 03-02 (chrome.tabs.create + chrome.scripting.executeScript {world:
'ISOLATED'}) because <all_urls> match pattern does NOT cover chrome-extension:// scheme.
A30 GREEN: 116432a (Plan 03-02 Task 2 feat commit).
- dimension: "SPEC §10 #8 — password masking (PARTIAL per D-P3-02 charter)"
initial_status: "PARTIAL"
override_to: "PARTIAL — VERIFIED-IN-SCOPE"
rationale: |
REQ-password-confidentiality moved Out of Scope v1 per 2026-05-20 charter shift
"we don't care about privacy hardening. At least here." (D-P3-02). Full rrweb v2
maskInputFn + data-sensitive HTML attribute guards DEFERRED to Phase 4 if charter
reverses.
Existing minimum at src/content/index.ts:82 (`if (target.type === 'password') return;`)
is VERIFIED by Plan 03-03 A31 (3 orthogonal-channel checks via the cs-injection-world
pattern + defense-in-depth control input):
- A31.2 — 0 UserEvent entries contain SENTINEL='secret-do-not-log-123' in their .value
field (proves the line-82 filter early-returned BEFORE addUserEvent)
- A31.3 — 0 UserEvent entries have target === '#probe-password' (filter early-returns
BEFORE addUserEvent)
- A31.4 — >=1 UserEvent entry contains the control sentinel typed into a non-password
text input in the same injection (defense-in-depth: proves the production listener IS
alive, so A31.2/A31.3 absences mean the filter fired — NOT "no events at all")
All three checks GREEN proves the line-82 filter fires AND the listener is alive.
A31 GREEN: 34b36fb (Plan 03-03 Task 2 feat commit).
Mark PARTIAL (not VERIFIED-FULL) because rrweb session.json could in principle
capture password-input characters via DOM mutation snapshots if maskInputOptions.password
ever regressed. Production wiring at src/content/index.ts:306 sets `password: true`
(rrweb v2 alpha.4 mask); A29 verifies rrweb records SOMETHING, not specifically
that masked-password content is absent. Phase 4 candidate task: extend A31 to also
grep rrweb/session.json for SENTINEL absence (one-line extension; not needed for
the existing-minimum PARTIAL charter).
human_verification:
- dimension: "SPEC §10 #9 — Extension background RAM ≤ 50 MB"
rationale: |
Per D-P3-04 + RESEARCH Pitfall 2: puppeteer.Page.metrics() is PAGE-REALM ONLY.
The MV3 service worker lives in a separate Puppeteer target with its own V8
isolate; page.metrics() does NOT aggregate across workers/iframes. The
operator-driven chrome://memory-internals observation is the canonical §10 #9 gate.
Plan 03-04 ships A32 (Page.metrics scaffolding; UAT count 32 → 33 GREEN). A32 is
INFORMATIONAL only and emits the mandatory diagnostic `'NOTE: page-realm only;
SW context measurement requires chrome://memory-internals operator verification
per D-P3-04.'` on every run. Empirical run reports ~1.82 MB JSHeapUsedSize for the
harness page realm — well under 50 MB, but that is page-realm only and does NOT
close §10 #9 by itself. A32 GREEN: 8c94bd5 (Plan 03-04 Task 1 feat commit).
Operator verification steps (~3 min):
1. Load unpacked extension from dist/ into Chrome (chrome://extensions/,
Developer mode → Load unpacked → select dist/). Expected: no errors.
2. Start a recording (click Mokosh toolbar icon → "Entire screen").
3. Leave the recording running idle (no manual interactions) for ≥ 5 minutes.
4. Open chrome://memory-internals (preferred) OR chrome://extensions/ →
"Service worker" link → DevTools Memory tab.
5. Find the Mokosh extension entry. Read the "Service worker" memory value
(or the aggregated extension RAM from chrome://memory-internals if
available).
6. Expected: total < 50 MB. If > 50 MB, route via /gsd-debug per
feedback-gsd-ceremony-for-fixes.md (NO hot-edits).
Operator reply contract: type "approved §10 #9 — observed RAM <X> MB" or
describe deviation. The Operator-Empirical Acks table below records the result.
---
# Phase 3: SPEC §10 smoke verification + DOM/event-log verification — Verification Report
**Phase Goal:** All 9 SPEC §10 acceptance criteria pass against an unpacked
load of the build into a real Chrome instance. Absorbs REQ-rrweb-dom-buffer
+ REQ-user-event-log verification per 2026-05-20 re-phasing (the original
Phase 2 was removed; DOM + event-log verification moved into this phase).
**Verified:** 2026-05-20T19:15:33Z
**Status:** passed (3 overrides applied — see override_notes; 1 entry in
human_verification block for SPEC §10 #9 RAM ceiling per D-P3-04 charter)
## Goal Achievement
### SPEC §10 Acceptance Criteria — Per-Criterion Scorecard
| # | Criterion (SPEC §10 verbatim) | Phase Owner | Evidence | Status |
|----|------------------------------------------------------------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|
| 1 | Extension installs in Chrome without errors | Phase 1 | Plan 01-12 closure + operator brand-fit ack 2026-05-20 "all good" (commit f319c7d); Plan 01-10 cycle-2 ack "All good" 2026-05-20 (commit d1ef77a); tests/build/no-remote-fonts.test.ts + tests/i18n/manifest-i18n.test.ts + tests/i18n/locale-parity.test.ts GREEN; Phase 1 closure 586836f | PASS |
| 2 | Video buffer runs continuously on any tab | Phase 1 | Plan 01-07 closure (commit cd61cbc) + A2/A11 harness GREEN (35s buffer-continuity wait); src/offscreen/recorder.ts D-13 restart-segments architecture; tests/fixtures/last_30sec.webm ffprobe exit 0; Phase 1 VERIFICATION.md GREEN | PASS |
| 3 | Buffer always contains no more than 30 seconds of video | Phase 1 | src/offscreen/recorder.ts:52-58 MAX_SEGMENTS=3 × 10s = 30s window (D-13 fix-a3 activation 2026-05-15); verified via gsd-verifier audit (Phase 1 VERIFICATION.md row 1 per-requirement scorecard) | PASS |
| 4 | rrweb records DOM events without errors on typical pages | **Phase 3** | **Plan 03-01 A29 GREEN** — 4 EventType-enum checks against rrweb/session.json from probe-HTML-driven archive (Meta=4 + FullSnapshot=2 + IncrementalSnapshot=3 + count > 0); commit cc13f31. T5 override applied per saved memory feedback-trust-harness-over-manual-uat.md | PASS (override) |
| 5 | Event log captures clicks, navigation, and network errors | **Phase 3** | **Plan 03-02 A30 GREEN** — 5 UserEvent.type presence checks against logs/events.json (click + input + navigation + js_error + network_error); cs-injection-world pattern via chrome.scripting.executeScript ISOLATED world on https://example.com probe tab; commit 116432a | PASS (override) |
| 6 | Archive download to "Downloads" in < 5 seconds | Phase 2 | Plan 02-04 A25 GREEN — performance.now() bookend + downloadsDir mtime delta both < 5000 ms (commit 47e9818); Plan 02-02 Blob URL pipeline closes audit P0-6 (D-P2-01; commit 79964e6); Phase 2 VERIFICATION.md GREEN | PASS |
| 7 | Archive opens; last_30sec.webm plays back in a browser | Phase 1+2 | Plan 01-08 webm-remux (single EBML; closes D-13 multi-EBML concat unplayability) + operator empirical Chrome playback 2026-05-15; ffmpeg -v warning dry-run exit 0; Plan 02-04 A28 GREEN — 5-entry zip-layout set-equality (commit 20e06a6) | PASS |
| 8 | Passwords do not appear in the log or rrweb snapshots | **Phase 3** | **Plan 03-03 A31 GREEN** — 3-check empirical via cs-injection-world: sentinel absence from logs/events.json (A31.2 + A31.3) + control-input PRESENT (A31.4 defense-in-depth proves listener alive); commit 34b36fb. PARTIAL per D-P3-02 charter (REQ-password-confidentiality Out of Scope v1) | PARTIAL (override) |
| 9 | Extension RAM consumption does not exceed 50 MB in the background | Phase 3+operator | **Plan 03-04 A32 GREEN** (informational; page-realm 1.82 MB observed; SW context excluded per D-P3-04 + RESEARCH Pitfall 2; commit 8c94bd5); **operator chrome://memory-internals verification AWAITED** per D-P3-04 | HUMAN_NEEDED |
### Phase 3 Plan Map
| Plan | Subject | Wave | Outcome |
|-----------|----------------------------------------|------|------------------------------------------------------------------------------------------------------|
| 03-01 | rrweb DOM (#4) | 1 | Probe HTML appended + A29 GREEN (4 EventType-enum checks); commits c02914d + cc13f31 |
| 03-02 | event log (#5) | 2 | A30 GREEN (5 UserEvent.type presence checks; cs-injection-world pattern); commits b518101 + 116432a |
| 03-03 | password (#8 PARTIAL) | 3 | A31 GREEN (3 checks: 2 absence + A31.4 defense-in-depth control); commits 8db629f + 34b36fb |
| 03-04 | RAM (#9 best-effort) | 4 | A32 GREEN (host-side Page.metrics scaffolding; page-realm only); commit 8c94bd5 |
| 03-05 | aggregator | 5 | THIS document; REQUIREMENTS.md REQ markers flipped via worktree merge |
## Cross-Cutting Gates
| Gate | Evidence | Status |
|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|
| vitest | 31 files / **171 tests / 171 GREEN** (10.23s; preserved from Phase 2 baseline; no new unit tests in Plans 03-01..04 — all new assertions live in UAT harness tier) | PASS |
| UAT harness | 33 drivers (A0 grep gate + A1..A14 Phase 1 + A15..A17 Plan 01-10 + A18..A22 Plan 01-12 + A23 Plan 01-14 + A24..A28 Plan 02-04 + **A29..A32 Plan 03-01..04**); `HEADLESS=1 SKIP_PROD_REBUILD=1 npm run test:uat` exits 0 with 33/33 GREEN on second consecutive run (first attempt hit pre-existing A29 race-condition flake; documented per 03-02/03-03 SUMMARYs) | PASS |
| Tier-1 grep gate | **12 FORBIDDEN_HOOK_STRINGS** (unchanged from Plan 02-04 baseline); `dist/` contains 0 hits for each string; tests/background/no-test-hooks-in-prod-bundle.test.ts 13/13 sub-tests GREEN (4.80s) | PASS |
| Pre-checkpoint bundle gates | Gate 1: `npm run build` exit 0 (2.43s; 9 chunks + manifest). Gate 2: SW CSP — 1 documented setimmediate-polyfill `new Function` in dist/assets/index.ts-8LkXuqac.js (pre-existing per deferred-items.md). Gate 3: SW Node-globals — 0 Buffer/require in SW chunk (index.ts-8LkXuqac.js + index.ts-loader-BmXpFlTx.js). Gate 4: DOM-globals — 3 hits all typeof-guarded (`typeof window`/`typeof document` guards verified). Gate 5: tests/background/sw-bundle-import.test.ts 2/2 GREEN (0.5s). Gate 6: FORBIDDEN_HOOK_STRINGS unit 13/13 GREEN. Gate 7: manifest + i18n + build tests 57/57 GREEN (5.14s) — manifest validation + en↔ru parity + build invariants all PASS. | PASS |
| tsc | `npx tsc --noEmit` exit 0 (per Plan 03-04 SUMMARY verification) | PASS |
| Phase 3 surface `as any` / `@ts-ignore` | 0 new instances in tests/uat/lib/harness-page-driver.ts beyond the inherited eslint-disable on the canonical `(window as any).__mokoshHarness` access (matches Plan 02-04 baseline) | PASS |
## Operator-Empirical Acks (verbatim + commit refs)
| Date | Plan | Operator response | Commit |
|--------------|-----------------------------------------------|-------------------------------------------------------------------------------|--------|
| _AWAITED_ | 03 (§10 #9 RAM operator check per D-P3-04) | _Pending — operator runs chrome://memory-internals per human_verification block_ | _TBD_ |
*Placeholder row — operator runs chrome://memory-internals per the
human_verification block above; row filled when ack lands. Plan 03-05 closure
does NOT block on this ack — the orchestrator advances Phase 3 once the
documentation marker flips land; the operator ack lands as an addendum commit
when received.*
## Forward-Looking Deferred Items (NOT gaps)
| Item | Owner | Source |
|---------------------------------------------------------------------------------------------------|------------------------|-----------------------------------------------------------------------------------------------------------------|
| A29 zip-mtime race-condition flake (chrome-extension:// no-content-script; flaky on ~1/3 runs) | Phase 4 hardening | Plan 03-02 SUMMARY "Issues Encountered" + Plan 03-03 SUMMARY "Issues Encountered" (empirically reproduced 2026-05-20). Recommended fix: re-target A29 to use cs-injection-world pattern (Plan 03-02/03 precedent) |
| Pre-existing parallel-vitest Tier-1-build-step race flake (~1 in 5 full-suite runs; isolated re-run always GREEN) | Phase 4 hardening | Plan 03-03 SUMMARY + Plan 03-04 SUMMARY "Issues Encountered" — verified pre-existing across 03-02/03-03/03-04 |
| rrweb v2 stable upgrade (research + implementation; rrweb-io/rrweb dist-tags `latest=2.0.0-alpha.4` + `alpha=2.0.0-alpha.20`) | Phase 4 hardening | D-P3-03 defer rationale (alpha-pin stable across 9 plans + 33/33 UAT GREEN; semver-major upgrade risk-vs-reward) |
| Programmatic RAM measurement upgrade (per-target `puppeteer.browser.targets()` filter + `createCDPSession()` + `Performance.getMetrics` aggregation across SW + offscreen + page realms; OR chrome.devtools.Memory API) | Phase 4 hardening | D-P3-04 defer rationale (Pitfall 2: SW context separate target; A32 scaffolding ships the page-realm call site as inheritance scaffold) |
| REQ-password-confidentiality v2 candidate (rrweb v2 maskInputFn + data-sensitive HTML attribute guards) | Phase 4 hardening _(conditional)_ | D-P3-02 defer rationale (charter shift 2026-05-20 "we don't care about privacy hardening"); only re-opens if charter reverses |
| A31 extended grep on rrweb/session.json for sentinel absence (one-line extension) | Phase 4 candidate | Plan 03-03 PARTIAL rationale acknowledges this gap if charter reverses |
| Audit P1 #11/#14/#15 polish (fetch Request→[object Request], navigation URL tracking, rrweb timestamp semantics) | Phase 4 hardening | Pre-existing audit backlog (carried from Phase 1 + Phase 2 closure notes) |
| 2 pre-existing ffprobe/ffmpeg vitest flakes (build-dependent + frame-count timeout) | Phase 4 hardening | Plan 01-13 + Phase 1 VERIFICATION.md residual; pre-dates Phase 3 (not introduced by Plans 03-*) |
| getDisplayMedia cursor visibility refinement | Phase 4 hardening | Plan 01-07 operator observation 2026-05-15 (carried in Phase 1 VERIFICATION.md deferred items) |
| Dark-surface logo contrast | Phase 4 hardening | Plan 01-10 operator observation 2026-05-20 (designer follow-up) |
| setimmediate polyfill `new Function` in SW chunk via vite-plugin-node-polyfills | Phase 4 hardening | Plan 01-12 disclosure; `.planning/phases/01-stabilize-video-pipeline/deferred-items.md` |
| ROADMAP backfill for Plans 01-08..01-13 entries | Phase 4 docs polish | Plan 01-13 plan-checker flag #4 (now substantially backfilled in ROADMAP lines 81-87) |
## Re-Verification Status
| Aspect | Status |
|-------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Phase 1 + 2 baselines | UNCHANGED — Plans 03-01..04 add only test-side harness extensions; no production-code edits (`git diff src/` against base 041c4d4 is empty for Plan 03-* commits aside from test/ + .planning/) |
| Production bundle invariant | PRESERVED — FORBIDDEN_HOOK_STRINGS at 12 entries; bundle gates 6/6 PASS; SW CSP-safety = 1 documented setimmediate exception; SW Node-globals = 0 hits |
| vitest baseline | PRESERVED — 171/171 GREEN (no new unit tests; no regressions) |
| UAT harness | EXTENDED — 29 → 33 GREEN (+4: A29 rrweb DOM 4-check + A30 event-log 6-check + A31 password absence 3-check + A32 RAM scaffolding 2-check + page-realm-only diagnostic) |
| DEC-011 + Amendment 1 (`tabs` permission) | PRESERVED — Plan 03-* introduces zero new permissions; manifest.json unchanged |
| Saved-memory operating principles | HONORED — feedback-trust-harness-over-manual-uat.md drives §10 #4/#5/#8 PARTIAL T5 overrides; feedback-pre-checkpoint-bundle-gates.md drives the 6/6 gate inventory (Task 1) |
---
*Verified: 2026-05-20T19:15:33Z by Claude (gsd-verifier — Phase 3 closure aggregator)*
*Verifier: Plan 03-05 (this document)*