Skip to content

fix(playback): warm catalog prefetch on detail reads, retry slow transcode manifests - #221

Merged
drondeseries merged 2 commits into
mainfrom
fix/cold-prefetch-transcode-manifest
Oct 5, 2026
Merged

drondeseries merged 2 commits into
mainfrom
fix/cold-prefetch-transcode-manifest

Conversation

@drondeseries

Copy link
Copy Markdown
Collaborator

Problem

Related issue: N/A
Validation tasks: none

Cold virtual starts still pay a full 3-7s provider list: clients press play straight from catalog and season lists, and the watch-detail prefetch from the earlier change never fires because no client reads watch detail first. Separately, a slow-but-alive transcode encoder answers a terminal-looking 503 while FFmpeg is still producing, and the web player burns its fatal budget instead of polling again.

Approach

Warm the same bounded best-result cache from the reads clients actually make: item detail warms its versions, season-episode lists warm the first episode's files only. A file-level admit gate plus a 4-slot load semaphore keep high-volume catalog reads from fanning out row loads before the existing bounded prefetch queue.

Manifest polls distinguish slow-alive from dead: alive-but-slow answers retryable 503 (not_ready_retry + Retry-After), and the web player reloads the manifest source while startup is still in flight instead of counting it against fatal recovery. Post-startup failures stay on the fatal path.

Validation

  • go build ./..., gofmt, go vet: clean
  • Focused handler tests (prefetch identity + collapse, decode-rejected, manifest): pass, including -race on prefetch
  • Web: pnpm run lint 0 errors, prettier clean, new manifest-not-ready + guard suites pass
  • Oracle adversarial review across 5 rounds to APPROVED (poll-back restricted to startup state, semaphore race fixed with sync.Once, invalid-200-stub rejected in favor of retryable 503)
  • Full CI required on the head
  • Android manifest retry behavior unverified follow-up

Risks

Prefetch stays speculative: first-2 file IDs, virtual-only filter, shed-when-saturated. Catalog reads gain a bounded background load, never response latency. Manifest not_ready_retry is a new code web clients poll on; other clients see a plain 503 with Retry-After as before.

Before / after

Signal Before After
Cold start from catalog Full 3-7s list, nothing warmed Detail/season reads warm up to 2 rows ahead of play
Repeated catalog reads Each pays row loads Same rows collapse pre-load; distinct keys bounded to 4 concurrent loads
Slow transcode manifest Bare 503 treated as terminal Retryable 503; web polls again while starting, fatal path after

Checklist

  • I read and can explain the complete diff.
  • This pull request addresses one concern.

AI Disclosure

  • Harness: OpenCode
  • Tool(s): OpenCode default tools; explorer and oracle subagents for scouting and review
  • Model(s): omniroute/workhorse (Workhorse, Gemini 3.8+ Tiered with Failover)
  • Involvement: AI-assisted
  • Adversarial review: oracle reviewed across 5 rounds (invalid playlist stub, admission-before-load, client retry behavior, semaphore init race, startup-state gating). All findings fixed and re-reviewed to APPROVED.

…scode manifests

Clients press play straight from catalog/season lists without a
watch-detail read, so the watch-detail prefetch never fired. Item
detail and season-episode reads now warm the same bounded cache, and
the file-level gate plus a 4-slot load semaphore keep high-volume
reads from fanning out.

Slow-but-alive transcode manifests answer retryable 503
(not_ready_retry + Retry-After) instead of a terminal error, and the
web player polls the manifest again while startup is still in flight
instead of burning the fatal budget.
@drondeseries
drondeseries merged commit 4437719 into main Oct 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant