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.
Files changed (45) hide show
  1. package/README.md +2 -2
  2. package/bin/install.mjs +19 -4
  3. package/data/model-catalog.json +1 -1
  4. package/docs/RELEASE-NOTES-4.0.md +4 -3
  5. package/kb/capability-only.mjs +27 -0
  6. package/kb/capability-summaries/cognitum-ruos/CAPABILITIES.md +26 -0
  7. package/kb/verify-citation.mjs +16 -4
  8. package/package.json +5 -1
  9. package/plugin/.claude-plugin/plugin.json +1 -1
  10. package/plugin/.codex-plugin/plugin.json +1 -1
  11. package/plugin/docs/RELEASE-NOTES-4.0.md +4 -3
  12. package/plugin/hooks/codex-hooks.json +6 -1
  13. package/plugin/hooks/hook-contracts.json +24 -2
  14. package/plugin/hooks/hooks.json +6 -1
  15. package/plugin/scripts/capacity-aware-parallel-work.mjs +200 -0
  16. package/plugin/scripts/codex-hook-adapter.mjs +37 -0
  17. package/plugin/scripts/continuity-hook-policy.mjs +4 -0
  18. package/plugin/scripts/coverage-integrity.mjs +17 -0
  19. package/plugin/scripts/hook-shim.mjs +1 -0
  20. package/plugin/scripts/lesson-gate.mjs +4 -1
  21. package/plugin/scripts/project-progression-reader.mjs +12 -1
  22. package/plugin/scripts/project-progression-session-start.mjs +24 -6
  23. package/plugin/scripts/project-progression-store.mjs +76 -4
  24. package/plugin/skills/release-proof/SKILL.md +28 -4
  25. package/plugin/skills/release-proof/scripts/release-proof.mjs +48 -24
  26. package/scripts/brain-novice-50.mjs +14 -16
  27. package/scripts/build-bundle.mjs +2 -0
  28. package/scripts/corpus-dispatch-receipt.mjs +22 -0
  29. package/scripts/corpus-reconcile.mjs +26 -4
  30. package/scripts/doc-currency.mjs +12 -4
  31. package/scripts/eval-brain.mjs +7 -5
  32. package/scripts/gist-git-transport.mjs +218 -0
  33. package/scripts/gist-receipts.mjs +168 -38
  34. package/scripts/ingest-gists.mjs +5 -2
  35. package/scripts/installed-brain-health.mjs +99 -0
  36. package/scripts/public-inputs.mjs +2 -1
  37. package/scripts/public-verification-inputs.mjs +14 -6
  38. package/scripts/refresh-capability-only-store.mjs +143 -0
  39. package/scripts/release-vector.mjs +44 -20
  40. package/scripts/run-operational-benchmark.mjs +151 -0
  41. package/scripts/run-operational-benchmark.v3.mjs +194 -0
  42. package/scripts/self-update.mjs +2 -0
  43. package/scripts/source-coverage.mjs +6 -1
  44. package/scripts/sync-version.mjs +10 -2
  45. package/scripts/wired-check.mjs +73 -45
@@ -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
- let src = '';
546
- try { src = fs.readFileSync(f, 'utf8'); } catch { continue; }
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(stripComments(src, path.extname(f)))) return { automated: true, via: `${rel} runs \`${n}\`` };
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
- let src = '';
563
- try { src = fs.readFileSync(f, 'utf8'); } catch { continue; }
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
- let source = '';
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
- try { body = stripComments(fs.readFileSync(file, 'utf8'), path.extname(file)); } catch { continue; }
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
- let pkgSrc = '';
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 { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return null; }
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
- let src = '';
780
- try { src = fs.readFileSync(path.join(repo, 'bin/install.mjs'), 'utf8'); } catch { return null; }
781
- const stripped = stripComments(src, '.mjs');
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
- let src = '';
791
- try { src = fs.readFileSync(path.join(repo, 'plugin/scripts/hook-shim.mjs'), 'utf8'); } catch { return {}; }
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
- let src = ''; try { src = fs.readFileSync(path.join(scriptsDir, from), 'utf8'); } catch { continue; }
871
- const stripped = stripComments(src, path.extname(from));
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(stripped)) { add(cand, `spawned by plugin/scripts/${from}`); changed = true; }
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
- let src = ''; try { src = fs.readFileSync(path.join(scriptsDir, f), 'utf8'); } catch { continue; }
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
- let src = '';
909
- try { src = fs.readFileSync(path.join(repo, 'plugin/scripts/lesson-hooks.sh'), 'utf8'); } catch { return new Set(); }
910
- const stripped = stripComments(src, '.sh');
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
- const requested = lessonHooksRequestedTriggers(repo);
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 { rows, operationalRows, dupes, inventory } = audit();
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`);