Files

83 lines
6.0 KiB
Markdown
Raw Permalink 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 1: Stabilize Video Pipeline — Discussion Log
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
**Date:** 2026-05-15
**Phase:** 01-stabilize-video-pipeline
**Areas discussed:** Offscreen source-of-truth location, Ring-buffer mechanism, Tab-switch behavior, State survival across SW unload
---
## Offscreen source-of-truth location
| Option | Description | Selected |
|--------|-------------|----------|
| `src/offscreen/recorder.ts` as crxjs offscreen entry | Real TS module bundled by crxjs; HTML references the bundle; type-check + source maps; deletes both `offscreen/index.ts` and the inline `copy-offscreen` plugin | ✓ |
| `src/offscreen/recorder.ts` via `web_accessible_resources` | Same source file, declared as WAR; reachable from `chrome.runtime.getURL()`; more boilerplate | |
| Keep vite.config.ts inline string | Status quo — hard NO per audit; no type-check, no source maps, easy to lose | |
**User's choice:** crxjs offscreen entry (Recommended)
**Notes:** Aligns with the audit's primary structural recommendation. The inline plugin and dead `offscreen/index.ts` are both deleted in the same phase.
---
## Ring-buffer mechanism
| Option | Description | Selected |
|--------|-------------|----------|
| Single continuous MediaRecorder + age-based trim (`start(2000)`) | Spec-aligned timeslice; retain header forever, drop later chunks by age; verify with ffprobe; pivot to restart-segments if verification fails | ✓ |
| Restart-segments every ~10 s | Each segment self-contained valid WebM; bulletproof playability; ~200300 ms gap per restart (~23% loss); higher RAM (3 segments in flight) | (fallback) |
| Cluster-aware EBML trim via ts-ebml | Theoretically optimal; ~80 KB dep + more test surface | (third fallback, in deferred) |
| Chunk-arrival-time trim, 200 ms timeslice (status quo) | Current broken approach | |
**User's choice:** "It seems that 2 is the most stable? But if you think 1 is better it is up to you."
After follow-up: locked **Option 1** with **Option 2 as documented fallback**.
**Notes:** Decision deferred to Claude after weighing the trade-offs; rationale captured in CONTEXT.md D-09..D-13. Plan-checker enforces ffprobe verification as the Phase 1 success gate; if it fails, the plan revision pivots to restart-segments without re-asking the user.
---
## Tab-switch behavior
| Option | Description | Selected |
|--------|-------------|----------|
| Hard restart (stop old recorder, start fresh on new tab) | SPEC §8-implied; spec-aligned | (rendered N/A by capture-API change) |
| Cross-tab carry-over | Preserve prior tab's buffer until new fills; ~2× RAM during overlap | |
| Per-tab buffers (one per recently-visited tab) | High RAM; risks CON-ram-ceiling | |
| **(emergent option from user: capture whole browser / whole screen)** | Switch capture API to `getDisplayMedia()` / `chrome.desktopCapture`; tab-switch handling becomes N/A | ✓ |
**User's choice:** "May we just record the whole browser? or the whole screen?" → confirmed in the follow-up question as **switch to chrome.desktopCapture / getDisplayMedia**.
**Notes:** This is a project-level amendment to DEC-003 (capture API), not just a Phase 1 implementation detail. Trade-off was made explicit to the user before confirming: Chrome shows a permanent "Sharing your screen" banner (loses SPEC §1 "silent for operator" property), picker dialog required on session start. User accepted. Phase 1's plan therefore includes the doc-amendment cascade (D-A1..D-A6) BEFORE any code work, and removes all `chrome.tabs.onActivated`/`onUpdated` reattachment logic.
---
## State survival across SW unload
| Option | Description | Selected |
|--------|-------------|----------|
| Move buffer ownership to offscreen + long-lived port keepalive | Offscreen survives SW; port resets idle timer (only mechanism that does); buffer in plain offscreen memory; honors CON-buffer-storage | ✓ |
| Same as above + chrome.storage.session belt-and-suspenders | Cold-start recovery on offscreen crash; borderline CON-buffer-storage compliance | (deferred to Phase 5) |
| Keep SW-owned buffer, add proper keepalive port | Smallest diff; SW can still die under memory pressure | |
| Accept buffer loss on SW unload | Don't fight lifecycle; violates "continuous" intent | |
**User's choice:** "one seems no problem." — locked **Option 1**.
**Notes:** `chrome.alarms` keepalive deleted (DEC-010 / CON-service-worker-keepalive amended). The `chrome.storage.session` belt-and-suspenders variant moved to Phase 5 deferred ideas. The SW-side IndexedDB code path in `vite.config.ts:43-104` and `src/background/index.ts:445-475` is deleted alongside.
---
## Claude's Discretion
- Internal protocol choice between `chrome.runtime.connect` port and `chrome.runtime.sendMessage` for offscreen↔SW messaging (decision: port for keepalive, sendMessage for one-shot requests — captured in CONTEXT.md D-19).
- Codec strictness — enforce vp9 only via `MediaRecorder.isTypeSupported`, fail loud if unavailable. No fallback chain (current code's vp9→vp8→h264→default is removed).
- Internal module naming for the offscreen recorder.
- Exact error-UX copy for "user stopped sharing" — deferred to Phase 3 (popup state machine territory).
- Code-style choices within `src/offscreen/` (already constrained by `tsconfig` strict mode).
## Deferred Ideas
- **Audio capture.** `getDisplayMedia({ audio: true })` makes this trivial — but SPEC §9 excludes audio from Phase 1. Phase 2 work.
- **Per-tab silent capture mode** (re-introducing `tabCapture` as an opt-in via `config.json`) for installations that prioritize silent operation over broad coverage.
- **Cluster-aware EBML trim (ts-ebml)** — third-line fallback under D-13 if even restart-segments don't produce playable output. Currently parked.
- **`chrome.storage.session` cold-start buffer-pointer recovery** — Phase 5 (Harden + clean up).
- **Error UX for "user stops sharing"** — popup state extension, Phase 3.