wip: phase-01 paused mid-Plan-01-09; Bug B fix + icon placeholder commit pending

This commit is contained in:
2026-05-17 16:05:17 +02:00
parent 949aa03db5
commit ed82fd6051
2 changed files with 140 additions and 107 deletions

80
.planning/HANDOFF.json Normal file
View File

@@ -0,0 +1,80 @@
{
"version": "1.0",
"timestamp": "2026-05-17T14:04:15Z",
"phase": "01",
"phase_name": "stabilize-video-pipeline",
"phase_dir": ".planning/phases/01-stabilize-video-pipeline",
"wave": 2,
"plan": "01-09",
"status": "paused",
"completed_this_session": [
{"id": "01-08", "name": "WebM remux via ts-ebml + webm-muxer", "status": "done", "commit_range": "5035314..e40949d", "notes": "Includes resolve.alias ebml CJS-main + vite-plugin-node-polyfills Buffer fix from debug session 01-08-sw-incompatibility (resolved). Tier-1 SW-bundle-import gate added at tests/background/sw-bundle-import.test.ts (2-layer)."},
{"id": "01-09-task1to4", "name": "Plan 01-09 Tasks 1-4: displaySurface monitor + cursor:always + toolbar onClicked + badge state machine + onStartup notification + popup SAVE-only", "status": "done", "commit_range": "333e0dc..c711d7e", "notes": "Task 5 operator empirical revealed 2 bugs — see remaining_work."},
{"id": "design-intel", "name": "Design system + assets spec for designer team handoff", "status": "done", "commit": "949aa03", "files": [".planning/intel/design-system.md", ".planning/intel/assets-spec.md"]}
],
"remaining_tasks": [
{
"id": "01-09-bug-fix",
"name": "Fix Plan 01-09 Bug B: route user-stopped-sharing → setIdleMode (not setErrorMode)",
"status": "not_started",
"details": "Per debug session 01-09-recovery-flow (NOT YET WRITTEN to disk — exists only in session context). Operator UAT surfaced: after clicking Chrome's Stop Sharing, badge stuck on ERROR (yellow), popup is SAVE-only, no recovery notification (Bug A icon failure), operator locked out of restart. Fix: switch RECORDING_ERROR handler in src/background/index.ts:725-744 on message.error code — 'user-stopped-sharing' → setIdleMode; other codes → setErrorMode (preserved). The onUserStoppedSharing handler in src/offscreen/recorder.ts:451-480 already calls resetBuffer() so there's nothing to save → IDLE is correct. Needs RED test before GREEN fix.",
"resume_with": "/gsd-debug continue 01-09-recovery-flow (if continuation works) OR /gsd-debug 'Plan 01-09 setErrorMode locks operator out — route user-stopped-sharing to setIdleMode' (fresh)"
},
{
"id": "01-09-icon-placeholders-commit",
"name": "Commit auto-generated icon placeholders (Bug A unblock)",
"status": "uncommitted_in_working_tree",
"details": "Generated via imagemagick (dark-square + green-dot) at icons/icon{16,48,128}.png. Sizes 574/1153/2615 bytes — all above the Chrome notification API minimums. Working tree has them uncommitted. They unblock operator UAT; designer team's branded assets later swap in cleanly. Commit message should reference .planning/intel/assets-spec.md Path A.",
"resume_with": "git add icons/icon{16,48,128}.png && commit per Path A in assets-spec.md"
},
{
"id": "01-09-uat-re-run",
"name": "Re-run smoke after Bug B fix + placeholder commit to verify full flow",
"status": "not_started",
"details": "Pre-checkpoint gates should be run FIRST (per saved memory feedback-pre-checkpoint-bundle-gates.md). Then operator: Chrome smoke, click Stop Sharing, verify badge → OFF + toolbar.onClicked re-fires for restart + recovery notification visible with placeholder icon."
},
{
"id": "01-10",
"name": "Plan 01-10 onboarding welcome tab",
"status": "pending",
"details": "Wave 3. depends_on: [01-09]. Unblocked once 01-09 closes. Plan exists at .planning/phases/01-stabilize-video-pipeline/01-10-PLAN.md.",
"resume_with": "/gsd-execute-phase 1 (continues from where Wave 2 closes)"
},
{
"id": "verify",
"name": "/gsd-verify-work 1 goal-backward verification",
"status": "not_started",
"resume_with": "/gsd-verify-work 1"
},
{
"id": "phase-close",
"name": "Flip Phase 1 closure markers back to Complete after UAT genuinely passes",
"status": "not_started",
"details": "REQUIREMENTS.md REQ-video-ring-buffer [ ] → [x]; ROADMAP Phase 1 [ ] → [x]; STATE.md status phase_reopened → phase_complete; progress 90% → 100%. Currently STATE.md is partially mid-pause state per the file modification I see."
}
],
"uncommitted_files": [
{"path": ".planning/STATE.md", "reason": "Auto-modified by session continuity logic; needs cleanup as part of phase closure or pause commit"},
{"path": "icons/icon128.png", "reason": "Plan 01-09 Bug A placeholder unblock (auto-generated 2615 bytes); commit as part of 01-09 closure"},
{"path": "icons/icon16.png", "reason": "Plan 01-09 Bug A placeholder unblock (574 bytes)"},
{"path": "icons/icon48.png", "reason": "Plan 01-09 Bug A placeholder unblock (1153 bytes)"},
{"path": "tests/fixtures/last_30sec.webm", "reason": "Operator's recent smoke run staged this; LIKELY needs revert (the committed one in e40949d is the Plan 01-08 closeout fixture). Verify: git diff tests/fixtures/last_30sec.webm to see if it differs from HEAD; if yes, restore via git checkout."}
],
"blockers": [],
"human_actions_pending": [
"Designer team to produce branded icons per .planning/intel/assets-spec.md (Priority 0). Placeholder icons unblock Plan 01-09 closeout in the meantime."
],
"decisions_this_session": [
{"decision": "Plan 01-08 WebM remux landed via ts-ebml@3.0.2 + webm-muxer@5.1.4 with two-stage fix (resolve.alias + Buffer polyfill via vite-plugin-node-polyfills)", "rationale": "ts-ebml has known browser incompatibility (issue #37, 5 years open). Vite/Rollup CJS interop initially tree-shook ebml; resolve.alias to CJS main entry fixed module-init. Buffer polyfill via vite-plugin-node-polyfills fixed runtime EBMLDecoder.constructor that calls Buffer.alloc(0)."},
{"decision": "smoke.sh diagnostic timer overlay (T+/wall) added", "rationale": "Operator's 'video isn't latest' observation needed precise measurement. Timer in every recorded frame lets operator compute (save-click value last-frame value) = stale gap. Confirmed D-13 trade-off (~5-10s gap) empirically."},
{"decision": "Two test fixtures: last_30sec.webm (post-remux output) + raw-3ebml-concat.webm (pre-remux input)", "rationale": "Plan 01-08 originally used last_30sec.webm as both remux INPUT and OUTPUT validation target. Once remux works, the fixture is the OUTPUT only. Unit tests need the INPUT format. Split fixtures resolves the conflict."},
{"decision": "Auto-generated placeholder icons via imagemagick (Path A from assets-spec.md)", "rationale": "Unblock Plan 01-09 UAT now; designer team's branded icons swap in cleanly later. Avoids blocking the operator empirical loop on design work that's already delegated externally."},
{"decision": "Design system + assets spec committed to .planning/intel/ as designer-team handoff docs", "rationale": "User stated will delegate all design execution to designer team. Specs capture hard technical floor (sizes/formats/contexts) + initial aesthetic direction the designer can override."}
],
"session_anti_patterns_recurring": [
{"name": "Subagent context anxiety surfacing", "severity": "blocking", "details": "Two subagents this session (gsd-executor at 66% and gsd-debug-session-manager at 72%) surfaced 'should I split / pause / accept partial scope' as user-facing decisions. The memory feedback-no-unilateral-scope-reduction.md hard sub-rule on context anxiety covers this BUT the rule was written for the orchestrator; needs strengthening to also bind subagents OR the orchestrator's spawn-prompt template must explicitly forbid the pattern. Workaround used: spawned fresh executor with explicit anti-context-anxiety directive baked into the prompt. Worked for executor; debug session manager did it again. Worth updating the saved memory to explicitly cover subagent-side surfacing + adjusting future spawn prompts."},
{"name": "Pre-checkpoint bundle gates pattern validated", "severity": "advisory", "details": "Plan 01-08 closeout taught us the gates BEFORE operator checkpoint pattern (memory feedback-pre-checkpoint-bundle-gates.md). Plan 01-09 also used it successfully — Tier-1 SW-bundle-import gate stayed GREEN throughout Plan 01-09 execution; gates 1-4 ran cleanly before operator UAT. The pattern is working."}
],
"context_notes": "Plan 01-09 Bug A (icon files) and Bug B (setErrorMode locks operator out) discovered during operator empirical Task 5. Bug A unblocked via placeholders in working tree (uncommitted). Bug B requires the route-on-error-code fix in src/background/index.ts:725-744. Both belong to Plan 01-09's closeout — should land before Wave 3 (Plan 01-10) starts. The debug session 01-09-recovery-flow was opened but its session manager hit context anxiety at 72% and stopped before writing the debug file or RED tests. Resume by spawning a FRESH /gsd-debug session with the orchestrator-context notes (including the explicit Bug B fix plan: route on message.error, IDLE for user-stopped-sharing, ERROR for other codes; preserve defensive ordering). All 3 hypotheses (icon corruption, popup-lock, design mismatch) are already verified empirically.",
"next_action": "After /clear: run /gsd-resume-work to load handoff. Recommended first step: commit the icon placeholders (icons/icon{16,48,128}.png — currently uncommitted), then spawn /gsd-debug for 01-09-recovery-flow Bug B fix per the orchestrator-context details above. Then re-run smoke for operator empirical verification. Then Wave 3 (Plan 01-10)."
}

View File

@@ -1,131 +1,84 @@
---
context: phase
phase: 01-stabilize-video-pipeline
task: review-fix-partial
total_tasks: 3
status: in_progress
last_updated: 2026-05-16T07:29:17.065Z
wave: 2
plan: 01-09
status: in_progress (paused mid-fix)
last_updated: 2026-05-17T14:04:15Z
---
# BLOCKING CONSTRAINTS — Read Before Anything Else
> These are not suggestions. Each constraint below was discovered through failure in the prior session.
> Acknowledge each one explicitly before proceeding.
These persist from prior sessions and were reaffirmed this session:
- [ ] **CONSTRAINT: Context-anxiety-driven scope reduction**Do NOT surface harness hook "CONTEXT WARNING" messages to the user. Do NOT narrow scope based on extrapolated context budget. Do NOT conflate subagent context (200K) with orchestrator context (1M). The user validates every quality-driven change themselves; pre-filtering is the wrong default for this project. The auto-loaded memory `feedback-no-unilateral-scope-reduction.md` has the full rule including the context-anxiety sub-rule.
- [ ] **CONSTRAINT: No unilateral scope reduction**auto-memory `feedback-no-unilateral-scope-reduction.md`. Surface options via AskUserQuestion or default to FULL scope; never pre-narrow. Apply this to BOTH orchestrator AND when briefing subagents (subagents must not surface their own context anxiety as user-facing decisions).
- [ ] **CONSTRAINT: GSD ceremony for fixes** — auto-memory `feedback-gsd-ceremony-for-fixes.md`. Route bugs through /gsd-debug; orchestrator does not hot-edit src/.
- [ ] **CONSTRAINT: Pre-checkpoint bundle gates** — auto-memory `feedback-pre-checkpoint-bundle-gates.md`. Before surfacing any operator empirical checkpoint, run: SW CSP grep (new Function/eval), SW Node-globals grep (Buffer.from), Tier-1 SW-bundle-import gate (`tests/background/sw-bundle-import.test.ts`), manifest validation. Failure = route to /gsd-debug, NOT to operator.
- [ ] **CONSTRAINT: Hot-edits bypassing GSD ceremony** — Do NOT call Edit/Write on `src/` files in response to bugs discovered during execute/verify. Route through `/gsd-debug` for investigation → RED test landed → `gsd-executor` agent for the fix. The auto-loaded memory `feedback-gsd-ceremony-for-fixes.md` has the full rule.
Acknowledge each before proceeding.
**Do not proceed until both boxes are checked.**
## Recurring anti-pattern this session
## Critical Anti-Patterns
**Subagent context-anxiety surfacing** — gsd-executor at 66% and gsd-debug-session-manager at 72% both surfaced "should I split / pause" as user-facing decisions despite explicit anti-context-anxiety directives in their spawn prompts. The saved memory covers orchestrator-side surfacing; subagent-side surfacing needs stronger handling. **For next session:** when spawning subagents, include explicit failure-path instructions ("if you genuinely run out: commit clean stopping point + return; orchestrator handles failover via fresh executor — do NOT pause for user decision").
| Pattern | Description | Severity | Prevention Mechanism |
|---------|-------------|----------|---------------------|
| Context-anxiety scope reduction | I'm on Opus 4.7 with 1M context; 30% remaining = ~300K tokens. The harness fires "CONTEXT WARNING at 65/67/70%" hooks calibrated for typical models — they are advisory infrastructure, not user voice. Treating them as user-binding led me to (a) pick "CR-only" unilaterally from a 3-option checkpoint without asking and (b) repeatedly surface hook messages to the user as if they were decisions to make. | blocking | Memory `feedback-no-unilateral-scope-reduction.md` is auto-loaded. The explicit rule: any time about to type "context is tight" / "this might exhaust context" / "let me ask whether to pause" — STOP and just continue work. Compact silently if needed. Never surface a harness hook to the user as a user-facing choice. |
| Hot-edits bypass GSD ceremony | When the D-12 bug surfaced (75-byte WebM), I started calling Edit on `src/shared/types.ts` to fix it inline. User correctly stopped me — fixes route through `/gsd-debug` → RED test → `gsd-executor`, not orchestrator hot-edits. | blocking | Memory `feedback-gsd-ceremony-for-fixes.md` is auto-loaded. Trigger: any Edit/Write on `src/` inside an execute/verify context in response to a checkpoint failure — STOP, route through `/gsd-debug` or proper plan-fix. |
| Pre-staged HIGH-risk fallback activation pattern | Both D-12 (base64 wire) and D-13 (restart-segments) pre-staged fallbacks from CONTEXT.md activated as designed when ffprobe + playback gates surfaced. Strong evidence the pre-staging strategy works. | advisory | No prevention needed — this is good behavior. But worth a GSD-framework retro item: should `/gsd-plan-phase` auto-inject empirical-acceptance gates (ffmpeg dry-run, Chrome playback) BEFORE phase close when RESEARCH.md flags HIGH-risk assumptions? See `01-07-SUMMARY.md` process-observation tail. |
---
<current_state>
Phase 1 is **functionally complete**:
- REQ-video-ring-buffer marked Complete in REQUIREMENTS.md
- ROADMAP.md Phase 1 row marked Complete (2026-05-15)
- SPEC §10 #7 satisfied (operator-confirmed clean Chrome playback + ffmpeg dry-run exit 0)
- 30/30 unit tests pass; tsc clean; `npm run build` succeeds
- Branch: `gsd/phase-01-stabilize-video-pipeline` (clean working tree)
- Two debug sessions resolved (`.planning/debug/resolved/d12-blob-port-transfer-fails.md`, `.planning/debug/resolved/webm-playback-freeze.md`)
- Phase 1 code review (deep depth) done — `01-REVIEW.md` (3 Critical + 9 Warning + 6 Info = 18 findings)
- Review fix **PARTIAL**: 5/18 landed in commit `2e3f524` (CR-01 + CR-02 + CR-03 + WR-03 + WR-09). 13 remain + 8 sweep targets discovered during review.
## Current State
What's left: finish remaining review fixes, run verifier, start Phase 2.
</current_state>
Phase 01 is mid-Wave-2 (Plan 01-09 closeout):
<completed_work>
- **Plan 01-08 (WebM remux):** DONE. Resolved via 2-stage fix — resolve.alias for ebml CJS-main + vite-plugin-node-polyfills Buffer polyfill. Commits 5035314..e40949d. Tier-1 SW-bundle-import gate landed (`tests/background/sw-bundle-import.test.ts`, 2 layers).
- **Plan 01-09 Tasks 1-4:** DONE in code. Commits 333e0dc..c711d7e. 17 new tests GREEN. 81/81 vitest GREEN. tsc clean. Build exit 0.
- **Plan 01-09 Task 5 operator empirical:** SURFACED 2 BUGS:
- **Bug A (icon files corrupt placeholders):** unblocked via auto-generated placeholders in working tree (uncommitted). icons/icon{16,48,128}.png at 574/1153/2615 bytes — all above Chrome notification API minimums.
- **Bug B (`setErrorMode` locks operator out):** state machine routes user-stopped-sharing → setErrorMode → popup stays SAVE-only → toolbar.onClicked won't fire → operator has no restart UI path. Plus recovery notification failed due to Bug A. Operator perception: "recording never stops."
- **Design intel committed:** .planning/intel/design-system.md + assets-spec.md (commit 949aa03). Designer-team handoff specs.
- **D-13 trade-off confirmed:** operator reports "some seconds missing in tail." Documented architectural trade-off, NOT a Plan 01-09 regression. Defer to Phase 5 hardening (sub-second rotation OR in-flight inclusion with synthetic Matroska finalization).
**Plans (all 7):**
- Plan 01-01: Doc cascade D-A1..D-A6 + manifest swap — commit `13b67f5`
- Plan 01-02: Vitest + 4 RED test files — commit `edc605d`
- Plan 01-03: `src/offscreen/recorder.ts` TDD GREEN (getDisplayMedia + ring buffer + codec strict-mode) — commit `30e5efd`
- Plan 01-04: Port keepalive + OFFSCREEN_READY handshake (TDD) — commit `05d0050`
- Plan 01-05: SW shrink + port host (T-1-04 sender-id check on both ends) — commit `9e236cb`
- Plan 01-06: Build pipeline collapse (vite.config 226 → 21 LoC; deleted orphan `offscreen/` dir) — commit `1ebfb42`
- Plan 01-07: Manual smoke + ffprobe gate + playback acceptance (3 attempts; closure commit `1d06d9d`)
Test/build baseline at pause:
- 81/81 vitest GREEN
- Tier-1 SW-bundle-import gate (Layer 1 + Layer 2) GREEN
- tsc clean
- npm run build exit 0
- Working tree has 5 uncommitted: STATE.md (auto-modified), 3 icon placeholders, tests/fixtures/last_30sec.webm (probably needs revert — verify against HEAD)
**Debug sessions (both resolved):**
- `d12-blob-port-transfer-fails` (5 commits `c0d9166..bf07619`): base64 wire format for port messages; Blobs were collapsing to "[object Object]" through chrome.runtime port JSON serialization
- `webm-playback-freeze` (6 commits `5530292..872f25d`): D-13 restart-segments activation; retired D-09..D-11 single-continuous + age-trim + first-chunk-pin
## Plan 01-10
**Code review + partial fix:**
- `01-REVIEW.md` committed
- `01-REVIEW-FIX.md` partial (`checkpoint: true`); 5/18 fixes landed in commit `2e3f524`
</completed_work>
Pending. Wave 3. depends_on: [01-09]. PLAN.md exists at `.planning/phases/01-stabilize-video-pipeline/01-10-PLAN.md`. Unblocked once 01-09 closes.
<remaining_work>
**Priority 1 — Finish review fixes (`/gsd-code-review-fix 1`):**
13 review findings + 8 sweep targets remain. ALL documented in `.planning/phases/01-stabilize-video-pipeline/01-REVIEW-FIX.md` "Remaining Work" section with file:line + intended fix per item.
Remaining labeled findings:
- 7 Warning: WR-01, WR-02, WR-04, WR-05, WR-06-defer, WR-07, WR-08
- 6 Info: IN-01, IN-02, IN-03, IN-04, IN-05, IN-06
- 8 sweep targets: described in REVIEW-FIX.md remaining-work section (ranked by impact)
**Priority 2 — Phase 1 verifier (`/gsd-verify-work 1`):**
Goal-backward verification: confirm REQ-video-ring-buffer + SPEC §10 acceptance criteria are actually delivered by code (not just claimed by SUMMARYs). Per Quality settings, verifier is enabled.
**Priority 3 — Phase 2 (`/gsd-plan-phase 2`):**
Stabilize DOM + event capture privacy. Per ROADMAP §"Phase 2": REQ-rrweb-dom-buffer, REQ-user-event-log, REQ-password-confidentiality. P0 #5 from original audit (rrweb v2 maskInputFn + content-script input-logger password+data-sensitive guard).
</remaining_work>
<decisions_made>
- **Switched capture API to `getDisplayMedia()`** (amends DEC-003). Operator picks share target; Chrome shows "Sharing your screen" banner. Trade-off accepted per D-04. Manifest swap: `tabCapture``desktopCapture`.
- **Activated D-13 restart-segments** lifecycle. Retired D-09..D-11. Each segment is a self-contained ~10s WebM with its own keyframe; up to MAX_SEGMENTS=3 retained.
- **Base64 wire format** for port messages (`TransferredVideoSegment.data: string`). Survives chrome.runtime port JSON serialization (Blobs don't).
- **Cursor visibility refinement deferred to Phase 5** (logged in ROADMAP.md Phase 5 P1/P2 list).
- **Cleanup decision: deleted `chrome.alarms` keepalive entirely** (audit P1 #8 + amends DEC-010). Long-lived `chrome.runtime.connect` port from offscreen → SW is the real keepalive.
</decisions_made>
<blockers>
None. Working tree is clean. All next-step commands are unblocked.
</blockers>
## Required Reading (in order)
1. `.planning/phases/01-stabilize-video-pipeline/01-REVIEW-FIX.md` — "Remaining Work" section is the work list for `/gsd-code-review-fix 1`.
2. `.planning/phases/01-stabilize-video-pipeline/01-REVIEW.md` — original review (cross-reference for ambiguity).
3. `.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md` — wraps Phase 1's two-attempt journey; has the process observation about pre-staged fallback strategy.
4. `.planning/phases/01-stabilize-video-pipeline/01-CONTEXT.md` — locked decisions; especially D-01..D-A6 (now mostly retired by amendments).
5. `.planning/debug/resolved/d12-blob-port-transfer-fails.md` — Resolution section explains the JSON-serialization root cause.
6. `.planning/debug/resolved/webm-playback-freeze.md` — Resolution section explains the A3 keyframe-gap root cause + D-13 activation.
7. `.planning/STATE.md` — current state; Decisions log appended.
8. `.planning/ROADMAP.md` — Phase 1 = Complete; Phase 2 next; cursor-visibility deferral now in Phase 5 P1/P2 list.
## Infrastructure State
- **Git:** branch `gsd/phase-01-stabilize-video-pipeline` checked out in main repo. Working tree clean. ~37 commits since the initial `chore: import broken Phase-1 extension as received`.
- **Chrome smoke profile:** `/tmp/mokosh-smoke-profile/` — extension loaded; KEEP_PROFILE=1 ./smoke.sh reuses it.
- **Tests:** `npx vitest run` → 30/30 across 8 test files. `npx tsc --noEmit` clean. `npm run build` succeeds; `dist/` is current.
- **Fixture:** `tests/fixtures/last_30sec.webm` (1.6 MB VP9 1142×1038, regenerated 2026-05-15 against D-13 recorder).
## Pre-Execution Critique Required
N/A — no design artifact awaiting critique. The two pre-staged fallback skeletons (D-12 base64, D-13 restart-segments) were both activated and resolved; no orphan designs remain.
<context>
The session went from "initialize GSD on a half-broken zip" → fully GSD-tracked Phase 1 closure across discuss → plan → execute → 2 debug sessions → code review → partial code-review-fix. The user is engaged, makes substantive decisions, and pushed back hard on two things I should never repeat: (1) unilateral scope reduction when they signaled max rigor + "I validate everything", (2) hot-edits bypassing GSD ceremony. Both memories saved at `~/.claude/projects/-home-parf-projects-work-repremium/memory/`.
The MAIN unfinished thread is the 13 review findings + 8 sweep targets. They're all documented; a fresh-context `gsd-code-fixer` agent should finish them in one pass without checkpointing. After that, verifier + Phase 2.
</context>
<next_action>
Run `/gsd-resume-work` to load this handoff cleanly, then:
## Next-session order of operations
1. **`/gsd-resume-work`** to load HANDOFF.json.
2. **Verify uncommitted files state:** `git diff tests/fixtures/last_30sec.webm` — if it differs from HEAD (which it probably does because operator's smoke regenerated it), revert: `git checkout HEAD -- tests/fixtures/last_30sec.webm`. The Plan 01-08 fixture committed at e40949d is the canonical one.
3. **Commit icon placeholders** (Bug A unblock):
```bash
git add icons/icon{16,48,128}.png
git commit -m "fix(01-09): Bug A — auto-generated icon placeholders unblock notification API"
```
/gsd-code-review-fix 1 # finish 13 review findings + 8 sweep targets (full scope, no narrowing)
/gsd-verify-work 1 # goal-backward verifier confirms REQ-video-ring-buffer delivered
/gsd-plan-phase 2 # begin Phase 2: rrweb + event log + password masking
```
4. **Spawn fresh /gsd-debug session for Bug B** with explicit anti-context-anxiety directive in the prompt. Use this prompt skeleton:
- slug: `01-09-recovery-flow`
- Bug B specifics: route src/background/index.ts:725-744 RECORDING_ERROR handler on `message.error` code — `'user-stopped-sharing'` → `setIdleMode()`; other codes → `setErrorMode()` (preserved).
- All 3 hypotheses already empirically verified (per prior session manager's checkpoint return); fresh session can skip verification phase and go straight to RED test + GREEN fix.
- RED test belongs in `tests/background/badge-state-machine.test.ts` (extend with routed-error-code case).
5. **Pre-checkpoint gates** (per saved memory) BEFORE re-surfacing operator UAT.
6. **Operator UAT re-run** to confirm Bug A + Bug B fixed.
7. **Wave 3: `/gsd-execute-phase 1`** continues to Plan 01-10.
8. **`/gsd-verify-work 1`** goal-backward.
9. **Phase 1 closure markers flip:** REQUIREMENTS.md [ ] → [x], ROADMAP [ ] → [x], STATE.md phase_reopened → phase_complete.
Do NOT narrow scope on the review-fix pass. The user said "Do all the problems" and pushed back twice on context-anxiety-driven narrowing in the prior session. If a subagent checkpoints offering scope options, surface the choice to the user via AskUserQuestion — do not pick for them.
</next_action>
## Required reading (in order)
1. `.planning/HANDOFF.json` — structured state
2. `.planning/intel/design-system.md` + `.planning/intel/assets-spec.md` — design specs for designer team
3. `src/background/index.ts` lines 54 (NOTIFICATION_ICON_PATH), 85-108 (state machine), 725-744 (RECORDING_ERROR handler — fix target), 833-840 (startup notification)
4. `src/offscreen/recorder.ts` lines 451-480 (onUserStoppedSharing — confirms resetBuffer happens)
5. `.planning/phases/01-stabilize-video-pipeline/01-09-PLAN.md` — full Plan 01-09 spec
6. `tests/background/badge-state-machine.test.ts` — RED test target for Bug B
## Infrastructure state
- Branch: `gsd/phase-01-stabilize-video-pipeline`, currently at `949aa03` (head)
- vite.config.ts has Buffer polyfill + ebml alias (Plan 01-08 critical fixes; do not touch)
- smoke.sh has timer overlay (commit 923aaca) AND SHARE_TARGET="Entire screen" (Plan 01-09); preserve both
- manifest.json has `notifications` permission (Plan 01-09)
- Tier-1 SW-bundle-import gate is the automation contract for ALL future bundle-touching changes