# TAKEABLE-ENFORCEMENT AUDIT **Date:** 2026-08-02 ยท **READ-ONLY** โ€” nothing enforced, built or fixed. The five accruing challengers were not touched. --- ## VERDICT: ๐Ÿ”ด GAPS EXIST, AND ONE IS LIVE CONTAMINATION OF THE LEDGER > **The ledger โ€” the exact table every accruing holdout resolves against โ€” is > stamping `book`, `locked_odds` and the `takeable` flag itself from books you > cannot bet: DFS pick'em, offshore, and exchanges.** > > **0% before 2026-08-01. 47.9% on 08-01. 42.5% on 08-02.** > > **I caused this.** It started the day I widened the books for display. **Enforcement is the next order, ahead of `hits`.** --- ## PER-PATH ANCHOR REPORT | path | anchors to | takeable? | |---|---|---| | **PROJECTION** | `g.line` via `dedupeProps` โ†’ `MODEL_BOOKS` | โš ๏ธ **model-gated, not takeable-gated** | | **GRADE** | same | โš ๏ธ same โ€” clean in practice today | | **CHALLENGERS** (arch-v1, tb-v1, proj-v1.1) | read off the grade | โœ… inherit the grade's anchor | | **LEDGER** | `prop.book` / `oddsForSide(prop)` over the **full widened props list** | ๐Ÿ”ด **CONTAMINATED** | | **DISPLAY / RANKING** | `takeablePWin` โ†’ `isTakeable(price)` | โš ๏ธ gate is correct, **but applied to a contaminated price** | ### The grade path is clean *today*, but not by construction Served snapshot, 428 grades: **draftkings 422, fanduel 6 โ€” 100% MODEL books.** `dedupeProps`' `MODEL_BOOKS` filter works. **But `MODEL_BOOKS` โŠ„ `TAKEABLE_BOOKS`.** `MODEL_BOOKS` contains **`pinnacle`**, which `isTakeableBook` correctly excludes โ€” it is a reference book, not a US retail one. So the projection *may* anchor to a reference line by design. **Currently harmless** (pinnacle has returned 0 props since 07-31) and therefore **exactly the kind of latent gap that bites when the feed recovers.** --- ## THE CONTAMINATION, LOCATED `ledgerService.recordPipelineGrades`: ```js const byKey = indexProps(oddsProps); // โ† the FULL, display-widened list const prop = byKey[`${nameKey(player)}|${stat}`]; // โ† first match wins ... locked_odds: locked.odds != null ? String(locked.odds) : oddsForSide(prop, side), takeable: takeableFor(locked.odds != null ? locked.odds : oddsForSide(prop, side)), book: (prop && prop.book) || g.book || null, ``` The grade is computed on a MODEL book, then the ledger row is **re-stamped** from whatever book happened to index first in the widened list. ### Books actually stamped on ledger rows since 2026-08-01 | book | rows | role | settled | |---|---:|---|---:| | draftkings | 518 | โœ… takeable | 49 | | **dabble** | **707** | ๐Ÿ”ด **DFS pick'em** | **44** | | betmgm | 348 | โœ… takeable | 126 | | hardrockbet | 298 | โœ… takeable | 0 | | **bovada** | **214** | ๐Ÿ”ด reference/offshore | 3 | | **onexbet** | **42** | ๐Ÿ”ด excluded | 0 | | **pinnacle** | **36** | ๐Ÿ”ด reference | 0 | | **kalshi** | **7** | ๐Ÿ”ด exchange โ€” mean \|odds\| **1120** | 0 | **`dabble` alone is 24% of all rows.** `kalshi`'s mean absolute price of **1120** is a self-evident tell: no US bettor is taking that as the anchor of a graded prop. ### What is confirmed contaminated, and what is not **Confirmed:** `book`, `locked_odds`, and **`takeable`** โ€” the flag is computed *from* the contaminated price, so it is not merely mislabelled, it is **wrong on its own terms**. **Not confirmed:** `line`. It comes from `locked.line`/`g.line`, which trace to the graded (model-book) prop. **I did not verify it end-to-end and am not claiming it is clean.** The enforcement order should check it. ### Blast radius on the accruing verdicts โ€” bounded, but growing | | settled rows since 08-01 | |---|---:| | clean-book | 178 | | **contaminated-book** | **47 (21%)** | **Most contaminated rows have not settled yet** โ€” 707 `dabble` rows are pending and **will settle into the holdouts tonight and tomorrow.** The damage is mostly *ahead* of us, which is what makes this urgent rather than merely historical. --- ## PREDICTION-TARGET vs REFERENCE-RULER โ€” the distinction holds **Do NOT over-enforce takeable onto the reference ruler.** They answer different questions and collapsing them would break market measurement: | quantity | must be | current | correct? | |---|---|---|---| | the line the model **projects against** | **TAKEABLE** | model-gated | โš ๏ธ gap | | the price the row is **scored on** (`locked_odds`) | **TAKEABLE** | contaminated | ๐Ÿ”ด gap | | `fair_prob` / consensus / `edge` diagnostics | **REFERENCE** (incl. exchanges, pinnacle) | reference | โœ… **correct โ€” leave alone** | `bookRoles`' three-way split is right and must not be collapsed. **The bug is not the split โ€” it is that one write path ignores it.** --- ## SEQUENCED STACK **(a) ๐Ÿ”ด TAKEABLE ENFORCEMENT โ€” next order.** Index the ledger's prop lookup over **takeable books only**, verify `line` end-to-end, decide whether `pinnacle` may anchor a projection (it may price the *ruler*, but should it price the *target*?), and decide what to do with the ~1,031 already-contaminated rows: **re-stamp, or tag and exclude from holdouts.** Do not silently pool them. **(b) Structural `Number(null) === 0` guard.** Six occurrences, the most recent in my own new module yesterday. A shared unknown-vs-zero helper. **`hits` will re-trigger it** โ€” its 0.5 lines make P(0) the whole game, and a null rate read as zero is maximally wrong exactly there. **(c) `hits` fix** โ€” built on both invariants above, not before them. **Carry-forward:** the tb-v1 verdict (accruing, slower clock) ยท the third pre-registered branch (*improves ranking but stays low โ†’ promote **and** recalibrate*) ยท the **100s Cloudflare origin timeout** on a ~115s snapshot (the work completes server-side, but the trigger returns 524 โ€” worth a flag before it is mistaken for a failure). ## TAGS **VERIFIED:** ledger `book`/`locked_odds`/`takeable` contaminated on 42โ€“48% of rows since 2026-08-01, 0% before ยท leak located at `recordPipelineGrades`' index over the widened props list ยท served grade path clean today (100% MODEL books) ยท `MODEL_BOOKS` โŠ„ `TAKEABLE_BOOKS` via `pinnacle` ยท 47 contaminated rows already settled, ~700 pending. **NOT VERIFIED:** whether the stored `line` is also contaminated. Check it in the enforcement order rather than assuming either way.