Files
vyndr/supabase/schema/model_snapshots.columns.json
builtbykev a8de676756 A probability is served because evidence supports it, not because nothing else answered
The band gate was blocked for its `else` branch. It read:

    candidate = F(raw)
    served    = inCertifiedBand(candidate) ? candidate : RAW

and above raw 0.60 the model is measured overconfident — holdout raw 0.80-0.90
predicts 0.843 and realizes 0.639. So "the calibrator is not supported here" was
being answered with a number already proven wrong. Unsupported calibration does
not make raw true.

Four candidates were adjudicated on ONE split — fit on the earliest 60% of
train, decide support on the last 40%, evaluate on a holdout that saw neither:

  A low-param      80.2% coverage  0.24374  REFUTED — its extra region
                   (raw 0.80-0.90) certified on cert (err +0.040, n=55) and
                   refuted on holdout (served 0.754 vs observed 0.639), and it
                   leaves a hole at 0.70-0.80 while serving the island above it
  B isotonic       91.3% coverage  0.24337  CERTIFIED, contiguous raw [0.50,0.80)
  C empirical band 91.3% coverage  0.24335  REFUTED — refitted point-in-time on
                   current-model hits the realized rates INVERT in grade order
                   (B+ 0.593 < B 0.614 < C+ 0.623), so the served function steps
                   down at raw 0.78. Its shipped constants come from 3,417 props
                   pooled across four batter stats and do not reproduce here
  D raw identity   43.1% coverage  0.24866  certifies raw 0.50-0.60 and only there

Raw is candidate D, not a fallback. It earns exactly one region (holdout error
+0.010 on n=1,316), which is why the law is "raw must earn its region" rather
than "raw is never true". B already covers that region, so no hybrid is built.

Above raw 0.80 nothing is certified and nothing is served. That is the region
where raw is most wrong, isotonic over-corrects (cert err -0.093) and its LODO
mapping at 0.95 has spread 0.180. 8.7% of holdout rows land there.

The registry did not need changing. `serves(stat, p)` already tested certified
bands against the RAW p_win — support in the input domain, the correct question —
and returned {serve:false, reason}. It never said "serve raw". The output-space
gate and the raw fallback were both invented downstream in calibrationService.

ACTIVATION IS OFF. PROBABILITY_CONTRACT_SHADOW defaults to 0, CALIBRATION_DEPLOYED
stays frozen empty, and every served field is byte-identical. This releases the
support first, which is the required order. The shadow records raw belief, the
candidate served value, the state, the estimator identity, and what EV/Kelly/VALUE
would be under the actionability law — into its own column, read by nothing.

Migration 051 was applied to production BEFORE retentionService named the column.
PostgREST builds a bulk insert from the first row's shape, so a key whose column
does not exist 400s the whole batch silently — that is how migration 038 took
retention down for three days.

The user-facing contradiction is NOT fixed here. A B+ still says "realized about
66%" beside a confidence of 84. Fixing that is activation, and activation costs
32% of VALUE flags and 46% of Kelly recommendations on the holdout.

Suite 401/401, 5,580 passed, 4 skipped, deterministic across three runs.
Teeth 23/23, each independently injected and restored byte-identically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
2026-09-02 21:03:16 -04:00

86 lines
2.6 KiB
JSON

{
"table": "model_snapshots",
"generated_by": "scripts/generate-schema-contract.js",
"derived_from": "supabase/migrations/*.sql applied in order to a disposable postgres:15-alpine",
"note": "Insertable columns only (no generated/identity columns). This is the contract the retention writer must satisfy. Regenerate after any migration that touches model_snapshots; scripts/verify-schema-contract.js detects drift against a live database.",
"known_production_drift": {
"columns_in_production_not_in_migrations": [
"quarantine_reason",
"re_settled_at",
"settlement_source"
],
"explanation": "Present in production but not created by any committed migration - added out of band, same class as the migration-014 debt. The contract deliberately uses the MIGRATION-derived set, which is the stricter of the two: a writer that stays within it is valid against both.",
"classification": "PROD-ONLY COLUMN -> DRIFT WARNING / RECORDED DEBT (not release-authorized)"
},
"column_count": 65,
"columns": [
"actual_value",
"archetype",
"book",
"book_odds",
"canonical_event_id",
"captured_at",
"chain_shadow",
"change_type",
"claim_digest",
"claim_schema_version",
"code_sha",
"confidence",
"confidence_basis",
"created_at",
"cycle_hour_utc",
"devig_method",
"digest_algorithm_version",
"edge_pct",
"ev_pct",
"event_identity_method",
"event_identity_source",
"event_identity_version",
"event_occurrence",
"factor_inputs",
"fair_odds",
"fair_prob",
"features",
"game_date",
"game_id",
"grade",
"grade_11",
"id",
"line",
"lineage_action",
"lineage_state",
"lineage_version",
"model_version",
"opponent",
"outcome",
"over_odds",
"overround",
"p_win",
"player_key",
"player_name",
"probability_contract",
"projection",
"publication_id",
"published",
"published_at",
"read_id",
"read_natural_key",
"recaptures_id",
"refusal_reason",
"refused",
"revision_ordinal",
"settled_at",
"side",
"snapshot_id",
"sport",
"stat",
"supersedes_id",
"takeable",
"team",
"under_odds",
"value"
],
"authority": "RELEASE-AUTHORIZED model_snapshots INSERT CONTRACT",
"authority_note": "Derived from the migration chain, which is the release authority. Production is not. A column present in production but in no migration is DRIFT / RECORDED DEBT and is NOT release-authorized; it must never be copied into this contract from live schema."
}