ruvnet-brain 4.0.90-dev → 4.3.1-dev
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.
- package/README.md +31 -7
- package/bin/install.mjs +153 -22
- package/console/architecture.html +12 -14
- package/console/install-mockup.html +3 -3
- package/kb/zip-extract.mjs +8 -2
- package/package.json +7 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/hooks/codex-hooks.json +1 -1
- package/plugin/hooks/hooks.json +10 -0
- package/plugin/host-adapters/claude.json +11 -0
- package/plugin/host-adapters/codex.json +11 -0
- package/plugin/mcp/managed-cli-interface.mjs +77 -10
- package/plugin/mcp/server.mjs +2 -1
- package/plugin/scripts/anticipate.sh +30 -1
- package/plugin/scripts/capability-claim-evidence.mjs +431 -0
- package/plugin/scripts/capability-inventory-receipt.mjs +225 -0
- package/plugin/scripts/capability-registry.mjs +6 -0
- package/plugin/scripts/capability-routing.mjs +70 -0
- package/plugin/scripts/continuation-gate.mjs +68 -2
- package/plugin/scripts/coverage-integrity.mjs +575 -0
- package/plugin/scripts/decision-outcomes.mjs +0 -0
- package/plugin/scripts/ground-ruvnet.sh +2 -2
- package/plugin/scripts/nightly-controller.mjs +19 -2
- package/plugin/scripts/project-progression-contract.mjs +409 -0
- package/plugin/scripts/project-progression-hook.mjs +196 -0
- package/plugin/scripts/project-progression-outbox.mjs +95 -0
- package/plugin/scripts/project-progression-session-start.mjs +183 -0
- package/plugin/scripts/project-progression-store.mjs +248 -0
- package/plugin/scripts/project-store-resolver.mjs +106 -0
- package/plugin/scripts/session-snapshot-hook.mjs +29 -1
- package/plugin/scripts/session-start-core.mjs +22 -18
- package/plugin/scripts/spend-guard.mjs +6 -1
- package/scripts/adr-072-completion.mjs +98 -0
- package/scripts/behavioral-l1-l4.mjs +11 -8
- package/scripts/brain-score.mjs +23 -9
- package/scripts/build-bundle.mjs +94 -8
- package/scripts/card-from-source.mjs +140 -0
- package/scripts/corpus-aggregates.mjs +194 -0
- package/scripts/corpus-candidate.mjs +314 -0
- package/scripts/corpus-reconcile.mjs +540 -0
- package/scripts/corpus-seed-publish.mjs +110 -0
- package/scripts/coverage-integrity.mjs +3 -0
- package/scripts/gist-receipts.mjs +183 -0
- package/scripts/git-hooks/pre-push +21 -0
- package/scripts/host-registry.mjs +118 -0
- package/scripts/independent-review-receipt.mjs +499 -0
- package/scripts/ingest-gists.mjs +34 -5
- package/scripts/ingest-new-repos.mjs +127 -0
- package/scripts/metaharness-gate.mjs +58 -0
- package/scripts/nightly-gists.sh +3 -3
- package/scripts/nightly-wrapper.sh +105 -64
- package/scripts/product-integrity-contract.mjs +156 -0
- package/scripts/public-inventory.mjs +4 -0
- package/scripts/public-verification-aggregate.mjs +342 -0
- package/scripts/public-verification-finalizer.mjs +59 -0
- package/scripts/public-verification-inputs.mjs +473 -0
- package/scripts/public-verification-lane.mjs +244 -0
- package/scripts/publication-receipt.mjs +50 -6
- package/scripts/rebuild-gists-from-receipts.mjs +291 -0
- package/scripts/release-projection.mjs +86 -0
- package/scripts/release-transaction-provider.mjs +43 -102
- package/scripts/release-transaction.mjs +165 -49
- package/scripts/release.mjs +158 -3
- package/scripts/restore-local-ingests.mjs +2 -2
- package/scripts/retrieval-canary.mjs +533 -0
- package/scripts/routing-flywheel.mjs +12 -1
- package/scripts/rvf-generation.mjs +50 -0
- package/scripts/self-update.mjs +19 -44
- package/scripts/source-coverage.mjs +415 -0
- package/scripts/source-scope-receipt.mjs +84 -0
- package/scripts/sync-census.mjs +0 -0
- package/scripts/wired-check.mjs +114 -24
- package/scripts/worktree-integrity.mjs +123 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { canonicalJson, digest, validateCoverageLedger } from './coverage-integrity.mjs';
|
|
8
|
+
|
|
9
|
+
const HEX40 = /^[a-f0-9]{40}$/;
|
|
10
|
+
const HEX64 = /^[a-f0-9]{64}$/;
|
|
11
|
+
|
|
12
|
+
const ordered = (value) => [...value].sort((a, b) => a.localeCompare(b));
|
|
13
|
+
const storeOf = (row) => String(row?.artifact?.store || '').toLowerCase();
|
|
14
|
+
const setDigest = (values) => digest(ordered(values));
|
|
15
|
+
|
|
16
|
+
function checkedSet(values, expectedDigest, label) {
|
|
17
|
+
if (!Array.isArray(values) || values.some((value) => typeof value !== 'string' || !value)
|
|
18
|
+
|| canonicalJson(values) !== canonicalJson(ordered(values)) || new Set(values).size !== values.length
|
|
19
|
+
|| setDigest(values) !== expectedDigest) throw new Error(`${label} set is invalid`);
|
|
20
|
+
return values;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function defaultReadPassages(assetsDir, store) {
|
|
24
|
+
const file = path.join(assetsDir, `${store}.passages.jsonl`);
|
|
25
|
+
if (!fs.existsSync(file) || !fs.lstatSync(file).isFile()) throw new Error(`${store} passage inventory is missing`);
|
|
26
|
+
return fs.readFileSync(file, 'utf8').split('\n').filter(Boolean).map((line, index) => {
|
|
27
|
+
try { return JSON.parse(line); }
|
|
28
|
+
catch (error) { throw new Error(`${store} passage ${index + 1} is invalid: ${error.message}`); }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function planPayload(plan) {
|
|
33
|
+
const { planSha256: _planSha256, ...payload } = plan;
|
|
34
|
+
return payload;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function regular(file, label) {
|
|
38
|
+
const resolved = path.resolve(file || '');
|
|
39
|
+
const stat = fs.lstatSync(resolved);
|
|
40
|
+
if (!stat.isFile() || stat.isSymbolicLink()) throw new Error(`${label} is not a trusted regular file`);
|
|
41
|
+
return resolved;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function queryEvidenceSourcePayload(evidence) {
|
|
45
|
+
return {
|
|
46
|
+
schemaVersion: evidence?.schemaVersion,
|
|
47
|
+
kind: evidence?.kind,
|
|
48
|
+
queryStoreSetSha256: evidence?.queryStoreSetSha256,
|
|
49
|
+
queries: evidence?.queries,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const normalizedQuery = (query) => String(query || '').trim().replace(/\s+/g, ' ').toLowerCase();
|
|
54
|
+
|
|
55
|
+
function queryEvidenceReceiptPayload(evidence) {
|
|
56
|
+
const { receiptSha256: _receiptSha256, ...payload } = evidence;
|
|
57
|
+
return payload;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function sealRetrievalQueryEvidence(evidence) {
|
|
61
|
+
const sourcePayload = queryEvidenceSourcePayload(evidence);
|
|
62
|
+
const payload = {
|
|
63
|
+
...sourcePayload,
|
|
64
|
+
sourceCommit: evidence?.sourceCommit,
|
|
65
|
+
sourcePath: evidence?.sourcePath,
|
|
66
|
+
sourceBlobSha256: digest(sourcePayload),
|
|
67
|
+
};
|
|
68
|
+
return { ...payload, receiptSha256: digest(payload) };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function validateRetrievalQueryEvidence(evidence) {
|
|
72
|
+
const keys = Object.keys(evidence || {}).sort();
|
|
73
|
+
const expectedKeys = ['kind', 'queries', 'queryStoreSetSha256', 'receiptSha256', 'schemaVersion',
|
|
74
|
+
'sourceBlobSha256', 'sourceCommit', 'sourcePath'];
|
|
75
|
+
if (canonicalJson(keys) !== canonicalJson(expectedKeys)
|
|
76
|
+
|| evidence?.schemaVersion !== 2 || evidence?.kind !== 'ruvnet-brain-retrieval-query-evidence'
|
|
77
|
+
|| !HEX40.test(String(evidence.sourceCommit || '')) || typeof evidence.sourcePath !== 'string'
|
|
78
|
+
|| !evidence.sourcePath || path.isAbsolute(evidence.sourcePath)
|
|
79
|
+
|| evidence.sourcePath.split(/[\\/]/).includes('..')
|
|
80
|
+
|| !HEX64.test(String(evidence.queryStoreSetSha256 || ''))
|
|
81
|
+
|| !evidence.queries || typeof evidence.queries !== 'object' || Array.isArray(evidence.queries)
|
|
82
|
+
|| Object.keys(evidence.queries).length === 0
|
|
83
|
+
|| evidence.sourceBlobSha256 !== digest(queryEvidenceSourcePayload(evidence))
|
|
84
|
+
|| evidence.receiptSha256 !== digest(queryEvidenceReceiptPayload(evidence))) {
|
|
85
|
+
throw new Error('independent retrieval query evidence is malformed');
|
|
86
|
+
}
|
|
87
|
+
const stores = ordered(Object.keys(evidence.queries));
|
|
88
|
+
if (digest(stores) !== evidence.queryStoreSetSha256) {
|
|
89
|
+
throw new Error('independent retrieval query evidence store set is invalid');
|
|
90
|
+
}
|
|
91
|
+
const seenQueries = new Set();
|
|
92
|
+
for (const store of stores) {
|
|
93
|
+
const row = evidence.queries[store];
|
|
94
|
+
const expected = row?.expected;
|
|
95
|
+
const normalized = normalizedQuery(row?.query);
|
|
96
|
+
if (Object.keys(row || {}).sort().join(',') !== 'expected,query,recordSha256'
|
|
97
|
+
|| typeof row.query !== 'string' || row.query !== row.query.trim().replace(/\s+/g, ' ')
|
|
98
|
+
|| normalized.length < 24 || seenQueries.has(normalized)
|
|
99
|
+
|| !expected || Object.keys(expected).sort().join(',') !== 'passageSha256,path'
|
|
100
|
+
|| typeof expected.path !== 'string' || !expected.path || path.isAbsolute(expected.path)
|
|
101
|
+
|| expected.path.split(/[\\/]/).includes('..')
|
|
102
|
+
|| !HEX64.test(String(expected.passageSha256 || ''))
|
|
103
|
+
|| row.recordSha256 !== digest({ store, query: row.query, expected })) {
|
|
104
|
+
throw new Error(`independent retrieval query evidence for ${store} is malformed`);
|
|
105
|
+
}
|
|
106
|
+
seenQueries.add(normalized);
|
|
107
|
+
}
|
|
108
|
+
return evidence;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function verifyQueryOracleSource(queryEvidence, candidateSourceSha, { cwd = process.cwd(), run = spawnSync } = {}) {
|
|
112
|
+
validateRetrievalQueryEvidence(queryEvidence);
|
|
113
|
+
if (!HEX40.test(String(candidateSourceSha || '')) || queryEvidence.sourceCommit === candidateSourceSha) {
|
|
114
|
+
throw new Error('query oracle source identity is invalid');
|
|
115
|
+
}
|
|
116
|
+
const ancestor = run('git', ['merge-base', '--is-ancestor', queryEvidence.sourceCommit, candidateSourceSha],
|
|
117
|
+
{ cwd, encoding: 'utf8' });
|
|
118
|
+
if (ancestor.error || ancestor.status !== 0) throw new Error('query oracle source is not a strict candidate ancestor');
|
|
119
|
+
const shown = run('git', ['show', `${queryEvidence.sourceCommit}:${queryEvidence.sourcePath}`],
|
|
120
|
+
{ cwd, encoding: null, maxBuffer: 64 * 1024 * 1024 });
|
|
121
|
+
let sourcePayload;
|
|
122
|
+
try { sourcePayload = queryEvidenceSourcePayload(JSON.parse(Buffer.from(shown.stdout || '').toString('utf8'))); }
|
|
123
|
+
catch { throw new Error('query oracle source payload is not valid JSON'); }
|
|
124
|
+
if (shown.error || shown.status !== 0 || digest(sourcePayload) !== queryEvidence.sourceBlobSha256) {
|
|
125
|
+
throw new Error('query oracle source payload differs from its immutable Git identity');
|
|
126
|
+
}
|
|
127
|
+
const candidateShown = run('git', ['show', `${candidateSourceSha}:${queryEvidence.sourcePath}`],
|
|
128
|
+
{ cwd, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
129
|
+
let candidateEvidence;
|
|
130
|
+
try { candidateEvidence = JSON.parse(String(candidateShown.stdout || '')); }
|
|
131
|
+
catch { throw new Error('candidate query oracle evidence is not valid JSON'); }
|
|
132
|
+
if (candidateShown.error || candidateShown.status !== 0
|
|
133
|
+
|| canonicalJson(candidateEvidence) !== canonicalJson(queryEvidence)) {
|
|
134
|
+
throw new Error('supplied query oracle evidence differs from candidate tracked bytes');
|
|
135
|
+
}
|
|
136
|
+
return queryEvidence;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const sha256Buffer = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex');
|
|
140
|
+
export function validateRetrievalCanaryPlan(plan) {
|
|
141
|
+
const observedBaseline = plan?.baseline?.kind === 'ruvnet-brain-observed-failed-public-baseline';
|
|
142
|
+
const baselineReceiptValid = observedBaseline
|
|
143
|
+
? plan.baseline.integrity === 'DEGRADED' && plan.baseline.historicalCorpusReceipt === false && plan.baseline.candidateVerificationEligible === false
|
|
144
|
+
&& HEX64.test(String(plan.baseline.observationReceiptSha256 || '')) && HEX64.test(String(plan.baseline.discrepancyDigest || ''))
|
|
145
|
+
: plan?.baseline?.kind === 'ruvnet-brain-verified-public-baseline'
|
|
146
|
+
&& HEX64.test(String(plan?.baseline?.verificationReceiptSha256 || ''));
|
|
147
|
+
if (plan?.schemaVersion !== 2 || plan?.kind !== 'ruvnet-brain-retrieval-canary-plan'
|
|
148
|
+
|| !HEX64.test(String(plan.coverage?.sha256 || '')) || !Number.isSafeInteger(plan.coverage?.bytes)
|
|
149
|
+
|| plan.coverage.bytes < 1 || !HEX64.test(String(plan.coverage?.releaseCoverageGeneration || ''))
|
|
150
|
+
|| !HEX64.test(String(plan.baseline?.archiveSha256 || '')) || !baselineReceiptValid
|
|
151
|
+
|| !HEX64.test(String(plan.baseline?.archiveManifestSha256 || '')) || !Number.isSafeInteger(plan.baseline?.archiveBytes)
|
|
152
|
+
|| !Number.isSafeInteger(plan.baseline?.storeCount) || plan.baseline.storeCount < 1
|
|
153
|
+
|| !Array.isArray(plan.baseline?.stores) || plan.baseline.stores.length !== plan.baseline.storeCount
|
|
154
|
+
|| !HEX64.test(String(plan.baseline?.storeSetSha256 || ''))
|
|
155
|
+
|| !HEX40.test(String(plan.candidate?.sourceSha || '')) || !HEX64.test(String(plan.candidate?.packageSha256 || ''))
|
|
156
|
+
|| !HEX64.test(String(plan.candidate?.archiveSha256 || ''))
|
|
157
|
+
|| !HEX64.test(String(plan.candidate?.coverageSha256 || '')) || !HEX64.test(String(plan.candidate?.publicLedgerSha256 || ''))
|
|
158
|
+
|| !HEX64.test(String(plan.candidate?.publicInventoryPartitionSha256 || ''))
|
|
159
|
+
|| !Number.isSafeInteger(plan.candidate?.publicLedgerBytes) || plan.candidate.publicLedgerBytes < 1
|
|
160
|
+
|| !Number.isSafeInteger(plan.candidate?.publicStoreCount) || plan.candidate.publicStoreCount < 1
|
|
161
|
+
|| !HEX64.test(String(plan.oracle?.receiptSha256 || ''))
|
|
162
|
+
|| !HEX64.test(String(plan.oracle?.queryStoreSetSha256 || ''))
|
|
163
|
+
|| !HEX40.test(String(plan.oracle?.sourceCommit || '')) || !HEX64.test(String(plan.oracle?.sourceBlobSha256 || ''))
|
|
164
|
+
|| !plan.denominator || plan.k !== 10
|
|
165
|
+
|| !Array.isArray(plan.cases) || plan.cases.length === 0) throw new Error('retrieval canary plan is malformed');
|
|
166
|
+
const ids = plan.cases.map((row) => row.id);
|
|
167
|
+
const evidence = validateRetrievalQueryEvidence(plan.oracle?.evidence);
|
|
168
|
+
if (evidence.receiptSha256 !== plan.oracle.receiptSha256
|
|
169
|
+
|| evidence.queryStoreSetSha256 !== plan.oracle.queryStoreSetSha256
|
|
170
|
+
|| evidence.sourceCommit !== plan.oracle.sourceCommit
|
|
171
|
+
|| evidence.sourceBlobSha256 !== plan.oracle.sourceBlobSha256) {
|
|
172
|
+
throw new Error('retrieval canary oracle differs from its sealed query evidence');
|
|
173
|
+
}
|
|
174
|
+
const baselineStores = ordered(plan.baseline.stores.map((store) => String(store).toLowerCase()));
|
|
175
|
+
if (new Set(baselineStores).size !== baselineStores.length
|
|
176
|
+
|| digest(baselineStores) !== plan.baseline.storeSetSha256) throw new Error('retrieval baseline store set is invalid');
|
|
177
|
+
checkedSet(plan.denominator.eligibleStores, plan.denominator.eligibleStoreSetSha256, 'eligible denominator');
|
|
178
|
+
checkedSet(plan.denominator.deltaStores, plan.denominator.deltaStoreSetSha256, 'delta denominator');
|
|
179
|
+
checkedSet(plan.denominator.legacyPopulationStores, plan.denominator.legacyPopulationStoreSetSha256,
|
|
180
|
+
'legacy population denominator');
|
|
181
|
+
checkedSet(plan.denominator.legacySelectedStores, plan.denominator.legacySelectedStoreSetSha256,
|
|
182
|
+
'legacy selected denominator');
|
|
183
|
+
if (setDigest(plan.denominator.eligibleStores) !== plan.oracle.queryStoreSetSha256) {
|
|
184
|
+
throw new Error('oracle denominator differs from eligible coverage');
|
|
185
|
+
}
|
|
186
|
+
if (new Set(ids).size !== ids.length) throw new Error('retrieval canary plan has duplicate case ids');
|
|
187
|
+
if (!plan.cases.some(({ cohort }) => cohort === 'delta') || !plan.cases.some(({ cohort }) => cohort === 'legacy')) {
|
|
188
|
+
throw new Error('retrieval canary plan requires delta and legacy cohorts');
|
|
189
|
+
}
|
|
190
|
+
for (const row of plan.cases) {
|
|
191
|
+
const oracleRow = evidence.queries[row.expected?.repo];
|
|
192
|
+
if (!['delta', 'legacy'].includes(row.cohort) || typeof row.query !== 'string' || row.query.length < 24
|
|
193
|
+
|| typeof row.expected?.repo !== 'string' || !row.expected.repo
|
|
194
|
+
|| typeof row.expected?.path !== 'string' || !row.expected.path
|
|
195
|
+
|| row.id !== `${row.cohort}:${row.expected.repo}`
|
|
196
|
+
|| !HEX64.test(String(row.expected?.passageSha256 || ''))
|
|
197
|
+
|| !HEX64.test(String(row.oracleRecordSha256 || ''))
|
|
198
|
+
|| !oracleRow || row.query !== oracleRow.query
|
|
199
|
+
|| canonicalJson(row.expected) !== canonicalJson({ repo: row.expected.repo, ...oracleRow.expected })
|
|
200
|
+
|| row.oracleRecordSha256 !== oracleRow.recordSha256) {
|
|
201
|
+
throw new Error(`retrieval canary ${row.id || '(missing)'} is malformed`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const deltaCases = ordered(plan.cases.filter(({ cohort }) => cohort === 'delta').map(({ expected }) => expected.repo));
|
|
205
|
+
const legacyCases = ordered(plan.cases.filter(({ cohort }) => cohort === 'legacy').map(({ expected }) => expected.repo));
|
|
206
|
+
if (canonicalJson(deltaCases) !== canonicalJson(plan.denominator.deltaStores)
|
|
207
|
+
|| canonicalJson(legacyCases) !== canonicalJson(plan.denominator.legacySelectedStores)
|
|
208
|
+
|| plan.cohorts?.delta !== deltaCases.length || plan.cohorts?.legacy !== legacyCases.length) {
|
|
209
|
+
throw new Error('retrieval canary cases differ from the sealed denominator');
|
|
210
|
+
}
|
|
211
|
+
if (digest(planPayload(plan)) !== plan.planSha256) throw new Error('retrieval canary plan digest mismatch');
|
|
212
|
+
return plan;
|
|
213
|
+
}
|
|
214
|
+
export function validatePlanAgainstCoverage(plan, coverage, { allowObservedBaseline = false } = {}) {
|
|
215
|
+
validateRetrievalCanaryPlan(plan);
|
|
216
|
+
if (plan.baseline.kind === 'ruvnet-brain-observed-failed-public-baseline' && !allowObservedBaseline) {
|
|
217
|
+
throw new Error('observed failed-public baseline is not candidate-verification eligible');
|
|
218
|
+
}
|
|
219
|
+
const checked = validateCoverageLedger(coverage);
|
|
220
|
+
if (!checked.valid) throw new Error(`coverage ledger is invalid: ${checked.failures.join('; ')}`);
|
|
221
|
+
const generation = coverage.kind === 'ruvnet-brain-release-coverage'
|
|
222
|
+
? coverage.releaseCoverageGeneration : coverage.coverageGeneration;
|
|
223
|
+
const eligible = ordered(coverage.rows.filter((row) => row.kind === 'repository'
|
|
224
|
+
&& row.disposition === 'eligible' && row.status === 'CURRENT').map(storeOf));
|
|
225
|
+
if (!eligible.length || new Set(eligible).size !== eligible.length) throw new Error('eligible coverage denominator is invalid');
|
|
226
|
+
const baseline = new Set(plan.baseline.stores);
|
|
227
|
+
const delta = eligible.filter((store) => !baseline.has(store));
|
|
228
|
+
const legacy = eligible.filter((store) => baseline.has(store));
|
|
229
|
+
if (generation !== plan.coverage.releaseCoverageGeneration
|
|
230
|
+
|| canonicalJson(eligible) !== canonicalJson(plan.denominator.eligibleStores)
|
|
231
|
+
|| canonicalJson(delta) !== canonicalJson(plan.denominator.deltaStores)
|
|
232
|
+
|| canonicalJson(legacy) !== canonicalJson(plan.denominator.legacyPopulationStores)
|
|
233
|
+
|| plan.denominator.legacySelectedStores.some((store) => !legacy.includes(store))) {
|
|
234
|
+
throw new Error('retrieval canary plan differs from exact coverage denominator');
|
|
235
|
+
}
|
|
236
|
+
return plan;
|
|
237
|
+
}
|
|
238
|
+
export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, coverageIdentity = null, queryEvidence, assetsDir = '.',
|
|
239
|
+
readPassages = defaultReadPassages, legacySampleSize } = {}) {
|
|
240
|
+
const checked = validateCoverageLedger(coverage);
|
|
241
|
+
if (!checked.valid) throw new Error(`coverage ledger is invalid: ${checked.failures.join('; ')}`);
|
|
242
|
+
const coverageGeneration = coverage.kind === 'ruvnet-brain-release-coverage'
|
|
243
|
+
? coverage.releaseCoverageGeneration : coverage.coverageGeneration;
|
|
244
|
+
if (!HEX64.test(String(coverageGeneration || ''))) throw new Error('coverage has no exact generation identity');
|
|
245
|
+
const observedBaseline = baseline?.kind === 'ruvnet-brain-observed-failed-public-baseline';
|
|
246
|
+
const receiptValid = observedBaseline
|
|
247
|
+
? baseline?.integrity === 'DEGRADED' && baseline?.historicalCorpusReceipt === false && baseline?.candidateVerificationEligible === false
|
|
248
|
+
&& HEX64.test(String(baseline?.observationReceiptSha256 || '')) && HEX64.test(String(baseline?.discrepancyDigest || ''))
|
|
249
|
+
&& Array.isArray(baseline?.ledgerDiscrepancies) && Array.isArray(baseline?.provenanceGaps)
|
|
250
|
+
: baseline?.kind === 'ruvnet-brain-verified-public-baseline'
|
|
251
|
+
&& HEX64.test(String(baseline?.verificationReceiptSha256 || ''));
|
|
252
|
+
if (baseline?.schemaVersion !== 1 || !receiptValid
|
|
253
|
+
|| !HEX64.test(String(baseline.archiveSha256 || '')) || !Number.isSafeInteger(baseline.archiveBytes) || baseline.archiveBytes < 1
|
|
254
|
+
|| !HEX64.test(String(baseline.archiveManifestSha256 || ''))
|
|
255
|
+
|| !Array.isArray(baseline.stores) || baseline.stores.length === 0 || baseline.storeCount !== baseline.stores.length
|
|
256
|
+
|| new Set(baseline.stores.map((store) => String(store).toLowerCase())).size !== baseline.stores.length) {
|
|
257
|
+
throw new Error('verified failed-public baseline identity is malformed');
|
|
258
|
+
}
|
|
259
|
+
if (!candidate || (coverage.kind === 'ruvnet-brain-release-coverage'
|
|
260
|
+
&& candidate.sourceSha !== coverage.releaseIdentity?.sourceSnapshot)) {
|
|
261
|
+
throw new Error('candidate source identity differs from release coverage');
|
|
262
|
+
}
|
|
263
|
+
if (!HEX40.test(String(candidate?.sourceSha || '')) || !HEX64.test(String(candidate?.packageSha256 || ''))
|
|
264
|
+
|| !HEX64.test(String(candidate?.archiveSha256 || ''))
|
|
265
|
+
|| !HEX64.test(String(candidate?.coverageSha256 || '')) || !HEX64.test(String(candidate?.publicLedgerSha256 || ''))
|
|
266
|
+
|| !Number.isSafeInteger(candidate?.publicLedgerBytes) || candidate.publicLedgerBytes < 1
|
|
267
|
+
|| !Number.isSafeInteger(candidate?.publicStoreCount) || candidate.publicStoreCount < 1
|
|
268
|
+
|| !HEX64.test(String(candidate?.publicInventoryPartitionSha256 || ''))) {
|
|
269
|
+
throw new Error('candidate public artifact identity is malformed');
|
|
270
|
+
}
|
|
271
|
+
if (coverage.kind === 'ruvnet-brain-release-coverage') {
|
|
272
|
+
const baselineReceiptSha256 = observedBaseline ? baseline.observationReceiptSha256 : baseline.verificationReceiptSha256;
|
|
273
|
+
if (baseline.tag !== coverage.corpusSeed?.tag || baseline.archiveSha256 !== coverage.corpusSeed?.archiveSha256
|
|
274
|
+
|| baseline.archiveBytes !== coverage.corpusSeed?.archiveBytes || baselineReceiptSha256 !== coverage.corpusSeed?.receiptSha256) {
|
|
275
|
+
throw new Error('failed-public baseline differs from the release corpus seed identity');
|
|
276
|
+
}
|
|
277
|
+
if (candidate.publicLedgerSha256 !== coverage.generationLedger?.sha256
|
|
278
|
+
|| candidate.publicLedgerBytes !== coverage.generationLedger?.bytes
|
|
279
|
+
|| candidate.publicStoreCount !== coverage.generationLedger?.storeCount
|
|
280
|
+
|| candidate.publicInventoryPartitionSha256 !== coverage.publicInventoryPartitionSha256
|
|
281
|
+
|| !coverageIdentity || candidate.coverageSha256 !== coverageIdentity.sha256
|
|
282
|
+
|| !Number.isSafeInteger(coverageIdentity.bytes) || coverageIdentity.bytes < 1) {
|
|
283
|
+
throw new Error('candidate identity differs from exact release coverage evidence');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
validateRetrievalQueryEvidence(queryEvidence);
|
|
287
|
+
if (queryEvidence.sourceCommit === candidate.sourceSha) throw new Error('independent query source is not pre-candidate');
|
|
288
|
+
const eligible = coverage.rows.filter((row) => row.kind === 'repository' && row.disposition === 'eligible');
|
|
289
|
+
if (!eligible.length || eligible.some((row) => row.status !== 'CURRENT' || !storeOf(row))) {
|
|
290
|
+
throw new Error('eligible repository coverage is incomplete');
|
|
291
|
+
}
|
|
292
|
+
const duplicateStores = eligible.map(storeOf).filter((store, index, stores) => stores.indexOf(store) !== index);
|
|
293
|
+
if (duplicateStores.length) throw new Error(`eligible repository stores are duplicated: ${ordered(new Set(duplicateStores)).join(', ')}`);
|
|
294
|
+
const eligibleStores = ordered(eligible.map(storeOf));
|
|
295
|
+
if (queryEvidence.queryStoreSetSha256 !== setDigest(eligibleStores)
|
|
296
|
+
|| canonicalJson(ordered(Object.keys(queryEvidence.queries))) !== canonicalJson(eligibleStores)) {
|
|
297
|
+
throw new Error('independent query oracle does not cover the exact eligible store set');
|
|
298
|
+
}
|
|
299
|
+
const baselineStores = new Set(baseline.stores.map((name) => String(name).toLowerCase()));
|
|
300
|
+
const delta = eligible.filter((row) => !baselineStores.has(storeOf(row)));
|
|
301
|
+
const legacyPool = eligible.filter((row) => baselineStores.has(storeOf(row)));
|
|
302
|
+
if (!delta.length || !legacyPool.length) throw new Error('coverage does not establish both failed-seed delta and legacy cohorts');
|
|
303
|
+
const passages = new Map(eligible.map((row) => [storeOf(row), readPassages(assetsDir, storeOf(row))]));
|
|
304
|
+
const rankedLegacy = legacyPool.map((row) => ({ row, count: passages.get(storeOf(row)).length }))
|
|
305
|
+
.sort((a, b) => a.count - b.count || storeOf(a.row).localeCompare(storeOf(b.row)));
|
|
306
|
+
const strata = new Map();
|
|
307
|
+
rankedLegacy.forEach((entry, index) => {
|
|
308
|
+
const stratum = Math.min(3, Math.floor(index * 4 / rankedLegacy.length));
|
|
309
|
+
if (!strata.has(stratum)) strata.set(stratum, []);
|
|
310
|
+
strata.get(stratum).push(entry);
|
|
311
|
+
});
|
|
312
|
+
const sampleCount = Math.min(legacyPool.length, legacySampleSize ?? Math.max(10, Math.ceil(eligible.length * 0.1)));
|
|
313
|
+
if (sampleCount < strata.size) throw new Error(`legacy sample must cover all ${strata.size} passage-count strata`);
|
|
314
|
+
const selected = [];
|
|
315
|
+
for (const [stratum, entries] of strata) {
|
|
316
|
+
entries.sort((a, b) => digest(`${coverageGeneration}:${stratum}:${storeOf(a.row)}`)
|
|
317
|
+
.localeCompare(digest(`${coverageGeneration}:${stratum}:${storeOf(b.row)}`)));
|
|
318
|
+
selected.push({ ...entries.shift(), stratum });
|
|
319
|
+
}
|
|
320
|
+
while (selected.length < sampleCount) {
|
|
321
|
+
let advanced = false;
|
|
322
|
+
for (const [stratum, entries] of strata) if (entries.length && selected.length < sampleCount) {
|
|
323
|
+
selected.push({ ...entries.shift(), stratum }); advanced = true;
|
|
324
|
+
}
|
|
325
|
+
if (!advanced) break;
|
|
326
|
+
}
|
|
327
|
+
const legacy = selected.map(({ row, stratum, count }) => ({ row, stratum, passageCount: count }));
|
|
328
|
+
const cases = [...delta.map((row) => ({ row, cohort: 'delta' })),
|
|
329
|
+
...legacy.map(({ row, stratum, passageCount }) => ({ row, cohort: 'legacy', stratum, passageCount }))]
|
|
330
|
+
.map(({ row, cohort, stratum = null, passageCount }) => {
|
|
331
|
+
const store = storeOf(row);
|
|
332
|
+
const observedPassageCount = passageCount ?? passages.get(store).length;
|
|
333
|
+
const evidence = queryEvidence.queries[store];
|
|
334
|
+
const matches = passages.get(store).filter((row) => row.path === evidence?.expected?.path
|
|
335
|
+
&& digest(row) === evidence.expected.passageSha256);
|
|
336
|
+
if (!evidence || matches.length !== 1) {
|
|
337
|
+
throw new Error(`${store} has no sealed independent query evidence`);
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
id: `${cohort}:${store}`,
|
|
341
|
+
cohort,
|
|
342
|
+
stratum,
|
|
343
|
+
passageCount: observedPassageCount,
|
|
344
|
+
query: evidence.query.trim(),
|
|
345
|
+
oracleRecordSha256: evidence.recordSha256,
|
|
346
|
+
expected: { repo: store, ...evidence.expected },
|
|
347
|
+
source: { key: row.key, upstreamSha: row.upstream?.sha || null, artifactSha256: row.artifact?.rvfSha256 || null,
|
|
348
|
+
queryEvidenceReceiptSha256: queryEvidence.receiptSha256 },
|
|
349
|
+
};
|
|
350
|
+
}).sort((a, b) => a.id.localeCompare(b.id));
|
|
351
|
+
const payload = {
|
|
352
|
+
schemaVersion: 2,
|
|
353
|
+
kind: 'ruvnet-brain-retrieval-canary-plan',
|
|
354
|
+
coverage: { sha256: coverageIdentity.sha256, bytes: coverageIdentity.bytes,
|
|
355
|
+
releaseCoverageGeneration: coverageGeneration },
|
|
356
|
+
baseline: { kind: baseline.kind, tag: baseline.tag, archiveSha256: baseline.archiveSha256, archiveBytes: baseline.archiveBytes,
|
|
357
|
+
archiveManifestSha256: baseline.archiveManifestSha256,
|
|
358
|
+
...(observedBaseline ? { integrity: baseline.integrity, historicalCorpusReceipt: false,
|
|
359
|
+
candidateVerificationEligible: false, observationReceiptSha256: baseline.observationReceiptSha256,
|
|
360
|
+
discrepancyDigest: baseline.discrepancyDigest } : { verificationReceiptSha256: baseline.verificationReceiptSha256 }),
|
|
361
|
+
stores: ordered(baseline.stores.map((store) => String(store).toLowerCase())),
|
|
362
|
+
storeCount: baseline.storeCount,
|
|
363
|
+
storeSetSha256: digest(ordered(baseline.stores.map((store) => String(store).toLowerCase()))) },
|
|
364
|
+
candidate: structuredClone(candidate),
|
|
365
|
+
denominator: {
|
|
366
|
+
eligibleStores,
|
|
367
|
+
eligibleStoreSetSha256: setDigest(eligibleStores),
|
|
368
|
+
deltaStores: ordered(delta.map(storeOf)),
|
|
369
|
+
deltaStoreSetSha256: setDigest(delta.map(storeOf)),
|
|
370
|
+
legacyPopulationStores: ordered(legacyPool.map(storeOf)),
|
|
371
|
+
legacyPopulationStoreSetSha256: setDigest(legacyPool.map(storeOf)),
|
|
372
|
+
legacySelectedStores: ordered(legacy.map(({ row }) => storeOf(row))),
|
|
373
|
+
legacySelectedStoreSetSha256: setDigest(legacy.map(({ row }) => storeOf(row))),
|
|
374
|
+
},
|
|
375
|
+
oracle: { receiptSha256: queryEvidence.receiptSha256,
|
|
376
|
+
queryStoreSetSha256: queryEvidence.queryStoreSetSha256,
|
|
377
|
+
sourceCommit: queryEvidence.sourceCommit, sourceBlobSha256: queryEvidence.sourceBlobSha256,
|
|
378
|
+
evidence: structuredClone(queryEvidence) },
|
|
379
|
+
cohorts: { delta: delta.length, legacy: legacy.length,
|
|
380
|
+
legacyStrata: [...strata.keys()].sort().map((stratum) => ({ stratum,
|
|
381
|
+
population: rankedLegacy.filter((_entry, index) => Math.min(3, Math.floor(index * 4 / rankedLegacy.length)) === stratum).length,
|
|
382
|
+
selected: legacy.filter((entry) => entry.stratum === stratum).length })) },
|
|
383
|
+
k: 10,
|
|
384
|
+
cases,
|
|
385
|
+
};
|
|
386
|
+
const plan = validateRetrievalCanaryPlan({ ...payload, planSha256: digest(payload) });
|
|
387
|
+
return validatePlanAgainstCoverage(plan, coverage, { allowObservedBaseline: observedBaseline });
|
|
388
|
+
}
|
|
389
|
+
function resultRows(value) {
|
|
390
|
+
if (Array.isArray(value)) return value;
|
|
391
|
+
if (Array.isArray(value?.results)) return value.results;
|
|
392
|
+
throw new Error('search result has no results array');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function receiptPayload(receipt) {
|
|
396
|
+
const { receiptSha256: _receiptSha256, ...payload } = receipt;
|
|
397
|
+
return payload;
|
|
398
|
+
}
|
|
399
|
+
export function validateRetrievalCanaryReceipt(receipt, { plan, requireAcceptance = true } = {}) {
|
|
400
|
+
validateRetrievalCanaryPlan(plan);
|
|
401
|
+
if (receipt?.schemaVersion !== 1 || receipt?.kind !== 'ruvnet-brain-retrieval-canary-receipt'
|
|
402
|
+
|| !HEX40.test(String(receipt.sourceSha || '')) || !HEX64.test(String(receipt.artifactSha256 || ''))
|
|
403
|
+
|| !HEX64.test(String(receipt.candidateArchiveSha256 || ''))
|
|
404
|
+
|| !HEX64.test(String(receipt.coverageGeneration || '')) || !HEX64.test(String(receipt.planSha256 || ''))
|
|
405
|
+
|| !Array.isArray(receipt.cases) || !receipt.cases.length) throw new Error('retrieval canary receipt is malformed');
|
|
406
|
+
if (digest(receiptPayload(receipt)) !== receipt.receiptSha256) throw new Error('retrieval canary receipt digest mismatch');
|
|
407
|
+
if (receipt.sourceSha !== plan.candidate.sourceSha
|
|
408
|
+
|| receipt.candidateArchiveSha256 !== plan.candidate.archiveSha256
|
|
409
|
+
|| receipt.artifactSha256 !== plan.candidate.packageSha256
|
|
410
|
+
|| receipt.coverageGeneration !== plan.coverage.releaseCoverageGeneration
|
|
411
|
+
|| receipt.planSha256 !== plan.planSha256 || receipt.k !== 10 || plan.k !== 10
|
|
412
|
+
|| canonicalJson(receipt.cases.map(({ id, cohort }) => ({ id, cohort })))
|
|
413
|
+
!== canonicalJson(plan.cases.map(({ id, cohort }) => ({ id, cohort })))) {
|
|
414
|
+
throw new Error('retrieval canary receipt denominator differs from the sealed plan');
|
|
415
|
+
}
|
|
416
|
+
if (receipt.cases.some((row) => !['COMPLETED', 'UNKNOWN', 'SKIPPED'].includes(row.status)
|
|
417
|
+
|| (row.retrievalHit === true && (row.status !== 'COMPLETED' || !Number.isInteger(row.rank)
|
|
418
|
+
|| row.rank < 1 || row.rank > 10))
|
|
419
|
+
|| (row.retrievalHit !== true && (row.rank !== null || row.citationResolved === true)))) {
|
|
420
|
+
throw new Error('retrieval canary case state is invalid');
|
|
421
|
+
}
|
|
422
|
+
for (const row of receipt.cases) {
|
|
423
|
+
const expected = plan.cases.find(({ id }) => id === row.id)?.expected;
|
|
424
|
+
const ranked = row.retrievalHit ? row.citations?.[row.rank - 1] : null;
|
|
425
|
+
if (row.retrievalHit && (String(ranked?.repo || '').toLowerCase() !== expected.repo
|
|
426
|
+
|| ranked?.path !== expected.path
|
|
427
|
+
|| (row.citationResolved === true && (row.citationEvidence?.passageSha256 !== expected.passageSha256
|
|
428
|
+
|| !HEX64.test(String(row.citationEvidence?.passageFileSha256 || '')))))) {
|
|
429
|
+
throw new Error(`retrieval canary ${row.id} hit or citation evidence differs from the sealed plan`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const delta = receipt.cases.filter(({ cohort }) => cohort === 'delta');
|
|
433
|
+
const hits = receipt.cases.filter(({ retrievalHit }) => retrievalHit === true).length;
|
|
434
|
+
const unknown = receipt.cases.filter(({ status }) => status === 'UNKNOWN').length;
|
|
435
|
+
const skipped = receipt.cases.filter(({ status }) => status === 'SKIPPED').length;
|
|
436
|
+
const metrics = {
|
|
437
|
+
total: receipt.cases.length,
|
|
438
|
+
hits,
|
|
439
|
+
deltaTotal: delta.length,
|
|
440
|
+
deltaHits: delta.filter(({ retrievalHit }) => retrievalHit === true).length,
|
|
441
|
+
deltaCitations: delta.filter(({ retrievalHit, citationResolved }) => retrievalHit === true && citationResolved === true).length,
|
|
442
|
+
recallAt10: hits / receipt.cases.length,
|
|
443
|
+
deltaCitationRate: delta.length ? delta.filter(({ retrievalHit, citationResolved }) => retrievalHit === true && citationResolved === true).length / delta.length : 0,
|
|
444
|
+
unknown,
|
|
445
|
+
skipped,
|
|
446
|
+
};
|
|
447
|
+
if (canonicalJson(metrics) !== canonicalJson(receipt.metrics)) throw new Error('retrieval canary metrics were not derived from case evidence');
|
|
448
|
+
if (requireAcceptance && (metrics.deltaCitationRate !== 1 || metrics.recallAt10 < 0.98 || unknown || skipped)) {
|
|
449
|
+
throw new Error('retrieval canary acceptance failed');
|
|
450
|
+
}
|
|
451
|
+
return receipt;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export async function runRetrievalCanaries({ plan, sourceSha, artifactSha256, candidateArchiveSha256,
|
|
455
|
+
search, citationResolver, concurrency = 3 } = {}) {
|
|
456
|
+
validateRetrievalCanaryPlan(plan);
|
|
457
|
+
if (!HEX40.test(String(sourceSha || '')) || !HEX64.test(String(artifactSha256 || ''))
|
|
458
|
+
|| !HEX64.test(String(candidateArchiveSha256 || '')) || sourceSha !== plan.candidate.sourceSha
|
|
459
|
+
|| artifactSha256 !== plan.candidate.packageSha256
|
|
460
|
+
|| candidateArchiveSha256 !== plan.candidate.archiveSha256
|
|
461
|
+
|| typeof search !== 'function' || typeof citationResolver !== 'function') {
|
|
462
|
+
throw new Error('retrieval canary execution identity is invalid');
|
|
463
|
+
}
|
|
464
|
+
const cases = new Array(plan.cases.length);
|
|
465
|
+
let next = 0;
|
|
466
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, concurrency), plan.cases.length) }, async () => {
|
|
467
|
+
for (let index = next++; index < plan.cases.length; index = next++) {
|
|
468
|
+
const canary = plan.cases[index];
|
|
469
|
+
try {
|
|
470
|
+
const rows = resultRows(await search({ query: canary.query, k: 10 }));
|
|
471
|
+
const top = rows.slice(0, 10);
|
|
472
|
+
const rank = top.findIndex((row) => String(row?.repo || '').toLowerCase() === canary.expected.repo
|
|
473
|
+
&& row?.path === canary.expected.path);
|
|
474
|
+
const matched = rank >= 0 ? top[rank] : null;
|
|
475
|
+
const resolved = matched ? await citationResolver(matched, canary.expected) : { resolved: false };
|
|
476
|
+
cases[index] = { id: canary.id, cohort: canary.cohort, status: 'COMPLETED', retrievalHit: rank >= 0,
|
|
477
|
+
citationResolved: resolved?.resolved === true, citationEvidence: resolved?.evidence || null,
|
|
478
|
+
rank: rank >= 0 ? rank + 1 : null, citations: top.map(({ repo, path: hitPath }) => ({ repo, path: hitPath })) };
|
|
479
|
+
} catch (error) {
|
|
480
|
+
cases[index] = { id: canary.id, cohort: canary.cohort, status: 'UNKNOWN', retrievalHit: false,
|
|
481
|
+
citationResolved: false, citationEvidence: null, rank: null, citations: [], error: error.message };
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}));
|
|
485
|
+
const delta = cases.filter(({ cohort }) => cohort === 'delta');
|
|
486
|
+
const hits = cases.filter(({ retrievalHit }) => retrievalHit).length;
|
|
487
|
+
const metrics = { total: cases.length, hits, deltaTotal: delta.length, deltaHits: delta.filter(({ retrievalHit }) => retrievalHit).length,
|
|
488
|
+
deltaCitations: delta.filter(({ retrievalHit, citationResolved }) => retrievalHit && citationResolved).length,
|
|
489
|
+
recallAt10: hits / cases.length, deltaCitationRate: delta.length ? delta.filter(({ retrievalHit, citationResolved }) => retrievalHit && citationResolved).length / delta.length : 0,
|
|
490
|
+
unknown: cases.filter(({ status }) => status === 'UNKNOWN').length,
|
|
491
|
+
skipped: cases.filter(({ status }) => status === 'SKIPPED').length };
|
|
492
|
+
const payload = { schemaVersion: 1, kind: 'ruvnet-brain-retrieval-canary-receipt', sourceSha, artifactSha256,
|
|
493
|
+
candidateArchiveSha256,
|
|
494
|
+
coverageGeneration: plan.coverage.releaseCoverageGeneration, planSha256: plan.planSha256, k: 10, cases, metrics };
|
|
495
|
+
return validateRetrievalCanaryReceipt({ ...payload, receiptSha256: digest(payload) }, { plan, requireAcceptance: false });
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function arg(argv, name) {
|
|
499
|
+
const index = argv.indexOf(name);
|
|
500
|
+
return index >= 0 ? argv[index + 1] : null;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export function buildPlanFromFiles({ coverageFile, baselineFile, candidateFile, oracleFile, assetsDir,
|
|
504
|
+
outFile, cwd = process.cwd() }) {
|
|
505
|
+
const coveragePath = regular(coverageFile, 'coverage');
|
|
506
|
+
const coverageBytes = fs.readFileSync(coveragePath);
|
|
507
|
+
const coverage = JSON.parse(coverageBytes);
|
|
508
|
+
const baseline = JSON.parse(fs.readFileSync(regular(baselineFile, 'baseline'), 'utf8'));
|
|
509
|
+
const candidate = JSON.parse(fs.readFileSync(regular(candidateFile, 'candidate identity'), 'utf8'));
|
|
510
|
+
const queryEvidence = JSON.parse(fs.readFileSync(regular(oracleFile, 'query oracle'), 'utf8'));
|
|
511
|
+
verifyQueryOracleSource(queryEvidence, candidate.sourceSha, { cwd });
|
|
512
|
+
const plan = buildRetrievalCanaryPlan({ coverage, baseline, candidate, queryEvidence,
|
|
513
|
+
coverageIdentity: { sha256: sha256Buffer(coverageBytes), bytes: coverageBytes.length },
|
|
514
|
+
assetsDir: regular(path.join(path.resolve(assetsDir), 'PRIVATE-STORES.json'), 'assets private fence')
|
|
515
|
+
&& path.resolve(assetsDir) });
|
|
516
|
+
const output = path.resolve(outFile || 'release-evidence/retrieval-canary-plan.json');
|
|
517
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
518
|
+
fs.writeFileSync(output, `${JSON.stringify(plan, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
519
|
+
return plan;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
523
|
+
try {
|
|
524
|
+
const argv = process.argv.slice(2);
|
|
525
|
+
const plan = buildPlanFromFiles({ coverageFile: arg(argv, '--coverage'), baselineFile: arg(argv, '--baseline'),
|
|
526
|
+
candidateFile: arg(argv, '--candidate'), oracleFile: arg(argv, '--oracle'), assetsDir: arg(argv, '--assets'),
|
|
527
|
+
outFile: arg(argv, '--out'), cwd: arg(argv, '--repo') || process.cwd() });
|
|
528
|
+
console.log(JSON.stringify({ ok: true, planSha256: plan.planSha256, cases: plan.cases.length }));
|
|
529
|
+
} catch (error) {
|
|
530
|
+
console.error(`[retrieval-canary] ${error.message}`);
|
|
531
|
+
process.exitCode = 1;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
canon,
|
|
54
54
|
} from '@metaharness/flywheel';
|
|
55
55
|
import { effectivePrices, loadLabelledRows, OUTCOMES } from './metaharness-router.mjs';
|
|
56
|
+
import { assertEvolutionAllowed } from './metaharness-gate.mjs';
|
|
56
57
|
import { loadCatalog, applyProfile, loadProfile } from './model-router-engine.mjs';
|
|
57
58
|
|
|
58
59
|
// ─── HARD CAPS — the self-DDoS fence. Clamped, never raised by flags. ─────────────────────────────
|
|
@@ -398,6 +399,10 @@ export async function runRoutingFlywheel(opts = {}) {
|
|
|
398
399
|
let proposer;
|
|
399
400
|
let dataSource;
|
|
400
401
|
if (mode === 'live') {
|
|
402
|
+
// A live proposer is the only path that can spend metered credits. Require an external,
|
|
403
|
+
// measured score/OIA/drift receipt and its explicit spend opt-in before constructing it.
|
|
404
|
+
// Synthetic replay remains available without this gate and never makes a paid call.
|
|
405
|
+
assertEvolutionAllowed(opts.gateReceipt);
|
|
401
406
|
if (!opts.apiKey) throw new Error('--live requires OPENROUTER_API_KEY');
|
|
402
407
|
const model = opts.proposerModel ?? LIVE_PROPOSER_MODEL;
|
|
403
408
|
const entry = catalog.find((c) => c.id === model);
|
|
@@ -440,9 +445,14 @@ export async function runRoutingFlywheel(opts = {}) {
|
|
|
440
445
|
const fp = gateFingerprint(meetsPromotionRule);
|
|
441
446
|
const verdict = verifyReplayBundle(result.replayBundle, { pinnedGateFingerprint: fp, promotionRule: meetsPromotionRule });
|
|
442
447
|
const promoted = result.promotions.filter((c) => c.verdict === 'PROMOTED');
|
|
448
|
+
// If a caller supplied the measured MetaHarness preflight, its promotion decision is an
|
|
449
|
+
// additional fail-closed wall. Live evolution may run only after explicit spend consent, but
|
|
450
|
+
// it never self-promotes; synthetic replay can be promoted only when the caller's receipt says
|
|
451
|
+
// so. The historical no-receipt path remains compatible for the $0 unit harness.
|
|
452
|
+
const promotionGate = opts.gateReceipt ? opts.gateReceipt.promotion?.allowed === true : true;
|
|
443
453
|
|
|
444
454
|
let candidatePath = null;
|
|
445
|
-
if (promoted.length) {
|
|
455
|
+
if (promoted.length && promotionGate) {
|
|
446
456
|
const provenance = {
|
|
447
457
|
ts: runIso,
|
|
448
458
|
mode,
|
|
@@ -483,6 +493,7 @@ export async function runRoutingFlywheel(opts = {}) {
|
|
|
483
493
|
lift_curve: result.replayBundle.lift_curve,
|
|
484
494
|
milestone_reached: result.milestoneReached,
|
|
485
495
|
candidate_path: candidatePath,
|
|
496
|
+
promotion_gate: opts.gateReceipt ? { allowed: promotionGate, reason: opts.gateReceipt.promotion?.reason || null } : null,
|
|
486
497
|
signer_public_key: signer.publicKey(),
|
|
487
498
|
};
|
|
488
499
|
appendReceipt(opts.receiptsFile ?? RECEIPTS_PATH_DEFAULT, receipt);
|
|
@@ -119,3 +119,53 @@ export function verifyRvfGenerations(dir, {
|
|
|
119
119
|
}
|
|
120
120
|
return { manifest, failures };
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
// Release-time closure check for the exact public roots selected for a bundle. Unlike the
|
|
124
|
+
// source-only verifier above, this rejects every ambiguity in the byte-bearing asset directory.
|
|
125
|
+
export function validateSelectedRvfGenerations(dir, {
|
|
126
|
+
selectedStores = canonicalRvfStores(dir),
|
|
127
|
+
privateStores = [],
|
|
128
|
+
excludedStores = [],
|
|
129
|
+
version,
|
|
130
|
+
releaseTag,
|
|
131
|
+
} = {}) {
|
|
132
|
+
const manifest = readRvfGenerations(dir);
|
|
133
|
+
const failures = [];
|
|
134
|
+
const selected = [...new Set(selectedStores)].sort();
|
|
135
|
+
const selectedLower = new Map(selected.map((name) => [name.toLowerCase(), name]));
|
|
136
|
+
const privateLower = new Set(privateStores.map((name) => String(name).toLowerCase()));
|
|
137
|
+
const excludedLower = new Set(excludedStores.map((name) => String(name).toLowerCase()));
|
|
138
|
+
if (version !== undefined && manifest.brainVersion !== version) failures.push(`brainVersion=${manifest.brainVersion}, expected ${version}`);
|
|
139
|
+
if (releaseTag !== undefined && manifest.releaseTag !== releaseTag) failures.push(`releaseTag=${manifest.releaseTag}, expected ${releaseTag}`);
|
|
140
|
+
for (const name of selected) if (privateLower.has(name.toLowerCase())) failures.push(`${name}: private store selected`);
|
|
141
|
+
for (const name of selected) if (excludedLower.has(name.toLowerCase())) failures.push(`${name}: excluded store selected`);
|
|
142
|
+
for (const [store, row] of Object.entries(manifest.stores || {})) {
|
|
143
|
+
const canonical = selectedLower.get(store.toLowerCase());
|
|
144
|
+
if (!canonical) {
|
|
145
|
+
if (!privateLower.has(store.toLowerCase()) && !excludedLower.has(store.toLowerCase())) {
|
|
146
|
+
failures.push(`${store}: extra generation record`);
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (canonical !== store) failures.push(`${store}: alias differs from selected store ${canonical}`);
|
|
151
|
+
const expectedFile = `${canonical}.big.rvf`;
|
|
152
|
+
if (row?.file !== expectedFile) failures.push(`${store}: file=${row?.file}, expected ${expectedFile}`);
|
|
153
|
+
const file = path.join(dir, expectedFile);
|
|
154
|
+
if (!fs.existsSync(file)) failures.push(`${store}: missing ${expectedFile}`);
|
|
155
|
+
else {
|
|
156
|
+
const stat = fs.statSync(file);
|
|
157
|
+
if (row?.bytes !== stat.size) failures.push(`${store}: bytes=${row?.bytes}, actual ${stat.size}`);
|
|
158
|
+
const digest = sha256File(file);
|
|
159
|
+
if (row?.sha256 !== digest) failures.push(`${store}: sha256=${digest}, recorded ${row?.sha256}`);
|
|
160
|
+
}
|
|
161
|
+
if (typeof row?.model !== 'string' || !row.model.trim()) failures.push(`${store}: invalid model`);
|
|
162
|
+
if (!Number.isInteger(row?.dimensions) || row.dimensions <= 0) failures.push(`${store}: invalid dimensions`);
|
|
163
|
+
if (row?.sourceCommit !== null && (typeof row?.sourceCommit !== 'string' || !/^[a-f0-9]{7,64}$/i.test(row.sourceCommit))) failures.push(`${store}: invalid sourceCommit`);
|
|
164
|
+
if (typeof row?.builtUtc !== 'string' || !Number.isFinite(Date.parse(row.builtUtc))) failures.push(`${store}: invalid builtUtc`);
|
|
165
|
+
}
|
|
166
|
+
for (const name of selected) if (!manifest.stores?.[name]) failures.push(`${name}: no exact generation record`);
|
|
167
|
+
const publicRows = Object.keys(manifest.stores || {}).filter((name) => !privateLower.has(name.toLowerCase())
|
|
168
|
+
&& !excludedLower.has(name.toLowerCase()));
|
|
169
|
+
if (publicRows.length !== selected.length) failures.push(`store count=${publicRows.length}, selected ${selected.length}`);
|
|
170
|
+
return { manifest, selectedStores: selected, excludedStores: [...excludedLower].sort(), failures };
|
|
171
|
+
}
|