mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
docs(spf): record realized live refetch policy + LL-HLS change-detection gap
live-presentation-modeling: category [3] refetch policy is realized as the pure §6.3.4 cadence (mediaPlaylistReloadDelay) + delayedReschedule + RecurringRunner, fetch scheduling per-track. Record the decided error semantics — a failed reload's rejection propagates and ends the recurrence; transient-fetch retry is deferred to network-resilience, kept out of the cadence — and mark the [3] placement open question decided. ll-hls-support: note that regular-live change-detection keys off the full-segment signature, so a parts-only update reads as unchanged; LL-HLS must fold part progression into change-detection or switch to blocking reload. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2ad9f01954
commit
a46a94e80b
@@ -94,6 +94,15 @@ Things this feature probably forces decisions on, not just additions:
|
||||
is the canonical example of a behavior that stays composition-
|
||||
variant-agnostic; the LL-HLS reload-loop is its inverse — a
|
||||
variant-specific behavior that exists *only* in the LL-HLS engine.
|
||||
- **Reload change-detection vs. partial segments** — the regular-live
|
||||
cadence (`mediaPlaylistReloadDelay`) classifies a reload "changed vs.
|
||||
unchanged" — full target vs. ½× per §6.3.4 — from the **full-segment**
|
||||
window signature (`mediaSequence` + segment count), so a parts-only LL-HLS
|
||||
update reads as *unchanged* and would poll at ½ target. The LL-HLS reload-
|
||||
loop must either fold part progression into change-detection (interval-
|
||||
polling variant) or replace interval pacing with response-driven blocking
|
||||
reload, which sidesteps the question. (Regular-live cadence is verified
|
||||
§6.3.4-correct in `reload-cadence.test.ts`; this is the LL-HLS-only gap.)
|
||||
- **Variant-decision point — open** — where does the engine commit to
|
||||
the LL-HLS variant: adapter-level upfront (consumer opts in), or
|
||||
after-first-playlist-parse from `EXT-X-SERVER-CONTROL` flags? The
|
||||
|
||||
@@ -177,8 +177,20 @@ here.
|
||||
target; ½× on an unchanged playlist). This is the category the
|
||||
decomposition most insists on isolating: it is a **delivery / scheduling**
|
||||
concern, *not* part of the time-*t* content snapshot, even though HLS
|
||||
happens to deliver both in the same playlist text. Its model placement
|
||||
(per-track vs presentation-level) is an [open question](#open-questions).
|
||||
happens to deliver both in the same playlist text.
|
||||
|
||||
**Realized** (`feat/spf-hls-live`) as a pure §6.3.4 cadence function
|
||||
`mediaPlaylistReloadDelay(current, previous)` (`media/hls/reload-policy.ts`) — full
|
||||
target on a changed window, ½× on an unchanged one, `null` once complete — consumed
|
||||
by `delayedReschedule` + a `RecurringRunner` (`core/tasks/`) that owns the loop but
|
||||
knows nothing about time. Fetch scheduling landed **per-track**: each `resolveXTrack`
|
||||
owns its runner (see the [placement open question](#open-questions)). A failed reload
|
||||
is **not** retried by the policy — the rejection propagates and ends that track's
|
||||
recurrence; transient-fetch resilience (retry/backoff) is a fetch-layer concern
|
||||
deferred to [network-resilience](./features/network-resilience.md), kept out of the
|
||||
cadence. "Changed" is detected from the full-segment window (`mediaSequence` + segment
|
||||
count); a parts-only LL-HLS update is invisible to it, which
|
||||
[ll-hls-support](./features/ll-hls-support.md) must extend.
|
||||
|
||||
### [4] Sync anchor — `PROGRAM-DATE-TIME`
|
||||
|
||||
@@ -228,7 +240,8 @@ behavior are the implementation efforts that consume this.
|
||||
model argues for a faithful per-fetch representation. This is the seam
|
||||
where this doc meets the parser refactor.
|
||||
- **`Presentation`** — add `streamType` ([2a]). Completeness ([2b]) rides the
|
||||
existing `duration` field. Refetch policy ([3]) placement TBD.
|
||||
existing `duration` field. Refetch policy ([3]) realized per-track — each
|
||||
`resolveXTrack` owns a `RecurringRunner` driven by an engine-injected reschedule.
|
||||
|
||||
---
|
||||
|
||||
@@ -314,16 +327,17 @@ prematurely fix.
|
||||
|
||||
## Open questions
|
||||
|
||||
- **[3] Refetch-policy placement — per-track vs presentation-level.** In
|
||||
- **[3] Refetch-policy placement — DECIDED (fetch scheduling per-track).** In
|
||||
HLS each media playlist (= each `Track`) carries its own
|
||||
`TARGETDURATION`; in DASH, `minimumUpdatePeriod` is MPD-level
|
||||
(presentation). Per-track bakes an HLS assumption; presentation-level
|
||||
fights HLS's per-playlist reality. Likely answer: a presentation-level
|
||||
concept fed by per-track source data — but decide deliberately. Ties
|
||||
to live-stream-support's per-type reload-coordination question, and to
|
||||
the observation that a not-yet-ended track *must* keep being refetched
|
||||
to stay current, so timeline reconciliation across tracks can't be
|
||||
fully independent even if fetch scheduling is.
|
||||
fights HLS's per-playlist reality. Landed (`feat/spf-hls-live`) as the
|
||||
anticipated split: **fetch scheduling is per-track** — each `resolveXTrack`
|
||||
owns a `RecurringRunner` paced by its own `TARGETDURATION` — while
|
||||
cross-track **timeline reconciliation** stays separate (the parser carries
|
||||
the timeline forward per fetch; `anchorLiveTracks` aligns renditions by PDT).
|
||||
So fetch scheduling is independent without the timeline reconciliation being
|
||||
forced independent, as this question anticipated.
|
||||
- **[4] How captured PDT feeds the A/V-sync anchor — DECIDED (anchor source).**
|
||||
Resolved in [live-timeline-anchoring](../../decisions/live-timeline-anchoring.md):
|
||||
align demuxed audio/video by equal PDT (same real instant), not by
|
||||
|
||||
Reference in New Issue
Block a user