MLB canonical event identity, impossible-binding refusal, event-aware dedupe, publication commit
Release-isolated slice built from 41ba38e. Ships ONLY the event-integrity +
publication + lineage-canary closure; the 90-path development tree stays
undeployed.
- canonical MLB event identity from statsapi gamePk (mlb:gamepk:<pk>), with
event_identity_source/method/version recorded. The id is canonical; the
binding is derived and says so.
- IMPOSSIBLE-BINDING REFUSAL. Verified in prod 2026-08-26: Joe Mack (Marlins)
was bound to Dodgers@Braves and Yandy Diaz (Rays) to Rangers@WhiteSox, both
from one book in the 01:00/03:01 UTC cycles after their own games began. Root
cause is source market data, not the binder. A prop whose player's team is not
an event participant now refuses; unknown team preserves uncertainty.
- event-aware dedupe: books still collapse, events no longer do. An unresolved
MLB event fractures rather than falling back to the collision-prone
date+teams key.
- publication commit moved AFTER the authoritative Redis slate write, with
exact parity-gap identity when the product publishes and the record does not.
- lineage dual-write behind LINEAGE_CANARY_SPORTS, DISABLED for this deploy.
Excluded deliberately: WNBA feed/chain, market ontology, PerformanceDistribution,
calibration certification, truth diagnostics, applyRevision Phase-1, and the
analyzeViaEngine1 confidence-rounding change (a served field).
Suite 380/5,040/0 from this worktree; web tsc exit 0; champion output identical
to production.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
-- Migration 046: publication semantics (ADDITIVE ONLY).
|
||||
--
|
||||
-- Every statement is ADD COLUMN IF NOT EXISTS or CREATE INDEX. Nothing is
|
||||
-- dropped, renamed, retyped or backfilled. Historical rows keep NULL.
|
||||
--
|
||||
-- ── WHY 045 WAS NOT ENOUGH ────────────────────────────────────────────────
|
||||
-- Migration 045 gave `model_snapshots` a lineage. Tracing the publication path
|
||||
-- afterwards showed the lineage would have described the wrong population:
|
||||
-- `gradeSlateService` fires its retention hook with BOTH sides, graded AND
|
||||
-- refused, BEFORE any filtering, and only the higher-confidence graded side
|
||||
-- becomes the served Read.
|
||||
--
|
||||
-- MEASURED, mlb 2026-08-26: of 13,012 captured rows, 3,859 were refusals and
|
||||
-- only 4,569 matched a prop that reached the ledger. **8,443 rows (64.9%)
|
||||
-- describe a state no user was ever shown**, and nothing on the row said which
|
||||
-- was which. Building chronology over all of them would have produced
|
||||
-- "publication history" for model activity that was never published.
|
||||
--
|
||||
-- `published` is the smallest missing link. It is set by the collector's
|
||||
-- publication signal at the one place that knows the answer — the moment the
|
||||
-- winner is selected — and defaults FALSE, because a capture is not a
|
||||
-- publication until something says it is.
|
||||
ALTER TABLE model_snapshots ADD COLUMN IF NOT EXISTS published boolean;
|
||||
|
||||
-- ── WHY THE PUBLISHED STATE ADVANCED ──────────────────────────────────────
|
||||
-- The revision ordinal says WHEN. It cannot say WHY, and the difference is the
|
||||
-- whole product question: VYNDR's belief can hold still while the market moves.
|
||||
-- A replay of one real date found 4,507 digest changes of which only 301 moved
|
||||
-- the grade — 4,206 were price alone. One undifferentiated "revision" count
|
||||
-- conflates a changed opinion with a changed price.
|
||||
ALTER TABLE model_snapshots ADD COLUMN IF NOT EXISTS change_type text;
|
||||
|
||||
-- ── CLAIM SEMANTICS ARE VERSIONED ─────────────────────────────────────────
|
||||
-- A digest is only interpretable against the claim definition that produced it.
|
||||
-- The first digest listed only `locked_odds` while this table stores
|
||||
-- `over_odds`/`under_odds`, so it was blind to price on exactly the rows it
|
||||
-- digested — caught by a replay crashing on a missing column, i.e. by luck.
|
||||
-- These stamps make the next such change visible instead of silent. A
|
||||
-- historical digest is never recomputed under a newer definition.
|
||||
ALTER TABLE model_snapshots ADD COLUMN IF NOT EXISTS claim_schema_version text;
|
||||
ALTER TABLE model_snapshots ADD COLUMN IF NOT EXISTS digest_algorithm_version text;
|
||||
|
||||
-- Publication chronology is read published-only; the partial index matches.
|
||||
CREATE INDEX IF NOT EXISTS model_snapshots_published_lineage_idx
|
||||
ON model_snapshots (read_id, revision_ordinal) WHERE published IS TRUE;
|
||||
|
||||
COMMENT ON COLUMN model_snapshots.published IS
|
||||
'TRUE only for the side that actually became the served Read. Measured: 64.9% of captured rows describe a state no user was shown, and before this column nothing on the row distinguished them. NULL on rows written before migration 046 - unknown, not reconstructed.';
|
||||
COMMENT ON COLUMN model_snapshots.change_type IS
|
||||
'INITIAL_PUBLICATION | BELIEF_CHANGE | MARKET_REPRICE | MARKET_LINE_CHANGE | COMPARISON_CHANGE | PROVENANCE_CHANGE | PRESENTATION_CHANGE | MIXED_CHANGE | NO_MATERIAL_PUBLISHED_CHANGE. Ordinal says when; this says why.';
|
||||
COMMENT ON COLUMN model_snapshots.claim_schema_version IS
|
||||
'The claim definition in force when the digest was computed. Never recompute a historical digest under a newer definition and present it as original.';
|
||||
Reference in New Issue
Block a user