ruvnet-brain 4.3.34 → 4.3.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,8 @@ import crypto from 'node:crypto';
5
5
  import readline from 'node:readline';
6
6
  import { spawnSync } from 'node:child_process';
7
7
  import { fileURLToPath } from 'node:url';
8
- import { canonicalJson, digest, validateCoverageLedger } from './coverage-integrity.mjs';
8
+ import { canonicalJson, digest, eligibleRepositoryStanding, validateCoverageLedger } from './coverage-integrity.mjs';
9
+ import { fixtureDenominator } from './fixture-denominator.mjs';
9
10
 
10
11
  // Both release phases resolve against an explicit installed context, never the checkout.
11
12
  export async function resolveInstalledCanaryCitation({ kbDir, matched, expected, passageFileDigests = new Map() }) {
@@ -204,8 +205,10 @@ export function auditOracleCoverage({ coverage, queryEvidence, exemptions = null
204
205
  const checked = validateCoverageLedger(coverage);
205
206
  if (!checked.valid) throw new Error(`coverage ledger is invalid: ${checked.failures.join('; ')}`);
206
207
  validateRetrievalQueryEvidence(queryEvidence);
208
+ // ADR-0091 D5: a shipped store is CURRENT or STALE with a verified carry (its bytes ship). A
209
+ // MISSING-with-failure store ships nothing; the fixture-vs-available denominator is D6.4's change.
207
210
  const eligibleRows = coverage.rows.filter((row) => row.kind === 'repository'
208
- && row.disposition === 'eligible' && row.status === 'CURRENT');
211
+ && row.disposition === 'eligible' && eligibleRepositoryStanding(row) === 'shipped');
209
212
  const eligible = ordered(eligibleRows.map(storeOf));
210
213
  if (!eligible.length || new Set(eligible).size !== eligible.length || eligible.some((store) => !store)) {
211
214
  throw new Error('eligible coverage denominator is invalid');
@@ -310,9 +313,20 @@ export function validateRetrievalCanaryPlan(plan) {
310
313
  'legacy population denominator');
311
314
  checkedSet(plan.denominator.legacySelectedStores, plan.denominator.legacySelectedStoreSetSha256,
312
315
  'legacy selected denominator');
316
+ // ADR-0091 D6.4: `eligibleStores` is the FROZEN FIXTURE denominator (it must equal the oracle's store
317
+ // set exactly, as before). Retired fixture stores are excluded from questioning; eligible stores the
318
+ // fixture does not cover are recorded, never questioned and never blocking.
319
+ checkedSet(plan.denominator.retiredFixtureStores, plan.denominator.retiredFixtureStoreSetSha256, 'retired fixture denominator');
320
+ checkedSet(plan.denominator.unfixturedEligibleStores, plan.denominator.unfixturedEligibleStoreSetSha256,
321
+ 'unfixtured eligible record');
313
322
  if (setDigest(plan.denominator.eligibleStores) !== plan.oracle.queryStoreSetSha256) {
314
323
  throw new Error('oracle denominator differs from eligible coverage');
315
324
  }
325
+ if (plan.denominator.retiredFixtureStores.some((store) => !plan.denominator.eligibleStores.includes(store))
326
+ || plan.denominator.unfixturedEligibleStores.some((store) => plan.denominator.eligibleStores.includes(store))
327
+ || plan.denominator.unfixturedEligibleCount !== plan.denominator.unfixturedEligibleStores.length) {
328
+ throw new Error('retrieval canary fixture denominator is inconsistent');
329
+ }
316
330
  if (new Set(ids).size !== ids.length) throw new Error('retrieval canary plan has duplicate case ids');
317
331
  const hasDelta = plan.cases.some(({ cohort }) => cohort === 'delta');
318
332
  if ((!hasDelta && plan.noDelta !== true) || (hasDelta && plan.noDelta === true)
@@ -352,14 +366,18 @@ export function validatePlanAgainstCoverage(plan, coverage, { allowObservedBasel
352
366
  if (!checked.valid) throw new Error(`coverage ledger is invalid: ${checked.failures.join('; ')}`);
353
367
  const generation = coverage.kind === 'ruvnet-brain-release-coverage'
354
368
  ? coverage.releaseCoverageGeneration : coverage.coverageGeneration;
355
- const eligible = ordered(coverage.rows.filter((row) => row.kind === 'repository'
356
- && row.disposition === 'eligible' && row.status === 'CURRENT').map(storeOf));
357
- if (!eligible.length || new Set(eligible).size !== eligible.length) throw new Error('eligible coverage denominator is invalid');
369
+ // Recomputed from the coverage and the plan's own sealed fixture, never trusted from the plan.
370
+ const denominator = fixtureDenominator({ coverage, fixtureStores: Object.keys(plan.oracle.evidence.queries) });
371
+ if (denominator.blocking.length) throw new Error(`fixture store(s) neither available nor retired: ${denominator.blocking.map(({ store }) => store).join(', ')}`);
372
+ const eligible = denominator.questioned;
373
+ if (!eligible.length) throw new Error('eligible coverage denominator is invalid');
358
374
  const baseline = new Set(plan.baseline.stores);
359
375
  const delta = eligible.filter((store) => !baseline.has(store));
360
376
  const legacy = eligible.filter((store) => baseline.has(store));
361
377
  if (generation !== plan.coverage.releaseCoverageGeneration
362
- || canonicalJson(eligible) !== canonicalJson(plan.denominator.eligibleStores)
378
+ || canonicalJson(denominator.fixture) !== canonicalJson(plan.denominator.eligibleStores)
379
+ || canonicalJson(denominator.retired) !== canonicalJson(plan.denominator.retiredFixtureStores)
380
+ || canonicalJson(denominator.unfixturedEligible) !== canonicalJson(plan.denominator.unfixturedEligibleStores)
363
381
  || canonicalJson(delta) !== canonicalJson(plan.denominator.deltaStores)
364
382
  || canonicalJson(legacy) !== canonicalJson(plan.denominator.legacyPopulationStores)
365
383
  || plan.denominator.legacySelectedStores.some((store) => !legacy.includes(store))) {
@@ -417,20 +435,19 @@ export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, covera
417
435
  }
418
436
  validateRetrievalQueryEvidence(queryEvidence);
419
437
  if (queryEvidence.sourceCommit === candidate.sourceSha) throw new Error('independent query source is not pre-candidate');
420
- const eligible = coverage.rows.filter((row) => row.kind === 'repository' && row.disposition === 'eligible');
421
- if (!eligible.length || eligible.some((row) => row.status !== 'CURRENT' || !storeOf(row))) {
422
- throw new Error('eligible repository coverage is incomplete');
423
- }
424
- const duplicateStores = eligible.map(storeOf).filter((store, index, stores) => stores.indexOf(store) !== index);
425
- if (duplicateStores.length) throw new Error(`eligible repository stores are duplicated: ${ordered(new Set(duplicateStores)).join(', ')}`);
426
- const eligibleStores = ordered(eligible.map(storeOf));
427
- if (queryEvidence.queryStoreSetSha256 !== setDigest(eligibleStores)
428
- || canonicalJson(ordered(Object.keys(queryEvidence.queries))) !== canonicalJson(eligibleStores)) {
429
- const oracleStores = new Set(Object.keys(queryEvidence.queries));
430
- const missing = eligibleStores.filter((store) => !oracleStores.has(store));
431
- const extra = [...oracleStores].filter((store) => !eligibleStores.includes(store)).sort();
432
- throw new Error(`independent query oracle does not cover the exact eligible store set (eligible=${eligibleStores.length}, oracle=${oracleStores.size}, missing=${missing.join(',') || 'none'}, extra=${extra.join(',') || 'none'})`);
433
- }
438
+ // ADR-0091 D6.4: fixture ⊆ available. The frozen fixture no longer has to EQUAL a living eligible
439
+ // set; every fixture store must ship (or be verified retired), and eligible stores the fixture does
440
+ // not cover are recorded as unfixturedEligible, never blocking.
441
+ let denominator;
442
+ try { denominator = fixtureDenominator({ coverage, fixtureStores: Object.keys(queryEvidence.queries) }); }
443
+ catch (error) { throw new Error(`eligible repository coverage is incomplete (${error.message})`); }
444
+ if (denominator.blocking.length) {
445
+ throw new Error(`independent query oracle names ${denominator.blocking.length} fixture store(s) that are neither shipped nor `
446
+ + `verified retired: ${denominator.blocking.map(({ store, status }) => `${store}:${status ?? 'no-row'}`).join(', ')}`);
447
+ }
448
+ const eligibleStores = denominator.fixture;
449
+ const eligible = denominator.questionedRows;
450
+ if (!eligible.length) throw new Error('eligible repository coverage is incomplete');
434
451
  const baselineStores = new Set(baseline.stores.map((name) => String(name).toLowerCase()));
435
452
  const delta = eligible.filter((row) => !baselineStores.has(storeOf(row)));
436
453
  const legacyPool = eligible.filter((row) => baselineStores.has(storeOf(row)));
@@ -502,6 +519,11 @@ export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, covera
502
519
  denominator: {
503
520
  eligibleStores,
504
521
  eligibleStoreSetSha256: setDigest(eligibleStores),
522
+ retiredFixtureStores: denominator.retired,
523
+ retiredFixtureStoreSetSha256: setDigest(denominator.retired),
524
+ unfixturedEligibleStores: denominator.unfixturedEligible,
525
+ unfixturedEligibleStoreSetSha256: setDigest(denominator.unfixturedEligible),
526
+ unfixturedEligibleCount: denominator.unfixturedEligible.length,
505
527
  deltaStores: ordered(delta.map(storeOf)),
506
528
  deltaStoreSetSha256: setDigest(delta.map(storeOf)),
507
529
  legacyPopulationStores: ordered(legacyPool.map(storeOf)),
@@ -133,8 +133,21 @@ const checks = [
133
133
  } },
134
134
 
135
135
  // C — one release path
136
- { id: 'C1', area: 'release', scope: 'repo', title: 'Unattended corpus promotion stays disarmed until a code release is install-verified',
137
- run: () => ({ ok: !tracked.includes('data/approved-runtime.json'), detail: tracked.includes('data/approved-runtime.json') ? 'data/approved-runtime.json present (arms the 07:17 UTC nightly)' : 'absent' }) },
136
+ // ADR-0091 D3: the approved runtime is RESOLVED at run time from the newest install-verified code
137
+ // release (its signed public-verification aggregate), never committed; the nightly is armed only by
138
+ // the CORPUS_NIGHTLY repository variable. A committed pin, or a workflow still reading one, is drift.
139
+ { id: 'C1', area: 'release', scope: 'repo', title: 'Corpus promotion resolves its runtime pin from an install-verified release at run time; nothing commits one',
140
+ run: () => {
141
+ const problems = [];
142
+ if (tracked.includes('data/approved-runtime.json')) problems.push('data/approved-runtime.json is committed (the pin must be resolved, never committed)');
143
+ for (const w of workflows) if (read(w).includes('data/approved-runtime.json')) problems.push(`${w} still reads data/approved-runtime.json`);
144
+ const dispatcher = read('.github/workflows/corpus-nightly-dispatch.yml');
145
+ if (!/vars\.CORPUS_NIGHTLY/.test(dispatcher)) problems.push('corpus-nightly-dispatch.yml is not gated on the CORPUS_NIGHTLY repository variable');
146
+ for (const w of ['corpus-nightly-dispatch.yml', 'protected-release.yml', 'corpus-seed.yml']) {
147
+ if (!read(`.github/workflows/${w}`).includes('approved-runtime.mjs --resolve')) problems.push(`${w} does not resolve the approved runtime`);
148
+ }
149
+ return none(problems);
150
+ } },
138
151
  { id: 'C2', area: 'release', scope: 'repo', title: 'Every scheduled workflow pages the phone on failure',
139
152
  run: () => {
140
153
  const alerts = read('.github/workflows/ntfy-alerts.yml');
@@ -341,7 +341,13 @@ function assertExclusionEvidence(repo, exclusion, upstreamSha) {
341
341
  }
342
342
  }
343
343
 
344
- export function classifyRepository(repo, evidence, exclusion = null) {
344
+ // ADR-0091 D5: `outcome` is what reconciliation recorded for this store when its refresh FAILED this
345
+ // generation -- { carry } (previous bytes kept, already re-hashed against the ledger), { failure } (no
346
+ // prior bytes), or { integrity } (carried bytes failed that re-hash). The status token is always the
347
+ // one the evidence proves; the record is attached only where it agrees with that status, so a carry
348
+ // can never dress up a row the bytes do not support. Rows are annotated BEFORE sealing, so the
349
+ // coverage generation digest covers them.
350
+ export function classifyRepository(repo, evidence, exclusion = null, outcome = null) {
345
351
  const upstreamSha = repo.defaultBranchRef?.target?.oid || null;
346
352
  const activeExclusion = Boolean(exclusion && String(exclusion.pushedAt || '') !== ''
347
353
  && String(exclusion.pushedAt) === String(repo.pushedAt || ''));
@@ -373,6 +379,14 @@ export function classifyRepository(repo, evidence, exclusion = null) {
373
379
  else if (evidence.receipt.sourceCommit !== upstreamSha) { status = 'STALE'; reasons.push('receipt sourceCommit differs from upstream HEAD'); }
374
380
  else if (!evidence.bytesVerified) { status = 'FAILED'; reasons.push('RVF bytes do not match receipt'); }
375
381
  else if (!evidence.passagesPresent) { status = 'FAILED'; reasons.push('passage inventory is absent'); }
382
+ const disposed = isIngestibleDisposition(disposition);
383
+ if (disposed && outcome?.integrity && ['CURRENT', 'STALE'].includes(status)) {
384
+ status = 'FAILED';
385
+ reasons.push(outcome.integrity);
386
+ }
387
+ const record = {};
388
+ if (disposed && outcome?.carry && status === 'STALE') record.carry = { ...outcome.carry };
389
+ if (disposed && outcome?.failure && status === 'MISSING') record.failure = { ...outcome.failure };
376
390
  return {
377
391
  key: repo.fullName ? `repo:${repo.fullName.toLowerCase()}` : `repo:${repo.databaseId}`,
378
392
  kind: 'repository',
@@ -391,6 +405,7 @@ export function classifyRepository(repo, evidence, exclusion = null) {
391
405
  cardPresent: evidence.cardPresent },
392
406
  status,
393
407
  reasons,
408
+ ...record,
394
409
  };
395
410
  }
396
411
 
@@ -567,7 +582,7 @@ export function explainCoverageDrift(recorded, current) {
567
582
  // where they are source-controlled (`<repo>/kb`) unless the caller names both directories, as the
568
583
  // release path does with `--assets`.
569
584
  export function buildCoverage({ owner = 'ruvnet', env = process.env, home = os.homedir(), kbDir = null, policyDir = null,
570
- observation = null, gh = runGh, now = () => new Date().toISOString() } = {}) {
585
+ observation = null, gh = runGh, now = () => new Date().toISOString(), storeOutcomes = null } = {}) {
571
586
  policyDir ??= kbDir ?? path.join(ROOT, 'kb');
572
587
  kbDir ??= storeRoot(env, home);
573
588
  if (rootNeverMaterialized(kbDir)) {
@@ -597,7 +612,8 @@ export function buildCoverage({ owner = 'ruvnet', env = process.env, home = os.h
597
612
  const exclusions = fs.existsSync(exclusionsPath) ? JSON.parse(fs.readFileSync(exclusionsPath, 'utf8')) : {};
598
613
  const rows = repositories.rows.map((repo) => {
599
614
  const store = storeName(repo.storeName || repo.name);
600
- return classifyRepository(repo, artifactEvidence(kbDir, ledger, cardStores, store), exclusions[store] || null);
615
+ return classifyRepository(repo, artifactEvidence(kbDir, ledger, cardStores, store), exclusions[store] || null,
616
+ storeOutcomes?.[store.toLowerCase()] || null);
601
617
  });
602
618
  const gistEvidence = { ...artifactEvidence(kbDir, ledger, cardStores, 'ruv-gists'), sources: gistSources };
603
619
  try {