ruvnet-brain 4.0.90-dev → 4.2.2-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 +26 -3
- package/bin/install.mjs +142 -20
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/scripts/decision-outcomes.mjs +0 -0
- package/scripts/brain-score.mjs +17 -8
- package/scripts/build-bundle.mjs +13 -3
- package/scripts/card-from-source.mjs +114 -0
- package/scripts/corpus-candidate.mjs +294 -0
- package/scripts/corpus-reconcile.mjs +273 -0
- package/scripts/corpus-seed-publish.mjs +110 -0
- package/scripts/ingest-new-repos.mjs +122 -0
- package/scripts/nightly-wrapper.sh +43 -8
- package/scripts/rebuild-gists-from-receipts.mjs +246 -0
- package/scripts/release-transaction.mjs +30 -2
- package/scripts/release.mjs +147 -0
- package/scripts/rvf-generation.mjs +44 -0
package/scripts/release.mjs
CHANGED
|
@@ -37,6 +37,7 @@ import { verifyPayload } from './release-payload.mjs';
|
|
|
37
37
|
|
|
38
38
|
const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
39
39
|
const PUBLISH = process.argv.includes('--publish');
|
|
40
|
+
const CORPUS_SEED = process.argv.includes('--corpus-seed');
|
|
40
41
|
let protectedCandidate = null;
|
|
41
42
|
let sealedPackageArtifact = null;
|
|
42
43
|
let publicationReceiptPath = null;
|
|
@@ -56,6 +57,147 @@ function runOrDie(label, cmd, args, opts = {}) {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
const cliArg = (argv, name) => {
|
|
61
|
+
const index = argv.indexOf(name);
|
|
62
|
+
return index >= 0 ? argv[index + 1] : undefined;
|
|
63
|
+
};
|
|
64
|
+
const isHex = (value, length) => new RegExp(`^[a-f0-9]{${length}}$`).test(String(value || ''));
|
|
65
|
+
const sha256File = (file) => {
|
|
66
|
+
const hash = crypto.createHash('sha256');
|
|
67
|
+
const fd = fs.openSync(file, 'r');
|
|
68
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
69
|
+
try {
|
|
70
|
+
let bytes;
|
|
71
|
+
while ((bytes = fs.readSync(fd, buffer, 0, buffer.length, null)) > 0) hash.update(buffer.subarray(0, bytes));
|
|
72
|
+
} finally {
|
|
73
|
+
fs.closeSync(fd);
|
|
74
|
+
}
|
|
75
|
+
return hash.digest('hex');
|
|
76
|
+
};
|
|
77
|
+
const exactFileIdentity = (value) => value && typeof value.file === 'string'
|
|
78
|
+
&& isHex(value.sha256, 64) && Number.isSafeInteger(value.bytes) && value.bytes >= 0;
|
|
79
|
+
|
|
80
|
+
function corpusFailure(message) {
|
|
81
|
+
throw new Error(`[corpus-seed] ${message}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function runProtectedCorpusSeed({
|
|
85
|
+
argv = process.argv.slice(2),
|
|
86
|
+
env = process.env,
|
|
87
|
+
root = ROOT,
|
|
88
|
+
run = (command, args, options) => spawnSync(command, args, { encoding: 'utf8', ...options }),
|
|
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');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const tag = cliArg(argv, '--corpus-tag');
|
|
96
|
+
const bundleFile = cliArg(argv, '--corpus-bundle');
|
|
97
|
+
const receiptFile = cliArg(argv, '--corpus-receipt');
|
|
98
|
+
const target = cliArg(argv, '--target');
|
|
99
|
+
const repo = cliArg(argv, '--repo') || env.GITHUB_REPOSITORY;
|
|
100
|
+
const digestMatch = String(tag || '').match(/^corpus-sha256-([a-f0-9]{64})$/);
|
|
101
|
+
if (!digestMatch) corpusFailure('corpus tag must be corpus-sha256- followed by 64 lowercase hex characters');
|
|
102
|
+
if (repo !== env.GITHUB_REPOSITORY || repo !== 'stuinfla/ruvnet-brain') corpusFailure('repository does not match the protected workflow');
|
|
103
|
+
|
|
104
|
+
for (const [label, file] of [['bundle', bundleFile], ['receipt', receiptFile]]) {
|
|
105
|
+
if (!file || !path.isAbsolute(file)) corpusFailure(`${label} must be an absolute regular file`);
|
|
106
|
+
try {
|
|
107
|
+
const stat = fs.lstatSync(file);
|
|
108
|
+
if (!stat.isFile() || stat.isSymbolicLink()) corpusFailure(`${label} must be an absolute regular file`);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
if (String(error.message).startsWith('[corpus-seed]')) throw error;
|
|
111
|
+
corpusFailure(`${label} must be an absolute regular file (${error.message})`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const headResult = run('git', ['rev-parse', 'HEAD'], {
|
|
116
|
+
cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
|
|
117
|
+
});
|
|
118
|
+
if (headResult.error || headResult.status !== 0) corpusFailure('cannot resolve release HEAD');
|
|
119
|
+
const head = String(headResult.stdout || '').trim();
|
|
120
|
+
|
|
121
|
+
let receipt;
|
|
122
|
+
try {
|
|
123
|
+
receipt = JSON.parse(fs.readFileSync(receiptFile, 'utf8'));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
corpusFailure(`corpus receipt is unreadable/corrupt (${error.message})`);
|
|
126
|
+
}
|
|
127
|
+
if (!isHex(target, 40) || target !== head || target !== env.GITHUB_SHA || target !== receipt.builderSourceSha) {
|
|
128
|
+
corpusFailure('target must exactly equal HEAD, GITHUB_SHA, and the corpus receipt builderSourceSha');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const boundaryIdentities = [receipt.privateFence, receipt.eligibilityPolicy, receipt.generationLedger];
|
|
132
|
+
const storeBindingsValid = Number.isSafeInteger(receipt.storeCount) && receipt.storeCount > 0
|
|
133
|
+
&& Array.isArray(receipt.stores) && receipt.stores.length === receipt.storeCount
|
|
134
|
+
&& receipt.stores.every((store) => typeof store?.name === 'string' && store.name.length > 0
|
|
135
|
+
&& /^[a-f0-9]{7,64}$/.test(String(store.sourceCommit || ''))
|
|
136
|
+
&& typeof store.builtUtc === 'string' && Number.isFinite(Date.parse(store.builtUtc))
|
|
137
|
+
&& typeof store.model === 'string' && store.model.length > 0
|
|
138
|
+
&& Number.isSafeInteger(store.dimensions) && store.dimensions > 0
|
|
139
|
+
&& Array.isArray(store.files) && store.files.length > 0 && store.files.every(exactFileIdentity));
|
|
140
|
+
const emptyFailureArrays = ['duplicateRvfDigests', 'unreceiptedRvfFiles', 'missingSidecars']
|
|
141
|
+
.every((key) => Array.isArray(receipt[key]) && receipt[key].length === 0);
|
|
142
|
+
const privateExclusionsValid = Array.isArray(receipt.excludedPrivateStores)
|
|
143
|
+
&& receipt.excludedPrivateStores.every((name) => typeof name === 'string' && name.length > 0);
|
|
144
|
+
const generatorFile = path.join(root, 'scripts/corpus-candidate.mjs');
|
|
145
|
+
const generatorValid = fs.existsSync(generatorFile)
|
|
146
|
+
&& receipt.generator?.corpusCandidateSha256 === sha256File(generatorFile);
|
|
147
|
+
if (receipt.schemaVersion !== 1 || receipt.kind !== 'ruvnet-brain-corpus-candidate'
|
|
148
|
+
|| !receipt.createdAt || !receipt.coverageGeneration || !storeBindingsValid || !emptyFailureArrays
|
|
149
|
+
|| !privateExclusionsValid || !boundaryIdentities.every(exactFileIdentity) || !exactFileIdentity(receipt.archive)
|
|
150
|
+
|| !generatorValid
|
|
151
|
+
|| receipt.archive.file !== path.basename(bundleFile)) {
|
|
152
|
+
corpusFailure('corpus receipt bindings are incomplete or invalid');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const archiveSha256 = sha256File(bundleFile);
|
|
156
|
+
if (archiveSha256 !== receipt.archive.sha256 || fs.statSync(bundleFile).size !== receipt.archive.bytes) {
|
|
157
|
+
corpusFailure('archive bytes do not match the corpus receipt');
|
|
158
|
+
}
|
|
159
|
+
if (digestMatch[1] !== archiveSha256) corpusFailure('corpus tag digest does not match the receipt and archive');
|
|
160
|
+
|
|
161
|
+
const viewArgs = ['release', 'view', tag, '--json', 'tagName', '--repo', repo];
|
|
162
|
+
const view = run('gh', viewArgs, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
163
|
+
if (!view.error && view.status === 0) corpusFailure(`release ${tag} already exists; refusing to overwrite immutable corpus seed`);
|
|
164
|
+
const viewError = String(view.error?.message || view.stderr || view.stdout || '');
|
|
165
|
+
if (!/(release not found|no release found)/i.test(viewError)) corpusFailure(`cannot prove ${tag} is absent (${viewError.trim() || `gh exited ${view.status}`})`);
|
|
166
|
+
|
|
167
|
+
const notes = [
|
|
168
|
+
'Content-addressed RuvNet Brain corpus seed.',
|
|
169
|
+
`Archive SHA-256: ${archiveSha256}`,
|
|
170
|
+
`Receipt SHA-256: ${sha256File(receiptFile)}`,
|
|
171
|
+
`Stores: ${receipt.storeCount}`,
|
|
172
|
+
`Coverage generation: ${receipt.coverageGeneration}`,
|
|
173
|
+
'This published prerelease is immutable and must never be replaced.',
|
|
174
|
+
].join('\n');
|
|
175
|
+
const createArgs = [
|
|
176
|
+
'release', 'create', tag,
|
|
177
|
+
'--prerelease', '--latest=false',
|
|
178
|
+
'--target', target,
|
|
179
|
+
'--repo', repo,
|
|
180
|
+
'--title', `Immutable corpus seed ${archiveSha256.slice(0, 16)}`,
|
|
181
|
+
'--notes', notes,
|
|
182
|
+
bundleFile, receiptFile,
|
|
183
|
+
];
|
|
184
|
+
const create = run('gh', createArgs, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
185
|
+
if (create.error || create.status !== 0) {
|
|
186
|
+
corpusFailure(`protected corpus publication failed (${String(create.error?.message || create.stderr || create.stdout || '').trim()})`);
|
|
187
|
+
}
|
|
188
|
+
return { tag, target, repository: repo, archiveSha256, receiptSha256: sha256File(receiptFile) };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (CORPUS_SEED) {
|
|
192
|
+
try {
|
|
193
|
+
const result = runProtectedCorpusSeed();
|
|
194
|
+
console.log(JSON.stringify({ ok: true, mode: 'corpus-seed', ...result }, null, 2));
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error(error.message);
|
|
197
|
+
process.exitCode = 1;
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
|
|
59
201
|
console.log(`\n${c.b('RuvNet Brain — release / definition-of-done')} ${c.dim('· ' + (PUBLISH ? 'PUBLISH' : 'check-only') + ' · shipping ' + V())}\n`);
|
|
60
202
|
|
|
61
203
|
// The local CLI remains useful as a read-only preflight, but publication authority lives only in
|
|
@@ -195,6 +337,8 @@ if (PUBLISH) {
|
|
|
195
337
|
bundleSignaturePath: path.join(payloadRoot, 'ruvnet-brain.zip.sig'),
|
|
196
338
|
bundleDigestPath: path.join(payloadRoot, 'ruvnet-brain.zip.sha256'),
|
|
197
339
|
packagePath: byRole.get('npm'),
|
|
340
|
+
corpusSeedPath: byRole.get('corpus-seed'),
|
|
341
|
+
generationLedgerPath: byRole.get('generation-ledger'),
|
|
198
342
|
};
|
|
199
343
|
for (const asset of Object.values(assets)) {
|
|
200
344
|
if (!fs.existsSync(asset)) {
|
|
@@ -224,6 +368,8 @@ if (PUBLISH) {
|
|
|
224
368
|
bundleSha256,
|
|
225
369
|
bundleSignatureSha256: crypto.createHash('sha256').update(fs.readFileSync(assets.bundleSignaturePath)).digest('hex'),
|
|
226
370
|
bundleDigestSha256: crypto.createHash('sha256').update(fs.readFileSync(assets.bundleDigestPath)).digest('hex'),
|
|
371
|
+
corpusSeedSha256: crypto.createHash('sha256').update(fs.readFileSync(assets.corpusSeedPath)).digest('hex'),
|
|
372
|
+
generationLedgerSha256: crypto.createHash('sha256').update(fs.readFileSync(assets.generationLedgerPath)).digest('hex'),
|
|
227
373
|
};
|
|
228
374
|
const privatePem = process.env.RUVNET_SIGNING_KEY;
|
|
229
375
|
if (!privatePem) throw new Error('RUVNET_SIGNING_KEY is required for signed transaction receipts');
|
|
@@ -254,3 +400,4 @@ if (PUBLISH) {
|
|
|
254
400
|
} else {
|
|
255
401
|
console.log(`\n${c.g(c.b('✓✓✓ PREFLIGHT PASS — NOT PUBLISHED'))} — the committed candidate passed every check-only gate.\n`);
|
|
256
402
|
}
|
|
403
|
+
}
|
|
@@ -119,3 +119,47 @@ 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
|
+
version,
|
|
129
|
+
releaseTag,
|
|
130
|
+
} = {}) {
|
|
131
|
+
const manifest = readRvfGenerations(dir);
|
|
132
|
+
const failures = [];
|
|
133
|
+
const selected = [...new Set(selectedStores)].sort();
|
|
134
|
+
const selectedLower = new Map(selected.map((name) => [name.toLowerCase(), name]));
|
|
135
|
+
const privateLower = new Set(privateStores.map((name) => String(name).toLowerCase()));
|
|
136
|
+
if (version !== undefined && manifest.brainVersion !== version) failures.push(`brainVersion=${manifest.brainVersion}, expected ${version}`);
|
|
137
|
+
if (releaseTag !== undefined && manifest.releaseTag !== releaseTag) failures.push(`releaseTag=${manifest.releaseTag}, expected ${releaseTag}`);
|
|
138
|
+
for (const name of selected) if (privateLower.has(name.toLowerCase())) failures.push(`${name}: private store selected`);
|
|
139
|
+
for (const [store, row] of Object.entries(manifest.stores || {})) {
|
|
140
|
+
const canonical = selectedLower.get(store.toLowerCase());
|
|
141
|
+
if (!canonical) {
|
|
142
|
+
if (!privateLower.has(store.toLowerCase())) failures.push(`${store}: extra generation record`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (canonical !== store) failures.push(`${store}: alias differs from selected store ${canonical}`);
|
|
146
|
+
const expectedFile = `${canonical}.big.rvf`;
|
|
147
|
+
if (row?.file !== expectedFile) failures.push(`${store}: file=${row?.file}, expected ${expectedFile}`);
|
|
148
|
+
const file = path.join(dir, expectedFile);
|
|
149
|
+
if (!fs.existsSync(file)) failures.push(`${store}: missing ${expectedFile}`);
|
|
150
|
+
else {
|
|
151
|
+
const stat = fs.statSync(file);
|
|
152
|
+
if (row?.bytes !== stat.size) failures.push(`${store}: bytes=${row?.bytes}, actual ${stat.size}`);
|
|
153
|
+
const digest = sha256File(file);
|
|
154
|
+
if (row?.sha256 !== digest) failures.push(`${store}: sha256=${digest}, recorded ${row?.sha256}`);
|
|
155
|
+
}
|
|
156
|
+
if (typeof row?.model !== 'string' || !row.model.trim()) failures.push(`${store}: invalid model`);
|
|
157
|
+
if (!Number.isInteger(row?.dimensions) || row.dimensions <= 0) failures.push(`${store}: invalid dimensions`);
|
|
158
|
+
if (row?.sourceCommit !== null && (typeof row?.sourceCommit !== 'string' || !/^[a-f0-9]{7,64}$/i.test(row.sourceCommit))) failures.push(`${store}: invalid sourceCommit`);
|
|
159
|
+
if (typeof row?.builtUtc !== 'string' || !Number.isFinite(Date.parse(row.builtUtc))) failures.push(`${store}: invalid builtUtc`);
|
|
160
|
+
}
|
|
161
|
+
for (const name of selected) if (!manifest.stores?.[name]) failures.push(`${name}: no exact generation record`);
|
|
162
|
+
const publicRows = Object.keys(manifest.stores || {}).filter((name) => !privateLower.has(name.toLowerCase()));
|
|
163
|
+
if (publicRows.length !== selected.length) failures.push(`store count=${publicRows.length}, selected ${selected.length}`);
|
|
164
|
+
return { manifest, selectedStores: selected, failures };
|
|
165
|
+
}
|