Lineage family lookup: bound it to a slate, and say what an action is
TWO DEFECTS, one lookup. SCALE. The family lookup sent 100 natural keys as a PostgREST IN-list. `read_natural_key` has NO pg_stats row at all -- the table's last autoanalyze (2026-08-26) predates the column ever being populated -- so the planner used a default per-value selectivity, estimated 172,409 rows and chose a sequential scan of 344,818: 8.5s, then 57014. At 50 keys the same shape returned in ~357ms. The cliff is a statistics artifact, not a volume one, which is why the repair does not depend on the estimate improving and is not CH=50. `readNaturalKey` builds `sport|game_date|player_key|stat|side|line[|#event]`, so SPORT AND GAME_DATE ARE COMPONENTS OF THE KEY. Two rows sharing a key necessarily share both, and scoping the lookup to the (sport, game_date) pairs present in the requested keys is LOSSLESS BY CONSTRUCTION. One index-backed range per date, walked with safePaginate; cost is bounded by ONE SLATE however long the chronology gets. Measured: 5,000 keys -> 1 scope, and the plan is `Index Scan using model_snapshots_lineage_family_idx, cost 0.28..1.92`. VALIDITY. A row carrying `read_natural_key` is not history: the key is stamped on every candidate BEFORE the lookup, so a failure leaves it on a row that never became an action. Proven this was not cosmetic -- fed the raw rows the old lookup returned, the resolver produced a REVISION with a NULL read_id (an orphaned chain node) and labelled a brand-new Read LEGACY_UNVERIFIED. `isValidLineageAction` states what a completed action IS: all nine fields, in the query and again in code. ATOMICITY. A failed attempt now leaves NO lineage-specific state. `publication_id`/`published_at` are untouched -- the slate really was published, and erasing a true fact to tidy a false one is the wrong repair. Replayed the exact failed 19:00Z cohort through the real resolver, side-effect free: 119 NEW / 379 CHANGED / 621 UNCHANGED -> ORIGIN 119 / REVISION 379 / RECAPTURE 621, 0 wrong parent, 0 wrong ordinal, 0 null read_id, 0 forks -- byte-identical with all 1,119 failed partial rows present. Clean-head parity 1,024/1,024. Migration 050 is CONCURRENTLY + IF NOT EXISTS, drops nothing, rewrites nothing. Lineage stays OFF. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
This commit is contained in:
@@ -265,10 +265,18 @@ describe('PUBLICATION COMMIT TRUTH', () => {
|
||||
await retention.commitPublication({ rows, publicationId: 's', publishedAt: 't' }, deps);
|
||||
const first = rows[0].claim_digest;
|
||||
// Second run sees the first as existing history.
|
||||
// A COMPLETED lineage action, in the shape production actually persists.
|
||||
// `attachLineage` assigns the action, the state and both version stamps in
|
||||
// one block, and all 1,024 live rows carry all nine fields — a digest with
|
||||
// no schema version is uninterpretable, so the validity predicate requires
|
||||
// them. This fixture previously omitted four of them, describing a row the
|
||||
// writer cannot emit.
|
||||
const existing = [{
|
||||
id: 1, read_id: rows[0].read_id, read_natural_key: rows[0].read_natural_key,
|
||||
game_id: rows[0].game_id, claim_digest: first, revision_ordinal: 0,
|
||||
lineage_action: 'ORIGIN', supersedes_id: null, captured_at: rows[0].captured_at,
|
||||
lineage_state: 'LIVE', lineage_version: 'lin@1',
|
||||
claim_schema_version: 'claim@1', digest_algorithm_version: 'sha256-json-sorted@1',
|
||||
claim: rows[0],
|
||||
}];
|
||||
const rows2 = [served()];
|
||||
|
||||
Reference in New Issue
Block a user