ruvnet-brain 4.3.3 → 4.3.8

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.
@@ -133,7 +133,7 @@ const identityOf = (leaf) => ({
133
133
  releaseTransactionId: leaf.releaseTransactionId,
134
134
  });
135
135
 
136
- export function buildPublicVerificationAggregate(leaves, reviews) {
136
+ export function buildPublicVerificationAggregate(leaves) {
137
137
  if (!Array.isArray(leaves) || leaves.length !== PUBLIC_VERIFICATION_OS.length * PUBLIC_VERIFICATION_MODES.length) {
138
138
  throw new Error('public verification requires exactly nine leaves');
139
139
  }
@@ -168,25 +168,11 @@ export function buildPublicVerificationAggregate(leaves, reviews) {
168
168
  if (metrics.recallAt10 < 0.98 || metrics.deltaCitationRate !== 1 || metrics.skipped || metrics.unknown) {
169
169
  throw new Error('public verification aggregate retrieval acceptance failed');
170
170
  }
171
- if (!Array.isArray(reviews) || reviews.length !== REQUIRED_REVIEW_MODELS.length) {
172
- throw new Error('public verification aggregate requires exactly two independent reviews');
173
- }
174
- reviews.forEach(validateIndependentReviewReceipt);
175
- const byModel = new Map(reviews.map((review) => [review.model, review]));
176
- if (byModel.size !== REQUIRED_REVIEW_MODELS.length || REQUIRED_REVIEW_MODELS.some((model) => !byModel.has(model))) {
177
- throw new Error('required independent review models are missing or duplicated');
178
- }
179
- const firstReview = byModel.get(REQUIRED_REVIEW_MODELS[0]);
180
- const semanticIdentity = validateReviewOracleAgainstPlan(firstReview, first.retrievalPlan);
181
- for (const model of REQUIRED_REVIEW_MODELS) {
182
- const review = byModel.get(model);
183
- const semantic = validateReviewOracleAgainstPlan(review, first.retrievalPlan);
184
- if (review.sourceSha !== identity.sourceSha || review.artifactSha256 !== identity.artifactSha256
185
- || review.payloadId !== identity.payloadId || review.productContractSha256 !== firstReview.productContractSha256
186
- || review.rubricSha256 !== firstReview.rubricSha256
187
- || semantic.recordSetSha256 !== semanticIdentity.recordSetSha256) {
188
- throw new Error(`${model} review identity, rubric, or oracle identity differs`);
189
- }
171
+ const oracle = first.retrievalPlan.oracle;
172
+ if (!oracle || !HEX64.test(String(oracle.receiptSha256 || ''))
173
+ || !HEX64.test(String(oracle.queryStoreSetSha256 || ''))
174
+ || oracle.queryStoreSetSha256 !== digest(first.retrievalPlan.denominator.eligibleStores)) {
175
+ throw new Error('sealed retrieval oracle identity is incomplete');
190
176
  }
191
177
  return {
192
178
  schemaVersion: 1,
@@ -194,17 +180,11 @@ export function buildPublicVerificationAggregate(leaves, reviews) {
194
180
  identity,
195
181
  coverage: first.coverage,
196
182
  lanes: required.map((lane) => ({ lane, leafSha256: byLane.get(lane).leafSha256 })),
197
- reviews: REQUIRED_REVIEW_MODELS.map((model) => ({ model, receiptSha256: byModel.get(model).receiptSha256,
198
- score: byModel.get(model).score })),
199
- evidence: { leaves: required.map((lane) => structuredClone(byLane.get(lane))),
200
- reviews: REQUIRED_REVIEW_MODELS.map((model) => structuredClone(byModel.get(model))) },
201
- productContractSha256: firstReview.productContractSha256,
202
- rubricSha256: firstReview.rubricSha256,
183
+ evidence: { leaves: required.map((lane) => structuredClone(byLane.get(lane))) },
203
184
  retrievalOracle: {
204
- oracleReceiptSha256: semanticIdentity.oracleReceiptSha256,
205
- queryStoreSetSha256: semanticIdentity.queryStoreSetSha256,
206
- recordCount: semanticIdentity.recordCount,
207
- recordSetSha256: semanticIdentity.recordSetSha256,
185
+ oracleReceiptSha256: oracle.receiptSha256,
186
+ queryStoreSetSha256: oracle.queryStoreSetSha256,
187
+ recordCount: first.retrievalPlan.denominator.eligibleStores.length,
208
188
  },
209
189
  metrics,
210
190
  verdict: 'PASS',
@@ -212,8 +192,8 @@ export function buildPublicVerificationAggregate(leaves, reviews) {
212
192
  };
213
193
  }
214
194
 
215
- export function signPublicVerificationAggregate({ leaves, reviews }, privateKey) {
216
- const payload = buildPublicVerificationAggregate(leaves, reviews);
195
+ export function signPublicVerificationAggregate({ leaves }, privateKey) {
196
+ const payload = buildPublicVerificationAggregate(leaves);
217
197
  const aggregateSha256 = digest(payload);
218
198
  const signed = { ...payload, aggregateSha256 };
219
199
  return { ...signed, signature: crypto.sign(null, Buffer.from(canonicalJson(signed)), privateKey).toString('base64') };
@@ -227,10 +207,10 @@ export function verifyPublicVerificationAggregate(aggregate, publicKey, expected
227
207
  }
228
208
  const payload = aggregatePayload(aggregate);
229
209
  if (digest(payload) !== aggregate.aggregateSha256) throw new Error('public verification aggregate digest mismatch');
230
- if (!Array.isArray(aggregate.evidence?.leaves) || !Array.isArray(aggregate.evidence?.reviews)) {
231
- throw new Error('public verification aggregate lacks raw leaf or review evidence');
210
+ if (!Array.isArray(aggregate.evidence?.leaves)) {
211
+ throw new Error('public verification aggregate lacks raw leaf evidence');
232
212
  }
233
- const rebuilt = buildPublicVerificationAggregate(aggregate.evidence.leaves, aggregate.evidence.reviews);
213
+ const rebuilt = buildPublicVerificationAggregate(aggregate.evidence.leaves);
234
214
  if (canonicalJson(rebuilt) !== canonicalJson(payload)) {
235
215
  throw new Error('public verification aggregate differs from rebuilt raw evidence');
236
216
  }
@@ -249,17 +229,10 @@ export function verifyPublicVerificationAggregate(aggregate, publicKey, expected
249
229
  || aggregate.coverage.gistCurrent !== aggregate.coverage.gistTotal) {
250
230
  throw new Error('public verification aggregate evidence is incomplete');
251
231
  }
252
- if (aggregate.reviews?.length !== REQUIRED_REVIEW_MODELS.length
253
- || REQUIRED_REVIEW_MODELS.some((model) => !aggregate.reviews.some((row) => row.model === model
254
- && Number.isInteger(row.score) && row.score >= 95 && HEX64.test(String(row.receiptSha256 || ''))))
255
- || !HEX64.test(String(aggregate.productContractSha256 || '')) || !HEX64.test(String(aggregate.rubricSha256 || ''))) {
256
- throw new Error('public verification aggregate reviews are incomplete');
257
- }
258
232
  if (aggregate.retrievalOracle?.oracleReceiptSha256 !== aggregate.evidence.leaves[0].retrievalPlan.oracle.receiptSha256
259
233
  || aggregate.retrievalOracle?.queryStoreSetSha256 !== aggregate.evidence.leaves[0].retrievalPlan.oracle.queryStoreSetSha256
260
- || aggregate.retrievalOracle?.recordCount !== aggregate.evidence.leaves[0].retrievalPlan.denominator.eligibleStores.length
261
- || !HEX64.test(String(aggregate.retrievalOracle?.recordSetSha256 || ''))) {
262
- throw new Error('public verification aggregate retrieval oracle review is incomplete');
234
+ || aggregate.retrievalOracle?.recordCount !== aggregate.evidence.leaves[0].retrievalPlan.denominator.eligibleStores.length) {
235
+ throw new Error('public verification aggregate retrieval oracle identity is incomplete');
263
236
  }
264
237
  if (expectedIdentity && canonicalJson(aggregate.identity) !== canonicalJson(expectedIdentity)) {
265
238
  throw new Error('public verification aggregate identity differs from the release transaction');
@@ -272,13 +245,13 @@ function parseCliArgs(argv) {
272
245
  for (let index = 0; index < argv.length; index += 2) {
273
246
  const flag = argv[index];
274
247
  const value = argv[index + 1];
275
- if (!['--lanes', '--reviews', '--out'].includes(flag) || !value) {
276
- throw new Error('usage: public-verification-aggregate.mjs --lanes <dir> --reviews <dir> --out <file>');
248
+ if (!['--lanes', '--out'].includes(flag) || !value) {
249
+ throw new Error('usage: public-verification-aggregate.mjs --lanes <dir> --out <file>');
277
250
  }
278
251
  parsed[flag.slice(2)] = value;
279
252
  }
280
- if (!parsed.lanes || !parsed.reviews || !parsed.out || Object.keys(parsed).length !== 3) {
281
- throw new Error('usage: public-verification-aggregate.mjs --lanes <dir> --reviews <dir> --out <file>');
253
+ if (!parsed.lanes || !parsed.out || Object.keys(parsed).length !== 2) {
254
+ throw new Error('usage: public-verification-aggregate.mjs --lanes <dir> --out <file>');
282
255
  }
283
256
  return parsed;
284
257
  }
@@ -314,12 +287,11 @@ function readLaneLeaves(directory) {
314
287
  return PUBLIC_VERIFICATION_OS.flatMap((osName) => byOs.get(osName));
315
288
  }
316
289
 
317
- export function generatePublicVerificationAggregate({ lanesDirectory, reviewsDirectory, outputFile, privateKey }) {
290
+ export function generatePublicVerificationAggregate({ lanesDirectory, outputFile, privateKey }) {
318
291
  if (!privateKey) throw new Error('RUVNET_SIGNING_KEY is required');
319
292
  if (fs.existsSync(outputFile)) throw new Error(`refusing to overwrite existing aggregate: ${outputFile}`);
320
293
  const leaves = readLaneLeaves(lanesDirectory);
321
- const reviews = readExactJsonFiles(reviewsDirectory, REQUIRED_REVIEW_MODELS.length, 'review');
322
- const aggregate = signPublicVerificationAggregate({ leaves, reviews }, privateKey);
294
+ const aggregate = signPublicVerificationAggregate({ leaves }, privateKey);
323
295
  fs.writeFileSync(outputFile, `${JSON.stringify(aggregate, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
324
296
  return aggregate;
325
297
  }
@@ -328,12 +300,11 @@ async function main() {
328
300
  const options = parseCliArgs(process.argv.slice(2));
329
301
  const aggregate = generatePublicVerificationAggregate({
330
302
  lanesDirectory: options.lanes,
331
- reviewsDirectory: options.reviews,
332
303
  outputFile: options.out,
333
304
  privateKey: process.env.RUVNET_SIGNING_KEY,
334
305
  });
335
306
  process.stdout.write(`${JSON.stringify({ ok: true, aggregateSha256: aggregate.aggregateSha256,
336
- leaves: aggregate.metrics.leaves, reviews: aggregate.reviews.length })}\n`);
307
+ leaves: aggregate.metrics.leaves })}\n`);
337
308
  }
338
309
 
339
310
  if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
@@ -33,6 +33,7 @@ const lanes = [
33
33
  'tests/unit/codex-claude-hook-parity.test.mjs',
34
34
  'tests/unit/brain-stamp-resolve-built-from-sha.test.mjs',
35
35
  'tests/unit/qa-runner-concurrency.test.mjs',
36
+ 'tests/unit/execution-preflight.test.mjs',
36
37
  '--reporter=dot']],
37
38
  ['mesh', 'npm', ['run', 'test:mesh']],
38
39
  ['plugin', 'npm', ['test']],
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  // scripts/refresh-model-catalog.mjs — pulls the LIVE OpenRouter model catalog and writes the committed
3
- // snapshot data/openrouter-catalog-snapshot.json (with a pulledAt stamp). verify-model-catalog.mjs then
3
+ // snapshot data/openrouter-catalog-snapshot.json (with a pulledAt stamp) and synchronizes the catalog's
4
+ // factual prices. verify-model-catalog.mjs then
4
5
  // enforces, offline in CI, that every model in data/model-catalog.json exists and is priced correctly
5
- // against this snapshot — and that the snapshot is fresh. Run nightly (the anti-rot mechanism) + on demand.
6
+ // against this snapshot — and that the snapshot is fresh. Run weekly (the anti-rot mechanism) + on demand.
6
7
  // ADR-0016.
7
8
  //
8
9
  // It ALSO flags drift so a new flagship (e.g. a GPT-5.6-class release) surfaces instead of rotting:
@@ -45,6 +46,30 @@ export function detectDrift(catalog, models) {
45
46
  return missing;
46
47
  }
47
48
 
49
+ /** Synchronize factual catalog prices from the same live map that backs the snapshot. */
50
+ export function syncCatalogPrices(catalog, models, pulledAt) {
51
+ const changes = [];
52
+ for (const [provider, entry] of Object.entries(catalog.providers || {})) {
53
+ if (entry.aliasOf) continue;
54
+ for (const tier of ['frontier', 'mid', 'cheap']) {
55
+ const candidate = entry[tier];
56
+ if (!candidate?.model) continue;
57
+ const live = models[candidate.model]
58
+ || (!candidate.model.includes('/') ? models[`anthropic/${candidate.model}`] : null);
59
+ if (!live) continue;
60
+ if (candidate.in !== live.in || candidate.out !== live.out) {
61
+ changes.push({ provider, tier, model: candidate.model, from: { in: candidate.in, out: candidate.out }, to: live });
62
+ candidate.in = live.in;
63
+ candidate.out = live.out;
64
+ }
65
+ }
66
+ }
67
+ if (catalog._meta?.sources) {
68
+ catalog._meta.sources.prices = `OpenRouter /api/v1/models live catalog, pulled ${pulledAt.slice(0, 10)} (in/out USD per Mtok).`;
69
+ }
70
+ return changes;
71
+ }
72
+
48
73
  export function shapeSnapshot(models, pulledAt) {
49
74
  return { _meta: { source: 'OpenRouter /api/v1/models (live metadata)', pulledAt, modelCount: Object.keys(models).length }, models };
50
75
  }
@@ -73,7 +98,8 @@ async function main() {
73
98
 
74
99
  const catalog = JSON.parse(fs.readFileSync(CATALOG, 'utf8'));
75
100
  const missing = detectDrift(catalog, models);
76
- const snapshot = shapeSnapshot(models, new Date().toISOString());
101
+ const pulledAt = new Date().toISOString();
102
+ const snapshot = shapeSnapshot(models, pulledAt);
77
103
  const next = JSON.stringify(snapshot, null, 2) + '\n';
78
104
 
79
105
  if (check) {
@@ -86,8 +112,11 @@ async function main() {
86
112
  return;
87
113
  }
88
114
 
115
+ const priceChanges = syncCatalogPrices(catalog, models, pulledAt);
89
116
  fs.writeFileSync(SNAPSHOT, next);
117
+ fs.writeFileSync(CATALOG, JSON.stringify(catalog, null, 2) + '\n');
90
118
  console.log(`✓ wrote ${SNAPSHOT.replace(ROOT + '/', '')} — ${Object.keys(models).length} live models, pulledAt ${snapshot._meta.pulledAt}`);
119
+ console.log(`✓ synchronized ${priceChanges.length} catalog price field(s) from the same live response`);
91
120
  if (missing.length) {
92
121
  console.log(`\n⚠ DRIFT: ${missing.length} catalog model(s) no longer in the live catalog — update data/model-catalog.json:`);
93
122
  for (const m of missing) console.log(' - ' + m);
@@ -11,7 +11,7 @@ const CANONICAL_PUBLISHERS = new Set([
11
11
  'scripts/release.mjs',
12
12
  'scripts/release-transaction-provider.mjs',
13
13
  ]);
14
- const SOURCE_EXTENSIONS = new Set(['.mjs', '.js', '.cjs', '.sh']);
14
+ const SOURCE_EXTENSIONS = new Set(['.mjs', '.js', '.cjs', '.sh', '.yml', '.yaml']);
15
15
 
16
16
  function executableSource(source) {
17
17
  const withoutBlocks = source.replace(/\/\*[\s\S]*?\*\//g, '');
@@ -28,7 +28,7 @@ const ACTIONS = [
28
28
  jsPatterns: [
29
29
  /\[\s*['"]release['"]\s*,\s*['"]create['"]/,
30
30
  ],
31
- shellPatterns: [/^\s*gh\s+release\s+create\b/m],
31
+ shellPatterns: [/^\s*(?:-\s*run:\s*)?gh\s+release\s+create\b/m],
32
32
  },
33
33
  {
34
34
  action: 'github-release-update',
@@ -36,7 +36,7 @@ const ACTIONS = [
36
36
  /['"]PATCH['"][\s\S]{0,120}releases\//,
37
37
  /\[\s*['"]release['"]\s*,\s*['"]edit['"]/,
38
38
  ],
39
- shellPatterns: [/^\s*gh\s+(?:release\s+edit|api\s+.*releases\/.*PATCH)\b/m],
39
+ shellPatterns: [/^\s*(?:-\s*run:\s*)?gh\s+(?:release\s+edit|api\s+.*releases\/.*PATCH)\b/m],
40
40
  },
41
41
  {
42
42
  action: 'npm-publish',
@@ -44,7 +44,7 @@ const ACTIONS = [
44
44
  /(?:execFileSync|spawnSync)\(\s*['"]npm['"]\s*,\s*\[\s*['"]publish['"]/,
45
45
  /runOrDie\(\s*['"]npm publish['"]/,
46
46
  ],
47
- shellPatterns: [/^\s*npm\s+publish\b/m],
47
+ shellPatterns: [/^\s*(?:-\s*run:\s*)?npm\s+publish\b/m],
48
48
  },
49
49
  {
50
50
  action: 'npm-dist-tag',
@@ -52,7 +52,7 @@ const ACTIONS = [
52
52
  /(?:execFileSync|spawnSync)\(\s*['"]npm['"]\s*,\s*\[\s*['"]dist-tag['"]\s*,\s*['"]add['"]/,
53
53
  /runOrDie\(\s*['"]npm dist-tag[^'"]*['"]/,
54
54
  ],
55
- shellPatterns: [/^\s*npm\s+dist-tag\s+add\b/m],
55
+ shellPatterns: [/^\s*(?:-\s*run:\s*)?npm\s+dist-tag\s+add\b/m],
56
56
  },
57
57
  ];
58
58
 
@@ -60,7 +60,10 @@ export function detectPublisherActions(file, source) {
60
60
  const relative = file.split(path.sep).join('/');
61
61
  if (CANONICAL_PUBLISHERS.has(relative)) return [];
62
62
  const executable = executableSource(source);
63
- const kind = path.extname(relative) === '.sh' ? 'shellPatterns' : 'jsPatterns';
63
+ const extension = path.extname(relative);
64
+ const kind = ['.sh', '.yml', '.yaml'].includes(extension) || relative.startsWith('package.json#scripts.')
65
+ ? 'shellPatterns'
66
+ : 'jsPatterns';
64
67
  return ACTIONS
65
68
  .filter((action) => action[kind].some((pattern) => pattern.test(executable)))
66
69
  .map(({ action }) => ({ file: relative, action }));
@@ -79,14 +82,23 @@ function sourceFiles(root) {
79
82
  visit(path.join(root, 'scripts'));
80
83
  visit(path.join(root, 'deploy'));
81
84
  visit(path.join(root, 'bin'));
85
+ visit(path.join(root, '.github', 'workflows'));
82
86
  return files;
83
87
  }
84
88
 
85
89
  export function findUnauthorizedPublishers(root = ROOT) {
86
- return sourceFiles(root).flatMap((absolute) => {
90
+ const findings = sourceFiles(root).flatMap((absolute) => {
87
91
  const relative = path.relative(root, absolute).split(path.sep).join('/');
88
92
  return detectPublisherActions(relative, fs.readFileSync(absolute, 'utf8'));
89
93
  });
94
+ const packageFile = path.join(root, 'package.json');
95
+ if (fs.existsSync(packageFile)) {
96
+ const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8'));
97
+ for (const [name, command] of Object.entries(pkg.scripts || {})) {
98
+ findings.push(...detectPublisherActions(`package.json#scripts.${name}`, String(command)));
99
+ }
100
+ }
101
+ return findings;
90
102
  }
91
103
 
92
104
  export function main(root = ROOT) {
@@ -11,18 +11,16 @@
11
11
  * for a month.
12
12
  *
13
13
  * WHAT IT WILL NOT DO. It does not publish. `scripts/self-update.mjs:56` refuses `--publish` and
14
- * only `protected-release.yml` may create a release, publish npm, or move a dist-tag. This script
15
- * DISPATCHES that workflow — the sanctioned path — and never substitutes for it. Every safety gate
16
- * (exact-SHA evidence, clean worktree, release-proof, host verification, post-publication seal)
17
- * still runs inside the workflow exactly as designed. Bypassing them to "get it done while nobody
18
- * is looking" would be the worst possible reading of an instruction to finish the job.
14
+ * `release-candidate-preflight.yml` owns the one-time long lanes and `protected-release.yml` is the
15
+ * sole publication controller. This watchdog is report-only: it never dispatches either phase and
16
+ * cannot manufacture typed candidate evidence.
19
17
  *
20
18
  * IT IS A NO-OP UNLESS EVERY PRECONDITION HOLDS. It runs from the nightly, unattended, for weeks.
21
19
  * A watchdog that acts on a partial picture is worse than no watchdog, so it refuses on anything
22
20
  * unexpected and says why. The default outcome is "nothing happened, here is the reason".
23
21
  *
24
22
  * node scripts/release-convergence-watchdog.mjs # report only, never acts
25
- * node scripts/release-convergence-watchdog.mjs --dispatch # act, but only if ALL gates pass
23
+ * node scripts/release-convergence-watchdog.mjs --dispatch # compatibility flag; still reports only
26
24
  */
27
25
  import { execFileSync } from 'node:child_process';
28
26
  import fs from 'node:fs';
@@ -99,21 +97,11 @@ const runsFor = (wf) => JSON.parse(tryShy(() => sh('gh', ['run', 'list', '--repo
99
97
  const greenAt = (wf) => runsFor(wf).find((r) => r.headSha === originMain && r.conclusion === 'success');
100
98
 
101
99
  const ci = greenAt('ci');
102
- const aggregate = greenAt('release-aggregate');
103
100
  if (!ci) stand_down(`no successful exact-SHA \`ci\` run at ${originMain.slice(0, 7)} yet`);
104
- if (!aggregate) stand_down(`no successful exact-SHA \`release-aggregate\` run at ${originMain.slice(0, 7)} yet`);
105
101
 
106
- log(`ALL GATES PASS — candidate=${originMain.slice(0, 7)} version=${version} ci=${ci.databaseId} aggregate=${aggregate.databaseId}`);
107
- if (!DISPATCH) {
108
- log('report-only mode; pass --dispatch to actually invoke the protected release workflow.');
109
- process.exit(0);
110
- }
111
-
112
- // ── 6. Dispatch THE SANCTIONED PUBLISHER. Nothing here publishes; the workflow does. ─────────────
113
- sh('gh', ['workflow', 'run', 'protected-release.yml', '--repo', REPO,
114
- '-f', `candidate_sha=${originMain}`,
115
- '-f', `version=${version}`,
116
- '-f', `release_qe_run_id=${ci.databaseId}`,
117
- '-f', `aggregate_run_id=${aggregate.databaseId}`]);
118
- log(`DISPATCHED protected-release for ${version}. The workflow owns every safety gate from here.`);
119
- log('Verify afterwards with: node scripts/published-surface-probe.mjs (D-version-coherence must PASS).');
102
+ log(`PRECONDITIONS VISIBLE — candidate=${originMain.slice(0, 7)} version=${version} ci=${ci.databaseId}`);
103
+ // ── 6. Never dispatch a publisher from the watchdog. ───────────────────────────────────────────
104
+ // Only protected-release may derive the complete typed evidence chain and cross Production.
105
+ // This unattended observer cannot turn visible preconditions into release authority.
106
+ log(`PRECONDITIONS ONLY — no candidate artifact inferred and no action taken for ${version} at ${originMain}`);
107
+ log('Run release-candidate-preflight on release/** once; fast-forward that exact SHA to main; then protected-release imports release-candidate-<SHA> without a run ID.');
@@ -565,7 +565,7 @@ export async function finalizeReleaseTransaction({
565
565
  lanes: aggregate.metrics.leaves,
566
566
  recallAt10: aggregate.metrics.recallAt10,
567
567
  deltaCitationRate: aggregate.metrics.deltaCitationRate,
568
- reviewReceipts: aggregate.reviews,
568
+ reviewReceipts: aggregate.reviews || [],
569
569
  },
570
570
  npm: snapshot.npm,
571
571
  github: snapshot.github,
@@ -29,7 +29,7 @@ import { fileURLToPath } from 'node:url';
29
29
  import { spawnSync, execFileSync } from 'node:child_process';
30
30
  import fs from 'node:fs';
31
31
  import crypto from 'node:crypto';
32
- import { validateProtectedPublishInvocation } from './protected-release-invocation.mjs';
32
+ import { validateProtectedPublishEnvironment, validateProtectedPublishInvocation } from './protected-release-invocation.mjs';
33
33
  import { runReleaseTransaction } from './release-transaction.mjs';
34
34
  import { liveReleaseProvider } from './release-transaction-provider.mjs';
35
35
  import { stagedHostVerifier } from './staged-host-verifier.mjs';
@@ -87,9 +87,9 @@ export function runProtectedCorpusSeed({
87
87
  root = ROOT,
88
88
  run = (command, args, options) => spawnSync(command, args, { encoding: 'utf8', ...options }),
89
89
  } = {}) {
90
- if (env.GITHUB_ACTIONS !== 'true' || env.GITHUB_WORKFLOW !== 'protected-release'
91
- || env.GITHUB_REPOSITORY !== 'stuinfla/ruvnet-brain') {
92
- corpusFailure('publication is allowed only inside the protected-release GitHub workflow for stuinfla/ruvnet-brain');
90
+ const environmentFailures = validateProtectedPublishEnvironment(env);
91
+ if (environmentFailures.length) {
92
+ corpusFailure(environmentFailures.join('; '));
93
93
  }
94
94
 
95
95
  const tag = cliArg(argv, '--corpus-tag');
@@ -399,7 +399,6 @@ if (!PUBLISH) {
399
399
 
400
400
  if (PUBLISH) {
401
401
  console.log(`\n${c.y(c.b('PUBLISHED, NOT VERIFIED'))}`);
402
- console.log(`\n${c.g(c.b('✓✓✓ SHIPPED'))} — every gate passed and every live channel is current. ${c.dim('A user on any path (npm, npx, explainer, --update) gets the working, current build.')}\n`);
403
402
  } else {
404
403
  console.log(`\n${c.g(c.b('✓✓✓ PREFLIGHT PASS — NOT PUBLISHED'))} — the committed candidate passed every check-only gate.\n`);
405
404
  }
@@ -6,6 +6,7 @@ import { spawnSync } from 'node:child_process';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { readRvfGenerations, sha256File } from './rvf-generation.mjs';
8
8
  import { canonicalJson, coverageGenerationFor, digest, validateGistAggregateReceipt } from './coverage-integrity.mjs';
9
+ import { repositoryNames } from '../kb/card-lane.mjs';
9
10
 
10
11
  export { canonicalJson, digest } from './coverage-integrity.mjs';
11
12
 
@@ -272,7 +273,15 @@ export function classifyGist(gist, evidence) {
272
273
  };
273
274
  }
274
275
 
275
- function artifactEvidence(kbDir, ledger, cardStores, name) {
276
+ // ALIAS-AWARE, BECAUSE THE ROUTER IS. `cardStores` holds card HEADINGS; a store reachable only
277
+ // under an alias (e.g. `metaharness` via its `## agent-harness-generator` card) has no heading of
278
+ // its own, so a direct `cardStores.has(store)` reports it card-absent even though the router finds
279
+ // it. `kb/store-root.mjs`'s `darkStores()` and `scripts/brain-score.mjs`'s `readCoverage()` were
280
+ // already fixed for this exact conflation (ADR-058; metaharness is the standing example in both);
281
+ // this sibling computation, which feeds the committed `data/source-coverage.json` and
282
+ // `docs/RUVNET-COVERAGE.md` (ADR-069), never received it. `repositoryNames` is the router's own
283
+ // resolver (kb/card-lane.mjs), imported rather than reimplemented.
284
+ export function artifactEvidence(kbDir, ledger, cardStores, name) {
276
285
  const store = storeName(name);
277
286
  const receipt = Object.entries(ledger.stores).find(([key]) => key.toLowerCase() === store)?.[1] || null;
278
287
  const rvfFile = receipt?.file || `${store}.big.rvf`;
@@ -284,7 +293,7 @@ function artifactEvidence(kbDir, ledger, cardStores, name) {
284
293
  bytesVerified: Boolean(rvfPresent && receipt?.sha256 && sha256File(rvfPath) === receipt.sha256),
285
294
  passagesPresent: fs.existsSync(path.join(kbDir, `${store}.passages.jsonl`))
286
295
  && fs.statSync(path.join(kbDir, `${store}.passages.jsonl`)).size > 0,
287
- cardPresent: cardStores.has(store),
296
+ cardPresent: repositoryNames(store, kbDir).some((alias) => cardStores.has(storeName(alias))),
288
297
  };
289
298
  }
290
299
 
@@ -3,7 +3,7 @@ import crypto from 'node:crypto';
3
3
  import fs from 'node:fs';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
- import { runHostMatrix } from './host-install-matrix.mjs';
6
+ import { runHostMatrixAsync } from './host-install-matrix.mjs';
7
7
 
8
8
  const sha256 = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
9
9
  const locate = (name) => {
@@ -50,7 +50,7 @@ export function stagedHostVerifier({ assets, identity }) {
50
50
  // install shape than the one that runs after publication — so the two halves of a release
51
51
  // were judging different things and could not be compared. Only the STAGED-vs-PUBLISHED
52
52
  // difference is real, and it is now a named variant rather than a second implementation.
53
- const matrix = runHostMatrix({
53
+ const matrix = await runHostMatrixAsync({
54
54
  packageRoot: prepared.packageRoot,
55
55
  version: identity.version,
56
56
  variant: 'staged',
@@ -95,6 +95,7 @@ const STANDALONE = [
95
95
  + 'RVFs to RVF-GENERATIONS.json and optionally prunes legacy sidecars; build-bundle.mjs consumes '
96
96
  + 'and validates the resulting manifest, so scheduling this destructive migration would be wrong'],
97
97
  ['release', 'the ship path, run by a human'],
98
+ ['execution-preflight', 'external orchestration boundary — invoked by the host before consequential Ruflo/Codex execution; no in-repo caller exists because the host supplies the live Brain and AgentDB receipts'],
98
99
  ['fix-workstream', 'session-supervised coordination CLI run explicitly by the integration owner or an '
99
100
  + 'isolated writing agent to start and hand off a fix lane. Scheduling it would violate its safety '
100
101
  + 'boundary: it prepares evidence but never merges, pushes, publishes, deletes, or cleans worktrees'],