ruvnet-brain 4.3.26 → 4.3.27
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 +2 -2
- package/bin/install.mjs +19 -4
- package/data/model-catalog.json +1 -1
- package/docs/RELEASE-NOTES-4.0.md +4 -3
- package/kb/capability-only.mjs +27 -0
- package/kb/capability-summaries/cognitum-ruos/CAPABILITIES.md +26 -0
- package/kb/verify-citation.mjs +16 -4
- package/package.json +5 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/docs/RELEASE-NOTES-4.0.md +4 -3
- package/plugin/hooks/codex-hooks.json +6 -1
- package/plugin/hooks/hook-contracts.json +24 -2
- package/plugin/hooks/hooks.json +6 -1
- package/plugin/scripts/capacity-aware-parallel-work.mjs +200 -0
- package/plugin/scripts/codex-hook-adapter.mjs +37 -0
- package/plugin/scripts/continuity-hook-policy.mjs +4 -0
- package/plugin/scripts/coverage-integrity.mjs +17 -0
- package/plugin/scripts/hook-shim.mjs +1 -0
- package/plugin/scripts/lesson-gate.mjs +4 -1
- package/plugin/scripts/project-progression-reader.mjs +12 -1
- package/plugin/scripts/project-progression-session-start.mjs +24 -6
- package/plugin/scripts/project-progression-store.mjs +76 -4
- package/plugin/skills/release-proof/SKILL.md +28 -4
- package/plugin/skills/release-proof/scripts/release-proof.mjs +48 -24
- package/scripts/brain-novice-50.mjs +14 -16
- package/scripts/build-bundle.mjs +2 -0
- package/scripts/corpus-dispatch-receipt.mjs +22 -0
- package/scripts/corpus-reconcile.mjs +26 -4
- package/scripts/doc-currency.mjs +12 -4
- package/scripts/eval-brain.mjs +7 -5
- package/scripts/gist-git-transport.mjs +218 -0
- package/scripts/gist-receipts.mjs +168 -38
- package/scripts/ingest-gists.mjs +5 -2
- package/scripts/installed-brain-health.mjs +99 -0
- package/scripts/public-inputs.mjs +2 -1
- package/scripts/public-verification-inputs.mjs +14 -6
- package/scripts/refresh-capability-only-store.mjs +143 -0
- package/scripts/release-vector.mjs +44 -20
- package/scripts/run-operational-benchmark.mjs +151 -0
- package/scripts/run-operational-benchmark.v3.mjs +194 -0
- package/scripts/self-update.mjs +2 -0
- package/scripts/source-coverage.mjs +6 -1
- package/scripts/sync-version.mjs +10 -2
- package/scripts/wired-check.mjs +73 -45
package/scripts/wired-check.mjs
CHANGED
|
@@ -246,6 +246,8 @@ const STANDALONE = [
|
|
|
246
246
|
* small lie that hides a real gap. Held work is VISIBLE work.
|
|
247
247
|
*/
|
|
248
248
|
const HELD = {
|
|
249
|
+
'source-tree': 'ADR-086 oracle-source-units/2 groundwork, not consumed by the current v1 oracle pipeline. Requires complete parser-adapter integration and source-bound inventory acceptance before activation; no production extraction-completeness claim.',
|
|
250
|
+
'unit-inventory': 'ADR-086 parser-independent v2 inventory core, currently exercised only by tests. Requires adapters for the declared source scope plus pipeline integration and failure-path qualification; cannot authorize a C3 pass.',
|
|
249
251
|
'correction-detect': 'N3 lesson extraction. Re-measured 2026-07-23 on a reproducible held-out split '
|
|
250
252
|
+ 'of 1,328 real transcripts (scripts/correction-detect-measure.mjs): 5 real detector bugs fixed, '
|
|
251
253
|
+ 'corpus detections 2->8, ~50-100% precision at n=4 on the holdout. TWO measured findings now bound '
|
|
@@ -477,6 +479,26 @@ export function stripComments(src, ext) {
|
|
|
477
479
|
.join('\n');
|
|
478
480
|
}
|
|
479
481
|
|
|
482
|
+
/** Source text cache whose lifetime is one audit call; never shared across invocations. */
|
|
483
|
+
export function createInvocationSourceCache(readFile = fs.readFileSync) {
|
|
484
|
+
const text = new Map();
|
|
485
|
+
const uncommented = new Map();
|
|
486
|
+
const read = (file) => {
|
|
487
|
+
if (!text.has(file)) {
|
|
488
|
+
try { text.set(file, readFile(file, 'utf8')); } catch { text.set(file, null); }
|
|
489
|
+
}
|
|
490
|
+
return text.get(file);
|
|
491
|
+
};
|
|
492
|
+
const commentFree = (file) => {
|
|
493
|
+
if (!uncommented.has(file)) {
|
|
494
|
+
const src = read(file);
|
|
495
|
+
uncommented.set(file, src === null ? null : stripComments(src, path.extname(file)));
|
|
496
|
+
}
|
|
497
|
+
return uncommented.get(file);
|
|
498
|
+
};
|
|
499
|
+
return { read, commentFree };
|
|
500
|
+
}
|
|
501
|
+
|
|
480
502
|
/**
|
|
481
503
|
* ── THE THIRD STATE (ADR-056, 2026-07-27) ────────────────────────────────────────────────────────
|
|
482
504
|
* DEFINING an npm script is not INVOKING it. `package.json` line 35 defines `doc:currency` as a
|
|
@@ -533,7 +555,7 @@ export function npmScriptsNaming(pkgSrc, modFile) {
|
|
|
533
555
|
* Automated means: npm itself runs it (a lifecycle name), or some file — a workflow, a shell hook,
|
|
534
556
|
* or another composite npm script — invokes it by name.
|
|
535
557
|
*/
|
|
536
|
-
export function npmScriptAutomated(names, files, repo = REPO) {
|
|
558
|
+
export function npmScriptAutomated(names, files, repo = REPO, sourceCache = createInvocationSourceCache()) {
|
|
537
559
|
for (const n of names) {
|
|
538
560
|
if (NPM_AUTO_LIFECYCLE.has(n)) return { automated: true, via: `npm lifecycle (\`${n}\` is run by npm itself)` };
|
|
539
561
|
}
|
|
@@ -542,36 +564,35 @@ export function npmScriptAutomated(names, files, repo = REPO) {
|
|
|
542
564
|
const re = new RegExp(`(?:npm|pnpm|yarn|npm-run-all|run-s|run-p)\\s+(?:run\\s+)?${esc(n)}(?![\\w:-])`);
|
|
543
565
|
for (const f of files) {
|
|
544
566
|
const rel = path.relative(repo, f).split(path.sep).join('/');
|
|
545
|
-
|
|
546
|
-
|
|
567
|
+
const src = sourceCache.commentFree(f);
|
|
568
|
+
if (src === null) continue;
|
|
547
569
|
// A composite script in package.json ("test:all": "npm run test:unit && …") IS automation.
|
|
548
|
-
if (re.test(
|
|
570
|
+
if (re.test(src)) return { automated: true, via: `${rel} runs \`${n}\`` };
|
|
549
571
|
}
|
|
550
572
|
}
|
|
551
573
|
return { automated: false, via: null };
|
|
552
574
|
}
|
|
553
575
|
|
|
554
576
|
/** Count REAL callers. Tests excluded deliberately: all seven failures had passing tests. */
|
|
555
|
-
export function callersOf(mod, files, repo = REPO) {
|
|
577
|
+
export function callersOf(mod, files, repo = REPO, sourceCache = createInvocationSourceCache()) {
|
|
556
578
|
const re = callerPattern(mod.file);
|
|
557
579
|
const hits = [];
|
|
558
580
|
for (const f of files) {
|
|
559
581
|
const rel = path.relative(repo, f).split(path.sep).join('/');
|
|
560
582
|
if (rel === mod.rel) continue; // self
|
|
561
583
|
if (isTestFile(rel)) continue; // a test is not a caller
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
if (re.test(stripComments(src, path.extname(f)))) hits.push(rel);
|
|
584
|
+
const src = sourceCache.commentFree(f);
|
|
585
|
+
if (src !== null && re.test(src)) hits.push(rel);
|
|
565
586
|
}
|
|
566
587
|
return hits;
|
|
567
588
|
}
|
|
568
589
|
|
|
569
|
-
export function operationalExportAudit({ repo = REPO, required = REQUIRED_OPERATIONAL_EXPORTS
|
|
590
|
+
export function operationalExportAudit({ repo = REPO, required = REQUIRED_OPERATIONAL_EXPORTS,
|
|
591
|
+
sourceCache = createInvocationSourceCache() } = {}) {
|
|
570
592
|
const files = callerFiles(repo);
|
|
571
593
|
const rows = required.map(({ rel, symbol }) => {
|
|
572
594
|
const sourceFile = path.join(repo, rel);
|
|
573
|
-
|
|
574
|
-
try { source = fs.readFileSync(sourceFile, 'utf8'); } catch { /* reported as missing below */ }
|
|
595
|
+
const source = sourceCache.read(sourceFile) || '';
|
|
575
596
|
const quoted = symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
576
597
|
const exported = new RegExp(`\\bexport\\s+(?:async\\s+)?function\\s+${quoted}\\s*\\(`).test(source);
|
|
577
598
|
if (!exported) return { rel, symbol, state: 'missing', callers: [] };
|
|
@@ -581,8 +602,8 @@ export function operationalExportAudit({ repo = REPO, required = REQUIRED_OPERAT
|
|
|
581
602
|
for (const file of files) {
|
|
582
603
|
const callerRel = path.relative(repo, file).split(path.sep).join('/');
|
|
583
604
|
if (isTestFile(callerRel)) continue;
|
|
584
|
-
let body =
|
|
585
|
-
|
|
605
|
+
let body = sourceCache.commentFree(file);
|
|
606
|
+
if (body === null) continue;
|
|
586
607
|
body = body.replace(declaration, 'export function __operational_definition__(');
|
|
587
608
|
if (invocation.test(body)) callers.push(callerRel);
|
|
588
609
|
}
|
|
@@ -592,7 +613,8 @@ export function operationalExportAudit({ repo = REPO, required = REQUIRED_OPERAT
|
|
|
592
613
|
}
|
|
593
614
|
|
|
594
615
|
export function audit({ repo = REPO, standalone = STANDALONE, held = HELD,
|
|
595
|
-
operationalExports = REQUIRED_OPERATIONAL_EXPORTS } = {}) {
|
|
616
|
+
operationalExports = REQUIRED_OPERATIONAL_EXPORTS, readFile = fs.readFileSync, sourceCache = null } = {}) {
|
|
617
|
+
const invocationSource = sourceCache ?? createInvocationSourceCache(readFile);
|
|
596
618
|
const dupes = [];
|
|
597
619
|
const seen = new Map();
|
|
598
620
|
for (const [name, why] of standalone) {
|
|
@@ -605,16 +627,15 @@ export function audit({ repo = REPO, standalone = STANDALONE, held = HELD,
|
|
|
605
627
|
for (const m of all) {
|
|
606
628
|
if (seen.has(m.base)) { rows.push({ ...m, state: 'exempt', why: seen.get(m.base) }); continue; }
|
|
607
629
|
if (held[m.base]) { rows.push({ ...m, state: 'held', why: held[m.base] }); continue; }
|
|
608
|
-
const callers = callersOf(m, files, repo);
|
|
630
|
+
const callers = callersOf(m, files, repo, invocationSource);
|
|
609
631
|
let state = callers.length ? 'wired' : 'unwired';
|
|
610
632
|
let why;
|
|
611
633
|
// ADR-056: callers that are ONLY the package.json line defining the script are not automation.
|
|
612
634
|
if (callers.length && callers.every((c) => c === 'package.json')) {
|
|
613
|
-
|
|
614
|
-
try { pkgSrc = fs.readFileSync(path.join(repo, 'package.json'), 'utf8'); } catch { /* none */ }
|
|
635
|
+
const pkgSrc = invocationSource.read(path.join(repo, 'package.json')) || '';
|
|
615
636
|
const names = npmScriptsNaming(pkgSrc, m.file);
|
|
616
637
|
if (names.length) {
|
|
617
|
-
const auto = npmScriptAutomated(names, files, repo);
|
|
638
|
+
const auto = npmScriptAutomated(names, files, repo, invocationSource);
|
|
618
639
|
if (!auto.automated) {
|
|
619
640
|
state = 'manual';
|
|
620
641
|
const list = names.map((n) => `\`${n}\``).join(', ');
|
|
@@ -626,7 +647,7 @@ export function audit({ repo = REPO, standalone = STANDALONE, held = HELD,
|
|
|
626
647
|
}
|
|
627
648
|
rows.push({ ...m, state, callers, ...(why ? { why } : {}) });
|
|
628
649
|
}
|
|
629
|
-
const operationalRows = operationalExportAudit({ repo, required: operationalExports }).rows;
|
|
650
|
+
const operationalRows = operationalExportAudit({ repo, required: operationalExports, sourceCache: invocationSource }).rows;
|
|
630
651
|
return { rows, operationalRows, dupes, inventory: all.length };
|
|
631
652
|
}
|
|
632
653
|
|
|
@@ -736,8 +757,11 @@ const HOOK_HELD = {
|
|
|
736
757
|
};
|
|
737
758
|
|
|
738
759
|
/** Read+JSON.parse a file. null on ANY failure (missing, unreadable, malformed) — never throws. */
|
|
739
|
-
function readJsonSafe(file) {
|
|
740
|
-
try {
|
|
760
|
+
function readJsonSafe(file, sourceCache) {
|
|
761
|
+
try {
|
|
762
|
+
const src = sourceCache ? sourceCache.read(file) : fs.readFileSync(file, 'utf8');
|
|
763
|
+
return src === null ? null : JSON.parse(src);
|
|
764
|
+
} catch { return null; }
|
|
741
765
|
}
|
|
742
766
|
|
|
743
767
|
/** Every `command` string inside a hooks.json / settings.json shaped `{ hooks: {...} }` document. */
|
|
@@ -775,10 +799,10 @@ function codexHookIdIn(cmd) {
|
|
|
775
799
|
* (`codex-hook-wrapper.mjs`). Both names plus the actual copy operation must be present; otherwise
|
|
776
800
|
* there is no proven bridge and the hook stays unwired.
|
|
777
801
|
*/
|
|
778
|
-
function installedCodexHookWrapper(repo) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const stripped =
|
|
802
|
+
function installedCodexHookWrapper(repo, sourceCache) {
|
|
803
|
+
const src = sourceCache.read(path.join(repo, 'bin/install.mjs'));
|
|
804
|
+
if (src === null) return null;
|
|
805
|
+
const stripped = sourceCache.commentFree(path.join(repo, 'bin/install.mjs'));
|
|
782
806
|
const source = stripped.match(/hookWrapperSource\s*=\s*path\.join\([\s\S]{0,240}?['"]([\w.-]+\.mjs)['"]\)/)?.[1];
|
|
783
807
|
const target = stripped.match(/const codexHookWrapperPath[\s\S]{0,260}?['"]([\w.-]+\.mjs)['"]\)/)?.[1];
|
|
784
808
|
const copiesSource = /fs\.copyFileSync\(hookWrapperSource,\s*tmp\)/.test(stripped);
|
|
@@ -786,9 +810,9 @@ function installedCodexHookWrapper(repo) {
|
|
|
786
810
|
}
|
|
787
811
|
|
|
788
812
|
/** hook-shim.mjs's own dispatch TABLE: id -> file. Parsed, not re-implemented — it IS the authority. */
|
|
789
|
-
function hookShimTable(repo) {
|
|
790
|
-
|
|
791
|
-
|
|
813
|
+
function hookShimTable(repo, sourceCache) {
|
|
814
|
+
const src = sourceCache.read(path.join(repo, 'plugin/scripts/hook-shim.mjs'));
|
|
815
|
+
if (src === null) return {};
|
|
792
816
|
const map = {};
|
|
793
817
|
const re = /'([\w-]+)':\s*{\s*file:\s*'([\w.-]+)'/g;
|
|
794
818
|
let m; while ((m = re.exec(src))) map[m[1]] = m[2];
|
|
@@ -813,6 +837,7 @@ export function hookWiringAudit({
|
|
|
813
837
|
repo = REPO,
|
|
814
838
|
homeSettingsFile = path.join(os.homedir(), '.claude', 'settings.json'),
|
|
815
839
|
held = HOOK_HELD,
|
|
840
|
+
sourceCache = createInvocationSourceCache(),
|
|
816
841
|
} = {}) {
|
|
817
842
|
const retirementFiles = [
|
|
818
843
|
path.join(repo, 'plugin/hooks/hooks.json'),
|
|
@@ -821,7 +846,7 @@ export function hookWiringAudit({
|
|
|
821
846
|
path.join(repo, '.codex/hooks.json'),
|
|
822
847
|
];
|
|
823
848
|
const automaticHooksConstrained = retirementFiles.every((file) => {
|
|
824
|
-
const doc = readJsonSafe(file);
|
|
849
|
+
const doc = readJsonSafe(file, sourceCache);
|
|
825
850
|
if (!doc?.hooks) return false;
|
|
826
851
|
const packageRegistry = file.endsWith('/plugin/hooks/hooks.json') || file.endsWith('/plugin/hooks/codex-hooks.json');
|
|
827
852
|
const rows = Object.entries(doc.hooks).flatMap(([event, groups]) => (groups ?? []).flatMap((group) =>
|
|
@@ -832,8 +857,8 @@ export function hookWiringAudit({
|
|
|
832
857
|
&& rows.every((row) => isAllowedContinuityRegistration({ ...row, host }))
|
|
833
858
|
: rows.length === 0;
|
|
834
859
|
});
|
|
835
|
-
const table = hookShimTable(repo);
|
|
836
|
-
const codexWrapper = installedCodexHookWrapper(repo);
|
|
860
|
+
const table = hookShimTable(repo, sourceCache);
|
|
861
|
+
const codexWrapper = installedCodexHookWrapper(repo, sourceCache);
|
|
837
862
|
const reached = new Map(); // basename -> Set(reason)
|
|
838
863
|
const add = (name, reason) => {
|
|
839
864
|
if (!name) return;
|
|
@@ -842,7 +867,7 @@ export function hookWiringAudit({
|
|
|
842
867
|
};
|
|
843
868
|
|
|
844
869
|
const scanConfig = (file, label, { codex = false } = {}) => {
|
|
845
|
-
const doc = readJsonSafe(file);
|
|
870
|
+
const doc = readJsonSafe(file, sourceCache);
|
|
846
871
|
if (!doc || !doc.hooks) return;
|
|
847
872
|
for (const cmd of commandStrings(doc.hooks)) {
|
|
848
873
|
const basenames = basenamesIn(cmd);
|
|
@@ -867,11 +892,11 @@ export function hookWiringAudit({
|
|
|
867
892
|
for (let i = 0; i < 10; i++) {
|
|
868
893
|
let changed = false;
|
|
869
894
|
for (const from of [...reached.keys()]) {
|
|
870
|
-
|
|
871
|
-
|
|
895
|
+
const src = sourceCache.commentFree(path.join(scriptsDir, from));
|
|
896
|
+
if (src === null) continue;
|
|
872
897
|
for (const cand of all) {
|
|
873
898
|
if (reached.has(cand)) continue;
|
|
874
|
-
if (callerPattern(cand).test(
|
|
899
|
+
if (callerPattern(cand).test(src)) { add(cand, `spawned by plugin/scripts/${from}`); changed = true; }
|
|
875
900
|
}
|
|
876
901
|
}
|
|
877
902
|
if (!changed) break;
|
|
@@ -880,7 +905,8 @@ export function hookWiringAudit({
|
|
|
880
905
|
const rows = [];
|
|
881
906
|
for (const f of all) {
|
|
882
907
|
if (HOOK_PLUMBING_NAMES.has(f)) continue; // plumbing, not a hook body — never part of the census
|
|
883
|
-
|
|
908
|
+
const src = sourceCache.read(path.join(scriptsDir, f));
|
|
909
|
+
if (src === null) continue;
|
|
884
910
|
const declared = hookHeaderDeclares(src);
|
|
885
911
|
const isReached = reached.has(f);
|
|
886
912
|
if (!declared && !isReached) continue; // not hook-intended at all — outside the census
|
|
@@ -904,10 +930,10 @@ export function hookWiringAudit({
|
|
|
904
930
|
* to this audit — and Check C would then depend on an unrelated dead case label merely coexisting in
|
|
905
931
|
* the file to report it correctly, which breaks the moment that dead label is ever cleaned up.
|
|
906
932
|
*/
|
|
907
|
-
function lessonHooksRequestedTriggers(repo) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const stripped =
|
|
933
|
+
function lessonHooksRequestedTriggers(repo, sourceCache) {
|
|
934
|
+
const src = sourceCache.read(path.join(repo, 'plugin/scripts/lesson-hooks.sh'));
|
|
935
|
+
if (src === null) return new Set();
|
|
936
|
+
const stripped = sourceCache.commentFree(path.join(repo, 'plugin/scripts/lesson-hooks.sh'));
|
|
911
937
|
const requested = new Set();
|
|
912
938
|
const re = /TRIGGERS="([^"]*)"/g;
|
|
913
939
|
let m;
|
|
@@ -921,8 +947,9 @@ function lessonHooksRequestedTriggers(repo) {
|
|
|
921
947
|
* CHECK C — LESSON-TRIGGER WIRING. See the file-level comment above for the full reasoning
|
|
922
948
|
* (advisory-only, deliberately, because the store is per-user/per-machine state outside this repo).
|
|
923
949
|
*/
|
|
924
|
-
export function lessonTriggerAudit({ repo = REPO, lessonsFile = undefined
|
|
925
|
-
|
|
950
|
+
export function lessonTriggerAudit({ repo = REPO, lessonsFile = undefined,
|
|
951
|
+
sourceCache = createInvocationSourceCache() } = {}) {
|
|
952
|
+
const requested = lessonHooksRequestedTriggers(repo, sourceCache);
|
|
926
953
|
const lessons = loadLessons(lessonsFile);
|
|
927
954
|
const live = lessons.filter((l) => !l.demoted && (l.status === STATUS.RATIFIED || l.status === STATUS.ACTIVE));
|
|
928
955
|
const labelOf = (trigger) => Object.values(TRIGGERS).find((t) => t.key === trigger)?.label || trigger;
|
|
@@ -936,17 +963,18 @@ const invokedDirectly = process.argv[1]
|
|
|
936
963
|
&& path.resolve(process.argv[1]).endsWith(`wired-check${path.extname(process.argv[1])}`);
|
|
937
964
|
|
|
938
965
|
if (invokedDirectly) {
|
|
939
|
-
const
|
|
966
|
+
const sourceCache = createInvocationSourceCache();
|
|
967
|
+
const { rows, operationalRows, dupes, inventory } = audit({ sourceCache });
|
|
940
968
|
const by = (s) => rows.filter((r) => r.state === s);
|
|
941
969
|
const unwired = by('unwired');
|
|
942
970
|
const operationalUnwired = operationalRows.filter((row) => row.state !== 'wired');
|
|
943
971
|
|
|
944
|
-
const hookAudit = hookWiringAudit();
|
|
972
|
+
const hookAudit = hookWiringAudit({ sourceCache });
|
|
945
973
|
const hookBy = (s) => hookAudit.rows.filter((r) => r.state === s);
|
|
946
974
|
const hookUnwired = hookBy('unwired');
|
|
947
975
|
const hookRetired = hookBy('retired');
|
|
948
976
|
|
|
949
|
-
const lessonAudit = lessonTriggerAudit();
|
|
977
|
+
const lessonAudit = lessonTriggerAudit({ sourceCache });
|
|
950
978
|
|
|
951
979
|
if (!argv.includes('--quiet')) {
|
|
952
980
|
console.log(`\n ${inventory} first-party module(s) in the inventory`);
|