ruvnet-brain 4.7.20 → 4.7.22

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 (260) hide show
  1. package/README.md +2 -2
  2. package/bin/install.mjs +618 -104
  3. package/console/activity.js +122 -38
  4. package/kb/download-retry.mjs +93 -21
  5. package/kb/forge-guard-injection.mjs +277 -0
  6. package/kb/forge-update.mjs +166 -38
  7. package/kb/lifecycle-evidence-retention.mjs +151 -14
  8. package/kb/model-requirements.mjs +4 -1
  9. package/kb/refresh-run.mjs +175 -27
  10. package/kb/verify-citation.mjs +15 -2
  11. package/package.json +3 -1
  12. package/plugin/.claude-plugin/plugin.json +1 -1
  13. package/plugin/.codex-plugin/plugin.json +1 -1
  14. package/plugin/mcp/managed-cli-interface.mjs +16 -8
  15. package/plugin/scripts/adr-currency-gate.mjs +2 -1
  16. package/plugin/scripts/advisory-contract.mjs +21 -0
  17. package/plugin/scripts/advocacy-route.mjs +5 -4
  18. package/plugin/scripts/agentdb-recall-process.mjs +115 -5
  19. package/plugin/scripts/agentdb-recall-reader.mjs +44 -2
  20. package/plugin/scripts/agentdb-recall.mjs +49 -17
  21. package/plugin/scripts/automatic-update.mjs +9 -1
  22. package/plugin/scripts/brain-confirmation.mjs +2 -1
  23. package/plugin/scripts/brain-footprint.mjs +72 -11
  24. package/plugin/scripts/capability-registry.mjs +1 -1
  25. package/plugin/scripts/capacity-aware-parallel-work.mjs +2 -1
  26. package/plugin/scripts/codex-overnight-notice.mjs +33 -0
  27. package/plugin/scripts/completion-claim-evidence.mjs +241 -23
  28. package/plugin/scripts/continuation-gate.mjs +75 -11
  29. package/plugin/scripts/decision-gate.mjs +13 -63
  30. package/plugin/scripts/decision-outcomes.mjs +36 -0
  31. package/plugin/scripts/decision-recall-gate.mjs +40 -5
  32. package/plugin/scripts/decision-record.mjs +8 -3
  33. package/plugin/scripts/degradation-watch.mjs +2 -1
  34. package/plugin/scripts/developer-update-lock.mjs +172 -33
  35. package/plugin/scripts/developer-update-owner.mjs +8 -5
  36. package/plugin/scripts/developer-update-policy.mjs +4 -1
  37. package/plugin/scripts/developer-update.mjs +155 -53
  38. package/plugin/scripts/doc-currency.mjs +2 -16
  39. package/plugin/scripts/duplicate-gate.mjs +2 -1
  40. package/plugin/scripts/entrypoint.mjs +34 -0
  41. package/plugin/scripts/footprint-io.mjs +135 -8
  42. package/plugin/scripts/grok-hook-adapter.mjs +2 -1
  43. package/plugin/scripts/ground-ruvnet.sh +6 -3
  44. package/plugin/scripts/grounding-answer.mjs +2 -1
  45. package/plugin/scripts/grounding-code-projection.mjs +2 -1
  46. package/plugin/scripts/grounding-substance.mjs +2 -1
  47. package/plugin/scripts/grounding-turn-gate.mjs +2 -2
  48. package/plugin/scripts/grounding-turn-mark.mjs +2 -2
  49. package/plugin/scripts/hook-context-budget.mjs +2 -1
  50. package/plugin/scripts/hook-input.mjs +2 -2
  51. package/plugin/scripts/hook-shim.mjs +9 -2
  52. package/plugin/scripts/host-update.mjs +29 -5
  53. package/plugin/scripts/identifier-preflight.mjs +2 -1
  54. package/plugin/scripts/kb-copy-proof.mjs +57 -9
  55. package/plugin/scripts/learn-capture.mjs +2 -1
  56. package/plugin/scripts/learning-store.mjs +62 -16
  57. package/plugin/scripts/lesson-bridge.mjs +2 -2
  58. package/plugin/scripts/lesson-gate.mjs +7 -39
  59. package/plugin/scripts/lesson-promote.mjs +83 -22
  60. package/plugin/scripts/lesson-scope.mjs +51 -0
  61. package/plugin/scripts/lesson-store.mjs +1 -1
  62. package/plugin/scripts/md-stamp.mjs +2 -1
  63. package/plugin/scripts/native-turn-transcript.mjs +98 -6
  64. package/plugin/scripts/nightly-scheduler.mjs +10 -5
  65. package/plugin/scripts/package-recommender.mjs +2 -2
  66. package/plugin/scripts/project-store-resolver.mjs +19 -0
  67. package/plugin/scripts/routing-outcome-capture.mjs +2 -1
  68. package/plugin/scripts/ruflo-bin.mjs +14 -6
  69. package/plugin/scripts/ruflo-memory-hooks.mjs +157 -19
  70. package/plugin/scripts/session-snapshot-hook.mjs +25 -5
  71. package/plugin/scripts/session-start-core.mjs +7 -16
  72. package/plugin/scripts/session-start-health.mjs +98 -10
  73. package/plugin/scripts/session-start-issue-alert.mjs +63 -0
  74. package/plugin/scripts/session-start-update-plane.mjs +15 -1
  75. package/plugin/scripts/signal-watch.mjs +2 -1
  76. package/plugin/scripts/spend-guard.mjs +2 -1
  77. package/plugin/scripts/substitution-wall.mjs +2 -1
  78. package/plugin/scripts/turn-outcome-capture.mjs +7 -3
  79. package/plugin/scripts/unprompted-runtime.mjs +20 -3
  80. package/plugin/scripts/update-apply.mjs +186 -15
  81. package/plugin/skills/release-proof/scripts/release-proof.mjs +2 -1
  82. package/plugin/skills/ruvnet-brain/PLAYBOOK.md +2 -2
  83. package/plugin/skills/ruvnet-brain/SKILL.md +3 -2
  84. package/scripts/adr-072-completion.mjs +2 -1
  85. package/scripts/agentdb-context.mjs +2 -1
  86. package/scripts/agentdb-fleet-doctor.mjs +30 -8
  87. package/scripts/approved-runtime.mjs +2 -1
  88. package/scripts/architecture-review-lock.mjs +2 -1
  89. package/scripts/ascii-drift.mjs +2 -1
  90. package/scripts/brain-latency-50.mjs +2 -1
  91. package/scripts/brain-novice-50.mjs +2 -16
  92. package/scripts/brain-score.mjs +13 -2
  93. package/scripts/build-bundle.mjs +2 -1
  94. package/scripts/build-concepts.mjs +2 -1
  95. package/scripts/candidate-ci-receipt.mjs +2 -1
  96. package/scripts/candidate-host-evidence.mjs +2 -1
  97. package/scripts/card-from-source.mjs +2 -1
  98. package/scripts/ci/warm-brain-models.mjs +2 -1
  99. package/scripts/claims-verify.mjs +7 -3
  100. package/scripts/claude-controlled-terminal.mjs +2 -1
  101. package/scripts/claude-terminal-mod.mjs +2 -1
  102. package/scripts/code-release-corpus.mjs +2 -1
  103. package/scripts/codex-boot-surface-proof.mjs +208 -0
  104. package/scripts/codex-hook-trust-reconcile.mjs +67 -1
  105. package/scripts/codex-hook-trust.mjs +40 -1
  106. package/scripts/codex-hook-wrapper-history.mjs +2 -1
  107. package/scripts/codex-host-execution-proof.mjs +2 -1
  108. package/scripts/completion-claim-replay.mjs +2 -1
  109. package/scripts/console-engine.mjs +8 -3
  110. package/scripts/corpus-canary.mjs +2 -1
  111. package/scripts/corpus-candidate.mjs +2 -2
  112. package/scripts/corpus-coverage-sidecar.mjs +2 -1
  113. package/scripts/corpus-dispatch-decision.mjs +2 -1
  114. package/scripts/corpus-dispatch-receipt.mjs +2 -1
  115. package/scripts/corpus-next-seed.mjs +2 -1
  116. package/scripts/corpus-qa.mjs +2 -1
  117. package/scripts/corpus-reconcile.mjs +2 -2
  118. package/scripts/corpus-watchdog.mjs +2 -1
  119. package/scripts/count-chunks.mjs +2 -1
  120. package/scripts/customer-state-matrix.mjs +2 -1
  121. package/scripts/derive-passage-content-map.mjs +2 -1
  122. package/scripts/development-push-check.mjs +2 -1
  123. package/scripts/dispatch-receipt.mjs +2 -1
  124. package/scripts/doc-currency.mjs +2 -1
  125. package/scripts/dream-issue-gate.mjs +2 -1
  126. package/scripts/dual-host-deliberation.mjs +2 -16
  127. package/scripts/dual-host-suggest.mjs +2 -16
  128. package/scripts/eval-brain.mjs +7 -3
  129. package/scripts/execution-policy.mjs +2 -1
  130. package/scripts/execution-preflight.mjs +2 -1
  131. package/scripts/falsify.mjs +2 -1
  132. package/scripts/fix-metaharness-memretrieve.mjs +2 -1
  133. package/scripts/fix-workstream.mjs +2 -1
  134. package/scripts/full-hints.mjs +2 -1
  135. package/scripts/full-suite-gate.mjs +2 -1
  136. package/scripts/grok-host.mjs +68 -0
  137. package/scripts/hook-qualify-core.mjs +3 -1
  138. package/scripts/hook-qualify.mjs +2 -1
  139. package/scripts/hook-retirement-check.mjs +2 -1
  140. package/scripts/host-registry.mjs +2 -1
  141. package/scripts/independent-review-receipt.mjs +2 -1
  142. package/scripts/ingest-new-repos.mjs +2 -1
  143. package/scripts/ingest-repo.mjs +12 -2
  144. package/scripts/integration-evidence.mjs +2 -1
  145. package/scripts/issue-fix.mjs +7 -24
  146. package/scripts/issue-watch.mjs +116 -40
  147. package/scripts/job-heartbeat.sh +54 -19
  148. package/scripts/key-canary.mjs +9 -3
  149. package/scripts/latency-to-surface.mjs +2 -1
  150. package/scripts/learning-replay-cli.mjs +97 -19
  151. package/scripts/learning-replay-execution.mjs +2 -0
  152. package/scripts/learning-replay-fixture.mjs +3 -0
  153. package/scripts/learning-replay-proof.mjs +14 -13
  154. package/scripts/learning-replay.mjs +3 -3
  155. package/scripts/learnings.mjs +2 -1
  156. package/scripts/lesson-ratify.mjs +88 -40
  157. package/scripts/loop-checkpoint.mjs +2 -1
  158. package/scripts/metaharness-receipts.mjs +2 -1
  159. package/scripts/model-catalog.mjs +2 -1
  160. package/scripts/model-currency-evidence.mjs +6 -4
  161. package/scripts/model-currency.mjs +33 -3
  162. package/scripts/model-native-catalog.mjs +2 -1
  163. package/scripts/model-router-agent-hook.mjs +2 -1
  164. package/scripts/model-router-dispatch.mjs +2 -1
  165. package/scripts/model-router-engine.mjs +2 -1
  166. package/scripts/model-router-outcome.mjs +2 -1
  167. package/scripts/model-router-setup.mjs +2 -1
  168. package/scripts/model-routing-eval.mjs +2 -1
  169. package/scripts/model-routing-gateway.mjs +2 -1
  170. package/scripts/model-routing-launchers.mjs +4 -1
  171. package/scripts/model-terminal-gateway.mjs +2 -1
  172. package/scripts/model-terminal-launchers.mjs +2 -1
  173. package/scripts/model-weekly-analyst.mjs +2 -1
  174. package/scripts/model-weekly-cycle.mjs +2 -1
  175. package/scripts/model-weekly-qualification.mjs +2 -1
  176. package/scripts/nightly-gists.sh +26 -20
  177. package/scripts/nightly-two-run-proof.mjs +2 -1
  178. package/scripts/nightly-watchdog.mjs +158 -47
  179. package/scripts/no-silent-substitution.mjs +2 -1
  180. package/scripts/notify.sh +11 -6
  181. package/scripts/ntfy-inbox.mjs +41 -18
  182. package/scripts/onboarding-console.mjs +123 -23
  183. package/scripts/oracle/abstain-threshold-sweep.mjs +2 -1
  184. package/scripts/oracle/abstain-trace.mjs +2 -1
  185. package/scripts/oracle/doc2query-generate.mjs +2 -1
  186. package/scripts/oracle/doc2query-reach.mjs +2 -1
  187. package/scripts/oracle/judge-train.mjs +2 -1
  188. package/scripts/oracle/need-set-split.mjs +2 -1
  189. package/scripts/oracle/produce-questions.mjs +2 -16
  190. package/scripts/oracle/repo-recall.mjs +2 -2
  191. package/scripts/oracle/retrieval-accuracy.mjs +2 -2
  192. package/scripts/oracle/sona-query-adapter-eval.mjs +2 -1
  193. package/scripts/oracle/source-tree.mjs +2 -15
  194. package/scripts/oracle/source-units.mjs +2 -16
  195. package/scripts/oracle/spike-run.mjs +2 -16
  196. package/scripts/oracle/validate-labels.mjs +2 -16
  197. package/scripts/org-repo-count.mjs +2 -1
  198. package/scripts/package-cards.mjs +2 -1
  199. package/scripts/prepublication-evidence.mjs +2 -1
  200. package/scripts/private-overlay.mjs +2 -1
  201. package/scripts/product-integrity-contract.mjs +2 -1
  202. package/scripts/protected-release-invocation.mjs +2 -1
  203. package/scripts/public-verification-abandon.mjs +2 -1
  204. package/scripts/public-verification-aggregate.mjs +2 -1
  205. package/scripts/public-verification-finalizer.mjs +2 -1
  206. package/scripts/public-verification-inputs.mjs +2 -1
  207. package/scripts/public-verification-lane.mjs +2 -1
  208. package/scripts/publication-receipt.mjs +2 -1
  209. package/scripts/published-surface-probe.mjs +2 -1
  210. package/scripts/qe/card-lane-gate.mjs +2 -16
  211. package/scripts/qe/session-start-gate.mjs +2 -16
  212. package/scripts/qe/ux-suite.mjs +2 -1
  213. package/scripts/qualified-candidate-check.mjs +2 -1
  214. package/scripts/rebuild-gists-from-receipts.mjs +2 -1
  215. package/scripts/recall-latency-probe.mjs +48 -0
  216. package/scripts/recommendation-eval.mjs +2 -1
  217. package/scripts/recommendation-floor.mjs +2 -1
  218. package/scripts/recommendation-judge-score.mjs +2 -1
  219. package/scripts/recommendation-real-host-score.mjs +2 -1
  220. package/scripts/recommendation-real-host.mjs +2 -1
  221. package/scripts/refresh-capability-only-store.mjs +2 -1
  222. package/scripts/refresh-model-catalog.mjs +2 -1
  223. package/scripts/rehearse-corpus-pipeline.mjs +2 -1
  224. package/scripts/release-authority.mjs +2 -1
  225. package/scripts/release-evidence-aggregate.mjs +2 -1
  226. package/scripts/release-payload.mjs +2 -1
  227. package/scripts/release-projection.mjs +2 -1
  228. package/scripts/release-proof.mjs +2 -1
  229. package/scripts/release-qualification-contract.mjs +82 -28
  230. package/scripts/release-qualification.mjs +8 -1
  231. package/scripts/release-vector.mjs +2 -1
  232. package/scripts/restore-local-ingests.mjs +2 -1
  233. package/scripts/retrieval-canary.mjs +2 -1
  234. package/scripts/route-cheap.mjs +2 -1
  235. package/scripts/route-gold-rank.mjs +2 -1
  236. package/scripts/route-index-memory.mjs +2 -1
  237. package/scripts/route-latency-warm.mjs +2 -1
  238. package/scripts/router-utilization.mjs +2 -1
  239. package/scripts/routing-flywheel.mjs +2 -1
  240. package/scripts/run-operational-benchmark.mjs +2 -1
  241. package/scripts/run-operational-benchmark.v3.mjs +2 -1
  242. package/scripts/rvf-index-audit.mjs +2 -16
  243. package/scripts/seal-gist-receipt.mjs +2 -1
  244. package/scripts/security-guidance-codex-compat.mjs +2 -1
  245. package/scripts/selfcheck.mjs +2 -1
  246. package/scripts/signal-watch.mjs +2 -1
  247. package/scripts/source-coverage.mjs +2 -1
  248. package/scripts/stabilization-receipt.mjs +2 -1
  249. package/scripts/stamp-sweep.mjs +2 -1
  250. package/scripts/status-honesty.mjs +2 -1
  251. package/scripts/sync-commands.mjs +2 -2
  252. package/scripts/top100-benchmark.mjs +2 -1
  253. package/scripts/top100-corpus.mjs +2 -1
  254. package/scripts/user-model-hook-install.mjs +2 -1
  255. package/scripts/user-model-prompt-hook.mjs +2 -1
  256. package/scripts/verify-bundle.mjs +3 -1
  257. package/scripts/verify-model-catalog.mjs +2 -1
  258. package/scripts/version.mjs +2 -1
  259. package/scripts/wired-check.mjs +13 -5
  260. package/scripts/worktree-integrity.mjs +2 -2
@@ -24,6 +24,7 @@ import { PUBLIC_GENERATIONS_FILE, generationLedgerBytes, projectPublicGeneration
24
24
  releaseCoverageGenerationFor, validateCoverageDirectory } from '../plugin/scripts/coverage-integrity.mjs';
25
25
  import { validatePublicInventory } from './public-inventory.mjs';
26
26
  import { readRvfGenerations } from './rvf-generation.mjs';
27
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
27
28
 
28
29
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
29
30
  const sha256 = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex');
@@ -238,7 +239,7 @@ export function projectReleaseFromAssets({ corpusCoverage, assetsDir, version, s
238
239
  return releaseBase;
239
240
  }
240
241
 
241
- if (((() => { try { return process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })())) {
242
+ if (isDirectInvocation(import.meta.url)) {
242
243
  const arg = (name, fallback = null) => { const i = process.argv.indexOf(name); return i >= 0 ? process.argv[i + 1] : fallback; };
243
244
  try {
244
245
  const corpusFile = path.resolve(arg('--corpus', path.join(ROOT, 'data', 'source-coverage.json')));
@@ -3,7 +3,8 @@ export * from '../plugin/skills/release-proof/scripts/release-proof.mjs';
3
3
  import { main } from '../plugin/skills/release-proof/scripts/release-proof.mjs';
4
4
  import path from 'node:path';
5
5
  import { pathToFileURL } from 'node:url';
6
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
6
7
 
7
- if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) {
8
+ if (isDirectInvocation(import.meta.url)) {
8
9
  process.exitCode = main(process.argv.slice(2));
9
10
  }
@@ -11,8 +11,8 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
11
11
  "reason": "Allowed channels and immutable Claude artifact paths reject downgrades, ambiguous registry records, changed bytes, extra active resources and escape paths; Console success requires the exact launched source closure. POSIX owner fixtures additionally enforce original-prefix installs, existing-tool-only policy, shared locks and source-bound scheduler receipts",
12
12
  "files": ["tests/unit/developer-update-policy-portable.test.mjs", "tests/unit/plugin-artifact-proof.test.mjs", "tests/unit/console-suite-update.test.mjs", "tests/unit/developer-update-scheduled-receipt.test.mjs"],
13
13
  "platformFiles": {
14
- "linux": ["tests/unit/developer-update.test.mjs", "tests/unit/developer-update-codex-launcher.test.mjs"],
15
- "macos": ["tests/unit/developer-update.test.mjs", "tests/unit/developer-update-codex-launcher.test.mjs"]
14
+ "linux": ["tests/unit/developer-update.test.mjs", "tests/unit/developer-update-codex-launcher.test.mjs", "tests/unit/developer-update-lock-reclaim.test.mjs", "tests/unit/developer-update-lock-release-race.test.mjs", "tests/unit/developer-update-stage-isolation.test.mjs"],
15
+ "macos": ["tests/unit/developer-update.test.mjs", "tests/unit/developer-update-codex-launcher.test.mjs", "tests/unit/developer-update-lock-reclaim.test.mjs", "tests/unit/developer-update-lock-release-race.test.mjs", "tests/unit/developer-update-stage-isolation.test.mjs"]
16
16
  }
17
17
  },
18
18
  {
@@ -22,16 +22,20 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
22
22
  },
23
23
  {
24
24
  "id": "honest-currency-lesson-and-metrics-evidence",
25
- "reason": "Foreign KB roots remain isolated; panel currency derives from measured completion rather than checkout time; exact lesson readback binds this shell-free write; public metrics never fabricate performance or a competing product score",
26
- "files": ["tests/unit/forge-currency-selected-root.test.mjs", "tests/unit/brain-score-producer.test.mjs", "tests/unit/brain-grade-groundtruth-timestamp.test.mjs", "tests/unit/record-lesson.test.mjs", "tests/unit/lesson-presentation-budget.test.mjs", "tests/unit/metrics-truth.test.mjs", "tests/unit/issue-watch-retry.test.mjs"]
25
+ "reason": "Foreign KB roots remain isolated; panel currency derives from measured completion rather than checkout time; exact lesson readback binds this shell-free write; public metrics never fabricate performance or a competing product score; SessionStart reports a host-sync-only failure after a passed knowledge update separately from knowledge currency",
26
+ "files": ["tests/unit/forge-currency-selected-root.test.mjs", "tests/unit/brain-score-producer.test.mjs", "tests/unit/brain-grade-groundtruth-timestamp.test.mjs", "tests/unit/record-lesson.test.mjs", "tests/unit/lesson-presentation-budget.test.mjs", "tests/unit/metrics-truth.test.mjs", "tests/unit/issue-watch-retry.test.mjs", "tests/unit/session-start-knowledge-currency.test.mjs"],
27
+ "platformFiles": {
28
+ "linux": ["tests/unit/session-start-knowledge-auto-update.test.mjs", "tests/unit/claims-verify.test.mjs", "tests/unit/capability-registry.test.mjs"],
29
+ "macos": ["tests/unit/session-start-knowledge-auto-update.test.mjs", "tests/unit/claims-verify.test.mjs", "tests/unit/capability-registry.test.mjs"]
30
+ }
27
31
  },
28
32
  {
29
33
  "id": "owner-alerting-volume-and-trust",
30
34
  "reason": "Alerts page on change, not repeat; an undelivered page is retried; overrunning jobs and their whole process tree stop; people's issues page once at SLA with one daily summary; the ntfy inbox never turns message text into instructions",
31
35
  "files": ["tests/unit/issue-watch-paging.test.mjs"],
32
36
  "platformFiles": {
33
- "linux": ["tests/unit/job-heartbeat-alerting.test.mjs", "tests/unit/ntfy-inbox.test.mjs"],
34
- "macos": ["tests/unit/job-heartbeat-alerting.test.mjs", "tests/unit/ntfy-inbox.test.mjs"]
37
+ "linux": ["tests/unit/job-heartbeat-alerting.test.mjs", "tests/unit/ntfy-inbox.test.mjs", "tests/unit/brain-alarm-paging.test.mjs", "tests/unit/ntfy-alerts-filter.test.mjs", "tests/unit/api-spend-watchdog-transition.test.mjs", "tests/unit/issue-watch-unreadable-exit.test.mjs", "tests/unit/nightly-watchdog.test.mjs", "tests/unit/ntfy-delivery.test.mjs"],
38
+ "macos": ["tests/unit/job-heartbeat-alerting.test.mjs", "tests/unit/ntfy-inbox.test.mjs", "tests/unit/brain-alarm-paging.test.mjs", "tests/unit/ntfy-alerts-filter.test.mjs", "tests/unit/api-spend-watchdog-transition.test.mjs", "tests/unit/issue-watch-unreadable-exit.test.mjs", "tests/unit/nightly-watchdog.test.mjs", "tests/unit/ntfy-delivery.test.mjs"]
35
39
  }
36
40
  },
37
41
  {
@@ -39,8 +43,8 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
39
43
  "reason": "Captured owner policy never falls back on read failures; installed-only automation avoids npx; transient GET and body failures retry without weakening trust; POSIX executable aliases retain interpreter identity",
40
44
  "files": ["tests/unit/automatic-update.test.mjs", "tests/unit/download-retry.test.mjs"],
41
45
  "platformFiles": {
42
- "linux": ["tests/unit/automatic-update-node-alias.test.mjs"],
43
- "macos": ["tests/unit/automatic-update-node-alias.test.mjs"]
46
+ "linux": ["tests/unit/automatic-update-node-alias.test.mjs", "tests/unit/host-update-knowledge-exit.test.mjs"],
47
+ "macos": ["tests/unit/automatic-update-node-alias.test.mjs", "tests/unit/host-update-knowledge-exit.test.mjs"]
44
48
  }
45
49
  },
46
50
  {
@@ -57,8 +61,8 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
57
61
  "reason": "Explicit document meaning requests retain corroboration; literal searches stay silent; POSIX complete-write exemptions preserve executable and managed-store grounding",
58
62
  "files": ["tests/unit/advocacy-route.test.mjs", "tests/unit/advocacy-catalog.test.mjs", "tests/unit/card-lane.test.mjs"],
59
63
  "platformFiles": {
60
- "linux": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs"],
61
- "macos": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs"]
64
+ "linux": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs", "tests/unit/package-recommender.test.mjs", "tests/unit/write-gate-policy.test.mjs"],
65
+ "macos": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs", "tests/unit/package-recommender.test.mjs"]
62
66
  }
63
67
  },
64
68
  {
@@ -68,11 +72,12 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
68
72
  },
69
73
  {
70
74
  "id": "canonical-learning-capture",
71
- "reason": "Fixed metadata capture, canonical scope, consent, exact readback and loud refusal retain privacy; learning is handed straight to ruflo memory store with no local queue",
75
+ "reason": "Fixed metadata capture, canonical scope, consent, exact readback and loud refusal retain privacy; learning is handed straight to ruflo memory store with no local queue; the SessionEnd checkpoint plans for Claude Code's real 1.5 s budget and detaches instead of being cancelled",
72
76
  "files": [
73
77
  "tests/unit/learn-capture-project-root.test.mjs",
74
78
  "tests/unit/learn-capture-redaction.test.mjs",
75
- "tests/unit/learner-scope-agreement.test.mjs"
79
+ "tests/unit/learner-scope-agreement.test.mjs",
80
+ "tests/unit/claude-session-end-budget.test.mjs"
76
81
  ]
77
82
  },
78
83
  {
@@ -111,7 +116,11 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
111
116
  "tests/unit/protected-release-workflow.test.mjs",
112
117
  "tests/unit/agentic-qe-early-public.test.mjs",
113
118
  "tests/unit/release-evidence-dag.test.mjs"
114
- ]
119
+ ],
120
+ "platformFiles": {
121
+ "linux": ["tests/unit/self-update-publish-branch-guard.test.mjs", "tests/unit/pre-push-worktree-root.test.mjs", "tests/unit/wired-baseline-classification.test.mjs"],
122
+ "macos": ["tests/unit/self-update-publish-branch-guard.test.mjs", "tests/unit/pre-push-worktree-root.test.mjs", "tests/unit/wired-baseline-classification.test.mjs"]
123
+ }
115
124
  },
116
125
  {
117
126
  "id": "public-verification",
@@ -127,7 +136,7 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
127
136
  },
128
137
  {
129
138
  "id": "safe-install-update",
130
- "reason": "Installation and update preserve prior and private state and reject invalid dependencies; the Codex hook bridge a retained Brain generation shipped upgrades reversibly while edited, linked, shared or foreign-owned bridges stay preserved",
139
+ "reason": "Installation and update preserve prior and private state and reject invalid dependencies; the Codex hook bridge a retained Brain generation shipped upgrades reversibly while edited, linked, shared or foreign-owned bridges stay preserved; a failed host sync rolls the Console runtime back and records its reason",
131
140
  "files": [
132
141
  "tests/unit/automatic-hook-retirement.test.mjs",
133
142
  "tests/unit/codex-wrapper-upgrade-ownership.test.mjs",
@@ -136,11 +145,13 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
136
145
  "tests/unit/forge-update-archive-digest.test.mjs",
137
146
  "tests/unit/kb-copy-proof-legacy-sidecars.test.mjs",
138
147
  "tests/unit/kb-copy-proof-unknown-content.test.mjs",
139
- "tests/unit/user-model-hook-install.test.mjs"
148
+ "tests/unit/user-model-hook-install.test.mjs",
149
+ "tests/unit/console-runtime-transaction.test.mjs",
150
+ "tests/unit/install-update-exit-semantics.test.mjs"
140
151
  ],
141
152
  "platformFiles": {
142
- "linux": ["tests/unit/codex-wrapper-upgrade-ownership-links.test.mjs"],
143
- "macos": ["tests/unit/codex-wrapper-upgrade-ownership-links.test.mjs"]
153
+ "linux": ["tests/unit/codex-wrapper-upgrade-ownership-links.test.mjs", "tests/unit/forge-update-signal.test.mjs", "tests/unit/console-runtime-replacement-posix.test.mjs", "tests/unit/update-apply-lock-identity.test.mjs", "tests/unit/update-apply-lock-takeover-race.test.mjs", "tests/integration/install-update-signals.test.mjs", "tests/unit/forge-guard-injection-log-location.test.mjs", "tests/unit/installer-sibling-imports-packaged.test.mjs", "tests/unit/npm-pack-json.test.mjs", "tests/unit/npm-tarball-codex.test.mjs", "tests/integration/pack-completeness.test.mjs"],
154
+ "macos": ["tests/unit/codex-wrapper-upgrade-ownership-links.test.mjs", "tests/unit/forge-update-signal.test.mjs", "tests/unit/console-runtime-replacement-posix.test.mjs", "tests/unit/update-apply-lock-identity.test.mjs", "tests/unit/update-apply-lock-takeover-race.test.mjs", "tests/integration/install-update-signals.test.mjs", "tests/unit/forge-guard-injection-log-location.test.mjs", "tests/unit/installer-sibling-imports-packaged.test.mjs", "tests/unit/npm-pack-json.test.mjs", "tests/unit/npm-tarball-codex.test.mjs", "tests/integration/pack-completeness.test.mjs", "tests/unit/spend-guard-install.test.mjs"]
144
155
  }
145
156
  },
146
157
  {
@@ -196,11 +207,12 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
196
207
  "tests/unit/model-native-catalog.test.mjs",
197
208
  "tests/unit/user-model-prompt-hook.test.mjs",
198
209
  "tests/unit/model-routing-policy-promotion.test.mjs",
199
- "tests/unit/codex-hook-trust.test.mjs"
210
+ "tests/unit/codex-hook-trust.test.mjs",
211
+ "tests/unit/model-catalog-refresh-workflow.test.mjs"
200
212
  ],
201
213
  "platformFiles": {
202
- "linux": ["tests/unit/model-weekly-cycle-native-stub.test.mjs", "tests/unit/goldie-weekly-path.test.mjs"],
203
- "macos": ["tests/unit/model-weekly-cycle-native-stub.test.mjs", "tests/unit/goldie-weekly-path.test.mjs"]
214
+ "linux": ["tests/unit/model-weekly-cycle-native-stub.test.mjs", "tests/unit/goldie-weekly-path.test.mjs", "tests/unit/model-currency-live-capture.test.mjs"],
215
+ "macos": ["tests/unit/model-weekly-cycle-native-stub.test.mjs", "tests/unit/goldie-weekly-path.test.mjs", "tests/unit/model-currency-live-capture.test.mjs"]
204
216
  }
205
217
  },
206
218
  {
@@ -240,25 +252,45 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
240
252
  },
241
253
  {
242
254
  "id": "lossless-lifecycle-retention",
243
- "reason": "Evidence compaction preserves tokens, private state and atomic transaction recovery",
255
+ "reason": "Evidence compaction preserves tokens, private state and atomic transaction recovery; an abandoned atomic receipt temporary is reclaimed or preserved, never a permanent blocker",
244
256
  "files": [
245
257
  "tests/unit/lifecycle-evidence-retention.test.mjs",
258
+ "tests/unit/refresh-run.test.mjs",
259
+ "tests/unit/refresh-run-stale-reclaim.test.mjs",
246
260
  "tests/unit/update-storage-transaction.test.mjs"
247
- ]
261
+ ],
262
+ "platformFiles": {
263
+ "linux": ["tests/unit/refresh-run-takeover-race.test.mjs"],
264
+ "macos": ["tests/unit/refresh-run-takeover-race.test.mjs"]
265
+ }
266
+ },
267
+ {
268
+ "id": "nightly-knowledge-jobs",
269
+ "reason": "The gists nightly re-embeds over a stale store, scales its stall budget with the slowest batch and reports its error paths; a stalled shard is detected; a reader never deadlocks the refresh",
270
+ "files": ["tests/unit/forge-big-stall.test.mjs"],
271
+ "platformFiles": {
272
+ "linux": ["tests/integration/ingest-gists.test.mjs", "tests/integration/nightly-gists-error-paths.test.mjs"],
273
+ "macos": ["tests/integration/ingest-gists.test.mjs", "tests/integration/nightly-gists-error-paths.test.mjs"]
274
+ }
248
275
  },
249
276
  {
250
277
  "id": "causal-learning-proof",
251
278
  "reason": "Recorded learning evidence rejects forged, absent and mismatched causal transcripts",
252
279
  "files": [
253
280
  "tests/unit/learning-replay-proof.test.mjs"
254
- ]
281
+ ],
282
+ "platformFiles": {
283
+ "linux": ["tests/unit/learning-replay-workflow-step.test.mjs"],
284
+ "macos": ["tests/unit/learning-replay-workflow-step.test.mjs"]
285
+ }
255
286
  },
256
287
  {
257
288
  "id": "qualification-topology",
258
289
  "reason": "Release promotion consumes qualified exact-source receipts and preserves required contexts",
259
290
  "files": [
260
291
  "tests/unit/qualify-once-workflow.test.mjs",
261
- "tests/unit/architecture-review-lock.test.mjs"
292
+ "tests/unit/architecture-review-lock.test.mjs",
293
+ "tests/unit/canonical-qa-preflight-parity.test.mjs"
262
294
  ]
263
295
  },
264
296
  {
@@ -291,10 +323,13 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
291
323
  ],
292
324
  "platformFiles": {
293
325
  "linux": [
294
- "tests/unit/hook-shim.test.mjs"
326
+ "tests/unit/hook-shim.test.mjs",
327
+ "tests/unit/continuation-gate-quiet-default.test.mjs"
295
328
  ],
296
329
  "macos": [
297
- "tests/unit/hook-shim.test.mjs"
330
+ "tests/unit/hook-shim.test.mjs",
331
+ "tests/unit/continuation-gate-quiet-default.test.mjs",
332
+ "tests/unit/hook-qualify.test.mjs"
298
333
  ]
299
334
  }
300
335
  },
@@ -310,6 +345,15 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
310
345
  "reason": "Complete outbox tails replay and accepted pending journal events survive capacity pressure without silent deletion",
311
346
  "files": [
312
347
  ]
348
+ },
349
+ {
350
+ "id": "open-issue-fixes-4-7-22",
351
+ "reason": "Reporter-filed defects stay fixed: completion evidence never binds a masked or negated check and a masked check is an advisory, not a false 'no check ran' stop; the boot surface of a recovered Codex host is proven per changed path; Console fleet and lesson counts match by store identity and never show unknown as zero; one project-scope rule is shared by the lesson gate and the Console; a refused or unreadable memory restore is reported as such and an aborted Ruflo call leaves no child process",
352
+ "files": [],
353
+ "platformFiles": {
354
+ "linux": ["tests/unit/continuation-gate-codex-transcript.test.mjs", "tests/unit/codex-boot-surface-proof.test.mjs", "tests/unit/console-activity-fleet-dedupe.test.mjs", "tests/unit/console-activity-identity.test.mjs", "tests/unit/console-activity-lessons.test.mjs", "tests/unit/lesson-gate.test.mjs", "tests/unit/ruflo-memory-session.test.mjs"],
355
+ "macos": ["tests/unit/continuation-gate-codex-transcript.test.mjs", "tests/unit/codex-boot-surface-proof.test.mjs", "tests/unit/console-activity-fleet-dedupe.test.mjs", "tests/unit/console-activity-identity.test.mjs", "tests/unit/console-activity-lessons.test.mjs", "tests/unit/lesson-gate.test.mjs", "tests/unit/ruflo-memory-session.test.mjs"]
356
+ }
313
357
  }
314
358
  ],
315
359
  "integration": [
@@ -358,10 +402,11 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
358
402
  },
359
403
  {
360
404
  "id": "installed-routing-and-hook-trust",
361
- "reason": "Actual installer update converges managed routing while preserving private overrides; POSIX archive and native metadata subprocess probes bind authorized hook trust to verified released bytes and preserve concurrent or disabled owner state",
405
+ "reason": "Actual installer update converges managed routing while preserving private overrides; POSIX archive and native metadata subprocess probes bind authorized hook trust to verified released bytes and preserve concurrent or disabled owner state; a running shared Codex app-server is reloaded after a plugin or trust change without granting approval (#492)",
362
406
  "files": [
363
407
  "tests/unit/model-router-update-convergence.test.mjs",
364
- "tests/unit/codex-hook-trust-reconcile.test.mjs"
408
+ "tests/unit/codex-hook-trust-reconcile.test.mjs",
409
+ "tests/unit/codex-shared-host-refresh.test.mjs"
365
410
  ]
366
411
  },
367
412
  {
@@ -405,6 +450,15 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
405
450
  "reason": "POSIX non-root permission refusal, capacity-pressure reporting and recovery preserve all accepted pending continuity events",
406
451
  "files": [
407
452
  ]
453
+ },
454
+ {
455
+ "id": "open-issue-fixes-4-7-22-integration",
456
+ "reason": "A named release over an existing install moves, skips truthfully or warns on a downgrade instead of reporting a false lookup failure; the Ruflo memory hooks honour the absolute deadline and abort, kill the whole child process group, and never report a refused or partly unreadable restore as restored",
457
+ "files": [],
458
+ "platformFiles": {
459
+ "linux": ["tests/integration/stale-install-trap.test.mjs", "tests/integration/ruflo-memory-hooks.test.mjs"],
460
+ "macos": ["tests/integration/stale-install-trap.test.mjs", "tests/integration/ruflo-memory-hooks.test.mjs"]
461
+ }
408
462
  }
409
463
  ]
410
464
  });
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url';
7
7
  import { digest } from './coverage-integrity.mjs';
8
8
  import { sourceIdentity } from './qa-contract.mjs';
9
9
  import { RELEASE_REQUIREMENTS } from './release-qualification-contract.mjs';
10
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
10
11
 
11
12
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
12
13
  const PLATFORM = { linux: 'linux', darwin: 'macos', win32: 'windows' }[process.platform];
@@ -124,6 +125,12 @@ export function runQualification({ suite = 'source', platform = PLATFORM, report
124
125
  }
125
126
  const sourceAfter = sourceIdentity(root);
126
127
  const sourceStable = source.digest === sourceAfter.digest;
128
+ if (!sourceStable && !failure) {
129
+ // Name what the run changed: "source changed" with no file is undiagnosable on a runner we cannot open.
130
+ const git = (args) => spawnSync('git', args, { cwd: root, encoding: 'utf8' }).stdout.split('\n').filter(Boolean);
131
+ const changed = [...git(['ls-files', '--others', '--exclude-standard']), ...git(['diff', '--name-only'])].slice(0, 20);
132
+ failure = `qualification changed the checkout: ${changed.join(', ') || 'unknown files'}`;
133
+ }
127
134
  const receipt = { schemaVersion: 1, kind: 'ruvnet-brain-release-qualification', suite, platform, checkoutRoot: path.resolve(root),
128
135
  source, sourceAfter, sourceStable, status: !failure && sourceStable ? 'PASS' : 'FAIL',
129
136
  requirements: plan.requirements.map((entry) => entry.id), contractSha256: plan.contractSha256,
@@ -135,7 +142,7 @@ export function runQualification({ suite = 'source', platform = PLATFORM, report
135
142
  return receipt;
136
143
  }
137
144
 
138
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
145
+ if (isDirectInvocation(import.meta.url)) {
139
146
  const args = process.argv.slice(2);
140
147
  const value = (flag, fallback) => { const i = args.indexOf(flag); return i < 0 ? fallback : args[i + 1]; };
141
148
  try {
@@ -22,6 +22,7 @@ import fs from 'node:fs';
22
22
  import path from 'node:path';
23
23
  import { fileURLToPath } from 'node:url';
24
24
  import { performance } from 'node:perf_hooks';
25
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
25
26
 
26
27
  export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
27
28
 
@@ -319,7 +320,7 @@ export function formatVectorOutput(result, { json = false } = {}) {
319
320
  return `${lines.join('\n')}\n`;
320
321
  }
321
322
 
322
- if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
323
+ if (isDirectInvocation(import.meta.url)) {
323
324
  const timings = process.argv.includes('--timings');
324
325
  const emitTiming = (phase, data) => process.stderr.write(`${JSON.stringify({
325
326
  schema: 'ruvnet-brain.release-vector.timing', phase, ...data,
@@ -43,6 +43,7 @@ import path from 'node:path';
43
43
  import { execFileSync } from 'node:child_process';
44
44
  import { fileURLToPath } from 'node:url';
45
45
  import { storeRoot, storesAt, rootNeverMaterialized } from '../kb/store-root.mjs';
46
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
46
47
 
47
48
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
48
49
  const LEDGER = path.join(ROOT, 'kb', 'local-ingests.json');
@@ -76,7 +77,7 @@ export function classify({ ledgerFile = LEDGER, root = storeRoot() } = {}) {
76
77
  }
77
78
 
78
79
  const isMain = (() => {
79
- try { return process.argv[1] && fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url); }
80
+ try { return isDirectInvocation(import.meta.url); }
80
81
  catch { return false; }
81
82
  })();
82
83
 
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url';
8
8
  import { canonicalJson, digest, eligibleRepositoryStanding, validateCoverageLedger } from './coverage-integrity.mjs';
9
9
  import { fixtureDenominator } from './fixture-denominator.mjs';
10
10
  import { passageMatches } from './retrieval-passage-identity.mjs';
11
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
11
12
 
12
13
  // Both release phases resolve against an explicit installed context, never the checkout.
13
14
  export async function resolveInstalledCanaryCitation({ kbDir, matched, expected, passageFileDigests = new Map(), contentMap }) {
@@ -740,7 +741,7 @@ export function auditOracleCoverageFromFiles({ coverageFile, oracleFile, exempti
740
741
  return { ...inventory, oracleSourceCommit: queryEvidence.sourceCommit, strictAncestor };
741
742
  }
742
743
 
743
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
744
+ if (isDirectInvocation(import.meta.url)) {
744
745
  try {
745
746
  const argv = process.argv.slice(2);
746
747
  if (argv.includes('--audit')) {
@@ -28,6 +28,7 @@ import os from 'node:os';
28
28
  import { spawnSync } from 'node:child_process';
29
29
  import { fileURLToPath, pathToFileURL } from 'node:url';
30
30
  import { loadRuntimePreferences, runtimeChildEnv } from '../plugin/scripts/runtime-preferences.mjs';
31
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
31
32
 
32
33
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
33
34
 
@@ -207,4 +208,4 @@ function main() {
207
208
  console.log(receiptLine(args.model, costs));
208
209
  }
209
210
 
210
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) main();
211
+ if (isDirectInvocation(import.meta.url)) main();
@@ -29,6 +29,7 @@ import fs from 'node:fs';
29
29
  import path from 'node:path';
30
30
  import { fileURLToPath, pathToFileURL } from 'node:url';
31
31
  import { wilson, repoMatchesExpected } from './eval-brain.mjs';
32
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
32
33
 
33
34
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
34
35
 
@@ -151,6 +152,6 @@ async function main() {
151
152
  console.log(JSON.stringify(brief, null, 1));
152
153
  }
153
154
 
154
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
155
+ if (isDirectInvocation(import.meta.url)) {
155
156
  await main();
156
157
  }
@@ -13,6 +13,7 @@
13
13
  import fs from 'node:fs';
14
14
  import path from 'node:path';
15
15
  import { fileURLToPath, pathToFileURL } from 'node:url';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
18
19
  const arg = (name) => { const i = process.argv.indexOf(name); return i >= 0 ? process.argv[i + 1] : undefined; };
@@ -48,4 +49,4 @@ async function main() {
48
49
  console.log(JSON.stringify({ impl: rel.startsWith('..') ? '<impl>' : rel, kbBuild, stores: repos.length, coldMs, warmMs, retained: retained(before, after) }));
49
50
  }
50
51
 
51
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
52
+ if (isDirectInvocation(import.meta.url)) await main();
@@ -22,6 +22,7 @@ import fs from 'node:fs';
22
22
  import os from 'node:os';
23
23
  import path from 'node:path';
24
24
  import { fileURLToPath, pathToFileURL } from 'node:url';
25
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
25
26
 
26
27
  export const percentile = (xs, p) => {
27
28
  const s = [...xs].sort((a, b) => a - b);
@@ -120,4 +121,4 @@ async function main() {
120
121
  process.exit(0);
121
122
  }
122
123
 
123
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
124
+ if (isDirectInvocation(import.meta.url)) await main();
@@ -179,4 +179,5 @@ export function mainUtil() {
179
179
 
180
180
  import { fileURLToPath } from 'node:url';
181
181
  import path from 'node:path';
182
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) mainUtil();
182
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
183
+ if (isDirectInvocation(import.meta.url)) mainUtil();
@@ -55,6 +55,7 @@ import {
55
55
  import { effectivePrices, loadLabelledRows, OUTCOMES } from './metaharness-router.mjs';
56
56
  import { assertEvolutionAllowed } from './metaharness-gate.mjs';
57
57
  import { loadCatalog, applyProfile, loadProfile } from './model-router-engine.mjs';
58
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
58
59
 
59
60
  // ─── HARD CAPS — the self-DDoS fence. Clamped, never raised by flags. ─────────────────────────────
60
61
  export const HARD_MAX_GENERATIONS = 6;
@@ -599,7 +600,7 @@ async function main() {
599
600
  }
600
601
  }
601
602
 
602
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
603
+ if (isDirectInvocation(import.meta.url)) {
603
604
  main().catch((e) => {
604
605
  process.stderr.write(`routing-flywheel: ${e.stack || e.message}\n`);
605
606
  process.exit(1);
@@ -14,6 +14,7 @@ import {
14
14
  latencyDistribution,
15
15
  verifyFixtureSourceSupport,
16
16
  } from '../evals/operational-benchmark.v2.mjs';
17
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
17
18
 
18
19
  const execFileAsync = promisify(execFile);
19
20
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
@@ -146,6 +147,6 @@ async function main() {
146
147
  if (report.passed !== report.total || report.unavailable.length) process.exitCode = 1;
147
148
  }
148
149
 
149
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
150
+ if (isDirectInvocation(import.meta.url)) {
150
151
  main().catch((error) => { console.error(error.stack || error.message); process.exitCode = 2; });
151
152
  }
@@ -16,6 +16,7 @@ import {
16
16
  preflightOperationalOracle,
17
17
  } from '../evals/operational-benchmark.v3.mjs';
18
18
  import { verifyGrounding as evaluatorVerifyGrounding } from '../kb/verify-citation.mjs';
19
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
19
20
 
20
21
  const execFileAsync = promisify(execFile);
21
22
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
@@ -189,6 +190,6 @@ async function main() {
189
190
  if (!report.qualificationPass) process.exitCode = 1;
190
191
  }
191
192
 
192
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
193
+ if (isDirectInvocation(import.meta.url)) {
193
194
  main().catch((error) => { console.error(error.stack || error.message); process.exitCode = 2; });
194
195
  }
@@ -37,6 +37,7 @@ import {
37
37
  writeRvfGeneration,
38
38
  } from './rvf-generation.mjs';
39
39
  import { metricFromId, readRvfStoredVectors } from './rvf-wire.mjs';
40
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
40
41
 
41
42
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
42
43
  export const RVF_HNSW_THRESHOLD = 1024;
@@ -675,22 +676,7 @@ async function main() {
675
676
  if (failed.length) process.exitCode = 1;
676
677
  }
677
678
 
678
- // Entry-point guard. Compares REALPATHS on both sides: path.resolve() normalizes a path but does
679
- // NOT follow symlinks, while import.meta.url IS symlink-resolved by Node. Through a symlink (npm bin
680
- // shims, wrapper scripts, and every os.tmpdir() path on macOS) the two sides disagree, so main()
681
- // never runs -- and because nothing throws, the process exits 0. A silent exit 0 is indistinguishable
682
- // from "ran, found nothing", which is how prepareCorpusCandidate once reported SUCCESS with no
683
- // archive on disk. Reproduced live 2026-07-27; pinned by tests/unit/entrypoint-symlink.test.mjs.
684
- function isDirectInvocation() {
685
- try {
686
- if (!process.argv[1]) return false;
687
- return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url));
688
- } catch {
689
- return false;
690
- }
691
- }
692
-
693
- if (isDirectInvocation()) {
679
+ if (isDirectInvocation(import.meta.url)) {
694
680
  main().catch((error) => {
695
681
  console.error(error.stack || error.message);
696
682
  process.exitCode = 1;
@@ -13,6 +13,7 @@ import fs from 'node:fs';
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { observeSourceUniverse } from './source-coverage.mjs';
15
15
  import { buildGistAggregate } from './gist-receipts.mjs';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  export const REPO_KB = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'kb');
18
19
 
@@ -57,7 +58,7 @@ async function main(argv = process.argv.slice(2)) {
57
58
  return 0;
58
59
  }
59
60
 
60
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
61
+ if (isDirectInvocation(import.meta.url)) {
61
62
  main().then((code) => { process.exitCode = code; }).catch((error) => {
62
63
  console.error(`[seal-gist-receipt] ${error.message}`);
63
64
  process.exitCode = 1;
@@ -14,6 +14,7 @@ import path from 'node:path';
14
14
  import os from 'node:os';
15
15
  import crypto from 'node:crypto';
16
16
  import { fileURLToPath } from 'node:url';
17
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
17
18
 
18
19
  export const COMPATIBILITY = Object.freeze({
19
20
  version: '2.0.9', nativeContract: 'Codex 0.160.0 PostToolUse',
@@ -128,7 +129,7 @@ export function repairSecurityGuidance({ codexHome = process.env.CODEX_HOME || p
128
129
  return { ...receipt, status: 'patched', backup, patchedSha256: sha256(readRegular(target).bytes) };
129
130
  }
130
131
 
131
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
132
+ if (isDirectInvocation(import.meta.url)) {
132
133
  try {
133
134
  const args = process.argv.slice(2);
134
135
  let codexHome; let apply = false;
@@ -67,6 +67,7 @@ import { fileURLToPath } from 'node:url';
67
67
  // THE canonical continuity policy — the same module bin/install.mjs and scripts/hook-retirement-check.mjs
68
68
  // import. Never re-implement this predicate locally; see the note below the imports.
69
69
  import { isAllowedContinuityRegistration } from '../plugin/scripts/continuity-hook-policy.mjs';
70
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
70
71
 
71
72
  // ── contract constants (ADR-053 §2.5 / §2.3) ────────────────────────────────────────────────────
72
73
  export const STDOUT_CAP_BYTES = 4096; // it lands in the user's context window
@@ -739,7 +740,7 @@ export function formatVerdict(result, { color = null } = {}) {
739
740
  }
740
741
 
741
742
  // ── CLI ─────────────────────────────────────────────────────────────────────────────────────────
742
- if (process.argv[1] && (() => { try { return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })()) {
743
+ if (isDirectInvocation(import.meta.url)) {
743
744
  const noSecurity = process.argv.includes('--no-security');
744
745
  const json = process.argv.includes('--json');
745
746
  const result = await selfCheck({ security: !noSecurity });
@@ -47,6 +47,7 @@ import os from 'node:os';
47
47
  import { spawnSync } from 'node:child_process';
48
48
  import { fileURLToPath, pathToFileURL } from 'node:url';
49
49
  import { assessCiGate } from './ci-verdict.mjs';
50
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
50
51
 
51
52
  const BRAIN_HOME = process.env.RUVNET_BRAIN_HOME || path.join(os.homedir(), '.cache', 'ruvnet-brain');
52
53
  const SIGNAL_DIR = process.env.RUVNET_SIGNAL_DIR || path.join(BRAIN_HOME, 'external-signals');
@@ -164,7 +165,7 @@ function main() {
164
165
  }
165
166
 
166
167
  function isMain() {
167
- try { return process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href; }
168
+ try { return isDirectInvocation(import.meta.url); }
168
169
  catch { return false; }
169
170
  }
170
171
 
@@ -10,6 +10,7 @@ import { canonicalJson, coverageGenerationFor, digest, validateGistAggregateRece
10
10
  import { repositoryNames } from '../kb/card-lane.mjs';
11
11
  import { rootNeverMaterialized, storeRoot } from '../kb/store-root.mjs';
12
12
  import { isTransientText, retryTransient, sleepSync } from './transient-gh.mjs';
13
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
13
14
 
14
15
  export { canonicalJson, digest } from './coverage-integrity.mjs';
15
16
 
@@ -759,6 +760,6 @@ export async function main(argv = process.argv.slice(2)) {
759
760
  return 0;
760
761
  }
761
762
 
762
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
763
+ if (isDirectInvocation(import.meta.url)) {
763
764
  process.exitCode = await main();
764
765
  }
@@ -8,6 +8,7 @@ import path from 'node:path';
8
8
  import { spawnSync } from 'node:child_process';
9
9
  import { pathToFileURL } from 'node:url';
10
10
  import { evaluateStabilizationCandidateReceipt } from './release-proof.mjs';
11
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
11
12
 
12
13
  const readJson = (file) => JSON.parse(fs.readFileSync(file, 'utf8'));
13
14
  const sha256 = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
@@ -115,4 +116,4 @@ export function main(args = process.argv.slice(2)) {
115
116
  }
116
117
  }
117
118
 
118
- if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) process.exitCode = main();
119
+ if (isDirectInvocation(import.meta.url)) process.exitCode = main();