ruvnet-brain 4.3.1 → 4.3.3
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 +12 -13
- package/bin/install.mjs +10 -1
- package/console/app.js +4 -4
- package/kb/verify-citation.mjs +32 -5
- package/package.json +12 -9
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/mcp/managed-cli-interface.mjs +4 -2
- package/plugin/scripts/codex-hook-adapter.mjs +12 -7
- package/plugin/scripts/codex-hook-events.mjs +39 -0
- package/plugin/scripts/coverage-integrity.mjs +4 -4
- package/plugin/scripts/hook-shim.mjs +9 -7
- package/plugin/scripts/learn-capture.sh +20 -1
- package/plugin/scripts/learn-flush.mjs +7 -1
- package/plugin/scripts/lesson-gate.mjs +17 -2
- package/plugin/scripts/lesson-hooks.sh +17 -2
- package/plugin/scripts/session-start-core.mjs +47 -11
- package/scripts/brain-stamp-resolve.mjs +22 -0
- package/scripts/brain-stamp.mjs +5 -3
- package/scripts/build-bundle.mjs +41 -4
- package/scripts/ci/step-watchdog.mjs +86 -0
- package/scripts/convergence-manifest.mjs +66 -0
- package/scripts/distill-project.mjs +22 -4
- package/scripts/eval-brain.mjs +13 -3
- package/scripts/execution-policy.mjs +66 -0
- package/scripts/git-hooks/pre-push +16 -0
- package/scripts/health-repair.mjs +5 -1
- package/scripts/public-verification-aggregate.mjs +3 -1
- package/scripts/public-verification-inputs.mjs +5 -3
- package/scripts/qa-runner.mjs +71 -0
- package/scripts/qe/agentic-qe-4.3.mjs +195 -0
- package/scripts/qe/aggregate-4.3.mjs +42 -0
- package/scripts/record-lesson.mjs +28 -6
- package/scripts/release-projection.mjs +76 -32
- package/scripts/release.mjs +6 -11
- package/scripts/retrieval-canary.mjs +14 -6
- package/scripts/set-version.mjs +31 -0
- package/scripts/verify-channels.mjs +1 -1
|
@@ -108,14 +108,17 @@ export function validateRetrievalQueryEvidence(evidence) {
|
|
|
108
108
|
return evidence;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
export function verifyQueryOracleSource(queryEvidence, candidateSourceSha, {
|
|
111
|
+
export function verifyQueryOracleSource(queryEvidence, candidateSourceSha, {
|
|
112
|
+
cwd = process.cwd(), run = spawnSync, allowSquashedSource = false,
|
|
113
|
+
} = {}) {
|
|
112
114
|
validateRetrievalQueryEvidence(queryEvidence);
|
|
113
115
|
if (!HEX40.test(String(candidateSourceSha || '')) || queryEvidence.sourceCommit === candidateSourceSha) {
|
|
114
116
|
throw new Error('query oracle source identity is invalid');
|
|
115
117
|
}
|
|
116
118
|
const ancestor = run('git', ['merge-base', '--is-ancestor', queryEvidence.sourceCommit, candidateSourceSha],
|
|
117
119
|
{ cwd, encoding: 'utf8' });
|
|
118
|
-
|
|
120
|
+
const strictAncestor = !ancestor.error && ancestor.status === 0;
|
|
121
|
+
if (!strictAncestor && !allowSquashedSource) throw new Error('query oracle source is not a strict candidate ancestor');
|
|
119
122
|
const shown = run('git', ['show', `${queryEvidence.sourceCommit}:${queryEvidence.sourcePath}`],
|
|
120
123
|
{ cwd, encoding: null, maxBuffer: 64 * 1024 * 1024 });
|
|
121
124
|
let sourcePayload;
|
|
@@ -184,7 +187,8 @@ export function validateRetrievalCanaryPlan(plan) {
|
|
|
184
187
|
throw new Error('oracle denominator differs from eligible coverage');
|
|
185
188
|
}
|
|
186
189
|
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')
|
|
190
|
+
if ((!plan.cases.some(({ cohort }) => cohort === 'delta') && plan.noDelta !== true)
|
|
191
|
+
|| !plan.cases.some(({ cohort }) => cohort === 'legacy')) {
|
|
188
192
|
throw new Error('retrieval canary plan requires delta and legacy cohorts');
|
|
189
193
|
}
|
|
190
194
|
for (const row of plan.cases) {
|
|
@@ -236,7 +240,7 @@ export function validatePlanAgainstCoverage(plan, coverage, { allowObservedBasel
|
|
|
236
240
|
return plan;
|
|
237
241
|
}
|
|
238
242
|
export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, coverageIdentity = null, queryEvidence, assetsDir = '.',
|
|
239
|
-
readPassages = defaultReadPassages, legacySampleSize } = {}) {
|
|
243
|
+
readPassages = defaultReadPassages, legacySampleSize, allowNoDelta = false } = {}) {
|
|
240
244
|
const checked = validateCoverageLedger(coverage);
|
|
241
245
|
if (!checked.valid) throw new Error(`coverage ledger is invalid: ${checked.failures.join('; ')}`);
|
|
242
246
|
const coverageGeneration = coverage.kind === 'ruvnet-brain-release-coverage'
|
|
@@ -294,12 +298,15 @@ export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, covera
|
|
|
294
298
|
const eligibleStores = ordered(eligible.map(storeOf));
|
|
295
299
|
if (queryEvidence.queryStoreSetSha256 !== setDigest(eligibleStores)
|
|
296
300
|
|| canonicalJson(ordered(Object.keys(queryEvidence.queries))) !== canonicalJson(eligibleStores)) {
|
|
297
|
-
|
|
301
|
+
const oracleStores = new Set(Object.keys(queryEvidence.queries));
|
|
302
|
+
const missing = eligibleStores.filter((store) => !oracleStores.has(store));
|
|
303
|
+
const extra = [...oracleStores].filter((store) => !eligibleStores.includes(store)).sort();
|
|
304
|
+
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'})`);
|
|
298
305
|
}
|
|
299
306
|
const baselineStores = new Set(baseline.stores.map((name) => String(name).toLowerCase()));
|
|
300
307
|
const delta = eligible.filter((row) => !baselineStores.has(storeOf(row)));
|
|
301
308
|
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');
|
|
309
|
+
if ((!delta.length && !allowNoDelta) || !legacyPool.length) throw new Error('coverage does not establish both failed-seed delta and legacy cohorts');
|
|
303
310
|
const passages = new Map(eligible.map((row) => [storeOf(row), readPassages(assetsDir, storeOf(row))]));
|
|
304
311
|
const rankedLegacy = legacyPool.map((row) => ({ row, count: passages.get(storeOf(row)).length }))
|
|
305
312
|
.sort((a, b) => a.count - b.count || storeOf(a.row).localeCompare(storeOf(b.row)));
|
|
@@ -376,6 +383,7 @@ export function buildRetrievalCanaryPlan({ coverage, baseline, candidate, covera
|
|
|
376
383
|
queryStoreSetSha256: queryEvidence.queryStoreSetSha256,
|
|
377
384
|
sourceCommit: queryEvidence.sourceCommit, sourceBlobSha256: queryEvidence.sourceBlobSha256,
|
|
378
385
|
evidence: structuredClone(queryEvidence) },
|
|
386
|
+
noDelta: delta.length === 0,
|
|
379
387
|
cohorts: { delta: delta.length, legacy: legacy.length,
|
|
380
388
|
legacyStrata: [...strata.keys()].sort().map((stratum) => ({ stratum,
|
|
381
389
|
population: rankedLegacy.filter((_entry, index) => Math.min(3, Math.floor(index * 4 / rankedLegacy.length)) === stratum).length,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// One release version command. The plugin manifest is the only editable source of truth;
|
|
3
|
+
// propagation and verification happen in the same process so a package-only bump cannot drift.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
|
+
const version = process.argv[2];
|
|
11
|
+
if (!version || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version)) {
|
|
12
|
+
console.error('usage: npm run version:set -- X.Y.Z[-channel]');
|
|
13
|
+
process.exit(2);
|
|
14
|
+
}
|
|
15
|
+
const manifest = path.join(root, 'plugin/.claude-plugin/plugin.json');
|
|
16
|
+
const doc = JSON.parse(fs.readFileSync(manifest, 'utf8'));
|
|
17
|
+
const previous = doc.version;
|
|
18
|
+
doc.version = version;
|
|
19
|
+
fs.writeFileSync(manifest, `${JSON.stringify(doc, null, 2)}\n`);
|
|
20
|
+
const sync = spawnSync(process.execPath, [path.join(root, 'scripts/sync-version.mjs')], {
|
|
21
|
+
cwd: root, encoding: 'utf8', stdio: 'inherit',
|
|
22
|
+
});
|
|
23
|
+
if (sync.status !== 0) {
|
|
24
|
+
console.error(`[version:set] propagation failed; source changed ${previous} -> ${version}, run version:sync after fixing the reported error`);
|
|
25
|
+
process.exit(sync.status || 1);
|
|
26
|
+
}
|
|
27
|
+
const check = spawnSync(process.execPath, [path.join(root, 'scripts/sync-version.mjs'), '--check'], {
|
|
28
|
+
cwd: root, encoding: 'utf8', stdio: 'inherit',
|
|
29
|
+
});
|
|
30
|
+
if (check.status !== 0) process.exit(check.status || 1);
|
|
31
|
+
console.log(`[version:set] ${previous} -> ${version}; all release surfaces agree`);
|
|
@@ -97,7 +97,7 @@ async function run() {
|
|
|
97
97
|
}
|
|
98
98
|
check('npm latest matches shipping version', ok,
|
|
99
99
|
ok ? `npm latest=${latest} · shipping=${V}`
|
|
100
|
-
: `npm latest=${latest || '(view failed: ' + lastErr + ')'} · shipping=${V}${latest && latest !== V ? ' ← STILL STALE after ~' + (ATTEMPTS * 5) + 's:
|
|
100
|
+
: `npm latest=${latest || '(view failed: ' + lastErr + ')'} · shipping=${V}${latest && latest !== V ? ' ← STILL STALE after ~' + (ATTEMPTS * 5) + 's: dispatch the protected-release workflow for the exact candidate SHA' : ''}`);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// 2) the self-update manifest URL actually resolves (the 404 that stranded users)
|