Files
vyndr/tests/unit/lineageProductization.test.js
T
builtbykev 1bdc3baec7 A valid chain can still have a hole in it
Measured against real production history while validating the ancestry
surface: `aj ewing / total_bases / over / 0.5` on 2026-08-28 carries a valid
ORIGIN from the 18:10 cohort AND a row from the 19:03 cohort that was stamped
for publication and never recorded an action.

The chain is genuinely valid and the partial row is correctly excluded from it
— that part of the contract held. But answering LINEAGE_AVAILABLE and nothing
else presents an incomplete chronology as a complete one, which is the exact
failure this surface exists to make visible, one grain finer than a whole Read.

The response now carries `chronology_complete` and `unrecorded_publications`.
The state is unchanged, because the chain that exists really is valid; what
changes is that the gap is disclosed instead of smoothed over.

Suite 397/5,498/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
2026-08-30 22:19:50 -04:00

524 lines
24 KiB
JavaScript

/**
* LINEAGE PRODUCTIZATION — persistent shadow writer, independent coverage
* observer, additive ancestry surface.
*
* Three properties this suite exists to hold:
* the product never depends on lineage;
* the observer never trusts the writer;
* the ancestry surface never invents history it does not have.
*/
const svc = require('../../src/services/snapshotService');
const mode = require('../../src/services/lineageWriteMode');
const coverage = require('../../src/services/lineageCoverage');
const ancestry = require('../../src/services/read/readAncestry');
const retention = require('../../src/services/retentionService');
const ENV = mode.ENV_VAR;
const setPersistent = (v) => { if (v === null) delete process.env[ENV]; else process.env[ENV] = v; };
afterEach(() => setPersistent(null));
/* ─────────────────────────── WRITE MODE ─────────────────────────── */
describe('write mode — three modes, one evaluator', () => {
test('unset -> OFF, nothing enabled', () => {
setPersistent(null);
expect(mode.evaluate().mode).toBe(mode.WRITE_MODE.OFF);
expect(mode.isEnabled('mlb')).toBe(false);
});
test('PERSISTENT_SHADOW writes without any lease', () => {
setPersistent('mlb');
const e = mode.evaluate();
expect(e.mode).toBe(mode.WRITE_MODE.PERSISTENT_SHADOW);
expect(mode.isEnabled('mlb')).toBe(true);
// No lease is involved, and none is required.
expect(e.canary_sports).toEqual([]);
expect(mode.modeFor('mlb')).toBe(mode.WRITE_MODE.PERSISTENT_SHADOW);
});
test('a sport outside the allowlist fails closed, and takes the whole list with it', () => {
setPersistent('wnba');
expect(mode.evaluate().persistent_invalid_reason).toBe('INVALID_SPORT_NOT_PERSISTABLE');
expect(mode.isEnabled('wnba')).toBe(false);
setPersistent('mlb,wnba');
// Keeping the valid half would enable a subset nobody asked for on its own.
expect(mode.isEnabled('mlb')).toBe(false);
});
test('the allowlist is the canary\'s, not a second one', () => {
const canary = require('../../src/services/lineageCanaryConfig');
expect(mode.PERSISTABLE_SPORTS).toBe(canary.LEASABLE_SPORTS);
});
test('another sport cannot become enabled by accident', () => {
setPersistent('mlb');
for (const s of ['wnba', 'nba', 'soccer', '']) expect(mode.isEnabled(s)).toBe(false);
});
test('status and gate come from the SAME evaluator', () => {
setPersistent('mlb');
const st = mode.state();
expect(st.mode).toBe(mode.evaluate().mode);
expect(st.effective_sports).toEqual(mode.evaluate().sports);
expect(st.authority).toBe('NON_AUTHORITATIVE');
});
test('rollback ON -> OFF disables future writes and touches nothing else', () => {
setPersistent('mlb');
expect(mode.isEnabled('mlb')).toBe(true);
setPersistent(null);
expect(mode.isEnabled('mlb')).toBe(false);
expect(mode.evaluate().mode).toBe(mode.WRITE_MODE.OFF);
});
});
describe('canary and persistent are DIFFERENT modes', () => {
test('an ambiguous configuration fails closed rather than double-enabling', () => {
// The two instructions disagree about WHEN WRITING STOPS. We cannot know
// which the operator meant, so the sport writes nothing.
const e = mode.evaluate.call(null);
const fake = {
lease_state: 'ACTIVE', effective_active_sports: ['mlb'],
};
jest.isolateModules(() => {
jest.doMock('../../src/services/lineageCanaryConfig', () => ({
LEASABLE_SPORTS: ['mlb'],
evaluate: () => fake,
}));
const m2 = require('../../src/services/lineageWriteMode');
process.env[m2.ENV_VAR] = 'mlb';
const ev = m2.evaluate();
expect(ev.conflict).toBe(m2.CONFLICT.SPORT_IN_BOTH_MODES);
expect(ev.conflict_sports).toEqual(['mlb']);
expect(ev.mode).toBe(m2.WRITE_MODE.OFF);
expect(m2.isEnabled('mlb')).toBe(false);
delete process.env[m2.ENV_VAR];
});
expect(e).toBeDefined();
});
test('a lease alone still enables, with the canary contract untouched', () => {
jest.isolateModules(() => {
jest.doMock('../../src/services/lineageCanaryConfig', () => ({
LEASABLE_SPORTS: ['mlb'],
evaluate: () => ({ lease_state: 'ACTIVE', effective_active_sports: ['mlb'] }),
}));
const m2 = require('../../src/services/lineageWriteMode');
delete process.env[m2.ENV_VAR];
expect(m2.evaluate().mode).toBe(m2.WRITE_MODE.CANARY_LEASED);
expect(m2.isEnabled('mlb')).toBe(true);
});
});
test('an EXPIRED lease enables nothing — dynamic expiry is preserved', () => {
jest.isolateModules(() => {
jest.doMock('../../src/services/lineageCanaryConfig', () => ({
LEASABLE_SPORTS: ['mlb'],
evaluate: () => ({ lease_state: 'EXPIRED', effective_active_sports: [] }),
}));
const m2 = require('../../src/services/lineageWriteMode');
delete process.env[m2.ENV_VAR];
expect(m2.isEnabled('mlb')).toBe(false);
expect(m2.evaluate().mode).toBe(m2.WRITE_MODE.OFF);
});
});
});
/* ────────────────── FAILURE ISOLATION (the product first) ────────────────── */
describe('lineage failure can never reach authoritative product truth', () => {
// HERMETIC. Injecting `retention` activates pipeline paths the other snapshot
// tests never reach, and several resolve a real Supabase client when the
// environment offers one. Blanking the credentials makes every database
// dependency a no-op, so this measures the ISOLATION PROPERTY and not the
// network. Restored afterwards so no other suite inherits it.
const SUPA_KEYS = ['SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY', 'SUPABASE_SERVICE_KEY', 'SUPABASE_ANON_KEY'];
const saved = {};
beforeAll(() => { for (const k of SUPA_KEYS) { saved[k] = process.env[k]; delete process.env[k]; } });
afterAll(() => { for (const k of SUPA_KEYS) { if (saved[k] === undefined) delete process.env[k]; else process.env[k] = saved[k]; } });
const memCache = () => { const store = {}; return { store, cacheGet: async (k) => (k in store ? store[k] : null), cacheSet: async (k, v) => { store[k] = v; } }; };
const sampleProps = [{ player: 'Aaron Judge', stat_type: 'total_bases', line: 1.5, over_odds: -115, under_odds: -105, book: 'draftkings' }];
const grades = [{ player: 'Aaron Judge', stat_type: 'total_bases', line: 1.5, direction: 'over', grade: 'A+', confidence: 80 }];
const deps = (cache, extra = {}) => ({
getOdds: async () => ({ sport: 'mlb', props: sampleProps, provider: 'propline' }),
// Fires the retention hook the real grader fires. Without it the collector
// stays empty, `persistedRows` stays null and the lineage gate is never
// reached — which would make every assertion below vacuously true.
gradeAndCacheSlate: async (_s, _p, opts) => {
if (typeof opts.onGraded === 'function') {
opts.onGraded(
{
player: 'Aaron Judge', stat_type: 'total_bases', line: 1.5, book: 'draftkings',
game_time: '2026-08-31T23:05:00Z', game_date: '2026-08-31',
canonical_event_id: 'mlb:gamepk:999001',
},
[
{ player: 'Aaron Judge', stat_type: 'total_bases', line: 1.5, direction: 'over', grade: 'A+', confidence: 80 },
{ player: 'Aaron Judge', stat_type: 'total_bases', line: 1.5, direction: 'under', grade: 'D', confidence: 40 },
],
);
}
await opts.cacheSet('grades:x', { grades });
return { written: true, count: 1 };
},
resolveStats: async () => ({ found: false }),
classify: require('../../src/services/archetypeService').classify,
cacheGet: cache.cacheGet, cacheSet: cache.cacheSet,
now: () => '2026-08-31T01:00:00Z', nowMs: () => 1000,
...extra,
});
test('a throwing lineage commit leaves the slate published and the run ok', async () => {
setPersistent('mlb');
const cache = memCache();
// The counter is the point. Without it this test passes when the lineage
// path is never entered at all, which asserts nothing about isolation.
let commits = 0;
const r = await svc.runSnapshot('mlb', deps(cache, {
retention: {
persist: async () => ({ attempted: 1, written: 1 }),
commitPublication: async () => { commits += 1; throw new Error('lineage exploded'); },
rowsFromSides: retention.rowsFromSides,
createCollector: retention.createCollector,
newSnapshotId: retention.newSnapshotId,
},
}));
expect(commits).toBe(1); // the failure really happened
expect(r.status).toBe('ok'); // and the run still completed
// The authoritative product write happened regardless...
expect(cache.store['snapshot:mlb:latest']).toBeTruthy();
// ...and so did every step AFTER the lineage block. This is what separates
// "the slate was already written" from "the exception was contained".
expect(cache.store['grades:mlb']).toBeTruthy();
});
test('a throwing lineage commit does not stop the Ledger write', async () => {
setPersistent('mlb');
const cache = memCache();
const ledgerCalls = [];
let commits = 0;
await svc.runSnapshot('mlb', deps(cache, {
retention: {
persist: async () => ({ attempted: 1, written: 1 }),
commitPublication: async () => { commits += 1; throw new Error('lineage exploded'); },
rowsFromSides: retention.rowsFromSides,
createCollector: retention.createCollector,
newSnapshotId: retention.newSnapshotId,
},
ledger: {
recordPipelineGrades: async (...a) => { ledgerCalls.push(a); return { written: 1 }; },
captureClosing: async () => ({}),
},
}));
expect(commits).toBe(1);
expect(ledgerCalls.length).toBe(1);
// read_id linkage is absent, never guessed.
expect(ledgerCalls[0][3].lineageIndex).toBeNull();
});
test('with the mode OFF no lineage commit is attempted at all', async () => {
setPersistent(null);
const cache = memCache();
let commits = 0;
await svc.runSnapshot('mlb', deps(cache, {
retention: {
persist: async () => ({ attempted: 1, written: 1 }),
commitPublication: async () => { commits += 1; return { published: 0, candidates: 0 }; },
rowsFromSides: retention.rowsFromSides,
createCollector: retention.createCollector,
newSnapshotId: retention.newSnapshotId,
},
}));
expect(commits).toBe(0);
});
});
/* ─────────────── PARTIAL-LINEAGE ATOMICITY (no half actions) ─────────────── */
describe('a failed lineage attempt writes no half action', () => {
test('a throwing family lookup leaves every row completely blank', async () => {
const rows = [
{ sport: 'mlb', game_date: '2026-08-31', player_key: 'a b', stat: 'hits', side: 'over', line: 0.5, published: true },
{ sport: 'mlb', game_date: '2026-08-31', player_key: 'c d', stat: 'hits', side: 'over', line: 0.5, published: true },
];
const out = await retention.attachLineage(rows, { fetchExisting: async () => { throw new Error('boom'); } });
expect(out.error).toMatch(/boom/);
for (const r of rows) {
expect(retention.isValidLineageAction(r)).toBe(false);
for (const k of retention.LINEAGE_KEYS) expect(r[k]).toBeNull();
}
// The natural key stamped before the lookup is cleared too — it is family
// identity, and a failed attempt has no claim to it.
expect(rows[0].read_natural_key).toBeNull();
expect(out.incomplete_cleared).toBe(2);
});
});
/* ───────────── INDEPENDENT COVERAGE OBSERVER (never trust the writer) ───────────── */
describe('coverage observer', () => {
const row = (o) => ({
sport: 'mlb', game_date: '2026-08-31', player_key: 'aaron judge', stat: 'hits',
side: 'over', line: 0.5, published: true, ...o,
});
const action = (o) => ({
read_id: 'r1', read_natural_key: 'k', lineage_action: 'ORIGIN', claim_digest: 'd',
revision_ordinal: 0, lineage_state: 's', lineage_version: 'lin@1',
claim_schema_version: 'claim@1', digest_algorithm_version: 'sha256-json-sorted@1', ...o,
});
test('THE DENOMINATOR IGNORES lineage_action — the property, not the spelling', () => {
const base = [row({ player_key: 'a' }), row({ player_key: 'b' })];
const withLineage = base.map((r) => ({ ...r, ...action({ read_natural_key: r.player_key }) }));
const without = base.map((r) => ({ ...r }));
// Same rows, opposite lineage state, identical expectation.
expect(coverage.expectedKeys(withLineage).keys.size).toBe(coverage.expectedKeys(without).keys.size);
expect([...coverage.expectedKeys(withLineage).keys].sort())
.toEqual([...coverage.expectedKeys(without).keys].sort());
});
test('unpublished rows are not expected to have lineage', () => {
expect(coverage.expectedKeys([row({ published: false })]).keys.size).toBe(0);
expect(coverage.expectedKeys([row({ published: null })]).keys.size).toBe(0);
});
test('a row with no derivable identity is counted, not silently dropped', () => {
const e = coverage.expectedKeys([row({ player_key: '' })]);
expect(e.keys.size).toBe(0);
expect(e.unkeyable_rows).toBe(1);
});
test('WRITER NEVER RAN: full slate, zero lineage -> MISSING_COVERAGE', () => {
const a = coverage.auditRows([row({ player_key: 'a' }), row({ player_key: 'b' })]);
expect(a.expected_keys).toBe(2);
expect(a.covered_keys).toBe(0);
expect(a.health).toBe(coverage.HEALTH.MISSING_COVERAGE);
});
test('zero expected and zero written are DIFFERENT answers', () => {
const none = coverage.auditRows([row({ published: false })]);
expect(none.health).toBe(coverage.HEALTH.NO_ELIGIBLE_CLAIMS);
expect(none.health).not.toBe(coverage.HEALTH.MISSING_COVERAGE);
});
test('partial coverage is detected', () => {
const rows = [
{ ...row({ player_key: 'a' }), ...action({ read_natural_key: 'mlb|2026-08-31|a|hits|over|0.500000' }) },
row({ player_key: 'b' }),
];
const a = coverage.auditRows(rows);
expect(a.health).toBe(coverage.HEALTH.PARTIAL_COVERAGE);
expect(a.missing_keys).toBe(1);
expect(a.coverage_pct).toBe(50);
});
test('full coverage is HEALTHY', () => {
const rows = ['a', 'b'].map((p) => ({
...row({ player_key: p }),
...action({ read_natural_key: `mlb|2026-08-31|${p}|hits|over|0.500000`, read_id: `r-${p}` }),
}));
const a = coverage.auditRows(rows);
expect(a.health).toBe(coverage.HEALTH.HEALTHY);
expect(a.coverage_pct).toBe(100);
expect(a.missing_keys).toBe(0);
expect(a.extra_keys).toBe(0);
});
test('an invalid partial action is INVALID_GRAPH, never counted as covered', () => {
const partial = { ...row({ player_key: 'a' }), read_natural_key: 'k', read_id: 'r' }; // 2 of 9
const a = coverage.auditRows([partial]);
expect(a.invalid_partial_actions).toBe(1);
expect(a.covered_keys).toBe(0);
expect(a.health).toBe(coverage.HEALTH.INVALID_GRAPH);
});
test('extra lineage — covered but never expected — is a defect', () => {
const rows = [{ ...row({ published: false, player_key: 'a' }), ...action({ read_natural_key: 'ghost' }) }];
const a = coverage.auditRows(rows);
expect(a.expected_keys).toBe(0);
expect(a.extra_keys).toBe(1);
expect(a.health).toBe(coverage.HEALTH.INVALID_GRAPH);
});
test('a forked chain is a graph defect', () => {
const k = 'mlb|2026-08-31|a|hits|over|0.500000';
const rows = [
{ ...row({ player_key: 'a' }), ...action({ read_natural_key: k, revision_ordinal: 0 }) },
{ ...row({ player_key: 'a' }), ...action({ read_natural_key: k, revision_ordinal: 0 }) },
];
const a = coverage.auditRows(rows);
expect(a.graph_defects).toBeGreaterThan(0);
expect(a.health).toBe(coverage.HEALTH.INVALID_GRAPH);
});
test('the observer\'s valid-action fields match the writer\'s, without importing it', () => {
expect([...coverage.VALID_ACTION_FIELDS].sort())
.toEqual([...retention.VALID_LINEAGE_ACTION_FIELDS].sort());
});
test('an unavailable audit is not a coverage claim', () => {
expect(coverage.classify({ audit_available: false })).toBe(coverage.HEALTH.AUDIT_UNAVAILABLE);
});
});
/* ───────────────────────── ADDITIVE ANCESTRY ───────────────────────── */
describe('ancestry surface tells the truth about what it has', () => {
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: 'sha256-json-sorted@1',
publication_id: 'p1', ...o,
});
test('a row lineage never ran for is LEGACY_UNVERIFIED, and nothing is synthesized', () => {
const out = ancestry.classifyAncestry([{ id: 1, publication_id: null, grade: 'B' }]);
expect(out.state).toBe(A.LEGACY_UNVERIFIED);
expect(out.revisions).toEqual([]);
expect(out.read_id).toBeUndefined();
});
test('a row lineage RAN for but did not complete is LINEAGE_UNAVAILABLE, not legacy', () => {
// This is the shape of the 1,119 historical partial rows.
const out = ancestry.classifyAncestry([{ id: 1, publication_id: 'p1', read_natural_key: 'k' }]);
expect(out.state).toBe(A.LINEAGE_UNAVAILABLE);
expect(out.state).not.toBe(A.LEGACY_UNVERIFIED);
});
test('a partial row is never elected as an ancestry head', () => {
const out = ancestry.classifyAncestry([
{ id: 1, publication_id: 'p1', read_natural_key: 'k', read_id: 'r1' },
]);
expect(out.state).toBe(A.LINEAGE_UNAVAILABLE);
expect(out.current).toBeUndefined();
});
test('ORIGIN alone reads as a one-entry chronology', () => {
const out = ancestry.classifyAncestry([act({})]);
expect(out.state).toBe(A.LINEAGE_AVAILABLE);
expect(out.revision_count).toBe(0);
expect(out.original.action).toBe('ORIGIN');
expect(out.current.action).toBe('ORIGIN');
expect(out.authority).toBe('NON_AUTHORITATIVE');
});
test('REVISION ancestry names the exact parent and order', () => {
const out = ancestry.classifyAncestry([
act({ id: 1, revision_ordinal: 0, lineage_action: 'ORIGIN' }),
act({ id: 2, revision_ordinal: 1, lineage_action: 'REVISION', supersedes_id: 1, claim_digest: 'd1', change_type: 'MIXED_CHANGE' }),
]);
expect(out.state).toBe(A.LINEAGE_AVAILABLE);
expect(out.revision_count).toBe(1);
expect(out.current.revision_ordinal).toBe(1);
expect(out.current.supersedes_row_id).toBe(1);
expect(out.current.change_type).toBe('MIXED_CHANGE');
});
test('RECAPTURE is reported as a recapture, never as a revision', () => {
const out = ancestry.classifyAncestry([
act({ id: 1, lineage_action: 'ORIGIN', revision_ordinal: 0 }),
act({ id: 2, lineage_action: 'RECAPTURE', revision_ordinal: 0, recaptures_id: 1 }),
]);
expect(out.state).toBe(A.LINEAGE_AVAILABLE);
expect(out.revision_count).toBe(0);
expect(out.recapture_count).toBe(1);
expect(out.recaptures[0].action).toBe('RECAPTURE');
});
test('a broken chain REFUSES rather than electing a head', () => {
const out = ancestry.classifyAncestry([
act({ id: 1, lineage_action: 'ORIGIN', revision_ordinal: 0 }),
act({ id: 2, lineage_action: 'REVISION', revision_ordinal: 1, supersedes_id: 999 }),
]);
expect(out.state).toBe(A.INVALID_LINEAGE);
expect(out.revisions).toEqual([]);
});
test('two read_ids under one natural key is INVALID_LINEAGE', () => {
const out = ancestry.classifyAncestry([act({ id: 1, read_id: 'r1' }), act({ id: 2, read_id: 'r2' })]);
expect(out.state).toBe(A.INVALID_LINEAGE);
});
test('the projection carries only what lineage knows', () => {
const p = ancestry.project({ ...act({}), p_win: 0.6, grade: 'A', locked_odds: '-110', outcome: 'hit' });
for (const forbidden of ['p_win', 'grade', 'locked_odds', 'outcome', 'projection']) {
expect(p[forbidden]).toBeUndefined();
}
expect(p.read_id).toBe('r1');
expect(p.claim_digest).toBe('d0');
});
test('a valid chain with a stamped-but-unrecorded sibling discloses the hole', () => {
// The production shape: one good ORIGIN plus a later publication that was
// attempted and never recorded. The chain stays valid and the partial row
// stays out of it, but the answer must not claim the chronology is whole.
const out = ancestry.classifyAncestry([
act({ id: 1, publication_id: 'p1' }),
{ id: 2, publication_id: 'p2', read_natural_key: 'k' },
]);
expect(out.state).toBe(A.LINEAGE_AVAILABLE);
expect(out.revisions).toHaveLength(1);
expect(out.revisions[0].snapshot_row_id).toBe(1); // the partial is excluded
expect(out.chronology_complete).toBe(false);
expect(out.unrecorded_publications).toBe(1);
});
test('a chain with no unrecorded siblings is complete', () => {
const out = ancestry.classifyAncestry([act({ id: 1, publication_id: 'p1' })]);
expect(out.chronology_complete).toBe(true);
expect(out.unrecorded_publications).toBe(0);
});
test('nothing found is NOT_FOUND, which is not an absence of lineage', () => {
expect(ancestry.classifyAncestry([]).state).toBe(A.NOT_FOUND);
});
});
/* ────────────────────── PRESERVATION ────────────────────── */
describe('this tranche changes nothing it was told not to', () => {
const fs = require('fs'); const path = require('path');
const ROOT = path.resolve(__dirname, '..', '..');
test('the grade-shift badge is untouched — no lineage anywhere near it', () => {
for (const f of ['src/routes/ledger.js', 'src/routes/profiles.js']) {
const src = fs.readFileSync(path.join(ROOT, f), 'utf8');
expect(src).toMatch(/revised_from_grade/);
expect(src).not.toMatch(/lineage|read_id/);
}
});
test('retention identity and its collision counter are unchanged', () => {
expect(retention.RETENTION_CONFLICT.split(',')).toEqual(
['snapshot_id', 'game_id', 'canonical_event_id', 'player_key', 'stat', 'line', 'side']);
const dup = [
{ snapshot_id: 's', game_id: 'g', canonical_event_id: 'e', player_key: 'a', stat: 'hits', line: 0.5, side: 'over' },
{ snapshot_id: 's', game_id: 'g', canonical_event_id: 'e', player_key: 'a', stat: 'hits', line: 0.5, side: 'over' },
];
expect(retention.expectedMaterialization(dup).collision_count).toBe(1);
});
test('participant identity guards are unchanged', () => {
const pid = require('../../src/services/model/participantIdentity');
const a = pid.auditParticipantIdentity([
{ canonical_event_id: 'e', mlb_person_id: 1, player_key: 'x' },
{ canonical_event_id: 'e', mlb_person_id: 1, player_key: 'y' },
]);
expect(a.participant_identity_split_count).toBe(1);
expect(pid.semanticPlayerKey({ player: 'Mickey Gasper', mlb_person_id: 681508, canonical_player_name: 'Mickey Gasper' }).canonical).toBe(true);
});
test('the ancestry surface writes nothing', () => {
const src = fs.readFileSync(path.join(ROOT, 'src/services/read/readAncestry.js'), 'utf8')
.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
for (const verb of ['.insert(', '.update(', '.upsert(', '.delete(']) {
expect(src).not.toContain(verb);
}
});
test('the coverage observer writes nothing', () => {
const src = fs.readFileSync(path.join(ROOT, 'src/services/lineageCoverage.js'), 'utf8')
.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
for (const verb of ['.insert(', '.update(', '.upsert(', '.delete(']) {
expect(src).not.toContain(verb);
}
});
});