Files
vyndr/supabase/migrations/038_chain_shadow.sql
T
builtbykev 6c34af3414 checkpoint: chain shadow, WNBA possession feed, baseball chain
Backup commit of uncommitted working-tree state found during Legion
recon (Tony resurrection, STEP 0). This work existed only on the
laptop disk.

- chain shadow accrual + probe script (038_chain_shadow.sql)
- WNBA possession feed: ESPN adapter, usage service, verify script
  (039_wnba_player_game.sql)
- baseball chain
- retention/snapshot service updates, tableKeys, matchupKeys
- specs: chain-v1, wnba-possession-feed, wnba-source-survey
- unit tests for the above

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnvJAkC3h5QGmb6dipoiWn
2026-08-14 16:53:37 -04:00

41 lines
2.3 KiB
SQL

-- Migration 038: model_snapshots.chain_shadow — the SHADOW CHAIN read.
--
-- The chain (src/services/model/chain.js) computes a probability by chaining
-- base-event atoms: p per plate appearance from the PA outcome tree, chained
-- over expected plate appearances. It is SERVED BY NOTHING. The counter
-- (probabilityEstimator) remains the only thing a user ever sees.
--
-- WHY A COLUMN AT ALL. Evidence you cannot adjudicate is not evidence. A chain
-- probability stored on its own could only ever be compared to itself. This
-- column stores the chain's number NEXT TO the number it must beat, on a row
-- that already carries the result:
--
-- chain_shadow.chain_p the chain's probability, SIDE-ALIGNED
-- chain_shadow.counter_p the served counter's p_win for that same side
-- model_snapshots.outcome written by the ordinary settle pass
--
-- Those three make the triple. Without all three on one row, the chain could be
-- described but never judged.
--
-- SIDE ALIGNMENT IS LOAD-BEARING. The chain computes P(over the line); p_win is
-- expressed for the graded side. An under row stores 1 - p_over. Storing the raw
-- over-probability against an under row would invert every later comparison,
-- silently.
--
-- IT IS LABELLED UN-SERVABLE IN THE DATA, not only in a comment: every block
-- carries status 'UN-SERVABLE' and servable=false, because it was produced with
-- requireCalibrated=false and the chain has never passed a calibration gate.
--
-- A SEPARATE COLUMN, not extra keys inside `features` — champion-ablation.js
-- iterates every key of `features` for its residual scan, so widening it would
-- silently enlarge that multiple-comparisons denominator. Same reasoning as 034.
--
-- NULLABLE and populated only on MLB `hits` rows the chain could read, so the
-- storage cost is bounded. Adding a nullable column is metadata-only in
-- Postgres — no table rewrite — which matters while this database sits near its
-- free-tier size cap.
ALTER TABLE model_snapshots ADD COLUMN IF NOT EXISTS chain_shadow jsonb;
COMMENT ON COLUMN model_snapshots.chain_shadow IS
'Chain v1 SHADOW: side-aligned chain_p + the served counter_p, forming the (chain_p, counter_p, outcome) triple with model_snapshots.outcome. UN-SERVABLE (requireCalibrated=false); read by no serving path.';