Champion grade UNCHANGED. Push scoring untouched. Additive tags only — nothing
deleted, nothing re-settled.
PART A — THE EFFICIENCY CHALLENGER: BLOCKED, NOT BUILT.
Review Zero came back ABSENT on all three inputs:
0.1 efficiency scores DO NOT EXIST (zero occurrences of market_efficiency /
marketEfficiency / efficiency_score in src/ or web/src/).
0.2 base thresholds DO NOT EXIST (engine1.js has zero `edge` references — the
grade is not an edge-vs-threshold comparison; grade_thresholds.json holds
PROBABILITY bands).
0.3 the +/-0.05 additive efficiency nudge DOES NOT EXIST. The only 0.05s on
the grade path are featureCache.teammate_absence_bump, a bvp_advantage
cutoff, and p*0.9+0.05 inside probabilityEstimator (the 0.5*0.1 term of
the shrink-toward-0.5). There is no additive scaling to replace.
So a challenger differing from the champion in EXACTLY ONE thing cannot be
constructed: there is no additive scaling to swap, no base threshold to
multiply, and engine1.js has zero `sport` references so market cannot reach the
grade. A threshold must exist first — that is R1 of
specs/full-output-grade-mapping.md, an explicitly held separate order. Shipping
R1+R4 together would make the Phase-3 delta report misleading: the re-letter
would be driven mostly by switching to probability grading while being
presented as the efficiency fix.
0.4 coverage: the spec names 5 scores; the live ledger has 11 markets and only
MLB total_bases maps to one. 9 of 11 have no score, so "all scored markets"
cannot be satisfied without inventing 9 numbers.
PART B — LEDGER TAKEABLE TAGGING: BUILT (the deferred C2).
New src/config/takeableStandard.js: floor on the minus side, UNCAPPED plus.
Deliberately NOT valueEngine.isTakeable (the -160..+200 PROMOTION band) — a
+400 prop is not promotable but IS takeable; a test asserts the two diverge on
the plus side and agree at the floor so they can never quietly merge. Absent
price returns null, never false (Number(null) === 0 would tag a missing price
takeable). The floor is POLICY not derived (C1 could not derive one) and is
labelled so; each row records takeable_floor so a re-derivation can re-tag.
Migration 034 (applied + tracked): ledger_entries.takeable boolean +
takeable_floor numeric, nullable, partial index. Forward tagging in
ledgerService at row build; backfill in one statement.
Result: 1254 rows, 1246 tagged (781 takeable / 465 below floor), 8 NULL with
null_despite_price = 0 (the NULLs are genuinely priceless rows). Settled 1163
and graded 1254 unchanged.
PART C — the model-version boundary tag is DELIBERATELY NOT APPLIED: no scaling
change shipped, so no boundary exists, and stamping one would mark a model
transition that never happened. modelEras.js is its home when a real one lands.
Floor: 312 suites / 3890 tests green (8 new), web build exit 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
6.8 KiB
SPEC — LEDGER TAKEABLE TAGGING (built) + MULTIPLICATIVE EFFICIENCY SCALING (BLOCKED)
2026-07-31. Champion grade UNCHANGED. Push scoring untouched.
PART A — THE EFFICIENCY CHALLENGER: BLOCKED, NOT BUILT
Review Zero came back ABSENT on all three inputs
- 0.1 efficiency scores — DO NOT EXIST. Zero occurrences of
market_efficiency,marketEfficiency, orefficiency_scoreinsrc/orweb/src/.src/config/holds no efficiency file (the one0.80there isproviders.js WARN_PCT, a quota warning). - 0.2 base thresholds — DO NOT EXIST. There is no "MLB A: 5% edge / NBA A: 7% edge"
table.
engine1.jscontains zeroedgereferences; the grade is not an edge-vs-threshold comparison.grade_thresholds.jsonholds PROBABILITY bands. - 0.3 the ±0.05 additive nudge — DOES NOT EXIST. Searched the whole grade path. The
only
0.05values arefeatureCache.teammate_absence_bump(a feature), abvp_advantagecutoff for a matchup letter, andp*0.9 + 0.05insideprobabilityEstimator(the0.5 × 0.1term of the shrink-toward-0.5, not efficiency). There is no additive efficiency application to replace. No market-conditional logic exists inengine1.jsoranalyzeViaEngine1.jsat all.
Why the challenger cannot be built as specified
The order requires a challenger differing from the champion in EXACTLY ONE thing — multiplicative vs additive scaling. That construction is impossible here:
- there is no additive scaling to swap,
- there is no base threshold to multiply,
- and
engine1.jshas zerosportreferences, so market/sport cannot reach the grade.
To have a threshold to scale, the challenger must FIRST grade on probability-vs-threshold —
which is rule R1 of specs/full-output-grade-mapping.md, an explicitly held separate
order. Shipping R1+R4 together would (a) violate the isolate-one-variable requirement and
(b) make the Phase-3 delta report misleading: the re-letter would be driven mostly by
switching to probability grading, presented as the efficiency fix. Kev would be approving
the wrong attribution. That is why this half stopped rather than guessed.
0.4 — coverage gap that would sink the build anyway
The spec names 5 scores (NFL passing .85, NBA points .80, MLB K .60, MLB TB .55, NBA role .55). The live public ledger contains 11 markets: MLB hits (376 rows), doubles (247), total_bases (44), stolen_bases (17), earned_runs (6), home_runs (4), outs (2); WNBA points (246), rebounds (156), assists (142), threes (10). Only MLB total_bases maps to a specced score. MLB K's and NFL passing do not appear at all; WNBA is not in the spec list. So 9 of 11 live markets have NO score — and the guardrail ("all scored markets, or it's incoherent") cannot be satisfied without inventing 9 numbers. Inventing them would be fabricated calibration.
What Part A needs before it can run: (1) R1 probability grading, so a threshold exists; (2) efficiency scores for the markets we actually grade — ideally FIT from each sport's own accrued record, not hand-set (that is R4's stated design).
PART B — LEDGER TAKEABLE TAGGING: BUILT (the deferred C2)
Independent of Part A: it needs no threshold, no scaling, no grade change.
The standard (src/config/takeableStandard.js)
isLedgerTakeable(american) = american >= LEDGER_TAKEABLE_FLOOR // default -160
// FLOOR on the minus side, UNCAPPED on the plus side.
🔴 It is deliberately NOT valueEngine.isTakeable. Those answer different questions:
| shape | question | |
|---|---|---|
valueEngine.isTakeable |
−160..+200, bounded both ends | "may we PROMOTE this to the hero / top of board?" |
takeableStandard.isLedgerTakeable |
≥ −160, uncapped plus | "was this a price a bettor could actually have TAKEN?" |
A +400 prop is NOT promotable but IS takeable — both true at once. A unit test asserts they diverge on the plus side and agree at the minus floor, so the two can never quietly merge.
Absent price → null, never false. Without the strict guard Number(null) === 0 is
≥ −160 and a MISSING price would be tagged takeable — fabricated data in the record.
The floor is POLICY, not derived, and is labelled so everywhere. C1 (2026-07-30) could not derive one: every price bucket's 95% ROI interval contained zero, the curve was non-monotone (deepest buckets positive), and resolving a 5-point edge needs 661–2,285 rows/bucket against actual sizes of 8–71. −160 is held because it is directionally the better half of the only available comparison (in-band ROI +3.84% vs out-of-band −0.04%, both spanning zero). Re-derivation trigger: any negative bucket reaching n ≥ 300, or the end of the MLB regular season — and adopt a derived floor only when a bucket's 95% CI excludes zero.
Schema (migration 034, applied + tracked)
ledger_entries.takeable boolean + takeable_floor numeric, both nullable, plus a partial
index on (sport, takeable) WHERE user_id IS NULL. takeable_floor records the floor each
row was judged under, so a future re-derivation can re-tag safely instead of guessing which
standard a row was tagged by. Additive only — nothing deleted, nothing re-settled.
Forward + backfill
Forward: ledgerService stamps takeable/takeable_floor at row build from the locked odds.
Backfill: every row with a parseable locked price, one statement, no outcome/grade/price touched.
Result — 1,254 rows: 1,246 tagged (781 takeable / 465 below floor), 8 NULL, and
null_despite_price = 0 — i.e. every priced row is tagged and the 8 NULLs are genuinely
priceless rows (honest absence). One distinct floor (−160). Settled 1,163 and graded 1,254
both unchanged.
PART C — MODEL-VERSION BOUNDARY TAG: DELIBERATELY NOT APPLIED
Phase 2.4 asks for a boundary separating pre-fix (additive) from post-fix (multiplicative)
grades. No scaling change shipped, so no such boundary exists. Stamping one would mark a
model transition that never happened — a fabricated era in the permanent record, which is the
exact class of thing the Data Semantics Rule forbids. src/config/modelEras.js (Session 64)
is the correct home for it on the day a real scaling change promotes.
VERIFY
Champion grade path untouched (engine1, analyzeViaEngine1, probabilityEstimator,
gradeSlateService, grade_thresholds.json — no diff). 312 suites / 3,890 tests green
(8 new), web build exit 0. Grade visuals are auth-gated → Chrome audit; this order changed
nothing visual.
TAGS
VERIFIED: efficiency scores/base thresholds/±0.05 nudge all absent; 11-market coverage gap; tagging built + backfilled + integrity-checked. CANNOT DETERMINE: none. BLOCKED: Part A (the efficiency challenger) — needs R1 probability grading plus fitted per-market scores.