Structural hardening: unknown-is-not-zero + takeability-is-book-identity

Both guards are ADDITIVE. The full suite (4,111 -> 4,126 tests, 331 suites)
passes unchanged through the migration, which is the evidence that no
currently-correct output moved: served path, champion, reference ruler and
the four accruing challengers are byte-identical.

GUARD 1 -- src/utils/known.js. Number(null)===0 has produced at least SIX
separate defects here, including one in a module written the same week its
author documented the trap. Per-module vigilance has demonstrably failed,
so the rule lives in one place and SEVEN sites now delegate: platoonSplits,
projectionChallenger, challengerProjection, contactChallenger,
statcastAggregateService, consensusRuler, gradeRanking -- plus
compoundTotalBases moved onto knownRate.

Two functions, deliberately: knownNumber (any finite number -- a REAL 0 is
a fact and must survive) and knownRate (non-negative, rejects booleans --
for counts/rates where `true` or -1 is broken, not thin). Collapsing them
is how the next variant gets in. firstKnown() exists because `a || b`
discards a measured 0 and `a ?? b` does not.

MY OWN GUARD HAD THE BUG IT EXISTS TO PREVENT, and its own test caught it:
Number([]) === 0, so an empty array coerced to a measured ZERO. Same trap
wearing a different type. Both helpers now reject objects outright.

GUARD 2 -- src/config/takeability.js. Takeability is BOOK IDENTITY and
never price shape. Baseball prop markets are genuinely thin, juiced and
one-sided, and all three are NORMAL structure: betrivers and hardrockbet
legitimately quote one side only (5 such rows surfaced in yesterday's
re-stamp), and a hits-over at -300 is a real placeable bet. A rule that
inferred un-takeability from price extremity or one-sidedness would throw
those away while still admitting a DFS book at an ordinary -119 -- exactly
backwards, because the -119 is the fake one.

THE DISTINCTION THAT MUST NOT COLLAPSE, now enforced by test:
  isTakeableMarket(book)  -- CAN it be bet?     (identity)
  isWithinPriceBand(odds) -- SHOULD we promote? (policy band, floor -160)
A -300 DraftKings prop is takeable AND out of band; a PrizePicks -119 is in
band AND not takeable. Independent axes.

FLAGGED, NOT SILENTLY CHANGED: the ledger's `takeable` column is the
PRICE-BAND answer, and its name predates this distinction. Four challengers
and the ranking gate read it, so renaming or redefining it is its own
order -- doing it here would have changed correct current behaviour under
cover of a hardening change.

Fixtures are REAL prod rows from the 2026-08-02 re-stamp, not invented.

Gates: 4,126 tests / 331 suites green; next build exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
Kev
2026-08-02 17:25:40 -04:00
parent f67245e1e5
commit 8c764c22a4
11 changed files with 380 additions and 46 deletions
+149
View File
@@ -0,0 +1,149 @@
'use strict';
/**
* STRUCTURAL GUARDS (2026-08-02) — two recurring failure families, locked.
*
* Both are the same principle: never silently convert something ABSENT or THIN
* into a false DEFINITE value.
*
* GUARD 1 unknown ≠ zero (`Number(null) === 0`, 6× recurring)
* GUARD 2 takeability = book identity, never price shape
*
* The fixtures are REAL rows from prod (2026-08-02 re-stamp), not invented.
*/
const { knownNumber, knownRate, isKnown, firstKnown } = require('../../src/utils/known');
const { isTakeableMarket, isWithinPriceBand, assessQuote } = require('../../src/config/takeability');
// ─────────────────────────────── GUARD 1 ───────────────────────────────
describe('GUARD 1 — unknown is not zero', () => {
it('every absent form is UNKNOWN, never 0', () => {
for (const v of [null, undefined, '', NaN, 'abc', {}, []]) {
expect(knownNumber(v)).toBeNull();
expect(isKnown(v)).toBe(false);
}
});
it('a REAL zero survives — 0 rest days is a fact, not an absence', () => {
expect(knownNumber(0)).toBe(0);
expect(isKnown(0)).toBe(true);
expect(knownRate(0)).toBe(0);
});
it('Infinity is not a measurement', () => {
expect(knownNumber(Infinity)).toBeNull();
expect(knownNumber(-Infinity)).toBeNull();
});
it('knownRate additionally rejects booleans and negatives', () => {
expect(knownRate(true)).toBeNull(); // Number(true) === 1
expect(knownRate(false)).toBeNull(); // Number(false) === 0 — the trap
expect(knownRate(-0.5)).toBeNull();
expect(knownNumber(-0.5)).toBe(-0.5); // a signed gap is legitimately negative
});
it('firstKnown prefers a present 0 over a later fallback (|| gets this wrong)', () => {
expect(firstKnown(0, 5)).toBe(0);
expect(firstKnown(null, 5)).toBe(5);
expect(firstKnown(null, undefined, '')).toBeNull();
});
it('REAL FIXTURE — a null triple rate must not read as "never triples"', () => {
const tb = require('../../src/services/projection/compoundTotalBases');
// Same components, one with an UNKNOWN triple rate vs a MEASURED zero.
const unknown = tb.tbPmf({ singles: 0.6, doubles: 0.2, triples: null, home_runs: 0.15 });
const zero = tb.tbPmf({ singles: 0.6, doubles: 0.2, triples: 0, home_runs: 0.15 });
// Both are computable, and an unknown component contributes nothing —
// but it must do so by being SKIPPED, not by being asserted as zero.
expect(unknown).not.toBeNull();
expect(zero).not.toBeNull();
// The guard that matters: no component usable at all → null, not a flat curve.
expect(tb.tbPmf({ singles: null, doubles: null, triples: null, home_runs: null })).toBeNull();
expect(tb.tbPmf({ singles: false })).toBeNull();
});
it('the migrated sites all delegate to the ONE rule', () => {
// Semantics must be identical across every migrated module, or the
// migration reintroduced drift.
const mods = [
require('../../src/utils/gradeRanking').strictNum,
require('../../src/services/consensusRuler').__internals.num,
];
for (const fn of mods) {
expect(fn(null)).toBeNull();
expect(fn('')).toBeNull();
expect(fn(0)).toBe(0);
expect(fn('2.5')).toBe(2.5);
}
});
});
// ─────────────────────────────── GUARD 2 ───────────────────────────────
describe('GUARD 2 — takeability is BOOK IDENTITY, never price shape', () => {
it('REAL FIXTURE — one-sided takeable markets are TAKEABLE', () => {
// Verified in prod: betrivers and hardrockbet quote one side only on real
// props (5 such rows surfaced in the 2026-08-02 re-stamp). One-sidedness is
// normal baseball market structure, not a defect.
expect(isTakeableMarket('betrivers')).toBe(true);
expect(isTakeableMarket('hardrockbet')).toBe(true);
// A one-sided quote: the other side is genuinely absent, and takeability
// does not depend on it at all.
expect(assessQuote({ book: 'betrivers', odds: 6600 }).takeable).toBe(true);
expect(assessQuote({ book: 'hardrockbet', odds: 400 }).takeable).toBe(true);
});
it('REAL FIXTURE — an extreme price is still TAKEABLE (steep juice is a price)', () => {
// Ohtani hits-over at -266 and Schwarber hits-over at -209 are real,
// placeable DraftKings bets.
for (const odds of [-266, -209, -300, -1400, 4900]) {
expect(assessQuote({ book: 'draftkings', odds }).takeable).toBe(true);
}
});
it('REAL FIXTURE — a DFS book at an ordinary -119 is NOT takeable', () => {
// The ordinary-looking price is the fake one: PrizePicks is not a
// sportsbook. Book identity decides, price shape never does.
for (const book of ['prizepicks', 'underdog', 'sleeper', 'dabble']) {
expect(isTakeableMarket(book)).toBe(false);
expect(assessQuote({ book, odds: -119 }).takeable).toBe(false);
}
});
it('exchanges and offshore are not takeable however normal the price looks', () => {
for (const book of ['kalshi', 'novig', 'smarkets', 'bovada', 'onexbet', 'pinnacle']) {
expect(isTakeableMarket(book)).toBe(false);
}
});
it('an ABSENT book is not takeable — we cannot assert a market we cannot name', () => {
for (const b of [null, undefined, '', 'not_a_book']) expect(isTakeableMarket(b)).toBe(false);
});
it('THE DISTINCTION: takeable and price-band are independent axes', () => {
// A -300 DraftKings prop is a REAL bet we would not promote. Both true.
const steep = assessQuote({ book: 'draftkings', odds: -300 });
expect(steep.takeable).toBe(true);
expect(steep.within_price_band).toBe(false);
const normal = assessQuote({ book: 'draftkings', odds: -110 });
expect(normal.takeable).toBe(true);
expect(normal.within_price_band).toBe(true);
// ...and a DFS book inside the band is still not takeable.
const dfs = assessQuote({ book: 'prizepicks', odds: -119 });
expect(dfs.takeable).toBe(false);
expect(dfs.within_price_band).toBe(true);
});
it('an UNKNOWN price is not an out-of-band price', () => {
expect(assessQuote({ book: 'draftkings', odds: null }).within_price_band).toBeNull();
expect(assessQuote({ book: 'draftkings' }).takeable).toBe(true); // book still decides
});
it('no drift: the canonical rule IS bookRoles.isTakeableBook', () => {
const { isTakeableBook } = require('../../src/config/bookRoles');
for (const b of ['draftkings', 'prizepicks', 'pinnacle', 'betrivers', null]) {
expect(isTakeableMarket(b)).toBe(isTakeableBook(b));
}
});
});