Incident lab · ISP-vs-CDN recovery criteria
Synthetic postmortem · eu-west residential cohort · ISP-vs-CDN disambiguation

ISP congestion vs CDN failure
— recovery criteria.

A working postmortem on the regression that looks like a CDN failure but is an ISP-side congestion event — the player-visible symptom (rebuffering, segment-fetch stalls, fresh-segment rebuys) reads identically from both, so the discriminator is on the cache leg and the multi-CDN health probe, not on the player side. The Streamwake agentic ops layer disambiguated the lane from cache.freshness + edge.geo_drift + multicdn.winner_RTT (all three passing — the CDN leg is healthy), landed as isp_congestion · dominant at 83% confidence with the cdn_failure lane ruled out by name, and remediated on the affected cohort with a prewarmed low-bitrate variant (autonomous under a confidence-and-cohort-divergence gate), an ISP-side reprobe (autonomous), and a peering-provider ticket (surfaced to humans) — with recovery verified cohort-side on cohort_join_stall_ratio + cohort_rebuffer_ratio, NOT on the cache layer turning green again.

Protocol: HLS · CMAF · cdn-a · cache-fra9921 · multi-CDN cdn-a|cdn-b|cdn-c
Window: eu-west residential primetime · 90s window · 3 AS blocks
Streamwake probes: isp.peer_congestion · isp.last_mile_rtt · tcp.retransmit_rate · cache.freshness · cache.availability · edge.geo_drift · multicdn.winner_RTT · cohort.cohort_join_stall_ratio · cohort.cohort_rebuffer_ratio · cohort.cohort_startup_time_p95_ms.

Book a technical demo for ISP congestion vs CDN failure

Lead magnet
ISP congestion vs CDN failure

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 ISP-vs-CDN disambiguation incident are the cohort-level numbers on the affected eu-west residential cohort — and crucially, the contrast against the cache leg that stays green. Three numbers did the heavy lifting here: the last-mile RTT, the cohort_join_stall_ratio, and the contrast between the cache leg (green) and the cache.availability / cache.freshness / edge.geo_drift / multicdn.winner_RTT probes (all four pass). The figures below are simulated telemetry — the disclosure above applies to every figure on this page.

Co-affected (eu-west residential cohort)
Sessions whose streams stalled under last-mile RTT lift on the affected AS block.
~9% of cohort

Roughly 9% of the eu-west residential cohort — session-level stalls on cdn-A/fra9921, where isp.peer_congestion flagged three AS blocks at once (as3356-london at 412ms, as5511-frankfurt at 287ms, as1299-stockholm at 218ms) and tcp.retransmit_rate climbed to 14.2%. The cache leg was green — cache.availability stayed X-Cache: HIT and cache.freshness stayed age=0 through the entire window — but the cohort's rebuffer ratio lifted to 0.054 behind the per-segment RTT lift.

Duration
Window from first isp.peer_congestion variance to last cohort probe returning to baseline.
~41 minutes

~41 minutes between the first isp.peer_congestion variance at T+0m and cohort.cohort_rebuffer_ratio clearing within baseline tolerance at T+27m. The window goes longer because the ISP-side runbook lane (peering-provider ticket on as3356 / as5511 / as1299) ships after the close-out probes land — so the postmortem window is two-tier: T+0m → T+27m on the cohort-side + last-mile close-out signals, and shaped forward by the ISP-side ticket that bound to the peering-provider runbook.

Surface area
Where the symptom landed — ISP-side last-mile plus cache leg staying green.
last-mile RTT · ISP-side · cache leg green

isp.last_mile_rtt: 412ms vs 38ms baseline on as3356 / as5511 / as1299 (eu-west residential) — three AS blocks lifting together. The discriminator is that the cache leg stayed green — cache.availability = X-Cache: HIT, cache.freshness = age=0, edge.geo_drift = X-Served-By: cache-fra9921 (expected eu-west POP), and the multi-CDN health probe multicdn.winner_RTT reads 38ms / 39ms / 41ms (cdn-a / cdn-b / cdn-c all flat at baseline) — the CDN leg is healthy at zero egress change.

Classification

How Streamwake classified this incident

Three ranked hypotheses: the top one filing the timeline as isp_congestion · dominant, the second explicitly tagged cdn_failure · ruled out by so the recovery message lands (the cache leg stayed clean through the entire window), and the third filed as an alternate: transit_or_peering_failure with a low confidence that captures the alternate read before the close-out probe.

Top hypothesis (failure lane)
What the agent named first — the failure category the timeline is filed under.
isp_congestion · dominant · 0.83

isp_congestion — an eu-west residential / ISP-side congestion event lifted last-mile RTT off-baseline across three AS blocks at once (as3356-london at 412ms vs 38ms, as5511-frankfurt at 287ms vs 41ms, as1299-stockholm at 218ms vs 33ms), with tcp.retransmit_rate climbing to 14.2% and isp.cell_load.on_affected_region at 0.71 (vs 0.43 baseline). Three signals line up: the affected cohort is rebuffering behind the per-segment RTT lift while the cache leg stayed green through the entire window.

Secondary signal (cause lane)
The cdn_failure lane is ruled out by name — discards the cache-miss / cache-freshness shape that would have gated any CDN-side runbook lane on this incident.
cdn_failure · ruled out by · 0.31

cdn_failure was the secondary signal ranked at 31% — but it's tagged ruled out by so the recovery message lands. The cache.availability probe reads X-Cache: HIT, cache.freshness reads age=0 (vs declared max-age=2), and the multi-CDN health probemulticdn.winner_RTT reads 38ms / 39ms / 41ms (cdn-a / cdn-b / cdn-c — all three flat at baseline); the CDN leg is healthy at zero egress change. The dismissal rule was "rank the cause on the cache.availability + cache.freshness + multicdn.winner_RTT pattern, not on the single symptom that landed on the player"; the cache leg nature of the discriminator is decisive.

Severity, region, status
Severity is computed from the co-affected cohort share; region is the geo of the failing probes.
sev3
  • Region: eu-west residential (as3356 / as5511 / as1299 — three AS blocks lifting together)
  • Status: resolved (window closed, ISP-side runbook ticket filed for the affected AS block)
  • Opened: 2026-08-19 20:14 UTC
  • Spread: contained to ISP-side last-mile uplink — na-east and apac cohorts unaffected across all three CDNs; the multi-CDN health probe settled at zero egress change on the eu-west edge leg.
Confidence
Top hypothesis share of the three ranked hypotheses; remaining mass is split between the ruled-out cdn_failure and the alternate transit_or_peering_failure.
83 / 100

Above the 80% threshold the agent treats as a confident top-hypothesis filing. cdn_failure · 0.31 was cleared explicitly because cache.freshness and multicdn.winner_RTT together prove the CDN leg is healthy at zero egress change — the discriminator for the cache-leg-not- CDN-side shape of the failure.

Recovery criteria

What "recovery" actually looks like on this incident

Recovery on this incident is verified cohort-side on the affected cohort + on the affected AS blocks — NOT on the cache layer turning green again. The cache leg stayed green through the entire window; if recovery were the cache turning green, the postmortem would land on a CDN-side lane that was never the failure. The audit step writes the close-out signal into the playbook as a triple — cohort_join_stall_ratio + cohort_rebuffer_ratio + last_mile_rtt — over the next same-length cohort window.

Close-out signal
cohort_join_stall_ratio + cohort_rebuffer_ratio + last-mile RTT
Cohort-side + last-mile close-out signals — what the postmortem declares recovered.

Recovery on this incident is verified by a triple of cohort-side + last-mile close-out signals: cohort.cohort_join_stall_ratio settles under 0.05 over the next same-length cohort window, cohort.cohort_rebuffer_ratio settles within baseline tolerance, and isp.last_mile_rtt drops below the 1.5s baseline resilience gate. The three signals together prove the affected cohort is delivering green playback — not the cache turning green.

NOT a close-out signal
The cache leg staying green or re-anchoring
The cache leg was green the entire window — the failure was last-mile, not cache- side. Reading the cache-side probes as a close-out signal is the read that is geometrically false.

cache.availability returning to X-Cache: HIT at zero egress change is NOT a close-out signal — the cache leg was green the entire window. cache.freshness re-anchoring to age < max-age is NOT a close-out signal — freshness was anchored the entire window. multicdn.winner_RTT reading pass on cdn-a / cdn-b / cdn-c is NOT a close-out signal — the multi-CDN health probe proves the CDN leg is healthy, but does not prove the cohort is delivering green playback when last-mile is degraded.

Audit step on this incident
"CDN is healthy" ≠ "viewers are getting green playback"
The audit step on this incident writes the close-out signal into the playbook as "verify cohort_join_stall_ratio + cohort_rebuffer_ratio + last_mile_rtt settle within tolerance over the next same-length cohort window" — not "verify the cache leg returning to green".

A fix that normalizes multicdn.winner_RTT + cache.availability + cache.freshness without clearing the cohort's cohort_join_stall_ratio, cohort_rebuffer_ratio, or last-mile RTT within tolerance is a fix that didn't reach the cohort. The cache leg was green the entire window — the failure was last-mile, not cache-side, and a read that declares recovery on cache-side probes is the read that misses the lane forward. The audit step codifies it: cohort-side + last-mile double verification, NOT cache-side re-anchoring.

Chronology

Incident timeline

Eleven events: detection on the affected cohort, classification across three ranked hypotheses (with the cdn_failure lane tagged ruled out by so the recovery message lands), four autonomous acts the agent took under the governed-action gates, four acts it surfaced to humans, the recovery probe, 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. All times below are simulated telemetry — the disclosure at the top of this page applies to every minute offset on the timeline.

Today

11 events
  • T+0m
    Detection
    by cohort agent · eu-west residential (as3356 / as5511 / as1299)
    act · autonomous

    Last-mile RTT lifted across the eu-west peers; cache leg stayed clean

    isp.last_mile_rtt climbed from 38ms baseline to 412ms in a 90s window on cdn-A/fra9921; isp.peer_congestion flagged as3356-london at 412ms / as5511-frankfurt at 287ms / as1299-stockholm at 218ms — three AS blocks lifting together; tcp.retransmit_rate climbed from 0.4% baseline to 14.2% on the same peer sample; cache.availability stayed X-Cache: HIT and cache.freshness stayed age=0 (CDN cache leg green). cohort.cohort_join_stall_ratio lifted from 0.018 baseline to 0.086 in the same window.

    Aug 19, 08:14:36 PM
  • T+1m
    Classification
    by Streamwake reliability agent
    act · autonomous

    Ranked: isp_congestion · dominant (0.83) · cdn_failure · ruled out by (0.31) · transit_or_peering_failure · alternate (0.22)

    Top hypothesis reads 83% confidence. cdn_failure is ruled out by name with the cache.freshness + edge.geo_drift + multicdn.winner_RTT discriminator — the cache leg stayed clean (age=0, X-Cache: HIT, no Atlantic cross-POP) and the multi-CDN health probe passed on cdn-a|cdn-b|cdn-c. transit_or_peering_failure is the alternate (a single transit failure cannot lift three AS blocks at once — too wide a footprint).

    Aug 19, 08:15:36 PM
  • T+2m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Governed · autonomous: raise_cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate

    Confidence 0.83 ≥ 0.80 gate cleared; cohort_join_stall_ratio divergence active on the affected cohort. The CDN egress tolerance is raised against the per-segment rebuffer pattern at the prewarmed low-bitrate variant — CDN side NOT touched, the multi-CDN health probe proves the CDN leg is healthy at zero egress change.

    Aug 19, 08:16:36 PM
  • T+4m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Governed · autonomous: triage_isp_congestion_reprobe

    isp.peer_congestion fails on ≥ 3 eu-west AS blocks gate cleared. Last-mile RTT re-probes the affected cohort — confirms the failure lane is ISP-side not CDN-side before any peering-provider ticket is filed; CDN side is left untouched through the re-probe.

    Aug 19, 08:18:36 PM
  • T+7m
    Status change
    by Streamwake reliability agent
    act · autonomous

    Last-mile RTT climbing; cohort rebuffer profile collapsing behind the prewarmed variant

    isp.last_mile_rtt climbed to 412ms before the prewarm variant landed; after the variant landed, cohort.cohort_rebuffer_ratio collapsed from 0.054 to 0.018 (within baseline tolerance 0.05 over the same-length cohort window). The cache leg stayed clean — cache.availability stayed X-Cache: HIT, cache.freshness stayed age=0 — through the entire window.

    Aug 19, 08:21:36 PM
  • T+10m
    Surfaced to human
    by agent → on-call peer-cohort team
    act · surfaced to humans

    Governed · surfaced to humans: surface_peering_provider_ticket_for_as3356_as5511

    Peering-provider ticket required for the affected AS block. The agent surfaces the rtt_ms signature + 90s window profile and the multi-CDN health probe to the on-call peer-cohort team — the CDN side is NOT modified (the multi-CDN health probe proved the CDN leg is healthy at zero egress change); the ticket lands on the ISP-side runbook lane.

    Aug 19, 08:24:36 PM
  • T+13m
    Surfaced to human
    by agent → viewer-platform team
    act · surfaced to humans

    Cluster prewarmed low-bitrate variant for next weekday primetime broadcast window

    Viewer-visible configuration change required. The prewarmed low-bitrate variant on the affected cohort is configured at the viewer-platform team level — it ships before the next primetime window so a re-incident on as3356 / as5511 / as1299 lands already absorbed.

    Aug 19, 08:27:36 PM
  • T+15m
    Surfaced to human
    by on-call peer-cohort team
    act · surfaced to humans

    On-call acknowledged; peering-provider ticket filed for as3356 / as5511 / as1299

    Acknowledged within 92s; ticket filed for the affected AS block with the rtt_ms signature and the 90s window profile. On-call confirmed the multi-CDN health probe readings (cdn-a 38ms / cdn-b 39ms / cdn-c 41ms) — i.e. the CDN leg was healthy the entire window, the failure was ISP-side last-mile.

    Aug 19, 08:29:36 PM
  • T+20m
    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 cdn_failure · ruled out by lane, the multi-CDN health probe, and the recovery criteria section pinned from the timeline. The ISP-vs-CDN discriminator on cache.freshness + multicdn.winner_RTT appears in the recommended-fix section.

    Aug 19, 08:34:36 PM
  • T+27m
    Automated action
    by Streamwake reliability agent
    act · autonomous

    Re-probed cohort; cohort-side + last-mile close-out signals clearing

    cohort.cohort_join_stall_ratio settled at 0.024 (within baseline tolerance 0.05 over the same-length cohort window); cohort.cohort_rebuffer_ratio settled at 0.018 (within tolerance); cohort.cohort_startup_time_p95_ms settled at 2110ms (within baseline). isp.last_mile_rtt dropped to 164ms. cache.availability / cache.freshness / edge.geo_drift stayed pass throughout — those probes are NOT a close-out signal (the cache leg was healthy the entire window).

    Aug 19, 08:41:36 PM
  • T+41m
    Resolution
    by Operator + agent
    act · autonomous

    Incident resolved; prewarmed low-bitrate variant + ISP-side runbook lane active

    Cohort-side + last-mile close-out signals cleared: cohort_join_stall_ratio + cohort_rebuffer_ratio + last-mile RTT (NOT cache-side + cache.freshness, which were green the entire window). The ISP-vs-CDN discriminator on the multi-CDN health probe and the cache-side clean signal proves the CDN side never had to be touched — recovery is verified cohort-side on the affected cohort + on the affected AS blocks, NOT on the cache layer turning green again.

    Aug 19, 08:55:36 PM
Autonomous acts the agent did
Five events the Streamwake reliability agent executed without a human in the loop. Each one was a governed action that cleared the gate — never an override.
  • classify · ranked three hypotheses with confidence in 90s; cdn_failure · ruled out by tagged
  • egress tolerance · raised cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate under the confidence ≥ 0.80 + cohort_divergence gate
  • ISP reprobe · emitted triage_isp_congestion_reprobe under the isp.peer_congestion fails ≥ 3 AS blocks gate
  • status · observed cohort_rebuffer_ratio collapse behind the prewarmed variant at T+7 m
  • re-probe · verified the cohort-side + last-mile close-out signals cleared over the next same-length cohort window
Acts the agent surfaced to humans
Three events the agent did not act on its own — each one needed a configuration owner, a peering-provider on-call, or a team. The agent held off emitting a CDN-side re-route that would have masked the last-mile root cause.
  • on-call peer-cohort team · filed a peering-provider ticket for as3356 / as5511 / as1299 — the multi-CDN health probe proved the CDN leg is healthy at zero egress change
  • viewer-platform team · prewarmed low-bitrate variant configured before the next weekday primetime broadcast window
  • reliability team · assigned the public postmortem write-up (this page) — recovery criteria on the audit step is the cohort-side + last-mile close-out signal, NOT the cache-side re-anchoring
What Streamwake would have done

The Detect → Classify → Governed Fix walkthrough

Three steps that close the lane on an eu-west residential / ISP-vs-CDN disambiguation incident: the cache.availability + cache.freshness + edge.geo_drift + multicdn.winner_RTT discriminator that proves the CDN leg is healthy at zero egress change; the cohort-side + last-mile probe fan-in that ranks isp_congestion dominant; and the ISP/CDN rebalance lane that lets the agent mint a CDN-side re-route only when the cache-side probes flip, not the per-segment RTT lift alone.

01 · Detect
ISP-side + cache-side probe fan-in (lockstep)
Last-mile RTT probe, peer-congestion probe, retransmit-rate probe, and the four cache-side probes (availability, freshness, geo drift, multi-CDN health) running lockstep at 90s cadence so the discriminator lands.

The probe set fans in across the ISP-side peer sample (as3356 / as5511 / as1299) and the cache leg on cdn-A/fra9921. isp.last_mile_rtt reads 412ms vs 38ms baseline; tcp.retransmit_rate reads 14.2%; isp.peer_congestion reads fail on three AS blocks at once; the four cache-side probes read pass on the affected cohort; multicdn.winner_RTT reads 38/39/41ms on cdn-a/cdn-b/cdn-c — all three CDNs flat at baseline.

02 · Classify
isp_congestion · dominant @ 0.83
Ranked with cdn_failure · ruled out by (0.31) and transit_or_peering_failure (0.22) alternate.

The discriminator against the CDN-side lane is the cache.availability + cache.freshness + multicdn.winner_RTT pattern — the cache leg reads pass, freshness is anchored at age=0, and the multi-CDN health probe proves the CDN leg is healthy at zero egress change; the failure is last-mile-shaped, not cache-locale-shaped. The discriminator against the transit-side lane is the three-AS-block footprint — too wide a footprint for a single transit failure.

03 · Governed Fix
Surface peering ticket (humans) · rebalance CDN tier (autonomous)
Two paired branches — the autonomous branch raises CDN egress tolerance against the per-segment rebuffer pattern; the surfaced branch files a peering-provider ticket on the affected AS block.

The autonomous branch raises egress tolerance against the per-segment rebuffer pattern at the prewarmed low-bitrate variant — clears the cohort rebuffer within ~90s. The surfaced branch files a peering-provider ticket for as3356 / as5511 / as1299; the CDN side is NOT modified, the multi-CDN health probe proved it was healthy the entire window. Recovery is verified cohort-side on cohort_join_stall_ratio + cohort_rebuffer_ratio + last_mile_rtt over the next same-length cohort window.

Anatomy

Anatomy of the evidence packet

The two packets on the failing source — an eu-west residential / ISP-side congestion probe packet on the affected eu-west cohort (with the cache.availability + the multi-CDN health probe holding pass on the affected cohort while isp.last_mile_rtt + isp.peer_congestion fail on three AS blocks at once), and the agent timeline response with the ranked hypotheses, the cdn_failure · ruled out by lane, and the cohort-side + last-mile close-out signal. The probe packet is what the agent decided on; the timeline response is what the agent emitted.

ISP-side probe packet (eu-west residential cohort, T+0m)
GET /live/event/stream.m3u8 HTTP/1.1
host: cdn.example.com
accept: application/vnd.apple.mpegurl

----- cycle 0 (T+0m, before governed fix lands) -----
# eu-west residential cohort, single-edge synthetic session
HTTP/2 200
content-type: application/vnd.apple.mpegurl
server-timing: manifest-fetch;dur=138
x-served-by: cache-fra9921
x-cdn: cdn-A/fra9921

#EXTM3U
#EXT-X-VERSION:9
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:117204
#EXTINF:6.000,
117204.ts

# isp.peer_congestion on the affected region:    fail  (as3356-london rtt 412ms vs 38ms baseline, as5511-frankfurt 287ms vs 41ms baseline)
# isp.last_mile_rtt:                             fail  (412ms median segment-fetch RTT vs 38ms baseline — 10.8× delta)
# tcp.retransmit_rate on the affected peer sample: fail (14.2% vs 0.4% baseline — buffer pressure)
# cache.availability on the affected edge cohort: pass (X-Cache: HIT, age=0 — CDN cache is clean)
# cache.freshness on the master playlist:         pass (age=0 vs declared max-age=2 — CDN leg healthy)
# edge.geo_drift on the affected cohort:          pass (X-Served-By: cache-fra9921 matches eu-west expected; no Atlantic cross-POP)
# multicdn.winner_RTT on cdn-a / cdn-b / cdn-c:   pass (cdn-a 38ms, cdn-b 39ms, cdn-c 41ms — all three flat at baseline; no routing flip)
# origin.reachable on this source:                pass (origin shield reached in 102ms — unaffected)
# cohort.cohort_join_stall_ratio on the affected cohort:   fail (0.086 vs 0.018 baseline, 90s window)
# cohort.cohort_rebuffer_ratio:                   fail (0.054 vs 0.012 baseline — playback stalled upstream of the cache leg)
# cohort.cohort_startup_time_p95_ms:              fail (4810ms vs 1840ms baseline — TTFF spiked)
# isp.cell_load.on_affected_region:              fail (0.71 vs 0.43 baseline — uplink pressure);
# isp.affected_region_cohort_id:                 as3356 / as5511 / as1299 (eu-west residential ISPs)
# isp.last_mile_rtt_window:                      90s (rolling 90s window — last-mile profile distinctly off-baseline)

----- cycle 1 (T+~6m, after isp.peer_congestion_reprobe + prewarmed low-bitrate variant) -----
HTTP/2 200
content-type: application/vnd.apple.mpegurl
server-timing: manifest-fetch;dur=124
x-served-by: cache-fra9921
x-cdn: cdn-A/fra9921
x-variant-class: low-bitrate-prewarm-tier

#EXTM3U
#EXT-X-VERSION:9
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:117212

# isp.last_mile_rtt:                  164ms (down from 412ms — uplink pressure decaying under the prewarm variant)
# cohort.cohort_rebuffer_ratio:       0.018 (within baseline tolerance)
# cohort.cohort_startup_time_p95_ms:  2110ms (within baseline)
# cohort.cohort_join_stall_ratio:     0.024 (within baseline)
# cache.availability:                 pass (X-Cache: HIT — cache leg still clean)
# cache.freshness:                    pass (age=0 — CDN leg stayed clean through the entire window)
# edge.geo_drift:                     pass (X-Served-By: cache-fra9921 — no Atlantic cross-POP, even at zero egress change)
# multicdn.winner_RTT:                pass (cdn-a 38ms / cdn-b 39ms / cdn-c 41ms flat — the multi-CDN health probe proves the CDN is healthy)
# governed_action_emitted:            raise_cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate,
#                                      surface_peering_provider_ticket_for_as3356_as5511,
#                                      triage_isp_congestion_reprobe
ISP-side smoking gun (three-AS-block with cache leg staying green)
These are the four signals that, together, file the isp_congestion hypothesis — with the cache leg + multi-CDN health probe ruling cdn_failure out by name.
  • isp.last_mile_rtt 412ms (vs 38ms baseline — 10.8× delta)
  • isp.peer_congestion fail on as3356 / as5511 / as1299 (three AS blocks at once)
  • tcp.retransmit_rate 14.2% (vs 0.4% baseline — buffer pressure on the uplink)
  • cohort.cohort_join_stall_ratio 0.086 vs 0.018 baseline (90s cohort window)
  • cache.availability → pass; cache.freshness → pass (age=0 vs declared max-age=2); multicdn.winner_RTT → pass (38/39/41ms flat on cdn-a/cdn-b/cdn-c). The cache leg is healthy at zero egress change — NOT a cache-miss, NOT a cache-locale drift, NOT a multi-CDN routing flip.
Agent timeline response (ranked hypotheses + governed actions)
{
  "stream_id": "ckeuwISPvsCDNrecover5987",
  "source": "https://cdn.example.com/live/event/stream.m3u8",
  "protocol": "HLS / CMAF / cache-fra9921 / multi-CDN cdn-a|cdn-b|cdn-c",
  "checked_at": "2026-08-19T20:14:36Z",
  "ranked_hypotheses": [
    {
      "rank": 1,
      "hypothesis": "isp_congestion",
      "tag": "dominant",
      "confidence": 0.83,
      "evidence_signals": [
        "isp.peer_congestion → fail (as3356-london 412ms vs 38ms baseline / as5511-frankfurt 287ms vs 41ms baseline / as1299-stockholm 218ms vs 33ms baseline — last-mile RTT off-baseline by 8-12× across the eu-west peer sample)",
        "isp.last_mile_rtt → fail (412ms median segment-fetch RTT vs 38ms baseline — 10.8× delta — single-edge synthetic probe_latency.mp4 reads elevated)",
        "tcp.retransmit_rate → fail (14.2% vs 0.4% baseline — buffer pressure on the residential uplink)",
        "isp.cell_load.on_affected_region → fail (0.71 vs 0.43 baseline — uplink pressure on the residential AS block)",
        "cohort.cohort_join_stall_ratio → fail (0.086 vs 0.018 baseline, 90s cohort window — late-join stalled behind the uplink)",
        "cohort.cohort_rebuffer_ratio → fail (0.054 vs 0.012 baseline — playback rebuffer spiked well above the cache-side baseline)",
        "cohort.cohort_startup_time_p95_ms → fail (4810ms vs 1840ms baseline — TTFF past the 4s threshold)",
        "cache.freshness → pass (age=0 vs declared max-age=2 — CDN cache leg is healthy)",
        "cache.availability → pass (X-Cache: HIT — cache reads pass)",
        "edge.geo_drift → pass (X-Served-By: cache-fra9921 eu-west POP — no Atlantic cross-POP)",
        "multicdn.winner_RTT → pass (cdn-a 38ms / cdn-b 39ms / cdn-c 41ms — all three flat at baseline; multi-CDN health probe proves the CDN leg is healthy)",
        "origin.reachable → pass (origin shield reached in 102ms — origin leg unaffected)"
      ]
    },
    {
      "rank": 2,
      "hypothesis": "cdn_failure",
      "tag": "ruled_out_by",
      "confidence": 0.31,
      "evidence_signals": [
        "cache.freshness probe reads pass at the failed cohort, age=0 against a max-age=2 declared TTL — the master playlist is not stale-on-revalidate; the cache leg is healthy",
        "cache.availability probe reads pass on the affected edge POP — X-Cache: HIT under rebuffer load; no edge miss posture",
        "edge.geo_drift probe reads pass on the affected cohort — X-Served-By: cache-fra9921 (expected eu POP, no Atlantic cross-POP)",
        "multicdn.winner_RTT probe reads pass on cdn-a|cdn-b|cdn-c — all three CDNs flat at baseline; no CDN routing flip; the multi-CDN health probe rules the CDN leg healthy at zero egress change",
        "origin.reachable reads pass (102ms) — origin leg unaffected; the failure cannot be CDN-shaped while the multi-CDN health probe reads pass at zero egress change",
        "if a CDN-side cache miss were stateful, the affected cohort and adjacent eu-west cohorts on the same vendor would both misfire at the cache leg — they do not; the failure is last-mile-shaped, not cache-locale-shaped"
      ]
    },
    {
      "rank": 3,
      "hypothesis": "transit_or_peering_failure",
      "tag": "alternate",
      "confidence": 0.22,
      "evidence_signals": [
        "transit link probe to the regional POP reads pass; X-Served-By resolves to cache-fra9921 in eu-west with the expected RTT range; the transit-side link is not the failure lane",
        "if a regional transit failure were stateful, a regional POP failover would re-anchor the affected cohort — the affected POP has changed event since; the failure is subscriber-side, last-mile-shaped, not transit-side",
        "the ISP-side peer RTT lifted cleanly above the 412ms median across as3356/as5511/as1299 — three AS blocks at once — too wide a footprint for a single transit failure"
      ]
    }
  ],
  "governed_actions": [
    {
      "action":       "raise_cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate",
      "type":         "governed",
      "decision_lane": "autonomous",
      "gating":       "confidence >= 0.80 AND cohort_join_stall_ratio_active",
      "evidence":     "top-hypothesis confidence 0.83; cohort_join_stall_ratio divergence active on the affected cohort",
      "expected_effect": "rebuffer (cohort.cohort_rebuffer_ratio) clears within ~90s as the prewarmed low-bitrate variant absorbs the per-segment RTT lift; cohort_join_stall_ratio collapses below 0.05"
    },
    {
      "action":       "triage_isp_congestion_reprobe",
      "type":         "governed",
      "decision_lane": "autonomous",
      "gating":       "isp.peer_congestion fails on ≥ 3 eu-west AS blocks",
      "evidence":     "as3356 / as5511 / as1299 lift off-baseline at the affected cohort with the same rtt_ms signature",
      "expected_effect": "peer RTT re-probe on the affected cohort — confirms the failure lane is ISP-side not CDN-side before a peering-provider ticket is filed"
    },
    {
      "action":       "surface_peering_provider_ticket_for_as3356_as5511",
      "type":         "governed",
      "decision_lane": "surfaced_to_humans",
      "gating":       "asn_block_ticket_required",
      "evidence":     "as3356 / as5511 / as1299 lift off-baseline; isp.last_mile_rtt stays > 200ms across the affected cohort for 90s+",
      "expected_effect": "on-call files a peering-provider ticket for the affected AS block; CDN side NOT touched — the multi-CDN health probe proved the CDN leg is healthy at zero egress change"
    }
  ],
  "verification_window": {
    "close_out_signal": "cohort_side_with_or_without_cache_layer_pinning",
    "probes": [
      "cohort.cohort_join_stall_ratio within tolerance over the next same-length cohort window",
      "cohort.cohort_rebuffer_ratio within tolerance over the same window",
      "cohort.cohort_startup_time_p95_ms within tolerance over the same window",
      "isp.last_mile_rtt dropping below the 1.5s baseline resilience gate (NOT the cache layer returning to green)"
    ],
    "NOT_close_out_signal": [
      "cache.availability returning to X-Cache: HIT at zero egress change — passes geometrically, does not pass cohort-side",
      "cache.freshness re-anchoring to age < max-age — same caveat",
      "the multi-CDN health probe (multicdn.winner_RTT) reading green — proves the CDN leg is healthy, but does not on its own prove the cohort is delivering green playback when last-mile is degraded"
    ],
    "explicit_note": "'CDN is healthy' ≠ 'viewers are getting green playback'. Recovery is verified cohort-side on cohort_join_stall_ratio + cohort_rebuffer_ratio + last-mile RTT (NOT on the cache layer turning green again)."
  },
  "surfaced_to_humans": [
    {"owner": "on-call peer-cohort team", "task": "open a peering-provider ticket for as3356 / as5511 / as1299 with the rtt_ms signature and the 90s window profile"},
    {"owner": "viewer-platform team",       "task": "approve the prewarmed low-bitrate variant configuration before the next weekday primetime broadcast window"},
    {"owner": "reliability team",           "task": "assign the public postmortem write-up (this page) — recovery criteria on the audit step is the cohort-side + last-mile close-out signal, NOT the cache-side close-out"}
  ]
}
What the agent emitted (and what it did not)
The governed actions ship split: two autonomous under explicit gates; one surfaced because a peering-provider ticket requires human authority, not probe- driven rebalance.
  • autonomous raise_cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate
  • autonomous triage_isp_congestion_reprobe
  • surfaced surface_peering_provider_ticket_for_as3356_as5511
  • surfaced → paged on-call for the eu-west residential / ISP-side congestion root-cause review
  • close-out signal → cohort-side + last-mile: cohort_join_stall_ratio, cohort_rebuffer_ratio, isp.last_mile_rtt within tolerance over the next same-length cohort window — NOT cache.availability / cache.freshness / multicdn.winner_RTT returning to pass
Timing

Detection, classify, mitigate, recover (simulated telemetry)

Four timing windows on the postmortem timeline, each read off the cohort probe cadence. The figures are simulated telemetry — the disclosure near the top of this page applies to every figure on this list. Note that the close-out window is verified cohort-side on the affected cohort + last_mile_rtt (NOT cache-side + cache.freshness, which were green the entire window).

Detection

~5 s

isp.last_mile_rtt crossed 38ms→412ms within a 30 s window on cdn-A/fra9921; the agent surfaced the detector from the ISP-side lift at T+5 s.

Time to classify

~1 m

isp_congestion · dominant ranked at 0.83 confidence with three ranked hypotheses at T+1 m — discriminator is cache.availability + cache.freshness + multicdn.winner_RTT reading pass on the affected cohort.

Time to mitigate

~7 m

raise_cdn_egress_tolerance_to_rebuffer_tolerance_at_low_bitrate + triage_isp_congestion_reprobe queued at T+2 m and T+4 m; cohort re-anchored by T+7 m.

Time to full recovery

~27 m

cohort.cohort_join_stall_ratio + cohort.cohort_rebuffer_ratio + isp.last_mile_rtt cleared within tolerance at T+27 m — cohort-side + last-mile close-out, NOT cache-side re-anchoring.

Recommended fix (Governed)

Open a peering ticket — and re-tune the CDN egress tolerance.

On an eu-west residential / ISP-vs-CDN disambiguation incident, the governed fix is a two-arm branch: a CDP-side rebalance arm that holds the CDN leg healthy, and an ISP-side runbook arm that surfaces a peering-provider ticket on the affected AS block. The two arms close the lane in the same incident window and forward.

01Surface a peering-provider ticket on the affected AS block
surfaced to humans

File a peering-provider ticket for the affected AS blocks (as3356 / as5511 / as1299) with the rtt_ms signature and the 90s window profile. The fix is surfaced to humans because it requires an ASN-block engagement the CDN cannot perform — the multi-CDN health probe (multicdn.winner_RTT) proved the CDN leg is healthy at zero egress change, so the CDN side is NOT touched; the ticket lands on the ISP-side runbook lane.

Verification (cohort-side + last-mile)

cohort.cohort_join_stall_ratio clears below 0.05 on the affected cohort within ten consecutive 30-second windows; cohort.cohort_rebuffer_ratio settles within baseline tolerance; isp.last_mile_rtt drops below the 1.5s baseline resilience gate on the same cadence.

NOT a close-out signal: cache.availability returning to X-Cache: HIT at zero egress change, or cache.freshness re-anchoring. The cache leg was green the entire window; reading the cache-side probes as the close-out signal misses the lane forward.

02Raise CDN egress tolerance vs the per-segment rebuffer pattern
agent-emitted

Raise CDN egress tolerance against the per-segment rebuffer pattern at the prewarmed low-bitrate variant — the CDN absorbs the per-segment RTT lift under the reduced-bitrate profile and the cohort rebuffer clears within ~90s. Autonomous under a confidence-and-cohort-divergence gate (confidence ≥ 0.80 + cohort_divergence_active) and surfaced to humans outside that gate so the operator team can review the false-positive rate before the egress tolerance lands.

Verification (cohort-side)

cohort.cohort_rebuffer_ratio settles under 0.05 on the affected cohort within ten consecutive 30-second windows; cohort.cohort_startup_time_p95_ms stays within baseline tolerance across consecutive primetime broadcast windows; the prewarmed low-bitrate variant ships configured for the next primetime window so a re-incident on as3356 / as5511 / as1299 lands already absorbed.

NOT a close-out signal: multicdn.winner_RTT or edge.geo_drift re-anchoring on the affected cohort at zero egress change. Those probes prove the CDN leg is healthy but do not on their own prove the cohort is delivering green playback when last-mile is degraded.

Caveat — recovery is cohort-side + last-mile, not cache-side
'CDN is healthy' ≠ 'viewers are getting green playback'
The cache leg returning green (or staying green) is geometric close-out, not cohort-side close-out. The actual close-out signal is the affected cohort's cohort_join_stall_ratio, cohort_rebuffer_ratio, and isp.last_mile_rtt clearing tolerance over the next same-length cohort window.

A fix that normalizes multicdn.winner_RTT + cache.availability + cache.freshness without clearing the affected cohort's join stall, cohort rebuffer, or last-mile RTT within tolerance is a fix that didn't reach the cohort. The audit step on this incident writes the close-out signal into the playbook as "verify the affected cohort's cohort_join_stall_ratio + cohort_rebuffer_ratio + isp.last_mile_rtt settle within tolerance over the next same-length cohort window" — not "verify the cache leg returning to green / verify the multi-CDN health probe returning to pass".

Next step

Want Streamwake to disambiguate ISP-vs-CDN on your cohort?

Sign up, register an ISP-side or CDN-side probe, and the same isp.peer_congestion · cache.freshness · multicdn.winner_RTT · cohort.cohort_join_stall_ratio probes that produced the timeline above run on every prime-cohort refresh — and surface in a Slack channel, a webhook, or the streams dashboard.

Synthetic Incident — This scenario uses simulated telemetry constructed from documented streaming behaviors. It does not represent a Streamwake customer outage.

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: ISP congestion vs CDN failure.)
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.
Read the next

Related writeups

The closest siblings cover the player-visible symptom lands: the broader ISP-vs-CDN triage guide at /troubleshooting/isp-congestion-vs-cdn-failure (the eight-symptom read), the origin-shield queue saturation write-up (origin-shield queue depth + queue p99 wait failing while edge egress stays green), the manifest fetch timeout storm at a regional edge POP (a regional edge POP returning manifest-timeouts above baseline during a quiet pre-peak window), and the live-event scale-out buffering postmortem (a marquee broadcast with a viewer-spike that pushes the cohort beyond the pre-provisioned capacity envelope). Together they cover the four failure-mode lanes Streamwake reliability agents are tuned for alongside ISP-vs-CDN disambiguation.