Software watches coverage now, and ancestry becomes a product contract

Three closeout items, traced before building.

THE OBSERVER WAS DIAGNOSTICS, NOT MONITORING. Traced from the deployed tree:
exactly two callsites, both manual internal routes, and nothing in the scheduler
or ops path consumed it. A persistent lineage failure could have sat unnoticed
until a human asked.

The monitor now runs on the scheduler's per-minute tick, throttled to 30
minutes. It is placed there rather than after a snapshot on purpose: an
in-snapshot audit structurally cannot report that no snapshot ran, which is the
failure mode that matters most, and it would run under peak write contention
where the audit already demonstrably times out. It reads only the durable
observer and never `attachLineage`'s counters, and every failure path is
swallowed — a monitor that can take down the pipeline it watches is worse than
no monitor.

HEALTHY IS SILENCE; EVERYTHING ELSE SPEAKS. `coverageAlarm` is pure, so the
policy is testable and cannot drift into the scheduler. AUDIT_UNAVAILABLE says
"could not be measured — the audit did not run", deliberately worded so it can
never be read as "coverage is zero": those are different claims and collapsing
them is how a monitor starts lying in the reassuring direction. Alerts dedupe on
(health, cohort) so a standing fault states itself once and a NEW cohort with
the same fault speaks again.

ANCESTRY BECOMES A PRODUCT CONTRACT. It was internal-only. `GET
/api/ancestry/ledger/:id` (requireAuth, rate-limited) plus the Next proxy that
makes it browser-reachable, keyed on the LEDGER ROW ID — a stable identifier the
ledger API already returns — rather than a raw natural key exposed because it
was convenient. Its own router, so `routes/ledger.js` stays free of lineage
entirely and the grade-badge guard keeps its teeth. Every response declares
`authority: LOCAL, authority_scope: ANCESTRY_ONLY`.

THREE TEETH CAME BACK GREEN AND ALL THREE WERE MY TESTS, NOT SAFE DEFECTS.
The badge guard was CASE-SENSITIVE, so `LINEAGE_ANCESTRY` and `readAncestry`
walked straight past it. `try/finally` is valid JavaScript, so removing the
monitor's catch produced no load error and nothing asserted the containment.
And the multi-date cohort check was a grep for `.gte('game_date'` that the
head query satisfied on its own. All three replaced with behavioural tests,
including a scheduler double whose fake client HONOURS its filters — a
pass-through would have made a narrowed cohort walk look correct.

Suite 398/5,522/0 · tsc 0 · web build 0 · teeth 14/14 and 15/15.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
This commit is contained in:
Kev
2026-08-30 23:44:46 -04:00
parent f9c0255060
commit e5b20b0509
12 changed files with 673 additions and 9 deletions
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env node
/* CLOSEOUT TEETH — inject, prove the suite CATCHES it, restore byte-identically.
Every tooth asserts its own injection landed first: a green teeth run means
the test is missing, not that the risk is absent. */
const fs = require('fs'); const path = require('path'); const cp = require('child_process');
const F = (p) => path.join(__dirname, p);
const C = 'tests/unit/lineageCloseout.test.js';
const P = 'tests/unit/lineageProductization.test.js';
const TEETH = [
{ n: 1, name: 'the automatic monitor is removed from the tick',
file: 'src/snapshotScheduler.js',
from: " await coverageTick();", to: "", suite: C },
{ n: 2, name: 'the monitor takes its denominator from the writer',
file: 'src/services/lineageCoverage.js',
from: " if (!r || r.published !== true) continue;",
to: " if (!r || r.published !== true || r.lineage_action == null) continue;",
suite: `${C} ${P}` },
{ n: 3, name: 'a multi-date cohort is audited as one date slice',
file: 'src/services/lineageCoverage.js',
from: " .eq('snapshot_id', h.snapshot_id)\n .gte('game_date', lo)\n .lte('game_date', hi)",
to: " .eq('snapshot_id', h.snapshot_id)\n .eq('game_date', h.game_date)",
suite: C },
{ n: 4, name: 'an audit timeout reports HEALTHY',
file: 'src/services/lineageCoverage.js',
from: " if (summary.audit_available === false) return HEALTH.AUDIT_UNAVAILABLE;",
to: " if (summary.audit_available === false) return HEALTH.HEALTHY;",
suite: `${C} ${P}` },
{ n: 5, name: 'missing coverage passes the monitor silently',
file: 'src/services/lineageCoverage.js',
from: " if (health === HEALTH.HEALTHY || health === HEALTH.NO_ELIGIBLE_CLAIMS) {",
to: " if (health === HEALTH.HEALTHY || health === HEALTH.NO_ELIGIBLE_CLAIMS || health === HEALTH.MISSING_COVERAGE) {",
suite: C },
{ n: 6, name: 'the ancestry contract elects a partial row',
file: 'src/services/read/readAncestry.js',
from: "const isValidAction = (r) => !!r && VALID_ACTION_FIELDS.every((f) => r[f] !== null && r[f] !== undefined);",
to: "const isValidAction = (r) => !!r && r.read_id !== null && r.read_id !== undefined;",
suite: `${C} ${P}` },
{ n: 7, name: 'an incomplete chronology reports itself complete',
file: 'src/services/read/readAncestry.js',
from: " const unrecorded = attempted.filter((r) => !isValidAction(r)).length;",
to: " const unrecorded = 0;",
suite: `${C} ${P}` },
{ n: 8, name: 'a legacy row is given synthetic lineage',
file: 'src/services/read/readAncestry.js',
from: " state: ANCESTRY_STATE.LEGACY_UNVERIFIED,\n reason: 'published before lineage recording began',",
to: " state: ANCESTRY_STATE.LINEAGE_AVAILABLE,\n reason: 'published before lineage recording began',",
suite: `${C} ${P}` },
{ n: 9, name: 'lineage is wired into the grade badge router',
file: 'src/routes/ledger.js',
from: "const ROW_COLUMNS = 'id, player_key",
to: "const LINEAGE_ANCESTRY = require('../services/read/readAncestry');\nconst ROW_COLUMNS = 'id, player_key",
suite: `${C} ${P}` },
{ n: 10, name: 'the monitor is allowed to break the scheduler',
file: 'src/snapshotScheduler.js',
from: " } catch { /* the monitor must never break the scheduler */ }",
to: " } finally { /* unguarded */ }",
suite: C, expectLoadError: true },
{ n: 11, name: 'persistent shadow is made subject to the canary lease',
file: 'src/services/lineageWriteMode.js',
from: " return Object.prototype.hasOwnProperty.call(evaluate(now).modes, sp);",
to: " return canary.isEnabled(sp, now);",
suite: P },
{ n: 12, name: 'participant identity convergence reverted',
file: 'src/services/model/participantIdentity.js',
from: " const canonical = p.mlb_person_id != null ? p.canonical_player_name : null;",
to: " const canonical = null;",
suite: `${P} tests/unit/participantIdentityConvergence.test.js` },
{ n: 13, name: 'the retention collision gate is weakened',
file: 'src/services/retentionService.js',
from: " if (seen.has(id)) collisions += 1;",
to: " if (false) collisions += 1;",
suite: `${P} tests/unit/canonicalParticipant.test.js` },
{ n: 14, name: 'model belief moved',
file: 'src/services/intelligence/probabilityEstimator.js',
from: "function estimate", to: "function estimate_TEETH_BROKEN",
suite: 'tests/unit/probabilityEstimator.test.js' },
];
let caught = 0; const missed = [];
for (const t of TEETH) {
const p = F(t.file);
const orig = fs.readFileSync(p, 'utf8');
if (!orig.includes(t.from)) { missed.push(`${t.n} ANCHOR NOT FOUND: ${t.name}`); continue; }
const broken = orig.replace(t.from, t.to);
if (broken === orig) { missed.push(`${t.n} INJECTION NO-OP: ${t.name}`); continue; }
fs.writeFileSync(p, broken);
const present = t.to === '' ? !fs.readFileSync(p, 'utf8').includes(t.from)
: fs.readFileSync(p, 'utf8').includes(t.to);
let failed = false;
try {
cp.execSync(`npx jest ${t.suite} --testPathIgnorePatterns "/node_modules/" --silent --forceExit`,
{ cwd: __dirname, stdio: 'pipe' });
} catch { failed = true; }
fs.writeFileSync(p, orig);
if (fs.readFileSync(p, 'utf8') !== orig) { console.error('RESTORE FAILED', t.file); process.exit(2); }
if (!present) { missed.push(`${t.n} INJECTION NOT PRESENT: ${t.name}`); continue; }
if (failed) { caught += 1; console.log(` tooth ${String(t.n).padStart(2)} CAUGHT ${t.name}`); }
else { missed.push(`${t.n} NOT CAUGHT: ${t.name}`); console.log(` tooth ${String(t.n).padStart(2)} MISSED ${t.name}`); }
}
console.log(`\n ${caught}/${TEETH.length} teeth landed`);
if (missed.length) { console.log(' PROBLEMS:'); missed.forEach((m) => console.log(' ', m)); process.exit(1); }
+4
View File
@@ -125,6 +125,10 @@ app.use('/api/alerts', alertsRoutes);
app.use('/api/bets', betsRoutes); app.use('/api/bets', betsRoutes);
// Session 49 — per-user onboarding preferences (auth-gated, user_metadata). // Session 49 — per-user onboarding preferences (auth-gated, user_metadata).
app.use('/api/preferences', require('./routes/preferences')); app.use('/api/preferences', require('./routes/preferences'));
// ADDITIVE ancestry contract — lineage is locally authoritative for Read
// ancestry and nothing else. Its own router so the ledger router stays free of
// lineage entirely, which is what keeps the grade-shift badge guard meaningful.
app.use('/api/ancestry', require('./routes/ancestry'));
app.use('/api/stripe', stripeRoutes); app.use('/api/stripe', stripeRoutes);
app.use('/api/stats', statsRoutes); app.use('/api/stats', statsRoutes);
app.use('/api/props', propsRoutes); app.use('/api/props', propsRoutes);
+80
View File
@@ -0,0 +1,80 @@
/**
* READ ANCESTRY — the narrow PRODUCT contract for the one truth lineage owns.
*
* LOCAL AUTHORITY, AND ONLY LOCAL. For this contract lineage IS the source of
* truth: which published Read came first, what superseded what, whether a later
* observation revised or recaptured the same claim. That says nothing about the
* live slate (Redis), the model, the market, the Ledger or settlement, all of
* which keep their own authorities untouched.
*
* IT IS NOT THE GRADE-SHIFT BADGE. `revised_from_grade` answers "did the
* model's letter change"; a lineage REVISION answers "did the published claim
* change", which includes price. Different questions, different fields,
* different route — deliberately not bolted onto the ledger response.
*
* The identifier is the LEDGER ROW ID: a stable product identifier the ledger
* API already returns, rather than a raw database natural key exposed because
* it happened to be convenient.
*/
const express = require('express');
const { createRateLimit } = require('../middleware/rateLimit');
const { requireAuth } = require('../middleware/auth');
const readAncestry = require('../services/read/readAncestry');
const router = express.Router();
router.use(createRateLimit({ max: 60, windowMs: 60 * 1000 }));
const LEDGER_COLUMNS = 'id, sport, game_date, player_key, player_name, stat, side, line, game_id';
/**
* GET /api/ancestry/ledger/:id
*
* Ancestry for the published Read behind one ledger row. Additive: no existing
* response changes, and nothing here is consulted by any other surface.
*/
router.get('/ledger/:id', requireAuth, async (req, res) => {
const id = Number.parseInt(req.params.id, 10);
if (!Number.isFinite(id) || id <= 0) {
return res.status(400).json({ error: 'invalid ledger id' });
}
try {
const { getSupabaseServiceClient } = require('../utils/supabase');
const supabase = getSupabaseServiceClient();
if (!supabase) {
return res.status(503).json({ state: readAncestry.ANCESTRY_STATE.LINEAGE_UNAVAILABLE, reason: 'store unavailable' });
}
const { data, error } = await supabase
.from('ledger_entries').select(LEDGER_COLUMNS).eq('id', id).limit(1);
if (error) return res.status(500).json({ error: error.message });
if (!data || data.length === 0) {
return res.status(404).json({ state: readAncestry.ANCESTRY_STATE.NOT_FOUND, reason: 'no such ledger row' });
}
const row = data[0];
const ancestry = await readAncestry.ancestryForRead({
sport: row.sport,
game_date: row.game_date,
player_key: row.player_key,
stat: row.stat,
side: row.side,
line: row.line,
});
return res.json({
ledger_id: row.id,
player_name: row.player_name,
stat: row.stat,
side: row.side,
line: row.line,
game_date: row.game_date,
sport: row.sport,
ancestry,
// Said on every response. This contract owns ancestry and nothing else.
authority: 'LOCAL',
authority_scope: 'ANCESTRY_ONLY',
});
} catch (e) {
return res.status(500).json({ error: e.message });
}
});
module.exports = router;
+94 -1
View File
@@ -183,6 +183,99 @@ const AUDIT_COLUMNS = [
* published and recorded nothing surfaces as MISSING_COVERAGE rather than as * published and recorded nothing surfaces as MISSING_COVERAGE rather than as
* silence. * silence.
*/ */
/**
* Audit ONE NAMED COHORT — the exact snapshot_id that just completed, across
* every game_date it spans.
*
* The snapshot_id is cohort IDENTITY, not a success claim: expected and covered
* are still derived here from durable state, and `attachLineage`'s counters are
* never consulted. Passing the id is what makes this "the cohort that just
* completed" rather than "whatever is newest", which the multi-date bug showed
* are not the same question.
*/
async function auditCohort(sport, snapshotId, deps = {}) {
const sp = String(sport || '').toLowerCase();
const unavailable = (reason) => Object.freeze({
audit_available: false, reason, sport: sp, snapshot_id: snapshotId || null,
health: HEALTH.AUDIT_UNAVAILABLE,
});
if (!snapshotId) return unavailable('no_snapshot_id');
try {
const getClient = deps.getClient || require('../utils/supabase').getSupabaseServiceClient;
const supabase = getClient();
if (!supabase) return unavailable('no_supabase_env');
const nowIso = deps.now ? deps.now() : new Date().toISOString();
// Same index discipline as the latest-cohort audit: every read bounded on
// game_date, because `snapshot_id` carries no index of its own.
const anchor = deps.gameDate || nowIso.slice(0, 10);
const lo = shiftDate(anchor, -2);
const hi = shiftDate(anchor, 2);
const { paginate } = require('../utils/safePaginate');
const rows = await paginate(() => supabase
.from('model_snapshots')
.select(AUDIT_COLUMNS)
.eq('sport', sp)
.eq('snapshot_id', snapshotId)
.gte('game_date', lo)
.lte('game_date', hi), { key: 'id', label: 'lineageCoverage.auditCohort' });
const dates = [...new Set(rows.map((r) => r.game_date))].sort();
const audit = auditRows(rows, {
snapshot_id: snapshotId, sport: sp, game_date: dates.join(','),
code_sha: rows[0] ? rows[0].code_sha : null,
captured_at: rows[0] ? rows[0].captured_at : null,
});
return Object.freeze({ ...audit, date_window: [lo, hi], game_dates_audited: dates });
} catch (e) {
return unavailable(e && e.message ? e.message : String(e));
}
}
/**
* Should the periodic monitor run now? Pure, so the cadence is testable without
* a clock or a scheduler.
*/
function coverageDue(lastAtMs, nowMs, everyMs = 30 * 60 * 1000) {
if (!Number.isFinite(nowMs)) return false;
if (!Number.isFinite(lastAtMs)) return true;
return nowMs - lastAtMs >= everyMs;
}
/**
* What, if anything, to say about an audit — pure, so the alert policy is
* testable and cannot drift into the scheduler.
*
* HEALTHY is silence. Everything else speaks, and AUDIT_UNAVAILABLE speaks
* DIFFERENTLY from MISSING_COVERAGE: "we could not measure" and "there is
* nothing there" are different claims, and collapsing them is how a monitor
* starts lying in the reassuring direction.
*
* Deduped on (health, snapshot_id) so a standing condition states itself once
* rather than paging every cycle.
*/
function coverageAlarm(prev, audit) {
const a = audit || {};
const health = a.health || HEALTH.AUDIT_UNAVAILABLE;
const key = `${health}|${a.snapshot_id || 'none'}`;
if (health === HEALTH.HEALTHY || health === HEALTH.NO_ELIGIBLE_CLAIMS) {
return { alert: false, key, message: null, priority: null };
}
if (prev === key) return { alert: false, key, message: null, priority: null, deduped: true };
const where = `${(a.sport || '?').toUpperCase()} cohort ${String(a.snapshot_id || 'unknown').slice(0, 8)}`;
const messages = {
[HEALTH.MISSING_COVERAGE]: `Lineage coverage MISSING on ${where} — ${a.expected_keys} published Reads, ${a.covered_keys} recorded. The slate published; the record did not. Product is unaffected.`,
[HEALTH.PARTIAL_COVERAGE]: `Lineage coverage PARTIAL on ${where} — ${a.covered_keys}/${a.expected_keys} recorded (${a.coverage_pct}%), ${a.missing_keys} missing. Product is unaffected.`,
[HEALTH.INVALID_GRAPH]: `Lineage graph INVALID on ${where} — ${a.invalid_partial_actions} partial actions, ${a.graph_defects} defects, ${a.extra_keys} unexpected. Product is unaffected.`,
[HEALTH.STALE]: `Lineage coverage STALE — newest audited cohort ${where} is ${Math.round((a.age_ms || 0) / 3600000)}h old. Coverage has stopped advancing.`,
[HEALTH.AUDIT_UNAVAILABLE]: `Lineage coverage COULD NOT BE MEASURED (${a.reason || 'unknown'}). This is not a coverage result; the audit did not run.`,
};
return {
alert: true,
key,
message: messages[health] || `Lineage coverage ${health} on ${where}.`,
priority: health === HEALTH.AUDIT_UNAVAILABLE ? 'default' : 'high',
};
}
/** ISO date offset by whole days, for the query-plan window below. */ /** ISO date offset by whole days, for the query-plan window below. */
function shiftDate(isoDate, days) { function shiftDate(isoDate, days) {
const d = new Date(`${String(isoDate).slice(0, 10)}T00:00:00Z`); const d = new Date(`${String(isoDate).slice(0, 10)}T00:00:00Z`);
@@ -278,5 +371,5 @@ async function auditLatestCohort(sport, deps = {}) {
module.exports = { module.exports = {
HEALTH, VALID_ACTION_FIELDS, AUDIT_COLUMNS, HEALTH, VALID_ACTION_FIELDS, AUDIT_COLUMNS,
isValidAction, expectedKeys, coveredKeys, graphDefects, classify, shiftDate, isValidAction, expectedKeys, coveredKeys, graphDefects, classify, shiftDate,
auditRows, auditLatestCohort, auditRows, auditLatestCohort, auditCohort, coverageDue, coverageAlarm,
}; };
+38 -1
View File
@@ -158,9 +158,46 @@ function startSnapshotScheduler(opts = {}) {
} catch { /* the pulse must never break the scheduler */ } } catch { /* the pulse must never break the scheduler */ }
}; };
// ── AUTOMATIC INDEPENDENT LINEAGE COVERAGE MONITOR ──────────────────────
//
// A protected endpoint that finds MISSING_COVERAGE only after a human asks is
// diagnostics, not monitoring. This runs on the per-minute cadence like the
// overdue watchdog, throttled, and it is INDEPENDENT of the lineage writer in
// both directions: it never sees `attachLineage`'s counters, and it does not
// need a snapshot to have completed in this process — so it still speaks when
// the writer never ran at all, which an in-snapshot audit structurally cannot.
//
// It is NOT product infrastructure. Every failure path here is swallowed; a
// monitor that can take down the pipeline it watches is worse than no monitor.
const lineageCoverage = opts.lineageCoverage || require('./services/lineageCoverage');
const COVERAGE_EVERY_MS = Number.parseInt(process.env.LINEAGE_COVERAGE_EVERY_MS || '', 10)
|| 30 * 60 * 1000;
let lastCoverageAtMs = null;
let lastCoverageAlertKey = null;
const coverageTick = async () => {
try {
const nowMs = now().getTime();
if (!lineageCoverage.coverageDue(lastCoverageAtMs, nowMs, COVERAGE_EVERY_MS)) return;
lastCoverageAtMs = nowMs;
const audit = await lineageCoverage.auditLatestCohort('mlb', { now: () => now().toISOString() });
const alarm = lineageCoverage.coverageAlarm(lastCoverageAlertKey, audit);
lastCoverageAlertKey = alarm.key;
console.log(`[lineage-coverage] mlb ${audit.health}`
+ ` ${audit.covered_keys ?? '?'}/${audit.expected_keys ?? '?'}`
+ ` cohort=${String(audit.snapshot_id || 'none').slice(0, 8)}`
+ `${audit.reason ? ` reason=${audit.reason}` : ''}`);
if (alarm.alert) {
await notify(alarm.message, {
title: 'VYNDR lineage', priority: alarm.priority, tags: ['open_book'],
});
}
} catch { /* the monitor must never break the scheduler */ }
};
const tick = async () => { const tick = async () => {
await checkOverdue(); await checkOverdue();
await pulseTick(); await pulseTick();
await coverageTick();
const d = now(); const d = now();
if (d.getUTCMinutes() !== 0) return; if (d.getUTCMinutes() !== 0) return;
const h = d.getUTCHours(); const h = d.getUTCHours();
@@ -467,7 +504,7 @@ function startSnapshotScheduler(opts = {}) {
console.log(`[settlement] armed — ${settleTags} outcomes + ledger settle pass runs FIRST at each snapshot slot (${HOURS_UTC.join(',')} UTC), idempotent re-runs`); console.log(`[settlement] armed — ${settleTags} outcomes + ledger settle pass runs FIRST at each snapshot slot (${HOURS_UTC.join(',')} UTC), idempotent re-runs`);
// Session 8 — same verifiability rule: every watchdog states itself at boot. // Session 8 — same verifiability rule: every watchdog states itself at boot.
console.log(`[opsWatch] armed — settle alarms (throw + morning zero-settle), failure pager (${failureTracker.threshold} consecutive), quota daily check, pulse ${PULSE_HOUR_UTC}:00 UTC`); console.log(`[opsWatch] armed — settle alarms (throw + morning zero-settle), failure pager (${failureTracker.threshold} consecutive), quota daily check, pulse ${PULSE_HOUR_UTC}:00 UTC`);
return { interval, tick, refreshTick, pulseTick }; return { interval, tick, refreshTick, pulseTick, coverageTick };
} }
module.exports = { startSnapshotScheduler, HOURS_UTC, mostRecentExpectedSlot, isSnapshotOverdue }; module.exports = { startSnapshotScheduler, HOURS_UTC, mostRecentExpectedSlot, isSnapshotOverdue };
+302
View File
@@ -0,0 +1,302 @@
/**
* LINEAGE PRODUCTIZATION CLOSEOUT — automatic coverage monitoring and the
* additive ancestry product contract.
*
* Two properties: the monitor speaks without being asked and never lies in the
* reassuring direction; the product contract owns ancestry and nothing else.
*/
const coverage = require('../../src/services/lineageCoverage');
const ancestry = require('../../src/services/read/readAncestry');
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..', '..');
/* ───────────────── AUTOMATIC MONITOR ───────────────── */
describe('the monitor runs without being asked', () => {
test('the scheduler invokes the durable observer on its own cadence', () => {
const src = fs.readFileSync(path.join(ROOT, 'src/snapshotScheduler.js'), 'utf8');
expect(src).toMatch(/coverageTick/);
expect(src).toMatch(/lineageCoverage\.auditLatestCohort/);
// Called from the per-minute tick, not from a slot branch: a monitor that
// only runs when a snapshot fires cannot report that no snapshot fired.
const tick = src.slice(src.indexOf('const tick = async () =>'));
expect(tick.slice(0, 300)).toMatch(/await coverageTick\(\)/);
});
test('the monitor consumes the observer, never the writer', () => {
const src = fs.readFileSync(path.join(ROOT, 'src/snapshotScheduler.js'), 'utf8');
const fn = src.slice(src.indexOf('const coverageTick'), src.indexOf('const tick = async () =>'));
expect(fn).not.toMatch(/attachLineage|lineage\.origins|pub\.lineage/);
});
test('cadence is a pure predicate', () => {
expect(coverage.coverageDue(null, 1_000)).toBe(true);
expect(coverage.coverageDue(1_000, 1_000 + 29 * 60_000)).toBe(false);
expect(coverage.coverageDue(1_000, 1_000 + 31 * 60_000)).toBe(true);
expect(coverage.coverageDue(1_000, Number.NaN)).toBe(false);
});
});
describe('alert policy — silence only when healthy', () => {
const A = (h, extra = {}) => coverage.coverageAlarm(null, { health: h, sport: 'mlb', snapshot_id: 'abc12345', ...extra });
test('HEALTHY and NO_ELIGIBLE_CLAIMS are silent', () => {
expect(A(coverage.HEALTH.HEALTHY).alert).toBe(false);
expect(A(coverage.HEALTH.NO_ELIGIBLE_CLAIMS).alert).toBe(false);
});
test('every unhealthy state alerts', () => {
for (const h of [coverage.HEALTH.MISSING_COVERAGE, coverage.HEALTH.PARTIAL_COVERAGE,
coverage.HEALTH.INVALID_GRAPH, coverage.HEALTH.STALE, coverage.HEALTH.AUDIT_UNAVAILABLE]) {
expect(A(h).alert).toBe(true);
expect(typeof A(h).message).toBe('string');
}
});
test('AUDIT_UNAVAILABLE says it could not measure — it is NOT a coverage result', () => {
const m = A(coverage.HEALTH.AUDIT_UNAVAILABLE, { reason: 'statement timeout' }).message;
expect(m).toMatch(/COULD NOT BE MEASURED/);
expect(m).toMatch(/did not run/);
expect(m).not.toMatch(/0 recorded|MISSING/);
});
test('a standing condition states itself once', () => {
const first = coverage.coverageAlarm(null, { health: coverage.HEALTH.MISSING_COVERAGE, snapshot_id: 's1' });
expect(first.alert).toBe(true);
const second = coverage.coverageAlarm(first.key, { health: coverage.HEALTH.MISSING_COVERAGE, snapshot_id: 's1' });
expect(second.alert).toBe(false);
// A NEW cohort with the same fault speaks again.
const third = coverage.coverageAlarm(first.key, { health: coverage.HEALTH.MISSING_COVERAGE, snapshot_id: 's2' });
expect(third.alert).toBe(true);
});
test('an unreadable audit never reports HEALTHY', () => {
expect(coverage.classify({ audit_available: false })).toBe(coverage.HEALTH.AUDIT_UNAVAILABLE);
expect(A(coverage.HEALTH.AUDIT_UNAVAILABLE).alert).toBe(true);
});
});
describe('STALE is provable without an outage', () => {
test('a healthy cohort older than the window becomes STALE by injected time', async () => {
const rows = [{
id: 1, sport: 'mlb', game_date: '2026-08-31', player_key: 'a', stat: 'hits', side: 'over',
line: 0.5, published: true, captured_at: '2026-08-31T03:00:00Z',
read_id: 'r1', read_natural_key: 'mlb|2026-08-31|a|hits|over|0.500000',
lineage_action: 'ORIGIN', claim_digest: 'd', revision_ordinal: 0, lineage_state: 's',
lineage_version: 'lin@1', claim_schema_version: 'claim@1', digest_algorithm_version: 'x',
}];
const client = () => ({
from: () => ({
select: () => ({
eq() { return this; }, gte() { return this; }, lte() { return this; },
order() { return this; },
limit: async () => ({ data: [{ snapshot_id: 's1', game_date: '2026-08-31', captured_at: '2026-08-31T03:00:00Z', code_sha: 'sha' }], error: null }),
range: async (from) => ({ data: from === 0 ? rows : [], error: null }),
}),
}),
});
const fresh = await coverage.auditLatestCohort('mlb', { getClient: client, now: () => '2026-08-31T04:00:00Z' });
expect(fresh.health).toBe(coverage.HEALTH.HEALTHY);
const stale = await coverage.auditLatestCohort('mlb', { getClient: client, now: () => '2026-09-01T12:00:00Z' });
expect(stale.health).toBe(coverage.HEALTH.STALE);
});
});
/** A test double must HONOUR a filter, not merely accept one: a pass-through
* fake would return every row regardless of the query and make a narrowed
* cohort walk look correct. */
function fakeClient(rows, headRow) {
const build = () => {
const preds = [];
const q = {
eq(col, val) { preds.push((r) => String(r[col]) === String(val)); return this; },
gte(col, val) { preds.push((r) => String(r[col]) >= String(val)); return this; },
lte(col, val) { preds.push((r) => String(r[col]) <= String(val)); return this; },
order() { return this; },
limit: async () => ({ data: [headRow], error: null }),
range: async (from) => ({
data: from === 0 ? rows.filter((r) => preds.every((p) => p(r))) : [],
error: null,
}),
};
return q;
};
return () => ({ from: () => ({ select: () => build() }) });
}
describe('a cohort spanning two game_dates is walked whole (behavioural)', () => {
const act = (d, p) => ({
id: p === 'a' ? 1 : 2, sport: 'mlb', game_date: d, player_key: p, stat: 'hits',
side: 'over', line: 0.5, published: true, captured_at: '2026-08-31T03:00:00Z',
snapshot_id: 's1', code_sha: 'sha',
read_id: `r-${p}`, read_natural_key: `mlb|${d}|${p}|hits|over|0.500000`,
lineage_action: 'ORIGIN', claim_digest: 'd', revision_ordinal: 0, lineage_state: 's',
lineage_version: 'lin@1', claim_schema_version: 'claim@1', digest_algorithm_version: 'x',
});
test('both date slices are counted, not just the head row\'s date', async () => {
const rows = [act('2026-08-31', 'a'), act('2026-08-30', 'b')];
const head = { snapshot_id: 's1', game_date: '2026-08-31', captured_at: '2026-08-31T03:00:00Z', code_sha: 'sha' };
const out = await coverage.auditLatestCohort('mlb', {
getClient: fakeClient(rows, head), now: () => '2026-08-31T03:30:00Z',
});
expect(out.rows).toBe(2);
expect(out.expected_keys).toBe(2);
expect(out.covered_keys).toBe(2);
expect(out.game_dates_audited).toEqual(['2026-08-30', '2026-08-31']);
expect(out.health).toBe(coverage.HEALTH.HEALTHY);
});
});
describe('the monitor cannot break the scheduler (behavioural)', () => {
const OLD = process.env.SNAPSHOT_CRON;
afterEach(() => { if (OLD === undefined) delete process.env.SNAPSHOT_CRON; else process.env.SNAPSHOT_CRON = OLD; });
test('an observer that throws is swallowed, and no alert is attempted', async () => {
process.env.SNAPSHOT_CRON = '1';
const { startSnapshotScheduler } = require('../../src/snapshotScheduler');
const notifies = [];
const sched = startSnapshotScheduler({
runAllSnapshots: async () => [],
notify: async (m) => { notifies.push(m); },
lineageCoverage: {
coverageDue: () => true,
auditLatestCohort: async () => { throw new Error('observer exploded'); },
coverageAlarm: () => { throw new Error('should not be reached'); },
},
});
expect(sched).toBeTruthy();
if (sched.interval) clearInterval(sched.interval);
// Must resolve, not reject. A monitor that can take down the pipeline it
// watches is worse than no monitor.
await expect(sched.coverageTick()).resolves.toBeUndefined();
expect(notifies).toEqual([]);
});
test('a healthy audit alerts nothing; an unhealthy one alerts once', async () => {
process.env.SNAPSHOT_CRON = '1';
const { startSnapshotScheduler } = require('../../src/snapshotScheduler');
const notifies = [];
const real = require('../../src/services/lineageCoverage');
let health = coverage.HEALTH.HEALTHY;
const sched = startSnapshotScheduler({
runAllSnapshots: async () => [],
notify: async (m) => { notifies.push(m); },
lineageCoverage: {
coverageDue: () => true,
auditLatestCohort: async () => ({ health, sport: 'mlb', snapshot_id: 's1', expected_keys: 801, covered_keys: 0 }),
coverageAlarm: real.coverageAlarm,
HEALTH: real.HEALTH,
},
});
if (sched.interval) clearInterval(sched.interval);
await sched.coverageTick();
expect(notifies).toEqual([]);
health = coverage.HEALTH.MISSING_COVERAGE;
await sched.coverageTick();
expect(notifies).toHaveLength(1);
expect(notifies[0]).toMatch(/MISSING/);
await sched.coverageTick();
expect(notifies).toHaveLength(1); // deduped
});
});
describe('index discipline is preserved', () => {
test('every cohort read is bounded on game_date', () => {
const src = fs.readFileSync(path.join(ROOT, 'src/services/lineageCoverage.js'), 'utf8');
for (const fn of ['auditLatestCohort', 'auditCohort']) {
const body = src.slice(src.indexOf(`async function ${fn}`));
const end = body.indexOf('\n}\n');
const scoped = body.slice(0, end);
expect(scoped).toMatch(/\.gte\('game_date'/);
expect(scoped).toMatch(/\.lte\('game_date'|\.gte\('game_date', from\)/);
}
});
test('a named cohort audit refuses without an id rather than auditing something else', async () => {
const out = await coverage.auditCohort('mlb', null, {});
expect(out.health).toBe(coverage.HEALTH.AUDIT_UNAVAILABLE);
expect(out.reason).toBe('no_snapshot_id');
});
});
/* ───────────────── PRODUCT ANCESTRY CONTRACT ───────────────── */
describe('the ancestry product contract', () => {
const routeSrc = fs.readFileSync(path.join(ROOT, 'src/routes/ancestry.js'), 'utf8');
test('it is authenticated', () => {
expect(routeSrc).toMatch(/requireAuth/);
expect(routeSrc).toMatch(/router\.get\('\/ledger\/:id', requireAuth/);
});
test('it is keyed on a stable product identifier, not a raw natural key', () => {
expect(routeSrc).toMatch(/ledger_entries/);
expect(routeSrc).not.toMatch(/read_natural_key/);
});
test('it declares LOCAL authority scoped to ancestry', () => {
expect(routeSrc).toMatch(/authority: 'LOCAL'/);
expect(routeSrc).toMatch(/authority_scope: 'ANCESTRY_ONLY'/);
});
test('it is reachable from the browser (the S25 proxy rule)', () => {
const proxy = path.join(ROOT, 'web/src/app/api/ancestry/ledger/[id]/route.ts');
expect(fs.existsSync(proxy)).toBe(true);
expect(fs.readFileSync(proxy, 'utf8')).toMatch(/api\/ancestry\/ledger/);
});
test('it is mounted', () => {
expect(fs.readFileSync(path.join(ROOT, 'src/app.js'), 'utf8'))
.toMatch(/app\.use\('\/api\/ancestry', require\('\.\/routes\/ancestry'\)\)/);
});
test('the ledger and profile routers still contain no lineage at all', () => {
for (const f of ['src/routes/ledger.js', 'src/routes/profiles.js']) {
const s = fs.readFileSync(path.join(ROOT, f), 'utf8');
expect(s).toMatch(/revised_from_grade/);
// CASE-INSENSITIVE on purpose: `LINEAGE_ANCESTRY` and `readAncestry`
// both slipped past a case-sensitive guard when this was injected.
expect(s).not.toMatch(/lineage|ancestry|read_id/i);
}
});
test('the route writes nothing', () => {
const stripped = routeSrc.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
for (const verb of ['.insert(', '.update(', '.upsert(', '.delete(']) {
expect(stripped).not.toContain(verb);
}
});
});
describe('ancestry response states, end to end', () => {
const A = ancestry.ANCESTRY_STATE;
const act = (o) => ({
id: 1, read_id: 'r1', read_natural_key: 'k', lineage_action: 'ORIGIN', claim_digest: 'd0',
revision_ordinal: 0, lineage_state: 'PUBLISHED', lineage_version: 'lin@1',
claim_schema_version: 'claim@1', digest_algorithm_version: 'x', publication_id: 'p1', ...o,
});
test('ORIGIN / REVISION / RECAPTURE / legacy / failed / incomplete / invalid', () => {
expect(ancestry.classifyAncestry([act({})]).state).toBe(A.LINEAGE_AVAILABLE);
expect(ancestry.classifyAncestry([
act({ id: 1 }), act({ id: 2, lineage_action: 'REVISION', revision_ordinal: 1, supersedes_id: 1 }),
]).revision_count).toBe(1);
expect(ancestry.classifyAncestry([
act({ id: 1 }), act({ id: 2, lineage_action: 'RECAPTURE', recaptures_id: 1 }),
]).recapture_count).toBe(1);
expect(ancestry.classifyAncestry([{ id: 1, publication_id: null }]).state).toBe(A.LEGACY_UNVERIFIED);
expect(ancestry.classifyAncestry([{ id: 1, publication_id: 'p' }]).state).toBe(A.LINEAGE_UNAVAILABLE);
expect(ancestry.classifyAncestry([act({ id: 1 }), { id: 2, publication_id: 'p2' }]).chronology_complete).toBe(false);
expect(ancestry.classifyAncestry([
act({ id: 1 }), act({ id: 2, lineage_action: 'REVISION', revision_ordinal: 1, supersedes_id: 999 }),
]).state).toBe(A.INVALID_LINEAGE);
expect(ancestry.classifyAncestry([]).state).toBe(A.NOT_FOUND);
});
test('other sports are unaffected — nothing here is sport-specific product logic', () => {
const out = ancestry.classifyAncestry([act({ id: 1 })]);
expect(out.state).toBe(A.LINEAGE_AVAILABLE);
expect(out.authority).toBe('NON_AUTHORITATIVE');
});
});
+1 -1
View File
@@ -501,7 +501,7 @@ describe('this tranche changes nothing it was told not to', () => {
for (const f of ['src/routes/ledger.js', 'src/routes/profiles.js']) { for (const f of ['src/routes/ledger.js', 'src/routes/profiles.js']) {
const src = fs.readFileSync(path.join(ROOT, f), 'utf8'); const src = fs.readFileSync(path.join(ROOT, f), 'utf8');
expect(src).toMatch(/revised_from_grade/); expect(src).toMatch(/revised_from_grade/);
expect(src).not.toMatch(/lineage|read_id/); expect(src).not.toMatch(/lineage|ancestry|read_id/i);
} }
}); });
+6 -2
View File
@@ -345,10 +345,14 @@ describe('NON-AUTHORITY — lineage cannot serve the product', () => {
.test(fs.readFileSync(f, 'utf8'))).map((f) => path.relative(ROOT, f)); .test(fs.readFileSync(f, 'utf8'))).map((f) => path.relative(ROOT, f));
expect(webHits).toEqual([]); expect(webHits).toEqual([]);
} }
// Exactly TWO routers may reach lineage: the protected internal router and
// the additive ancestry contract. The ledger and profile routers — which
// serve the grade-shift badge — must never appear here, which is what makes
// this list a boundary rather than a rubber stamp.
const routeHits = walk(path.join(ROOT, 'src/routes')) const routeHits = walk(path.join(ROOT, 'src/routes'))
.filter((f) => /readLineage|readAncestry|lineageCoverage/.test(fs.readFileSync(f, 'utf8'))) .filter((f) => /readLineage|readAncestry|lineageCoverage/.test(fs.readFileSync(f, 'utf8')))
.map((f) => path.basename(f)); .map((f) => path.basename(f)).sort();
expect(routeHits).toEqual(['internal.js']); expect(routeHits).toEqual(['ancestry.js', 'internal.js']);
}); });
test('no route or web file reads a publication-semantics column', () => { test('no route or web file reads a publication-semantics column', () => {
+6 -2
View File
@@ -398,10 +398,14 @@ describe('SHADOW AUTHORITY', () => {
.test(fs.readFileSync(f, 'utf8'))).map((f) => path.relative(ROOT, f)); .test(fs.readFileSync(f, 'utf8'))).map((f) => path.relative(ROOT, f));
expect(webHits).toEqual([]); expect(webHits).toEqual([]);
} }
// Exactly TWO routers may reach lineage: the protected internal router and
// the additive ancestry contract. The ledger and profile routers — which
// serve the grade-shift badge — must never appear here, which is what makes
// this list a boundary rather than a rubber stamp.
const routeHits = walk(path.join(ROOT, 'src/routes')) const routeHits = walk(path.join(ROOT, 'src/routes'))
.filter((f) => /readLineage|readAncestry|lineageCoverage/.test(fs.readFileSync(f, 'utf8'))) .filter((f) => /readLineage|readAncestry|lineageCoverage/.test(fs.readFileSync(f, 'utf8')))
.map((f) => path.basename(f)); .map((f) => path.basename(f)).sort();
expect(routeHits).toEqual(['internal.js']); expect(routeHits).toEqual(['ancestry.js', 'internal.js']);
}); });
test('no route or web file selects a lineage column', () => { test('no route or web file selects a lineage column', () => {
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -0,0 +1,38 @@
import { NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Read-ancestry proxy. A new Express route is not reachable from the browser
* until a matching Next route forwards to it (the S25 rule), so this is what
* makes the ancestry contract product-accessible rather than internal-only.
*
* Thin pass-through, auth header forwarded. This surface is NON-AUTHORITATIVE
* for everything except ancestry, and it replaces no existing response.
*/
export async function GET(
req: Request,
ctx: { params: Promise<{ id: string }> },
) {
const { id } = await ctx.params;
try {
const auth = req.headers.get('authorization');
const upstream = await fetch(`${BACKEND_URL}/api/ancestry/ledger/${encodeURIComponent(id)}`, {
method: 'GET',
headers: {
Accept: 'application/json',
...(auth ? { Authorization: auth } : {}),
},
cache: 'no-store',
});
const data = await upstream.json().catch(() => ({ state: 'LINEAGE_UNAVAILABLE', reason: 'upstream unreadable' }));
return NextResponse.json(data, { status: upstream.status });
} catch {
return NextResponse.json(
{ state: 'LINEAGE_UNAVAILABLE', reason: 'ancestry service unreachable' },
{ status: 200 },
);
}
}
File diff suppressed because one or more lines are too long