One ad break, seven records, one first disagreement
Discrepancies usually get argued at the end of the chain, as two totals that do not match. OpenCTV walks the chain in order instead, and stops at the first step where the evidence no longer agrees with the step before it.
- 1DecisionOpenRTB
- 2Ad responseVAST
- 3InsertionSSAI, SGAI
- 4 ยท first divergenceManifestHLS
- 5PlaybackPlayer
- 6MeasurementBeacons
- 7BillingReconciliation
sketch, not real output ad response creative 30.0s VAST insertion break filled 30.0s stitcher log manifest break window 15.0s HLS DATERANGE first divergence insertion โ manifest
In the sketch, the stitcher filled a 30 second break but the manifest only opened 15 seconds of it. Everything downstream is internally consistent and still wrong: the player shows half the ad, the later quartile beacons never fire, and the invoice and the measurement report will not reconcile.
The decision stage is classified but not executed. Bid-side signals cannot be observed end to end by any one party, so OpenCTV names those failures without pretending to replay them. HLS comes first; DASH is out of scope for the first release.
Four kinds of output, kept apart on purpose
Most tools blur what they saw with what they concluded. OpenCTV keeps them separate, and when the evidence runs out it says so instead of guessing.
evidenceWhat a system emitted
A record of what one system actually produced, with where it came from and when.
changeWhat moved between looks
What differs between two observations of the same thing, such as two refreshes of one manifest.
findingA named divergence
A divergence matched to a library entry, carrying the chain of evidence that supports it.
unresolvedWhat the evidence cannot settle
Where the trail stops, what is missing, and what would settle it. Insufficient evidence is an answer.
Five pieces, each useful on its own
They ship in this order, and the last one ties the first four together. Each release is announced here and on GitHub when it is ready, not on a date.
divergence-library
A taxonomy of how CTV ad transactions go wrong, and the shared schemas the other four depend on. Every entry starts from a specification read or a failure observed. None are generated.
hls-manifest-diff
Compares two HLS manifests by meaning rather than by text, and shows what actually changed. Built to be useful to streaming engineers who never touch advertising.
stream-fixtures
A reproducible corpus of broken streams, each tied to a library entry and checked byte for byte, so a defect can be handed over as something to run rather than something to describe.
cuechain
Follows one ad break signal from SCTE-35 through every cue that claims to represent it, and reports where they stop telling the same story.
openctv
One command, one report, one evidence chain. Runs on your machine with a local UI and exports a single HTML file you can attach to a ticket.
Code under Apache-2.0. The library, schemas and fixtures under CC-BY-4.0.
How the work gets done
OpenCTV replaces no standard and no vendor tool. It is the layer between them: the part nobody owns, and the part where most of the failures actually live.
Depend, never reimplement
Existing open parsers and test servers are used as they are. Published specifications decide every rule.
Evidence or nothing
Every finding cites what it rests on. A gap in the evidence is reported as a gap, never filled with a plausible story.
Releases, not dates
Something ships when it installs clean, its quickstart works and its tests pass. The roadmap carries no dates.
Local first
It runs against your own captures on your own machine. There is no hosted service to send traffic to.