Order Zero: book-breadth test + accrual clock correction (measure-only)
STEP 0 disproved the premise before any request was fired. PropLine's OpenAPI contract states verbatim that `bookmakers` omitted = ALL books, so proplineAdapter omitting it is correct and always was. Firing a guessed param would have RESTRICTED the response and produced exactly the false negative the order warned about. The real cause is ours: PropLine sends 18 books; oddsNormalizer ALLOWED_BOOKS intersects them at exactly 5 -- which is precisely the "5 MLB books" the 2.18 audit measured. Measured on real public data (no key, no quota): 4.41 books/prop from the feed, 1.50 after our filter, and 12 of 34 props go invisible entirely. Also corrected: "73% single-book" is the long tail of deep props sole-posted by DraftKings or Bovada. On the core props we grade, the market is 10-12 books wide. pinnacle appears on 0 of 40 MLB props -- the independent low-vig references present on 100% of core props are exchanges (novig/smarkets/kalshi). DFS pick'em also covers 100% but is not a market price and must never enter a consensus. Verdict is outcome (d) ALREADY OPEN, not (a)/(b)/(c) -- all three assumed the feed was the constraint. Ruler change scoped (not built): split one allow-list into takeable/reference/excluded, fair_prob_lock becomes a median consensus with n>=2 or a labelled fallback. Gated on exchange price validation + the WNBA measurement, which needs the PropLine key (prod-only, absent locally). MLB isotonic p_win declared PROVISIONAL until re-run on the real ruler. Side finding: we use 1 of 29 endpoints. /odds/closing, /movement, /odds/history, /best-line, /ev, /results, /exports/resolved-props, /context (free) map directly onto documented gaps -- and resolution across 33 sports suggests "no free settled feed for NBA/soccer" may be a $19/mo problem, not a data problem. Documented, not verified. Plan edits: §10.1 rewritten, §10.2/§10.5 corrected, and §11 adds the sequential post-completion accrual clock -- pre-completion data does not count, no pooling across the completion boundary, two clocks stated separately, per-sport clocks, verification gate before any accrual, users onboarded to a complete product only. §9.1's "6-10 weeks out" corrected: that is accrual duration, not distance to the answer. The ruler change independently forces the same no-pooling boundary by arithmetic. No API key was used, printed, or committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
+165
-11
@@ -183,9 +183,22 @@ scaffolding around that. Building all 23 orders and *not* closing this leaves a
|
||||
beautifully-built product that doesn't do the one thing it sells.
|
||||
|
||||
**What closes it:** not code. **Sample and honest iteration.** The instrument
|
||||
fields are ~10 days old (442 rows). At ~90 decided MLB rows/week, a defensible
|
||||
verdict is **6–10 weeks out**. That clock cannot be shortened by engineering, and
|
||||
any attempt to shorten it is the fabrication this whole session has been removing.
|
||||
fields are ~10 days old (442 rows). At ~90 decided MLB rows/week, that is ~6–10
|
||||
weeks *of accrual*.
|
||||
|
||||
> **CORRECTED 2026-07-31 — see §11.** The "6–10 weeks out" above quietly assumed
|
||||
> the clock is **already running**. It is not. Those 442 rows measure a model
|
||||
> with a bent single-book ruler and six disconnected layers — **a model that
|
||||
> will not exist once Phase 1 lands.** They do not count toward the verdict and
|
||||
> **must not be pooled** with post-completion rows.
|
||||
>
|
||||
> The clock starts at a **verified** "running as intended" gate, per sport.
|
||||
> **6–10 weeks is the accrual duration, not the distance to the answer.** The
|
||||
> distance to the answer is *build time + verification + 6–10 weeks.*
|
||||
>
|
||||
> Independently forced by arithmetic, not just discipline: the §10.1 ruler fix
|
||||
> changes the denominator, so pre-fix and post-fix edge/CLV numbers are not the
|
||||
> same measurement.
|
||||
|
||||
## 9.2 The projection — the actual engine — is thin and unvalidated
|
||||
The grade's only real inputs today are **l5/l20 averages, an opponent rank, rest
|
||||
@@ -253,6 +266,35 @@ in two places.** Fix the data breadth and both halves improve at once.*
|
||||
|
||||
## 10.1 The one finding that reframes everything
|
||||
|
||||
> **CORRECTED 2026-07-31 by Order Zero — `specs/order-zero-book-breadth-test.md`.**
|
||||
> The original text below blamed a missing `regions`/`bookmakers` param. **That
|
||||
> was wrong.** PropLine's OpenAPI contract states verbatim: `bookmakers` …
|
||||
> **"Omitted = all books."** Omitting it is correct and always was.
|
||||
>
|
||||
> **The real cause is ours.** PropLine sends **18 books**; `oddsNormalizer`
|
||||
> `ALLOWED_BOOKS` (11 entries) intersects them at **exactly 5** — which is
|
||||
> precisely the "5 MLB books" the audit measured. We discard 13 of 18 ourselves,
|
||||
> and 6 of our 11 allow-list entries don't exist at PropLine at all.
|
||||
>
|
||||
> Measured on real public data (MLB `pitcher_strikeouts`, 5 complete events):
|
||||
> the feed carries **4.41 books/prop**; after our filter, **1.50** — and **12 of
|
||||
> 34 props become invisible entirely** (zero allowed books).
|
||||
>
|
||||
> Also corrected: "73% single-book" is the **long tail** of deep/reliever props
|
||||
> sole-posted by DraftKings or Bovada. **On the core props we actually grade,
|
||||
> the market is 10–12 books wide.**
|
||||
>
|
||||
> And a real negative: **`pinnacle` appears on 0 of 40 MLB props.** The one
|
||||
> sharp book in our allow-list contributes nothing here. The independent
|
||||
> low-vig references that *are* present on 100% of core props are **exchanges**
|
||||
> — `novig`, `smarkets`, `kalshi` (+ `matchbook`, `polymarket`). DFS pick'em
|
||||
> (`prizepicks`/`underdog`/`sleeper`/`dabble`) also covers 100% but is **not a
|
||||
> market price** and must never enter a consensus.
|
||||
>
|
||||
> **So this is not a test to run. It is a build we can do: split one allow-list
|
||||
> into takeable / reference / excluded, and make `fair_prob_lock` a median
|
||||
> consensus across reference books.** No param, no cost, no tier, no new source.
|
||||
|
||||
**Our "market" is often ONE book.** MLB props are **73% single-book** (2.18 audit).
|
||||
And `proplineAdapter` sends only `{ apiKey, markets }` — **no `regions`, no
|
||||
`bookmakers` param** (`:152`). We take PropLine's *default* response.
|
||||
@@ -264,17 +306,31 @@ That single fact causes four separate problems we have been treating as unrelate
|
||||
3. **CLV is weak** — you cannot measure "beat the close" against one book's close.
|
||||
4. **No steam/disagreement detection** — needs ≥2 books to even exist.
|
||||
|
||||
**So the highest-leverage unblocked action in the whole plan is a cheap API test:
|
||||
does PropLine return more books with a `regions`/`bookmakers` param on our tier?**
|
||||
It is one request. If yes, it upgrades the free product, the model's denominator,
|
||||
and the CLV instrument simultaneously.
|
||||
*(Items 1–4 stand. Only the **cause** was wrong — and the fix is cheaper than
|
||||
the original diagnosis implied.)*
|
||||
|
||||
### 10.1b We use 1 of PropLine's 29 endpoints
|
||||
|
||||
Reading the full spec surfaced ten unused endpoints that map directly onto §10.2
|
||||
and §10.3 gaps — `/odds/closing` ("the canonical CLV helper"), `/odds/history`,
|
||||
`/exports/odds-history`, `/movement` (steam across all 16 books), `/best-line`,
|
||||
`/ev`, `/results` + `/exports/resolved-props` (**resolution across 33 sports**),
|
||||
`/context` (**free**: probable pitchers, confirmed lineups, home-plate umpire,
|
||||
first-pitch weather), `/markets/hit-rates`, `/players/{n}/trends`.
|
||||
|
||||
Two overturn standing beliefs: **"NBA/WNBA/soccer have no free settled feed"** may
|
||||
be a **$19/mo** problem rather than a data problem; and we hand-built probable
|
||||
pitchers / depth charts / lineup confirmation that `/context` serves free.
|
||||
|
||||
**Caveat:** these are *documented*, not verified for our tier — that needs the
|
||||
PropLine key (prod-only, absent locally). Do not plan on them as facts yet.
|
||||
|
||||
## 10.2 What a real DATA AGGREGATOR has that we don't
|
||||
|
||||
| capability | ours | gap |
|
||||
|---|---|---|
|
||||
| **Book breadth** | 5 MLB / 2 WNBA, 73% single-book | the category runs 10–20. **Root gap (10.1)** |
|
||||
| **True consensus / no-vig line** | single-book de-vig | needs breadth first |
|
||||
| **Book breadth** | 5 admitted of **18 sent**; 4.41→1.50 books/prop after our own filter | **not a feed gap — one allow-list (10.1).** Core props are already 10–12 books wide |
|
||||
| **True consensus / no-vig line** | single-book de-vig | **unblocked now**: median across reference books (exchanges + pinnacle), n≥2 or labelled fallback |
|
||||
| **Historical odds archive** | **STARTED** — `closing_captures` 844k rows, `lock_lines` (033) new, in-grade history capped at **24 points** | no full open→close series per prop. This is what makes CLV and backtesting real |
|
||||
| **Market breadth** | 11 live markets | the category ships 50+ (alt lines, combos, innings, quarters) |
|
||||
| **Alt-line ladders from books** | we *compute* a ladder; we don't *ingest* the books' | users shop rungs |
|
||||
@@ -321,8 +377,11 @@ the work.
|
||||
|
||||
## 10.5 If I had to order it for "top product"
|
||||
|
||||
1. **Book breadth test + consensus fair line** (10.1) — one API call to find out;
|
||||
upgrades aggregator, model denominator and CLV together.
|
||||
1. ~~Book breadth **test**~~ → **Book breadth FIX + consensus fair line** (10.1).
|
||||
The test is done (Order Zero). It is now a build: split `ALLOWED_BOOKS` into
|
||||
takeable / reference / excluded, make `fair_prob_lock` a median consensus.
|
||||
Upgrades aggregator, model denominator and CLV together. **Gated on** exchange
|
||||
prop-price validation + the WNBA measurement (needs the PropLine key).
|
||||
2. **Opportunity projection** (10.3.2) — the biggest genuine modelling gain.
|
||||
3. **Per-stat distributions** — connect `distribution.js`, prove per stat.
|
||||
4. **Connect the built layers** (Phase 1) — each proven on held-out or left off.
|
||||
@@ -342,3 +401,98 @@ unfinished, but because **we have not measured it at adequate n on a market we c
|
||||
trust.** Book breadth + the odds archive + accrued settlements are what make that
|
||||
claim *possible*. Everything in §10 is in service of being able to make it — or of
|
||||
being able to say honestly that we can't.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# 11. THE ACCRUAL CLOCK — SEQUENTIAL, POST-COMPLETION
|
||||
|
||||
*Kev's correction, 2026-07-31. Supersedes any "accrual runs in parallel with
|
||||
building" framing anywhere in this document.*
|
||||
|
||||
## 11.1 The causality
|
||||
|
||||
You cannot meaningfully accrue until the product is **right and running as
|
||||
intended** — model layers connected, ruler fixed (real consensus, not one soft
|
||||
book), sports in, operating in the vision.
|
||||
|
||||
**Only then does the accrual clock start, and only then does time produce a
|
||||
verdict. Building faster shortens the time TO clock-start. It never runs the
|
||||
clock.**
|
||||
|
||||
The flawed assumption being removed: that today's half-connected model accrues
|
||||
useful evidence while we build. It does not. That data measures a model that
|
||||
**will not exist** after the layers are connected — a different model wearing the
|
||||
same name.
|
||||
|
||||
## 11.2 Measurement rule (non-negotiable)
|
||||
|
||||
- Settled data accrued **before** completion does **NOT** count toward the edge
|
||||
verdict.
|
||||
- **NO POOLING across the completion boundary.** Pre-fix and post-fix are
|
||||
different models — the same class of error as the model-version boundary, at
|
||||
whole-model scale.
|
||||
- The clock starts at **verified** "running as intended", not at "today".
|
||||
|
||||
## 11.3 Two clocks — stated separately so neither corner-cuts
|
||||
|
||||
**1. MLB-MODEL VERDICT clock.** Starts when MLB is genuinely complete: built
|
||||
layers connected + honest consensus ruler + running as designed. Its accrued n
|
||||
judges **MLB**.
|
||||
|
||||
**2. FULL-PRODUCT TRACK RECORD clock.** Starts when the vision is running:
|
||||
sports in, aggregator built, operating as intended. Its accrued n judges **the
|
||||
product claim**.
|
||||
|
||||
**Each subsequent sport gets its OWN clock**, starting when *that* sport's model
|
||||
is complete — never when it is stubbed in. (Per-sport doctrine: a sport that
|
||||
merely renders is not a sport that measures.)
|
||||
|
||||
## 11.4 "Complete" — defined honestly
|
||||
|
||||
A model/sport is **complete-enough-to-accrue** when its **built layers are
|
||||
connected** and it runs against an **honest ruler** (real consensus), **operating
|
||||
as designed** — *not* when every conceivable feature exists.
|
||||
|
||||
This definition is doing real work in both directions: it blocks the corner-cut
|
||||
("close enough, start counting") **and** it blocks never-ship ("one more
|
||||
feature"). The full-product claim additionally requires the vision's sports +
|
||||
aggregator running.
|
||||
|
||||
## 11.5 The verification gate
|
||||
|
||||
**Between build and clock.** Before any accrual counts, verify — not assume —
|
||||
that the product is running as intended:
|
||||
|
||||
- connected layers actually **fire** (present in the served payload, not merely
|
||||
present in the repo)
|
||||
- the ruler is a **real consensus** (`fair_prob_source: 'consensus_n'`, n≥2)
|
||||
- the sport **settles correctly** (spot-checked against real box scores)
|
||||
- surfaces are **honest** (no fabricated values; absent renders absent)
|
||||
|
||||
**This gate is verified, not assumed.** No accrual line item runs during the
|
||||
build phases.
|
||||
|
||||
## 11.6 The 10-user track, reframed
|
||||
|
||||
Real users are onboarded to a **complete** product, so their usage teaches about
|
||||
the real thing rather than a half-built one.
|
||||
|
||||
**We do NOT acquire users early to "start accrual."** That is the corner being
|
||||
explicitly refused.
|
||||
|
||||
## 11.7 The finish line
|
||||
|
||||
```
|
||||
build orders complete
|
||||
↓
|
||||
running-as-intended VERIFIED (§11.5 gate)
|
||||
↓
|
||||
clock starts (per sport, two clocks, §11.3)
|
||||
↓
|
||||
verdict reported honestly — including if it says the edge is not there
|
||||
```
|
||||
|
||||
That last clause is the whole point. A clock you are willing to stop early is not
|
||||
a measurement, and a verdict you are only willing to publish if it is favourable
|
||||
is not a verdict.
|
||||
|
||||
Reference in New Issue
Block a user