- Add ts-ebml ^3.0.2 (parse half) and webm-muxer ^5.1.4 (write half) per
CONTEXT.md amendment D-14-remux; both MIT, both verified SW-compatible
in the d13 debug-session library survey.
- tests/background/webm-remux-deps.test.ts pins two contracts:
(a) named exports surface (Muxer + ArrayBufferTarget + Decoder).
(b) both libraries import cleanly when window/document are absent on
globalThis — guards the published dist against accidentally
acquiring DOM globals on the hot path that would crash the
Chrome service-worker runtime.
- Note: webm-muxer 5.1.4 upstream-deprecated in favor of Mediabunny; the
pinned version still meets the d13 architectural requirement
(single-EBML output via addVideoChunkRaw). Migration to Mediabunny is
out of scope for Plan 01-08 and would require a new ADR.
- Baseline 53 GREEN + 2 new GREEN; tsc clean; 2 webm-playback duration
RED still pending (drive to GREEN in Tasks 3-5).
Implements Option C step 3 per .planning/debug/empty-archive-port-race.md:
"Continuous end-to-end vitest covering 600 s of port lifecycle
(2 reconnects + simulated REQUEST_BUFFER round-trips). Becomes the
new pinning contract for the port lifecycle."
The UAT Test 3 BLOCKER surfaced because no test exercised the full
operator timeline — 5+ minute recording with port-replacement windows
crossing real SAVE_ARCHIVE round-trips. This file pins that contract
end-to-end at the unit-test level.
What's exercised:
- Both SW (src/background/index.ts) and offscreen recorder
(src/offscreen/recorder.ts) loaded into the SAME chrome stub, with
paired port-pair factory (one connect() yields offPort + swPort
that talk to each other through captured listeners).
- 12 ping/pong cycles (~300 s simulated wall-clock).
- 3 SAVE_ARCHIVE round-trips (one before reconnect, two after each
of the two forced reconnects).
- 2 EXTERNAL port disconnects (port._disconnected=true) — simulates
the SW eviction / port glitch path that the H1.b test pins.
- JSZip mocked at file scope (vi.mock) because Node 22+ JSZip can't
read native Blobs — preserves integration shape (size accounting)
without depending on JSZip's Node compatibility.
Final assertions:
1. All 3 saveArchive calls return success:true.
2. EVERY BUFFER message that crossed the wire carried segments (no
silent-loss path was reachable).
3. PONGs round-tripped (proves health-probe loop closes).
Suite: 53 GREEN / 53 tests. tsc --noEmit exit 0; type-safety grep clean;
npm run build exit 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per .planning/debug/empty-archive-port-race.md "Fix Strategy: Option C
(Architectural)", land RED tests that pin the 4 sub-behaviours the
refactor must satisfy at the unit level. These complement the operator-
facing contract already pinned by port-reconnect-race.test.ts (H1+H2).
Offscreen side (tests/offscreen/port-health-probe.test.ts):
A. Bootstrap installs no 290_000 ms pre-emptive reconnect timer
(the timing-based race window from b064a21 is gone).
B. Missed PONGs (5 PINGs without echo) trigger a clean reconnect via
the same path the onDisconnect handler uses.
C. PONG echoes within timeout keep the port alive indefinitely
(counter-test for over-eager probe — already GREEN today).
D. REQUEST_BUFFER with requestId → BUFFER response echoes the same id
(the architectural mechanism that retires cross-talk).
SW side (tests/background/request-id-protocol.test.ts):
1. getVideoBufferFromOffscreen sends REQUEST_BUFFER with a generated
uuid requestId on the live videoPort.
2. Stale BUFFER (mismatched requestId) is ignored — no resolution.
3. Port replacement mid-request → SW re-issues REQUEST_BUFFER on the
new port with the SAME requestId. Retires the H2 silent-drop class.
4. Empty video segments → saveArchive returns {success:false, error}
(operator-visible) instead of {success:true} with no-video archive.
5. SW echoes PONG on PING, closing the health-probe loop.
Suite status: 10 files / 52 tests (42 GREEN, 10 RED).
- 40 baseline + 2 new GREEN (port-health-probe C; request-id 2 & 4
accidentally pass due to test-stub side effects — they will continue
to pass after fix for the right reasons).
- 3 RED in port-reconnect-race + 3 RED in port-health-probe + 4 RED
in request-id-protocol.
Quality gates: tsc --noEmit exit 0; type-safety grep clean.
No production code touched in this commit — fix lands in subsequent commits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>