The broadcast becomes the data feed.
Video in, settlement decision out. Frames are sampled, the regions an adapter declares are read, a reconciler argues the reads against each other across time, and what survives is one candidate with a confidence tier. The tier decides what is allowed to happen to money — and three of the four tiers decline to pay.
A recorded VOD today; the live source exists but has never been run.
Frames pulled on the adapter's declared cadence, not every frame.
Only the boxes the adapter declares are read, gated by a presence probe.
Debounce and guards across frames — one bad frame cannot become an outcome.
At most one per game: a score, a winner, and a confidence tier.
Vision proposes. The gate disposes, and applies the tier as a ceiling.
These are bench results, not production results.
Everything below comes from an internal accuracy harness run against recorded video — publicly available match uploads, cited by clip id. It is not a sample of live traffic, because there is none: PLLAY Vision has never been run against a live stream. A bench of recorded footage is a weaker claim than production volume, and publishing it as what it is beats implying what it isn't.
- Each clip runs the full pipeline, not a replay of a saved read — the same extractor, reconciler, and gate the service uses.
- The run exits non-zero if, and only if, a wrong auto-settlement occurred. A single wrong payout fails the run outright; nothing else can.
- Every trial writes a row: clip id, adapter, tier, outcome, and the reason. That file is what this page reads at build time.
- Processing takes 2.4s–19 minutes of wall clock per clip. This is a batch process. Nothing here is real-time, and nothing here settles anything.
Correct means the system behaved as designed — which includes refusing. A trial that declined to settle ambiguous footage is correct. A trial that returned the winner but flagged it for review is correct.
So the totals below are deliberately never shown as a ratio. A correct/total fraction would read as an accuracy rate, and it is not one — it would count every refusal as a success in a way that flatters the number.
A wrong auto-settlement is the only failure that costs a user money: an automatic settle that paid the wrong side.
Where every trial landed.
One tier settles. The other three are the product. A system that pays out confidently when it is right is ordinary; a system that reliably refuses when it is unsure is the thing worth building, and the only thing worth trusting with a pool of other people's stakes.
Terminal score stable, high-confidence, and unanimous. The only tier that can move money.
31Readable, but not clean enough to pay on: two signals disagree, or a scoreboard read leaned on a low-confidence frame or recovered from lost continuity. Downgraded, never auto-paid.
1The terminal state has no winner. Stakes are returned rather than guessed at.
2No candidate cleared the bar at all. Silence is recorded as silence, never read as an outcome.
431 settled · 7 declined · 0 paid the wrong side
The trials that declined to pay.
These are the most informative rows in the record, so they are named individually rather than summarised. In each case the footage was readable enough that a less careful system would have produced an answer.
FINAL banner score disagrees with in-game bar (read discrepancy) -> hold for confirmation
madden26_ea_broadcast.json · clip Ukxgys0alBs
voided (terminal score is a tie -> void_and_refund)
cs2_matchresult.json · clip xBJMU3WYn_I
no candidate (safe) — EXPECTED for this clip
cs2_matchresult.json · clip tPjEdpdRQGQ
no candidate (safe) — EXPECTED for this clip
madden26_ea_broadcast.json · clip XBhsOfXEDa4
no candidate (safe) — EXPECTED for this clip
dota2_victory.json · clip rgQU28d2y9s
no candidate (safe) — EXPECTED for this clip
r6_result.json · clip dlUFN2avVxs
voided (terminal score is a tie -> void_and_refund)
ow2_result.json · clip UjT_U_7GP68
On a tournament-platform broadcast, the end banner names the winning team rather than printing the result word the adapter was calibrated for. The wider banner fragments across detections and the read falls below the confidence floor, so nothing settles. The point of view player's team had in fact won — a confident wrong read here would have paid out.
Closing this is a new calibrated adapter for that overlay, not looser matching logic. Loosening the matcher is how a system starts guessing.
Several refusals share one cause: the upload cuts before the screen that actually declares the result. A game-winning play is visible, the celebration is visible, and the terminal frame never arrives. The system holds.
One of them is a win whose upload ends on a flavour-texted victory splash that is deliberately excluded as a read surface, because its wording varies. Holding is the designed behaviour, not a miss.
14 games with a measured record.
Grouped by the identifier each adapter declares for itself, so a title with more than one calibrated overlay is one row here and its adapter files are both named. Coverage is uneven on purpose — a title is added by finding footage of both outcomes, not by writing a plausible adapter and assuming.
| Game | Adapters | Trials | Settled | Declined |
|---|---|---|---|---|
| overwatch-2 | ow2_result.json | 5 | 4 | 1 |
| league-of-legends | lol_result.json | 4 | 4 | 0 |
| cs2 | cs2_matchresult.json | 3 | 1 | 2 |
| fortnite | fortnite_result.json | 3 | 3 | 0 |
| madden | madden26_ea_broadcast.json, madden26_final_banner.json | 3 | 1 | 2 |
| rainbow-six-siege | r6_result.json | 3 | 2 | 1 |
| rocket-league-sideswipe | sideswipe_winner.json | 3 | 3 | 0 |
| apex-legends | apex_result.json | 2 | 2 | 0 |
| dota2 | dota2_victory.json | 2 | 1 | 1 |
| nba2k | nba2k26_broadcast.json | 2 | 2 | 0 |
| pubg | pubg_result.json | 2 | 2 | 0 |
| rocket-league | rocketleague_winner.json | 2 | 2 | 0 |
| valorant | valorant_result.json | 2 | 2 | 0 |
| warzone | warzone_summary.json | 2 | 2 | 0 |
There are 22 adapter files in the repository. 15 of them have trials on the record above. The remaining 7 have never been run against footage — some are placeholders written ahead of a game's release, some are superseded calibrations kept for reference. They are not supported titles and are not counted as any.
A new title is mostly a new config file.
An adapter is a JSON file describing where on screen to look and what the words there mean: normalised boxes, the token vocabulary that maps to an outcome, and the reconciler thresholds that guard it. Supporting a broadcast overlay is calibration against real frames rather than an engineering project — with an honest caveat: the engine has occasionally had to change, and each time it was because a game exposed a genuinely new settlement shape rather than a new layout.
The end screen is the only evidence stream. A presence probe gates every frame cheaply, and when the result banner appears its wording maps to a winner. Most titles are this shape, because most end screens simply name the outcome.
Sports broadcasts carry a running score as well as a final card, giving two independent readings of the same fact. That redundancy is what makes the disagreement guard possible: when the two do not agree, the settlement is downgraded rather than resolved in favour of whichever read looked stronger.
Every region declared across the 15 benchmarked adapters. There is nothing here that reads chat, a kill feed, or player identity — the settlement path looks at scoreboards, result banners, and the clock, and at nothing else.
A presence probe answers only “is the overlay on screen”, so frames showing a replay, a cutscene, or an advert cost almost nothing and contribute nothing. Text regions must match a declared token to count; a value the adapter does not recognise becomes nothing rather than a guess.
All 38 trials.
The complete record, in the order the harness ran it. Clip identifiers are the public uploads each trial was run against, so any row here can be checked against the footage it came from.
Open the full record →
| Trial | Adapter | Clip | Outcome | Tier | Processing |
|---|---|---|---|---|---|
| madden-walkoff-banner | madden26_final_banner.json | Ukxgys0alBs | 32-34 away | AUTO | 42.2s |
| madden-walkoff-dual | madden26_ea_broadcast.json | Ukxgys0alBs | 32-34 away | CONFIRM | 119s |
| nba2k-houmil | nba2k26_broadcast.json | vw6h2mrWkRY | 135-126 home | AUTO | 708.2s |
| cs2-tie | cs2_matchresult.json | xBJMU3WYn_I | VOID | VOID | 428s |
| cs2-win-pov | cs2_matchresult.json | WZQ2uQq8tjk | 1-0 home | AUTO | 164.5s |
| cs2-faceit-hold | cs2_matchresult.json | tPjEdpdRQGQ | HOLD | HOLD | 465.9s |
| dota-dire-victory | dota2_victory.json | jRRDQ5VOR6E | 0-1 away | AUTO | 2.4s |
| fortnite-win | fortnite_result.json | HK3Wd-w2SJI | 1-0 home | AUTO | 1089.5s |
| fortnite-loss | fortnite_result.json | Ip4FwkQwZrQ | 0-1 away | AUTO | 868.8s |
| madden-ot-cut | madden26_ea_broadcast.json | XBhsOfXEDa4 | HOLD | HOLD | 519.9s |
| dota-team-lobby | dota2_victory.json | rgQU28d2y9s | HOLD | HOLD | 611.6s |
| nba2k-minokc | nba2k26_broadcast.json | 2lqbuJhcxso | 34-38 away | AUTO | 480.9s |
| warzone-win | warzone_summary.json | vAkzIZCL2iI | 1-0 home | AUTO | 1153.6s |
| warzone-loss | warzone_summary.json | 99-OtWZK7Rs | 0-1 away | AUTO | 1054.5s |
| valorant-win-surrender | valorant_result.json | ASjWottDK6s | 1-0 home | AUTO | 433s |
| valorant-loss | valorant_result.json | qjOIE4UBZhQ | 0-1 away | AUTO | 307.3s |
| rocketleague-blue-win | rocketleague_winner.json | 2KyScgSWUqM | 1-0 home | AUTO | 167s |
| rocketleague-orange-win | rocketleague_winner.json | XoDgXubVawM | 0-1 away | AUTO | 223.8s |
| fortnite-loss-ch6 | fortnite_result.json | JieJN4Bjrpk | 0-1 away | AUTO | 937.5s |
| apex-win | apex_result.json | WFBCi-ta168 | 1-0 home | AUTO | 888.8s |
| apex-loss | apex_result.json | XFq3wYbI9JM | 0-1 away | AUTO | 26s |
| lol-win-720 | lol_result.json | o4dsmNKsSIA | 1-0 home | AUTO | 51.9s |
| lol-win-1080 | lol_result.json | lFXLzuvlTpM | 1-0 home | AUTO | 51.4s |
| lol-defeat-720 | lol_result.json | 13gF_JO-FjE | 0-1 away | AUTO | 72.5s |
| lol-defeat-1080 | lol_result.json | YORYLUNLJw4 | 0-1 away | AUTO | 76.5s |
| r6-victory-1080 | r6_result.json | lqZ-uH-jDHM | 1-0 home | AUTO | 234.9s |
| r6-defeat-720 | r6_result.json | A0YDZ7k4-9w | 0-1 away | AUTO | 136s |
| r6-splash-only-hold | r6_result.json | dlUFN2avVxs | HOLD | HOLD | 98.8s |
| pubg-win-chickendinner | pubg_result.json | UrOwJPNqj_s | 1-0 home | AUTO | 221.9s |
| pubg-loss-betterluck | pubg_result.json | izzLxN2jhRE | 0-1 away | AUTO | 212.9s |
| ow2-victory-1080 | ow2_result.json | UjT_U_7GP68 | 1-0 home | AUTO | 8.9s |
| ow2-defeat-1080 | ow2_result.json | UjT_U_7GP68 | 0-1 away | AUTO | 8.8s |
| ow2-draw-void | ow2_result.json | UjT_U_7GP68 | VOID | VOID | 9.5s |
| ow2-defeat-720 | ow2_result.json | KKDWc2zpPCw | 0-1 away | AUTO | 66.3s |
| ow2-defeat-1080-b | ow2_result.json | 5h-8Ajy5tK8 | 0-1 away | AUTO | 84s |
| sideswipe-away-169 | sideswipe_winner.json | hhXtXyKGOsA | 0-1 away | AUTO | 120.2s |
| sideswipe-home-209 | sideswipe_winner.json | qbQTl9JS_k8 | 1-0 home | AUTO | 13.9s |
| sideswipe-away-209 | sideswipe_winner.json | qbQTl9JS_k8 | 0-1 away | AUTO | 12.2s |
The gates were built before the automation.
The honest summary is that the safety machinery is finished and the automation is not. The queue, the audit trail, the off switch, and the rule that this service can only ever propose a settlement are all in place — and nothing is deployed behind them. That ordering was deliberate, and stating it plainly is more useful than a launch date.
The pipeline and its guards
Frame sampling, per-region OCR, and the reconciler run end to end today. Every guard the offline suites cover runs on every trial in the record above.
The durable job queue
A vision_jobs table and a claim function exist in the database, so runs can be queued and claimed rather than executed by hand from a laptop.
The off switch, shipped off
Autonomous settlement is gated behind a platform config flag that ships disabled. The gate was built before the automation it gates, deliberately.
Propose-only by construction
The worker process never calls a settlement function. It writes a verdict and hands it to the resolution layer, which treats the tier as a ceiling on what may happen next.
Shadow mode
One worker, running against live footage, writing verdicts to the audit log and settling nothing. Comparing those verdicts against what actually settled is the only honest way to earn the right to automate.
Deployment
There is no container image and no deploy configuration for the vision service anywhere in the codebase, and continuous integration runs only the offline suites. It runs where an engineer runs it, and nowhere else.
Live ingest
A live frame source is written and unit-tested against the reconciler's wall-clock guards. Nothing calls it. PLLAY Vision has never been pointed at a live stream.
No pilot is open, no availability is being offered, and no date is being given for any of the above. The next honest milestone is shadow mode, and until its verdicts have been compared against real settlements there is nothing further to claim.
Watch a real run, frame by frame.
A single trial from the record above, played back against the reconciler's own log — what it saw, when it changed its mind, and why it landed where it did.