Files
vyndr/specs/order-zero-widening.md
T
builtbykev c79528abae Order Zero: tier-reality report + widening fingerprint
PHASE 1 resolved on our real keys, and a bad source was discarded on the
way: a fetched rendering of PropLine's docs "tier matrix" claimed
/odds/closing is 403 on free and that /odds returns prices nulled on free.
Both are contradicted by direct observation (200-redacted, and 6,196
two-sided PRICED groups on MLB). Not cited. The report uses only the
machine-readable OpenAPI contract and the verbatim detail bodies our keys
received.

Verdict: every one of the six endpoints behaves exactly as the Free tier's
published contract says. error:"upgrade_required" with an explicit
required_tier is unambiguous -- NOT a key-permission problem, NOT a plan
problem. $9/mo Hobby buys /results + /odds/closing (the CLV instrument) +
/movement (steam across 18 books); $19/mo Pro adds the 90-day settlement
export. Priced and evidenced; not recommended here -- it is a decision.

PHASE 2 fingerprint on the SERVED feed: 5 books -> 13, props rendered
546 -> 2,780 (5.1x), mean 4.22 books/prop.

The unflattering half, stated up front: of 2,234 newly-visible props only
698 (31.2%) carry a real non-DFS market price; 1,536 (68.8%) are DFS-only
pick'em rows. The honest headline is not "80% of the slate unlocked" --
the board is 5x fuller, about a third of the new depth is real market
data, and the rest is pick'em inventory now shown but tagged.

PHASE 3 verified: 546 gradeable props, unchanged. CURRENT_RULER_VERSION
still v1_first_book.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-08-01 00:57:12 -04:00

7.5 KiB
Raw Blame History

Order Zero — TIER REALITY + AGGREGATOR WIDENING

Date: 2026-08-01 · Phase 1 verified on our real prod keys · Phase 2 LIVE · Phase 3 model path byte-identical.

Gates: 4,028 tests / 322 suites green · next build exit 0 · tier-reality report per endpoint · widening fingerprinted on the served feed · model input unchanged.


PHASE 1 — THE FREE-TIER DISCREPANCY, RESOLVED

The order was right to demand this. I found and discarded a bad source on the way. A fetched rendering of PropLine's docs "tier matrix" claimed /odds/closing is 403 on free and that /odds returns prices nulled on free. Both are contradicted by direct observation: we get 200 redacted on /odds/closing, and 6,196 two-sided PRICED prop groups on MLB /odds. That matrix is not cited anywhere below.

Two authoritative sources are used instead: the machine-readable OpenAPI contract, and the verbatim detail bodies our own keys received.

The verdict per endpoint

endpoint our keys verbatim reason verdict
/events/{id}/results 403 upgrade_required · required_tier: "hobby" · "Prop resolution is a paid feature — start at $9/mo Hobby" Free-tier exclusion. $9/mo.
/exports/resolved-props 403 ×4 sports upgrade_required · required_tier: "pro" · "Resolved-prop exports are a Pro feature" Free-tier exclusion. $19/mo.
/events/{id}/odds/closing 200, 1,847 outcomes, 0 priced, upgrade_url present OpenAPI: "Paid tiers: full data. Free tier: redacted (structure only)." Free-tier redaction. $9/mo.
/events/{id}/movement 200, 1,847 outcomes, 0 priced, steam: [] OpenAPI: "Paid tiers (Hobby+): full data. Free tier: redacted." Free-tier redaction. $9/mo.
/events/{id}/context (MLB) 200, full data Free. Works.
/events/{id}/context (WNBA) 404 · "No context on file for this event yet." Not a tier issue — MLB-only coverage.

It is NOT a key-permission problem and NOT a plan problem. The keys return exactly what the Free tier's published contract says they should, on every one of the six endpoints. error: "upgrade_required" with an explicit required_tier is as unambiguous as this gets.

What money would buy

tier cost unlocks
Hobby $9/mo /results (settled outcomes + actual values) · /odds/closing (the CLV instrument) · /movement (steam across 18 books) · /odds/history (30d) · /players/trends + /history · /ev
Pro $19/mo the above + /exports/resolved-props90-day bulk settlement CSV incl. closing price, the backtest input

$9/mo buys the two instruments we have been unable to build — a real closing line and cross-book steam. /exports/odds-history (the full tick firehose) stays Enterprise-only at any price we'd consider.

I am not recommending the spend in this order. It is a decision, priced and evidenced, for you to make.


PHASE 2 — AGGREGATOR WIDENING (LIVE)

normalizeProps now emits every DISPLAY book instead of 5 of 18.

Fingerprint — the SERVED MLB feed, post-deploy

before after
distinct books served 5 13
book rows 11,737
props rendered (player+stat) 546 2,780
mean books/prop ~0.6 4.22

Props that render now and rendered nothing before: 2,234. The slate a user sees is 5.1× larger.

The part that isn't flattering, stated up front

Of those 2,234 newly-visible props:

  • 698 (31.2%) carry at least one real non-DFS market price — genuinely new market data.
  • 1,536 (68.8%) are DFS-only — PrizePicks/Underdog/Sleeper/Dabble rows, which are not a market at all.

So the honest headline is not "80% of the slate was unlocked". It is: the board is 5× fuller, about a third of the new depth is real market data, and the rest is pick'em inventory that is now shown but tagged.

Served role mix: dfs 8,515 · reference 2,042 · both 791 · offshore 389.

book_role is load-bearing, not decorative

Every row carries book_role ∈ {both, takeable, reference, dfs, offshore} — through the normalizer and through the odds route's grouping, which was silently dropping it.

Why it matters, from live data. On one MLB prop:

betmgm      +450 / -750     ← a real two-way market
prizepicks  +100 / +100     ← fixed-payout pick'em

Rendered side by side untagged, the PrizePicks row reads as a dramatically better price. It is a different product. Untagged breadth would have been a new way to mislead, dressed as a feature — which is exactly what the split exists to prevent. Consumers gate on book_role !== 'dfs' before treating a row as a market price.

The ?book= filter now accepts any DISPLAY book, since shopping a real book against an exchange is the point.


PHASE 3 — THE MODEL DOES NOT MOVE

bookRoles.js splits MODEL_BOOKS (the legacy allow-list, character for character) from DISPLAY_BOOKS. Both model paths re-filter before they pick a line:

  1. gradeSlateService.dedupeProps — filters to MODEL_BOOKS before first-row-wins and before the 25-prop limit, so the graded set is byte-identical through the widening. A test asserts exactly this.
  2. intradayRefreshService.indexOddsProps — the one that would have bitten. It re-grades props at the current line, so without a gate the widened feed would have silently moved locked lines onto DFS and exchange numbers the model has never been calibrated against.

Props the model can grade: 546 — unchanged. CURRENT_RULER_VERSION is still v1_first_book.

The gate lifts only when the MLB calibration is re-run on the consensus ruler and v2 is promoted.


HONEST FRAMING — do not let this read as model progress

  • This is an AGGREGATOR win. It does not fix the model. Not one grade changed.
  • WNBA still abstains. It is a model problem, not a coverage problem — WNBA is better covered than MLB (4.21 vs 3.61 books/prop). Coverage was never its constraint.
  • MLB isotonic p_win is still PROVISIONAL until re-run on the consensus ruler.
  • The consensus is MARKET, not SHARP. pinnacle, matchbook and polymarket are 0% on both sports. No sharp anchor exists in our feed — and none is purchasable from this provider, because it is a coverage fact, not a tier gate.
  • A third of the new depth is real; two thirds is pick'em. Both are shown; only one is a market.

THREE SUPERSEDED TESTS, UPDATED TO STRONGER PROPERTIES (not deleted)

  1. roleOf(dfs) returned 'excluded' → now names the kind ('dfs'), plus assertions that it is display-visible, non-reference and non-model.
  2. "filters out books not in the allowed set" → now asserts the display set widens with correct role tags, unknown books are still dropped, and the model set does not move.
  3. "returns 400 for invalid book" (bovada) → split into: an unknown book still 400s, and a newly-visible one no longer does.

OPEN

  1. $9/mo Hobby — buys the CLV instrument and steam. Evidenced above; your call.
  2. $19/mo Pro — adds the 90-day settlement export, which is the backtest input and the thing that makes soccer settle.
  3. The display layer should now surface multi-book line shopping — the data is live and tagged; no surface consumes it yet. That is a frontend order.