← All findingssource · memory/reference_hypothesis_harness.md
python3 scripts/test_hypothesis.py --list
python3 scripts/test_hypothesis.py --test pairs --by opponent --stat pts
python3 scripts/test_hypothesis.py --test split --by favorite --stat pts
Conditions: opponent (the grudge test), home, favorite, big_spread, rest.
Stats: pts reb ast min fga fg3m stl blk tov.
What it does that eyeballing cannot. It does NOT ask "is there a hot split" — there always is. It asks whether the real data holds MORE extreme splits than chance produces. Null built by shuffling each player's condition labels among her OWN games (destroys the association, preserves her form/minutes/level/schedule). Headline is a max-statistic p-value — corrected for multiple comparisons by construction, which a per-pair p-value is not. Performance always measured vs the player's own leak-safe trailing baseline.
Measured, WNBA 2022/2025/2026 — all DO-NOT-BUILD
| hypothesis | p | verdict |
|---|---|---|
| opponent grudge ("personal play") | 0.159 | noise |
| favourite vs underdog | 0.552 | noise, and backwards — favourites score slightly MORE |
| favoured/dog by 7+ | 0.930 | noise |
| home/away | 0.020 | suggestive, but gap is only 0.22 pts |
The canonical trap, worth re-reading before any hunch: Alanna Smith scored +9.10 pts over her own form vs WAS, six games running, z=+3.74. Textbook grudge. Then 31 of 200 pure-noise shuffles produced something that extreme. 1,272 pairs guarantee a few spectacular ones.
Why the blowout story fails in the WNBA specifically: starters lose under a minute even at spreads of 9+ (big fav −0.82, big dog −0.70). Short rotations + 40-minute games mean NBA garbage time does not transfer.
A 3+ bucket split prints its table then says NOT TESTED in as many words — a silent table with no verdict looks like a result.
Related: project_conditional_minutes_refuted, feedback_model_edge_calibration, feedback_verify_before_extend
Discover mode + ledger (added 2026-08-26, commit after 4c34764)
--test discover sweeps all (condition,stat) pairs, Bonferroni-corrects across
the WHOLE sweep, and appends EVERY test to .audit-cache/hypothesis/ledger.csv
— duds included, so the denominator is always known.
THE FLOOR BUG (do not reintroduce): at 400 perms the p floor (1/401=0.0025) sat ABOVE the 84-test threshold (0.0006) → "0 survive" was true by construction and the tool printed "quiet board" over a t=5.47 effect. Fix = screen cheap, escalate raw p<=0.05 leaders to ~4000 perms. Always check floor < threshold.
13/84 survivors (WNBA 22/25/26):
big_spread min +0.888 / fga +0.438(p=0.00025) — game script is REAL, in minutes+shots; pts dead flat (offsetting efficiency). Pre-game knowable; minutes props exist. NEXT: register as formula for CLV before staking.ftanegative for away/underdogs in all three framings — the home whistle.starterx8 — machine rediscovered the promotion effect unprompted (sanity check, not tradeable; it IS the bias the quarantine handles).
Also added: b2b/starter/high_total conditions; fta/oreb/fg3a stats; totals.
gamescript_minutes: BENCHED same morning — the market does not exist
Registered at 09:30Z, unregistered 10:00Z (grading f960954), never fanned out.
No book prices WNBA minutes: odds-service 422s on the prop_type (not in its
enum); bulk feed + snapshot carry exactly 8 prop types (pts/reb/ast/threes +
combos). The trap that caused the registration: the CLV ledger's 173 "minutes"
rows are UNPRICED diagnostics (bet_odds=0) from system_lineedges — the ledger
shadows our own model, not the market. Never read ledger prop_types as market
existence; check the odds BULK feed.
The clean pattern: every discovery survivor (min, fga, fta) lives in an UNPRICED stat; every priced stat measured null in the same split. Plausibly why the effects persist — nothing arbitrages them. An edge in a nonexistent market is trivia. Formula file kept, tested, header states the re-register condition.
(superseded) First graduate: gamescript_minutes (registered 2026-08-26)
grading-service 68e11db + c1d964e: dog minutes OVER / fav minutes UNDER on
7+ spreads, WNBA + minutes only, in the auto-formula slate (now 10). First live
fanout 18:00Z 2026-08-26 (CON@GSV is a 13.5 spread that night). Check
/clv/by-formula for formula_id=gamescript_minutes; trustworthy at 100
priced. Guardrails in the file header: silent <7, silent NBA, needs 3+ spread
quotes, unplaceable players skipped. The formula is FROZEN at v1.0.0 so the
record stays clean — findings accumulate as its ledger, never as edits.
Process note: the registering commit shipped with the auto-slate census test still asserting nine — my verify ran AFTER the push. Verify-then-push, always.