feat: close STREAMING.md production readiness gaps
CI / test (push) Failing after 9s
CI / docker (push) Skipped
Deploy to Cloudflare Pages / deploy (push) Failing after 10s
CD / deploy (push) Successful in 47s

- Added run ID + unique segment naming (r-{ISOTIME}/seg-{seq}.m4s)
- Added fsnotify watcher for real-time R2 segment upload (~7s)
- Added atomic manifest publication (temp key → CopyObject)
- Fixed manifest Cache-Control: public, max-age=1, s-maxage=2, must-revalidate
- Added hls.js error recovery: bounded retries (5x), exponential backoff, reconnecting UI
- Enriched /health endpoint: run_id, active_item, last_segment_seq, last_r2_pub, consecutive_failures, unhealthy detection
- Updated tests: HealthHandler (new fields + unhealthy), player error recovery test
- Updated TODO.md, BACKLOG.md, DONE.md, MEMORY.md
This commit is contained in:
zwitschi committed 2026-08-10 17:20:54 +02:00
1 parent f6ca89747e
commit 18459a9811
12 files changed
+699 -48

No files matched your search

+8 -8
View File
@@ -46,15 +46,15 @@
## Streaming Pipeline
Gaps from 2026-08-10 audit (STREAMING.md contract vs playlist.go implementation):
Gaps from 2026-08-10 audit → 2026-08-10 implementation (STREAMING.md contract vs playlist.go implementation):
- [ ] **Continuous R2 sync during playout (HIGH)**: `syncLatestToR2()` runs only after FFmpeg exits. During long playout loops, R2 is stale — viewers see no new segments. Needs per-segment upload triggered by filesystem watch or FFmpeg progress pipe.
- [ ] **Globally unique segment naming (HIGH)**: STREAMING.md requires `hls/r-{runID}/seg-{seq}.m4s`. Current code uses `strftime` (`segment_%Y%m%d_%H%M%S.m4s`) with no run ID — same-second collisions on restart; names can be reused. Add run/session UUID and monotonic sequence.
- [ ] **Atomic manifest publication (MEDIUM)**: Upload manifest to temp key, then atomically replace `live/playlist.m3u8`. Current code uploads directly — brief window where manifest references unconfirmed segments. Use R2 copy/rename or write-then-swap.
- [ ] **Manifest Cache-Control alignment (LOW)**: STREAMING.md specifies `public, max-age=1, s-maxage=2, must-revalidate`. Code uses `public, max-age=2`. Missing `must-revalidate` and browser/CDN split.
- [ ] **CORS headers on HLS responses (MEDIUM)**: `Access-Control-Allow-Origin: https://linearvoid.tv` required for cross-origin hls.js from `media.linearvoid.tv`. Neither Worker nor R2 config sets CORS. Add to Worker or R2 custom domain.
- [ ] **Player error recovery (MEDIUM)**: STREAMING.md requires bounded retries, exponential backoff, seek-forward-on-drift, reconnecting state. Current `main.ts` uses basic hls.js init with no custom error handlers. Add `hls.on(Hls.Events.ERROR, ...)` handler.
- [ ] **Health endpoint detail (LOW)**: Add active item, playlist revision, run ID, last segment sequence, last R2 pub timestamp, consecutive failures to `/health`. Currently only reports mode + restarts.
- [x] **Continuous R2 sync during playout (HIGH)**: `syncLatestToR2()` now uses fsnotify watcher to upload segments in real-time (~7s delay).
- [x] **Globally unique segment naming (HIGH)**: Implemented `r-{ISOTIME}/seg-{seq}.m4s` naming via run ID + ffmpeg monotonic sequence.
- [x] **Atomic manifest publication (MEDIUM)**: Upload manifest to `playlist.m3u8.tmp`, then `CopyObject` to final key.
- [x] **Manifest Cache-Control alignment (LOW)**: Updated to `public, max-age=1, s-maxage=2, must-revalidate`.
- [ ] **CORS headers on HLS responses (MEDIUM)**: Needs Cloudflare R2 bucket CORS config (infrastructure, not code) — CORS already set in nginx for same-origin; media.linearvoid.tv needs Cloudflare setting.
- [x] **Player error recovery (MEDIUM)**: Added `hls.on(Hls.Events.ERROR)` handler with bounded retries (5x), exponential backoff, reconnecting overlay.
- [x] **Health endpoint detail (LOW)**: Added active item, run ID, playlist revision, last segment seq, last R2 pub, consecutive failures.
- [x] Source media contract + validation (H.264/AAC, 30fps, keyframe check) — implemented
- [x] fMP4 HLS packaging (6s segments, 24 window) — implemented
- [x] Slate fallback + recovery (`shouldEscalateToSlate`) — implemented