ruvnet-brain 4.3.21 → 4.3.26

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 (143) hide show
  1. package/README.md +5 -5
  2. package/bin/install.mjs +275 -60
  3. package/console/app.js +189 -9
  4. package/console/index.html +70 -24
  5. package/console/scope.css +137 -0
  6. package/console/scope.html +144 -0
  7. package/console/scope.js +209 -0
  8. package/console/style.css +26 -0
  9. package/console/tips.html +1 -0
  10. package/kb/corpus-release-identity.mjs +239 -0
  11. package/kb/update-storage-transaction.mjs +20 -3
  12. package/package.json +9 -2
  13. package/plugin/.claude-plugin/plugin.json +2 -2
  14. package/plugin/.codex-plugin/plugin.json +1 -1
  15. package/plugin/commands/checkpoint.md +61 -0
  16. package/plugin/hooks/codex-hooks.json +64 -1
  17. package/plugin/hooks/hook-contracts.json +299 -6
  18. package/plugin/hooks/hooks.json +81 -1
  19. package/plugin/mcp/server.mjs +23 -0
  20. package/plugin/scripts/advocacy-catalog.mjs +245 -0
  21. package/plugin/scripts/advocacy-route.mjs +460 -0
  22. package/plugin/scripts/continuation-gate.mjs +25 -2
  23. package/plugin/scripts/continuation-objective.mjs +7 -1
  24. package/plugin/scripts/continuity-hook-policy.mjs +190 -15
  25. package/plugin/scripts/coverage-integrity.mjs +7 -0
  26. package/plugin/scripts/gates.mjs +113 -10
  27. package/plugin/scripts/grounding-turn-gate.mjs +167 -0
  28. package/plugin/scripts/grounding-turn-mark.mjs +91 -0
  29. package/plugin/scripts/hook-shim.mjs +14 -0
  30. package/plugin/scripts/nightly-scheduler.mjs +37 -4
  31. package/plugin/scripts/project-progression-checkpoint.mjs +145 -0
  32. package/plugin/scripts/project-progression-contract.mjs +16 -0
  33. package/plugin/scripts/project-progression-hook.mjs +3 -0
  34. package/plugin/scripts/project-progression-producer.mjs +252 -0
  35. package/plugin/scripts/project-progression-reader.mjs +271 -0
  36. package/plugin/scripts/project-progression-session-start.mjs +93 -16
  37. package/plugin/scripts/project-progression-sources.mjs +220 -0
  38. package/plugin/scripts/project-progression-store.mjs +106 -13
  39. package/plugin/scripts/ruvnet-gate1-pattern.mjs +29 -0
  40. package/plugin/scripts/session-snapshot-hook.mjs +115 -7
  41. package/plugin/scripts/session-start-budget.mjs +59 -0
  42. package/plugin/scripts/session-start-core.mjs +234 -457
  43. package/plugin/scripts/session-start-fsutil.mjs +61 -0
  44. package/plugin/scripts/session-start-health.mjs +64 -0
  45. package/plugin/scripts/session-start-hook-description.mjs +45 -0
  46. package/plugin/scripts/session-start-issue-alert.mjs +77 -0
  47. package/plugin/scripts/session-start-repo-identity.mjs +54 -0
  48. package/plugin/scripts/session-start-signals.mjs +73 -0
  49. package/plugin/scripts/session-start-trace.mjs +86 -0
  50. package/plugin/scripts/session-start-update-plane.mjs +104 -0
  51. package/plugin/scripts/unprompted-runtime.mjs +32 -2
  52. package/plugin/skills/ruvnet-brain/PLAYBOOK.md +26 -2
  53. package/plugin/skills/ruvnet-brain/SKILL.md +67 -2
  54. package/scripts/adr-072-completion.mjs +1 -1
  55. package/scripts/agentdb-fleet-doctor.mjs +5 -1
  56. package/scripts/approved-runtime.mjs +197 -0
  57. package/scripts/brain-novice-50.mjs +16 -1
  58. package/scripts/brain-score.mjs +23 -5
  59. package/scripts/build-bundle.mjs +971 -530
  60. package/scripts/build-concepts.mjs +36 -116
  61. package/scripts/console-engine.test.mjs +8 -7
  62. package/scripts/console-runtime-identity.mjs +4 -0
  63. package/scripts/corpus-aggregates.mjs +94 -77
  64. package/scripts/corpus-candidate.mjs +475 -222
  65. package/scripts/corpus-next-seed.mjs +225 -0
  66. package/scripts/corpus-promotion.mjs +58 -0
  67. package/scripts/corpus-reconcile.mjs +411 -105
  68. package/scripts/doc-currency.mjs +16 -1
  69. package/scripts/dual-host-deliberation.mjs +25 -2
  70. package/scripts/dual-host-suggest.mjs +17 -1
  71. package/scripts/falsify.mjs +13 -3
  72. package/scripts/gist-receipts.mjs +482 -87
  73. package/scripts/github-health-watch.mjs +12 -2
  74. package/scripts/handoff-asset.mjs +34 -0
  75. package/scripts/hook-retirement-check.mjs +8 -1
  76. package/scripts/host-registry.mjs +1 -1
  77. package/scripts/ingest-gists.mjs +74 -101
  78. package/scripts/job-heartbeat.sh +77 -14
  79. package/scripts/learning-replay-execution.mjs +10 -4
  80. package/scripts/nightly-gists.sh +27 -13
  81. package/scripts/nightly-two-run-proof.mjs +1 -1
  82. package/scripts/nightly-watchdog.mjs +61 -4
  83. package/scripts/onboarding-console.mjs +364 -28
  84. package/scripts/oracle/produce-questions.mjs +293 -0
  85. package/scripts/oracle/producer-hosts.mjs +235 -0
  86. package/scripts/oracle/repo-recall.mjs +448 -0
  87. package/scripts/oracle/retrieval-accuracy.mjs +818 -0
  88. package/scripts/oracle/source-tree.mjs +165 -0
  89. package/scripts/oracle/source-units.mjs +391 -0
  90. package/scripts/oracle/spike-run.mjs +98 -0
  91. package/scripts/oracle/unit-inventory.mjs +141 -0
  92. package/scripts/oracle/unit-sampling.mjs +128 -0
  93. package/scripts/oracle/validate-labels.mjs +250 -0
  94. package/scripts/private-overlay.mjs +248 -0
  95. package/scripts/product-integrity-contract.mjs +1 -1
  96. package/scripts/proxy/claude-proxied.sh +6 -0
  97. package/scripts/proxy/proxy-revert.sh +5 -0
  98. package/scripts/proxy/proxy-up.sh +6 -0
  99. package/scripts/proxy/proxy-verify.mjs +4 -0
  100. package/scripts/public-inputs.mjs +409 -0
  101. package/scripts/public-verification-inputs.mjs +112 -26
  102. package/scripts/public-verification-lane.mjs +1 -1
  103. package/scripts/published-surface-probe.mjs +34 -4
  104. package/scripts/qe/card-lane-gate.mjs +16 -1
  105. package/scripts/qe/session-start-gate.mjs +16 -1
  106. package/scripts/rebuild-gists-from-receipts.mjs +58 -78
  107. package/scripts/record-lesson.mjs +4 -1
  108. package/scripts/rehearse-corpus-pipeline.mjs +994 -0
  109. package/scripts/release-abort-stale.mjs +5 -1
  110. package/scripts/release-authority.mjs +104 -12
  111. package/scripts/release-channel-kind.mjs +86 -0
  112. package/scripts/release-convergence-watchdog.mjs +7 -2
  113. package/scripts/release-projection.mjs +177 -72
  114. package/scripts/release-transaction-provider.mjs +47 -10
  115. package/scripts/release-transaction.mjs +40 -11
  116. package/scripts/release.mjs +252 -17
  117. package/scripts/retrieval-canary.mjs +87 -0
  118. package/scripts/rvf-index-audit.mjs +573 -13
  119. package/scripts/rvf-wire.mjs +269 -0
  120. package/scripts/seal-gist-receipt.mjs +65 -0
  121. package/scripts/selfcheck.mjs +42 -21
  122. package/scripts/source-coverage.mjs +253 -24
  123. package/scripts/status-honesty.mjs +25 -0
  124. package/scripts/sync-census.mjs +0 -0
  125. package/scripts/sync-version.mjs +2 -0
  126. package/scripts/trismart.mjs +42 -0
  127. package/scripts/updater-manifest.mjs +162 -0
  128. package/scripts/verify-channels.mjs +17 -5
  129. package/scripts/wired-check.mjs +48 -10
  130. package/tri-smart-skill/QUICKSTART.md +37 -0
  131. package/tri-smart-skill/README.md +92 -0
  132. package/tri-smart-skill/install.cmd +14 -0
  133. package/tri-smart-skill/install.command +13 -0
  134. package/tri-smart-skill/install.mjs +51 -0
  135. package/tri-smart-skill/install.sh +9 -0
  136. package/tri-smart-skill/tri-smart/SKILL.md +90 -0
  137. package/tri-smart-skill/tri-smart/evals/evals.json +25 -0
  138. package/tri-smart-skill/tri-smart/references/protocol.md +25 -0
  139. package/tri-smart-skill/tri-smart/references/provider-cli.md +18 -0
  140. package/tri-smart-skill/tri-smart/scripts/review.mjs +154 -0
  141. package/tri-smart-skill/tri-smart/scripts/setup.mjs +97 -0
  142. package/tri-smart-skill/tri-smart/scripts/verify-access.mjs +107 -0
  143. package/scripts/corpus-seed-publish.mjs +0 -110
@@ -39,6 +39,7 @@ import os from 'node:os';
39
39
  import { spawnSync, execFileSync } from 'node:child_process';
40
40
  import { fileURLToPath, pathToFileURL } from 'node:url';
41
41
  import { NIGHTLY_LABEL, schedulerStatus } from '../plugin/scripts/nightly-scheduler.mjs';
42
+ import { oldestIncompleteProgress } from '../kb/shard-progress.mjs';
42
43
 
43
44
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
44
45
  const REGISTRY = process.env.WATCHDOG_REGISTRY || path.join(ROOT, 'config', 'scheduled-jobs.json');
@@ -51,6 +52,28 @@ export const MISSING = 'MISSING';
51
52
  export const NEVER_RAN = 'NEVER-RAN';
52
53
  export const STALE = 'STALE';
53
54
  export const FAILING = 'FAILING';
55
+ export const STALLED = 'STALLED';
56
+
57
+ /**
58
+ * Per-shard progress evidence for a job that declares `progressGlob` + `stallMinutes` in the
59
+ * registry (see kb/shard-progress.mjs, written by kb/forge-big.mjs's `embed`/`shard-all` modes).
60
+ *
61
+ * WHY THIS EXISTS (2026-09-11): a live wrapper pid proves the WRAPPER survived a run; it proves
62
+ * NOTHING about whether the work inside it is still moving — an 8-shard gists embed once sat at 0%
63
+ * CPU for six hours with `judge()`'s existing pid-liveness check reporting it OK the entire time
64
+ * (the pid genuinely was alive; it just was not doing anything). `job.stallMinutes` is deliberately
65
+ * independent of `job.maxAgeHours`/the 6h long-run branch below — a job stuck at 0% progress for 20
66
+ * minutes must be flagged well before its overall schedule budget or the long-run grace period would
67
+ * ever trip.
68
+ */
69
+ export function readJobProgress(job, { root = ROOT } = {}) {
70
+ if (!job.progressGlob) return null;
71
+ const full = path.join(root, job.progressGlob);
72
+ const dir = path.dirname(full);
73
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
74
+ const pattern = new RegExp(`^${path.basename(full).split('*').map(escapeRegExp).join('.*')}$`);
75
+ return oldestIncompleteProgress(dir, pattern);
76
+ }
54
77
 
55
78
  /** Labels currently loaded in launchd. A job that isn't here CANNOT fire, whatever its plist says. */
56
79
  export function loadedLabels(run = () => spawnSync('launchctl', ['list'], { encoding: 'utf8' }).stdout || '') {
@@ -67,7 +90,7 @@ export function loadedLabels(run = () => spawnSync('launchctl', ['list'], { enco
67
90
  * Judge one job from its receipt. `hb === null` means NO RECEIPT EXISTS — which is NEVER-RAN, never OK.
68
91
  * This single line is the whole lesson of 2026-07-13: absence of evidence is not evidence of health.
69
92
  */
70
- export function judge(job, hb, loaded, now) {
93
+ export function judge(job, hb, loaded, now, { root = ROOT } = {}) {
71
94
  if (!loaded) {
72
95
  return { state: MISSING, detail: 'declared in the registry but NOT LOADED in launchd — it can never fire' };
73
96
  }
@@ -80,6 +103,20 @@ export function judge(job, hb, loaded, now) {
80
103
  }
81
104
  const ageHours = (now - stamp) / HOUR;
82
105
 
106
+ // STALLED: checked BEFORE the long-run pid-liveness branch below, and independent of it — a live
107
+ // pid is not proof of progress. Only applies when the job declares a stall budget; absence of a
108
+ // progress file is never treated as a stall (the job may not have reached embedding yet).
109
+ if (hb.state === 'running' && job.stallMinutes) {
110
+ const progress = readJobProgress(job, { root });
111
+ if (progress) {
112
+ const staleMinutes = (now - progress.updatedAt) / 60_000;
113
+ if (staleMinutes > job.stallMinutes) {
114
+ return { state: STALLED, ageHours,
115
+ detail: `${progress.detail} has not advanced in ${staleMinutes.toFixed(0)}m — its stall budget is ${job.stallMinutes}m. The wrapper pid may be alive; the work is not.` };
116
+ }
117
+ }
118
+ }
119
+
83
120
  // Started and never finished? DERIVE it from process liveness, not wall-clock alone (2026-07-19):
84
121
  // a full corpus rebuild legitimately runs 12h+ (five changed repos = a long day), and the old
85
122
  // ">6h running ⇒ FAILING" rule false-alarmed on exactly that — a 13.5h nightly whose worker was
@@ -110,8 +147,12 @@ export function judge(job, hb, loaded, now) {
110
147
  if (hb.state === 'skipped') {
111
148
  return { state: NEVER_RAN, ageHours, detail: 'only a lock-skip receipt exists — no real run has ever recorded a result' };
112
149
  }
113
- if (hb.state === 'failed' || (typeof hb.exit_code === 'number' && hb.exit_code !== 0)) {
114
- return { state: FAILING, ageHours, detail: `last run FAILED with exit ${hb.exit_code} (${ageHours.toFixed(1)}h ago)` };
150
+ if (hb.state === 'failed' || hb.state === 'killed' || (typeof hb.exit_code === 'number' && hb.exit_code !== 0)) {
151
+ // job-heartbeat.sh distinguishes "failed" (plain non-zero exit) from "killed" (died to a
152
+ // signal — the wrapper's own trap, or a direct kill of the child; POSIX 128+signal) — surface
153
+ // which one it was rather than collapsing both into one undifferentiated exit code.
154
+ const how = hb.state === 'killed' ? `KILLED by signal ${hb.signal ?? '?'}` : `FAILED with exit ${hb.exit_code}`;
155
+ return { state: FAILING, ageHours, detail: `last run ${how} (${ageHours.toFixed(1)}h ago)` };
115
156
  }
116
157
  if (hb.state === 'running') {
117
158
  return { state: OK, ageHours, detail: `running right now (started ${ageHours.toFixed(1)}h ago)` };
@@ -153,7 +194,7 @@ export function checkAll(now, { registry = REGISTRY, loaded = loadedLabels(), hb
153
194
  const { jobs } = JSON.parse(fs.readFileSync(registry, 'utf8'));
154
195
  return jobs.map((job) => {
155
196
  const hb = readHeartbeat(job.label, hbDir) || readLegacyLog(job, root);
156
- const verdict = judge(job, hb, loaded.has(job.label), now);
197
+ const verdict = judge(job, hb, loaded.has(job.label), now, { root });
157
198
  if (hb?._tier2 && verdict.state === OK) verdict.detail += ' (via its log — no receipt yet; the next run writes one)';
158
199
  return { ...job, ...verdict };
159
200
  });
@@ -162,6 +203,22 @@ export function checkAll(now, { registry = REGISTRY, loaded = loadedLabels(), hb
162
203
  export function productSchedulerVerdict(status) {
163
204
  const base = { label: NIGHTLY_LABEL, what: 'Refreshes the installed Brain corpus and converges every detected host',
164
205
  schedule: 'daily 03:47', maxAgeHours: 30, required: true };
206
+ // A 'degraded' adapter whose only defect is a NON-ZERO LAST EXIT is a job that is loaded, verified
207
+ // and FIRED — the exact opposite of MISSING ("not loaded — it can never fire", top of this file).
208
+ // Its truth is the receipt. Measured 2026-09-12 against two FAILED receipts: this projected as
209
+ // MISSING with the detail "LaunchAgent is loaded and runner digest verified, but last exited 1" —
210
+ // a contradiction in one line, and the receipt's reason never surfaced.
211
+ if (status?.state === 'degraded' && Number.isInteger(status.lastExitCode) && status.lastExitCode !== 0) {
212
+ const run = status.runHealth || null;
213
+ if (run?.state === 'stale') return { ...base, state: STALE, detail: run.evidence };
214
+ if (!run || run.state === 'never-ran') {
215
+ return { ...base, state: FAILING, detail: `runner last exited ${status.lastExitCode} and left no receipt — it fired and died before recording a run` };
216
+ }
217
+ if (run.state === 'ok' || run.state === 'running') {
218
+ return { ...base, state: FAILING, detail: `runner last exited ${status.lastExitCode} although its latest receipt reads ${run.state} — the run after that receipt died without recording one (${run.evidence})` };
219
+ }
220
+ return { ...base, state: FAILING, detail: run.evidence };
221
+ }
165
222
  if (status?.state !== 'on') return { ...base, state: MISSING, detail: status?.evidence || 'scheduler is not registered' };
166
223
  const run = status.runHealth || { state: 'never-ran', evidence: 'No nightly refresh receipt exists yet.' };
167
224
  const mapped = run.state === 'ok' || run.state === 'running' ? OK