feat: coordinate slate playout with interstitial ad breaks - #394
Conversation
Build the ad-break filler slate from the configured adBreak.slate (uri/repetitions/duration) via a new _buildAdBreakSlate helper and bracket it with the #368 interstitial EXT-X-DATERANGE. The slate segment run spans repetitions * duration/1000 seconds, matching the interstitial PLANNED-DURATION exactly, and the DATERANGE START-DATE lands on the slate's first segment (the break boundary) so the tag brackets exactly the slate. The leading EXT-X-DISCONTINUITY that HLSRepeatVod prepends is stripped so the DATERANGE attaches to the true first slate segment. Strictly gated on adBreak.enabled and a configured adBreak.slate; when disabled or unconfigured the helper is a no-op and the existing error/gap filler slate machinery is untouched. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
birme
left a comment
There was a problem hiding this comment.
pr-reviewer verdict: APPROVE (with a documented limitation + follow-up recommendation)
- PROOF:
npm run build→ clean;npm test→100 specs, 0 failures, 7 pending specs. - Slate run duration equals #368's
PLANNED-DURATIONby construction; DATERANGE attached to the slate's first segment so it brackets exactly the slate (single tag, correct START-DATE) — proven by spec. - Strictly gated on
adBreak.enabled+ configured slate; existing error/gap filler slate paths untouched (spec-asserted). No commercial names/trademarks; operator-controlled URI (low risk); commit message conforms.
Judgment call (uncalled-in-production helper): investigated all production seams — _insertSlate is an error/gap-recovery path (wrong place), and content-VOD boundaries would force slate on every transition (wrong). AdBreakOpts carries no timing/cue field, so no legitimate trigger seam exists yet. This mirrors how #368 shipped emission with scheduling deferred. Approving as correct foundation code; recommend a follow-up issue to define the ad-break trigger and wire _buildAdBreakSlate into it.
Awareness note: alignment relies on stripping HLSRepeatVod's leading EXT-X-DISCONTINUITY via regex — coupled to vodlib output format, but guarded by the "brackets exactly the slate" spec.
Summary
EXT-X-DATERANGE. Builds on feat: add ad-break/interstitial channel configuration surface #367 (config) + feat: emit HLS interstitial (EXT-X-DATERANGE) tags for configured ad breaks #368 (emission).Changes
engine/session.js: add_buildAdBreakSlate(afterVod, unixTs, injectSlateLoaders). UsesHLSRepeatVod(slate.uri, slate.repetitions)so the slate run spans exactlyrepetitions * slate.duration / 1000s — the identical value_addInterstitialMetadata(feat: emit HLS interstitial (EXT-X-DATERANGE) tags for configured ad breaks #368) computes forPLANNED-DURATION. Attaches the interstitial DATERANGE to the slate VOD's first segment soSTART-DATElands on the break boundary and the tag brackets exactly the slate run.EXT-X-DISCONTINUITYthatHLSRepeatVodprepends, so the DATERANGE lands on the true first segment (no vodlib change / no feat: emit HLS interstitial (EXT-X-DATERANGE) tags for configured ad breaks #368 rework).adBreak.enabled+ a configuredadBreak.slate.uri; returnsnullotherwise. The existing error/gap filler slate paths (_insertSlate/_loadSlate/_truncateSlate,slateUri/slateRepetitions/slateDuration) are untouched.Integration note for reviewer
There is no ad-break scheduling/trigger mechanism anywhere in this series yet (the #367→#371 breakdown does not define one; #368 emits the tag at content-VOD boundaries). Accordingly this PR delivers the slate-building + exact-alignment logic and its spec coverage, but the helper is not yet invoked from a live trigger. Please assess whether that satisfies #369's acceptance given the series state, or whether it should block.
Test plan
npm run build→ clean (no errors)npm test→100 specs, 0 failures, 7 pending specs(baseline 94; +6 specs asserting slate spans the window, DATERANGE brackets exactly the slate (single tag, correct START-DATE/PLANNED-DURATION), alignment holds at a different size, disabled/no-slate → null, non-ad-break slate untouched)Closes #369
🤖 Automated via Channel Engine Dev daily-backlog-pr skill