Closes Plan 01-11 honestly per GSD spike-pivot pattern. Original
Approach A (Puppeteer sw.evaluate per RESEARCH §1+6) empirically
falsified across Wave 3 execution + feasibility research. Approach B
(extension-internal-page harness + offscreen synthetic stream) proven
via c647f61 prototype; full implementation moves to Plan 01-13.
What this commit does:
- ADDS 01-11-SUMMARY.md (spike-then-pivot framing per GSD artifact-
types.md PLAN→SUMMARY lifecycle; captures retained infrastructure,
falsified hypotheses, working prototype, bridge to 01-13)
- REVERTS frontmatter amendment block in 01-11-PLAN.md; replaces with
closed_as/pivoted_in/closure_note pointing at SUMMARY + 01-13
- DELETES 01-11-PLAN-AMENDMENT-A.md (improvised artifact type — not
recognized in GSD artifact-types.md; content folded into SUMMARY)
Lesson for orchestrator (captured in SUMMARY §Architectural Notes):
when a plan attempts an approach that proves infeasible, the right
move is honest SUMMARY + new plan, NOT in-place rewrite + AMENDMENT
artifact. The project's own pattern (01-08, 01-09, 01-10, 01-11
added mid-phase as new work surfaced) confirms add-new-plan-when-
scope-shifts is the established pattern.
Plan 01-09 closure via harness PASS NOT achieved by 01-11; still
requires operator UAT pending Plan 01-13 landing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Architectural pivot triggered by feasibility research prototype
(commit c647f61, A6 PASS 5/5 + Bug-B regression rewind verified).
Two empirical findings invalidate original architecture:
1. MV3 service workers BLOCK dynamic import. await import('test-hooks/
sw-hooks') in src/background/index.ts silently kills the SW —
chunk loads, await never resolves, no listeners register. Cited
Chromium es_modules.md + w3c/webextensions#212.
2. Puppeteer WebWorker.evaluate against MV3 SW only exposes chrome.
{loadTimes,csi} — not the extension chrome.* API surface.
The Wave 1 (cb1a729) SW-side hooks are fundamentally broken in test
builds (production unaffected — gated by __MOKOSH_UAT__ which is
false in prod). Executor must DELETE the SW-side dynamic import +
sw-hooks.ts entirely; offscreen-side hooks stay (offscreen IS a DOM
document; dynamic import works there).
Replacement (Verdict-A architecture, proven by prototype):
- Extension-internal harness page at chrome-extension://<id>/tests/
uat/extension-page-harness.html — privileged extension context
with FULL chrome.* API access
- Puppeteer drives the page via page.goto + page.evaluate
- For SW state: page calls chrome.runtime.sendMessage; SW responds
via production messaging
- For getDisplayMedia: offscreen-side installFakeDisplayMedia() patches
navigator.mediaDevices.getDisplayMedia → Canvas captureStream
synthetic MediaStream
A6 (Bug B regression catch) PROVEN. Industry-standard pattern (MetaMask,
eyeo, Chrome MV3 official testing docs all converge).
Effort remaining: ~7-10h subagent budget (Wave 0 + bonus debug-import
commits keep; Wave 1 hooks rewire 30min; Wave 2 scaffolding 1-2h;
Wave 3 13 more assertions 4-6h; Wave 4 closure 1h).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Retires operator-as-assertion-library role from Plan 01-09 Task 5. Bug A
(notification icon API rejection) and Bug B (state-machine routing of
user-stopped-sharing) both escaped vitest unit coverage and cost ~4-6h of
operator UAT cycles in Phase 1. Plan 01-11 ships a Puppeteer-driven Node
harness with CDP attach to SW + offscreen contexts; the 14 assertions cover
the Plan 01-08/01-09 functional contract end-to-end.
Locked from research (RESEARCH §1-§11):
- Puppeteer 25.0.2 + tsx + node:assert/strict (no vitest browser mode)
- Two-bundle separation via vite.test.config.ts (mode 'test' + dist-test/)
- Hook gating: import.meta.env.MODE === 'test' + dynamic import (Vite
tree-shakes from production)
- Bug B trigger: track.dispatchEvent(new Event('ended')) — NOT track.stop()
(W3C spec + empirical probe7 — track.stop does NOT fire 'ended')
- Tier-1 grep gate (tests/background/no-test-hooks-in-prod-bundle.test.ts)
enforces zero __mokoshTest in production dist/
- Single browser, serial assertions, bail-on-first-failure (open question 4)
Wave structure (4 waves):
- Wave 0 (Task 1): puppeteer+tsx install, vite.test.config, build:test +
test:uat scripts, Tier-1 grep gate committed GREEN.
- Wave 1 (Task 2): gated SW + offscreen hooks at src/test-hooks/; production
bundle remains hook-free.
- Wave 2 (Task 3): harness scaffolding — tests/uat/lib/* + harness.test.ts
with assertion 0 wired GREEN + assertions 1-13 stubbed RED.
- Wave 3 (Tasks 4-7): wire 13 assertions in 4 logically-grouped bundles
(1-4 toolbar/displaySurface; 5-7 SAVE+BugB+ERROR; 8-10 BugA+icons+manifest;
11-13 buffer continuity + ffprobe + zip).
- Wave 4 (Tasks 8-9): amend Plan 01-09 Task 5 to redirect functional steps
to npm run test:uat; operator confirms brand/design.
Bug A + Bug B each have RED-on-regression canonical demos required in the
respective task's commit body — proves the harness CAN catch the regression,
not just passes under current conditions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>