Incident library · SCTE-35 marker loss
Public postmortem

SCTE-35 ad-marker loss
across the live→VOD stitch seam.

A working postmortem on the Friday primetime VOD-publish event where the live-to-VOD stitcher dropped the splice_insert / splice_null cue points crossing the cdn-A → cdn-E seam, so the resulting VOD HLS manifest carried no EXT-X-CUE-OUT or EXT-X-DATERANGE cues and the downstream SSAI/DSA ad server never received the cue trigger — and the Streamwake agentic ops layer caught it from manifest + cue-coverage telemetry, ranked it as a stitcher cue filter overshoot with 89% confidence, and remediated it with a split live/VOD cue-pass policy plus a raised vod.cue_point_coverage probe — split explicitly into the acts the agent did autonomously and the acts it surfaced to humans.

Protocol: HLS + SCTE-35 + stitcher
Format: MPEG-TS splice cues · HLS manifest · SSAI/DSA cue trigger
Streamwake probes: scte35.cue_dropped · vod.cue_point_coverage · vod.manifest_first_segment.ext_x_cue_out_count · wrapper.scte35_signal_in_manifest.

Book a technical demo for SCTE-35 ad-marker loss (live→VOD stitching)

Lead magnet
SCTE-35 ad-marker loss (live→VOD stitching)

Read the postmortem — then bring your own incident to Streamwake.

Two ways to engage on this exact failure pattern: book a 30-minute technical demo where we walk through the probe cascade on your source, or hand us an archived incident and watch the agent diagnose it end-to-end.

Both routes land on the scoping intake form — no SDR gate.

Viewer impact

What the cohort saw

The first things to read on any real primetime ad-insertion incident are the cohort-level numbers — how broad the cue-coverage collapse was, how many VOD assets carried cue-free manifests after the seam, and where the symptom landed on the stitcher cue filter. Three numbers did the heavy lifting here.

Co-affected (cue-point coverage)
VOD assets crossing the cdn-A→cdn-E seam where vod.cue_point_coverage dropped to 0.
~22% of replay cohort

Roughly 22% of the eu-west primetime VOD-replay cohort — assets crossing thecdn-A → cdn-E stitch seam — left the packager with zero EXT-X-CUE-OUT / EXT-X-DATERANGE cues; downstream SSAI/DSA servers received no cue trigger on those assets, so pre-roll / mid-roll ad break count collapsed to ~1 per hour instead of the expected ~4 per hour.

Duration
Window from first manifest-without-cue to last cue-preserving re-publish.
~13 minutes

~13 minutes between the first cue-drop on the cdn-A→cdn-E seam at T+0m and the vod.cue_point_coverage probe returning to 1.0 at T+41m. The postmortem window goes longer because the split cue-pass policy ships as a deploy-time config — not in the same incident window.

Surface area
Where the symptom landed on the stitcher cue-filter lane.
stitcher · cdn-A→cdn-E

scte35.cue_dropped: true on seam_header (cdn-A → cdn-E) with vod.cue_point_coverage: 0.0 on the first VOD segment after the seam. The cue points were healthy upstream on live egress; the failure was on the stitcher’s shared cue filter leaking into the VOD path, not on the source signal.

Classification

How Streamwake classified this incident

Three ranked hypotheses, with the top one filing the timeline and the secondary signal carrying the cause. The vod_manifest_missing_cue and scte35_signal_replay_normal lanes are included to make explicit that the agent ruled them out — the symptom was on the stitcher cue filter leaking into the VOD path, not on the manifest parser or the upstream SCTE-35 signal.

Top hypothesis (failure lane)
What the agent named first — the failure category the timeline is filed under.
stitcher_cue_filter_overshoot · 0.89

stitcher_cue_filter_overshoot — the stitcher’s shared cue filter (designed for the live egress anti cue-re-fire policy) leaked into the VOD stitch path and dropped every splice_insert / splice_null cue point crossing the cdn-A → cdn-E seam. Four signals line up: scte35.cue_dropped true on the seam header, vod.cue_point_coverage at 0.0 on the first VOD segment, vod.manifest_first_segment.ext_x_cue_out_count at 0 vs 4 expected, wrapper.scte35_signal_in_manifest fail (no EXT-X-CUE-OUT / EXT-X-DATERANGE post-seam).

Secondary signal (cause lane)
Why the failure happened — this signal determines whether the fix is on the stitcher, the VOD packager, or the upstream SCTE-35 signal.
vod_manifest_missing_cue · 0.07

vod_manifest_missing_cue was the secondary signal ranked at 7% — the VOD manifest parsed successfully on cdn-E (no parse errors), so the missing cues are a cue-passthrough gap on the stitcher, not a manifest construction failure on the packager. The dismissal rule ranked on the cue-coverage pattern rather than on manifest state alone, because the seam_header flag (file-level filter applied, no parse error on the VOD side) is the decisive signal for a passthrough regression.

Severity, region, status
Severity is computed from the co-affected VOD asset share; region is the geo of the failing stitch seam.
sev2
  • Region: eu-west (cdn-A → cdn-E)
  • Status: resolved (window closed)
  • Opened: 2026-08-07 19:38 UTC
  • Spread: contained to eu-west stitch seam — na-east VOD cohort unaffected
Confidence
Top hypothesis share of the three ranked hypotheses; remaining mass is split between vod_manifest_missing_cue and scte35_signal_replay_normal.
89 / 100

Above the 80% threshold the agent treats as a confident top-hypothesis filing. scte35_signal_replay_normal · 0.04 was cleared explicitly because the live egress emitted 8 cue points across the 90s window with no signal error — the upstream splice_insert / splice_null signal was healthy; the failure was on the crossover into the VOD packager, not on the upstream signal.

Chronology

Incident timeline

Ten events: detection on the cohort, classification across three ranked hypotheses, five autonomous acts the agent took on its own, three acts it surfaced to humans, and the resolution. The right-hand “act” tag is what makes this postmortem distinct from a generic write-up — it pins the split between autonomous agentic ops and the work that genuinely needed a person.

Today

10 events
  • T+0m
    Detection
    by cohort agent · eu-west
    act · autonomous

    Stitcher dropped cue points crossing the cdn-A→cdn-E seam; VOD manifest cue-free after the seam

    seam_header.scte35.cue_dropped flipped to true on the live→VOD stitch seam; vod.cue_point_coverage dropped to 0.0 on the first VOD segment after the seam; vod.manifest_first_segment.ext_x_cue_out_count fell to 0 vs the expected 4 per hour; ad_break_count_per_hour on the replayed asset collapsed from ~4 to ~1.

    Aug 7, 07:38:04 PM
  • T+1m
    Classification
    by Streamwake reliability agent
    act · autonomous

    Ranked: stitcher_cue_filter_overshoot (0.89) · secondary vod_manifest_missing_cue (0.07)

    Top hypothesis reads 89% confidence. Two ranked alternatives dismissed: vod_manifest_missing_cue (the manifest parses green on cdn-E — the gap is on the cue passthrough, not on manifest construction), scte35_signal_replay_normal (the live egress emitted 8 cue points across the 90s window — the upstream signal was healthy; the failure is specifically on the crossover into the VOD packager).

    Aug 7, 07:39:04 PM
  • T+2m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Emitted split_cue_pass_policy_live_vs_vod + raise_vod_cue_passer_threshold

    Split the stitcher’s cue-pass policy so the live egress keeps the anti cue-re-fire filter (still required there) and the VOD path passes every cue point through unchanged. Raise the vod.cue_point_coverage threshold from 0.85 to 0.95 so the next cue passthrough regression surfaces as a hard miss instead of a quiet drift.

    Aug 7, 07:40:04 PM
  • T+3m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Pinned the stitcher to the pre-migration cue policy for affected VOD assets

    Pinned the affected VOD asset cohort to the pre-migration shared cue policy (the filter that was active before the cdn-A→cdn-E migration) so the next publish keeps the cues intact while the vendor-side fix is reviewed; the post-migration policy stays in place for live egress.

    Aug 7, 07:41:04 PM
  • T+6m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Re-published 4 affected VOD assets with the split cue-pass policy in effect

    Forced a replay-cycle publish on the 4 affected VOD assets that crossed the cdn-A→cdn-E seam during the incident window; the replayed assets now carry EXT-X-CUE-OUT / EXT-X-DATERANGE cues end-to-end and ad_break_count_per_hour is back at ~4 per hour.

    Aug 7, 07:44:04 PM
  • T+9m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Rebalance hint queued: dry-run the cue passthrough split off-peak over the weekend

    Run a dry-run of the split_cue_pass_policy_live_vs_vod config on a low-volume replay cohort over the weekend (off-peak eu-west) before promoting it to the live VOD stitch path, so the post-migration cue policy can land on live egress without breaking cues on the VOD seam again. Staged for the next deploy.

    Aug 7, 07:47:04 PM
  • T+16m
    Surfaced to human
    by agent → operator
    act · surfaced to humans

    Operator engaged the stitcher vendor on the shared cue filter leaking into the VOD path

    Vendor confirmed the shared cue filter config was retained unchanged from the pre-migration cue policy and was never split between the live egress and VOD stitch paths; the filter was correctly retaining the anti cue-re-fire behaviour on live egress, but its scope leaked into VOD, dropping every cue point crossing the seam. New policy: keep the live_egress_anti_refire_policy on live egress, switch VOD stitch to vod_passthrough_policy that passes every cue through unchanged.

    Aug 7, 07:54:04 PM
  • T+19m
    Surfaced to human
    by on-call
    act · surfaced to humans

    On-call paged for the cue-drop root-cause review on the live→VOD seam

    Page acknowledged within 70s; reviewer confirmed the agent’s rank and that the re-publish on the 4 affected VOD assets + the pinned pre-migration cue policy had restored ad_break_count_per_hour to its baseline before the formal fix ship.

    Aug 7, 07:57:04 PM
  • T+24m
    Surfaced to human
    by reliability team
    act · surfaced to humans

    Postmortem write-up assigned (this page)

    Reliability team assigned the public postmortem; this page is the resulting write-up, with the ranked hypotheses, recommended fix, and agentic-act split pinned from the timeline.

    Aug 7, 08:02:04 PM
  • T+41m
    Resolution
    by Operator + agent
    act · autonomous

    Incident resolved; split cue-pass policy ships next deploy · vod.cue_point_coverage probe raised

    vod.cue_point_coverage returned to 1.0 on the first VOD segment after the seam; vod.manifest_first_segment.ext_x_cue_out_count climbed back to 4 per hour on the affected assets; the split_cue_pass_policy_live_vs_vod config and the raised vod.cue_point_coverage probe threshold both ship in the next deploy window.

    Aug 7, 08:19:04 PM
Autonomous acts the agent did
Six events the Streamwake reliability agent executed without a human in the loop. Each one was a rebalance decision, an emit, or a re-publish — never an override.
  • classify · ranked three hypotheses with confidence in 90s
  • split · emitted split_cue_pass_policy_live_vs_vod so the VOD path passes every cue point through
  • threshold · emitted raise_vod_cue_passer_threshold so the next cue passthrough miss surfaces as a hard hit
  • pin · pinned the affected VOD asset cohort to the pre-migration cue policy while the vendor-side fix ships
  • republish · forced a re-publish on the 4 affected VOD assets with the split cue-pass policy in effect
  • rebalance · queued a dry-run of the cue passthrough split off-peak over the weekend
Acts the agent surfaced to humans
Three events the agent did not act on its own — each one needed a person, a vendor, or a team. The agent held off emitting a rebalance that would have masked the root cause.
  • operator · engaged the stitcher vendor on the shared cue filter leaking into the VOD path
  • on-call · paged for the cue-drop root-cause review on the live→VOD seam
  • reliability team · assigned the public postmortem write-up (this page)
Anatomy

Anatomy of the evidence packet

The two packets on the failing source — a 12-line splice_insert cue excerpt crossing the cdn-A → cdn-E stitch seam (with the cue filter leaking across the seam and the resulting VOD HLS manifest cue-free after the seam) and the agent timeline response with the ranked hypotheses and the rebalance hints. The cue excerpt is what the agent decided on; the timeline response is what the agent emitted.

Splice_insert cue excerpt (cdn-A→cdn-E stitch seam)
----- splice_insert cue excerpt (12 lines, crossing the cdn-A→cdn-E seam) -----
# section 1: live egress (cdn-A), 8 cue points emitted across the 90s window
[cue 1] splice_insert  pts=441,243,200 dur=15000  preroll=4000  avp_segmentation_type=1
[cue 2] splice_null    pts=442,118,400 dur=8000                          avp_segmentation_type=1
[cue 3] splice_insert  pts=443,920,100 dur=15000  preroll=4000  avp_segmentation_type=1
[cue 4] splice_null    pts=445,082,600 dur=8000                          avp_segmentation_type=1
[cue 5] splice_insert  pts=446,704,400 dur=15000  preroll=4000  avp_segmentation_type=1
[cue 6] splice_null    pts=447,884,200 dur=8000                          avp_segmentation_type=1
[cue 7] splice_insert  pts=449,406,700 dur=15000  preroll=4000  avp_segmentation_type=1
[cue 8] splice_null    pts=450,719,500 dur=8000                          avp_segmentation_type=1
# ─── stitch seam (cdn-A → cdn-E) ───────────────────────────────────────
# seam_header.scte35.cue_dropped: true
# seam_header.cue_filter_applied: live_egress_anti_refire_policy
# (the stitcher’s shared cue filter held across the seam; 8 cues dropped)
[cue 9]  splice_insert  pts=452,400,300 dur=15000  preroll=4000  avp_segmentation_type=1  # DROPPED
[cue 10] splice_null    pts=453,930,000 dur=8000                          avp_segmentation_type=1  # DROPPED

----- VOD HLS manifest excerpt (first 8 segments across the seam, after stitch) -----
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:42
#EXT-X-MAP:URI="init.mp4"
#EXTINF:6.000,
seg-042.m4s
#EXTINF:6.000,
seg-043.m4s
#EXTINF:6.000,
seg-044.m4s
#EXTINF:6.000,
seg-045.m4s
#EXTINF:6.000,
seg-046.m4s
#EXTINF:6.000,
seg-047.m4s
#EXTINF:6.000,
seg-048.m4s
#EXTINF:6.000,
seg-049.m4s
# ranking note: the VOD manifest carries zero `#EXT-X-CUE-OUT` and zero
# `#EXT-X-DATERANGE` lines after the seam — the splice_insert cues never
# reached the VOD packager. SSAI/DSA receives no cue trigger on this asset.

----- cycle 1 (T+0m +8s, after split live/VOD cue-pass policy) -----
seam_header.scte35.cue_dropped:                   false
seam_header.cue_filter_applied:                  vod_passthrough_policy
vod.cue_point_coverage:                           1.0
vod.manifest_first_segment.ext_x_cue_out_count:   4
vod.manifest_first_segment.ext_x_daterange_count: 4
# rebalance_hints emitted:                        split_cue_pass_policy_live_vs_vod,
#                                                 raise_vod_cue_passer_threshold,
#                                                 pin_stitcher_to_pre_migration_cue_policy
# ad_break_count_per_hour (replayed asset):       4  (baseline was ~1)
Cue-drop smoking gun (on the failing seam)
These are the four signals that, together, file the stitcher cue filter overshoot hypothesis.
  • scte35.cue_dropped true on seam_header (8 cues dropped)
  • vod.cue_point_coverage 0.0 (fail, baseline 1.0)
  • vod.manifest_first_segment.ext_x_cue_out_count 0 vs 4 expected per hour
  • wrapper.scte35_signal_in_manifest fail (no EXT-X-CUE-OUT / DATERANGE post-seam)
  • manifest parse → pass. VOD manifest parses green on cdn-E — symptom is on the stitcher filter, not the packager.
Agent timeline response (ranked hypotheses + rebalance)
{
  "stream_id": "cklivestitchertocuevod7921",
  "source": "https://cdn.example.com/live/event/manifest.m3u8",
  "protocol": "HLS+STITCH+SCTE-35",
  "checked_at": "2026-08-07T19:46:02Z",
  "ranked_hypotheses": [
    {
      "rank": 1,
      "hypothesis": "stitcher_cue_filter_overshoot",
      "confidence": 0.89,
      "evidence_signals": [
        "scte35.cue_dropped → fail (true on seam_header across cdn-A→cdn-E)",
        "vod.cue_point_coverage → fail (0.0 on the first VOD segment after the seam)",
        "vod.manifest_first_segment.ext_x_cue_out_count → fail (0 vs 4 expected per hour)",
        "wrapper.scte35_signal_in_manifest → fail (no EXT-X-CUE-OUT / EXT-X-DATERANGE post-seam)"
      ]
    },
    {
      "rank": 2,
      "hypothesis": "vod_manifest_missing_cue",
      "confidence": 0.07,
      "evidence_signals": [
        "manifest served green on cdn-E with no parse errors; the missing cues are a packager-side passthrough gap, not a manifest parse failure"
      ]
    },
    {
      "rank": 3,
      "hypothesis": "scte35_signal_replay_normal",
      "confidence": 0.04,
      "evidence_signals": [
        "SCTE-35 signal healthy on the live egress (8 cue points across the 90s window); the failure is on the crossover into the VOD packager, not on the upstream signal"
      ]
    }
  ],
  "agent_rebalance_hints": [
    "split_cue_pass_policy_live_vs_vod",
    "raise_vod_cue_passer_threshold",
    "pin_stitcher_to_pre_migration_cue_policy"
  ],
  "surfaced_to_humans": [
    {"owner": "stitcher vendor",   "task": "engage on the shared cue filter leaking into the VOD path"},
    {"owner": "on-call",           "task": "page for the cue-drop root-cause review on the live→VOD seam"},
    {"owner": "reliability team",  "task": "assign the postmortem write-up"}
  ]
}
What the agent emitted (and what it did not)
The rebalance hints ship autonomously; the surfaced list is what the agent escalated instead.
  • rebalance hint split_cue_pass_policy_live_vs_vod
  • rebalance hint raise_vod_cue_passer_threshold
  • rebalance hint pin_stitcher_to_pre_migration_cue_policy
  • rebalance hint dry_run_cue_passthrough_split_offpeak (queued, ships in the next deploy)
  • surfaced → engaged the stitcher vendor on the shared cue filter leaking into the VOD path
  • surfaced → paged on-call for the cue-drop root-cause review on the live→VOD seam
Recommended fix

Split the cue-pass policy live vs VOD · raise the vod.cue_point_coverage probe

Two changes close the gap the timeline exposed. The first is what the agent already emitted on this incident (the split live/VOD cue-pass policy + the re-publish on the 4 affected VOD assets); the second is what ships on the next deploy (the raised vod.cue_point_coverage probe threshold + the vendor-side shared cue filter audit). Both are tracked as exported rebalance_hints rows.

01Split the stitcher cue-pass policy — keep the live egress filter, pass every cue through to VOD
agent-emitted

The stitcher’s shared cue filter (designed for the live egress anti cue-re-fire policy) was leaking into the VOD stitch path. The fix is to split the cue-pass policy by egress lane: keep live_egress_anti_refire_policy on the live egress path (still required there to prevent premature cue re-fire), and switch the VOD stitch path to vod_passthrough_policy that passes every splice_insert / splice_null cue point through unchanged. The agent emitted split_cue_pass_policy_live_vs_vod on the failing path and re-published the 4 affected VOD assets to restore ad_break_count_per_hour to its baseline before the formal fix shipped.

Verification

scte35.cue_dropped stays false on every seam_header for ten consecutive days; vod.cue_point_coverage stays at 1.0 on the first VOD segment after every seam, with vod.manifest_first_segment.ext_x_cue_out_count at the expected count per hour.

02Raise the vod.cue_point_coverage probe threshold so the next cue passthrough miss is a hard hit
queued

The vod.cue_point_coverage probe was set with a 0.85 threshold, which meant a cue passthrough regression that dragged coverage to 0.0 only landed as a quiet drift instead of a hard miss. Raising the threshold to 0.95 keeps the coverage lane trustworthy as a hard clip on the VOD stitch path and ensures the next cue passthrough regression surfaces as a real alert, not a quiet drift. The cohort impact at the current setting is a 0.0 cue coverage clipped by the 0.85 threshold; at the new setting it becomes a real cue-coverage alert, plus the seam_header flag it always fired. Ships next deploy alongside a dry-run of the cue passthrough split off-peak over the weekend.

Verification

vod.cue_point_coverage drift over the affected geo stays at 1.0 over a 24-hour window; vod.manifest_first_segment.ext_x_cue_out_count stays at the expected count per hour for ten consecutive seam crossings.

Next step

Want Streamwake to catch this on your live→VOD stitch path?

Sign up, register an HLS+STITCH+SCTE-35 probe, and the same scte35.cue_dropped · vod.cue_point_coverage · vod.manifest_first_segment.ext_x_cue_out_count · wrapper.scte35_signal_in_manifest probes that produced the timeline above run on every stitch seam — and surface in a Slack channel, a webhook, or the streams dashboard.

Need Streamwake on one of your incidents?
Would you like Streamwake to analyze one of your historical incidents and show where AI could reduce investigation time? (Filed under: SCTE-35 ad-marker loss (live→VOD stitching).)
Incident analysis
  • Pick a recent on-call incident — manifest stall, edge miss, player-side stall, or peer congestion.
  • We replay it through the same reliability-agent probe cascade used on the postmortem above.
  • You walk away with a written what-could-have-been-Automated readout, not a sales deck.
Back to library

Read the next postmortem

The other live entries cover DRM-keyserver cold-starts, ISP-vs-CDN disambiguation, live-sports buffering, player-startup regressions on a cross-platform release, and encoder ABR ladder switchovers.