ruvnet-brain 4.7.20 → 4.7.21

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 (250) hide show
  1. package/README.md +2 -2
  2. package/bin/install.mjs +494 -97
  3. package/kb/download-retry.mjs +93 -21
  4. package/kb/forge-guard-injection.mjs +277 -0
  5. package/kb/forge-update.mjs +166 -38
  6. package/kb/lifecycle-evidence-retention.mjs +151 -14
  7. package/kb/model-requirements.mjs +4 -1
  8. package/kb/refresh-run.mjs +175 -27
  9. package/kb/verify-citation.mjs +15 -2
  10. package/package.json +3 -1
  11. package/plugin/.claude-plugin/plugin.json +1 -1
  12. package/plugin/.codex-plugin/plugin.json +1 -1
  13. package/plugin/mcp/managed-cli-interface.mjs +16 -8
  14. package/plugin/scripts/adr-currency-gate.mjs +2 -1
  15. package/plugin/scripts/advisory-contract.mjs +21 -0
  16. package/plugin/scripts/advocacy-route.mjs +5 -4
  17. package/plugin/scripts/agentdb-recall.mjs +15 -5
  18. package/plugin/scripts/automatic-update.mjs +9 -1
  19. package/plugin/scripts/brain-confirmation.mjs +2 -1
  20. package/plugin/scripts/brain-footprint.mjs +72 -11
  21. package/plugin/scripts/capability-registry.mjs +1 -1
  22. package/plugin/scripts/capacity-aware-parallel-work.mjs +2 -1
  23. package/plugin/scripts/codex-overnight-notice.mjs +33 -0
  24. package/plugin/scripts/completion-claim-evidence.mjs +56 -12
  25. package/plugin/scripts/continuation-gate.mjs +28 -9
  26. package/plugin/scripts/decision-gate.mjs +13 -63
  27. package/plugin/scripts/decision-outcomes.mjs +36 -0
  28. package/plugin/scripts/decision-recall-gate.mjs +40 -5
  29. package/plugin/scripts/decision-record.mjs +8 -3
  30. package/plugin/scripts/degradation-watch.mjs +2 -1
  31. package/plugin/scripts/developer-update-lock.mjs +172 -33
  32. package/plugin/scripts/developer-update-owner.mjs +8 -5
  33. package/plugin/scripts/developer-update-policy.mjs +4 -1
  34. package/plugin/scripts/developer-update.mjs +155 -53
  35. package/plugin/scripts/doc-currency.mjs +2 -16
  36. package/plugin/scripts/duplicate-gate.mjs +2 -1
  37. package/plugin/scripts/entrypoint.mjs +34 -0
  38. package/plugin/scripts/footprint-io.mjs +135 -8
  39. package/plugin/scripts/grok-hook-adapter.mjs +2 -1
  40. package/plugin/scripts/ground-ruvnet.sh +6 -3
  41. package/plugin/scripts/grounding-answer.mjs +2 -1
  42. package/plugin/scripts/grounding-code-projection.mjs +2 -1
  43. package/plugin/scripts/grounding-substance.mjs +2 -1
  44. package/plugin/scripts/grounding-turn-gate.mjs +2 -2
  45. package/plugin/scripts/grounding-turn-mark.mjs +2 -2
  46. package/plugin/scripts/hook-context-budget.mjs +2 -1
  47. package/plugin/scripts/hook-input.mjs +2 -2
  48. package/plugin/scripts/hook-shim.mjs +9 -2
  49. package/plugin/scripts/host-update.mjs +29 -5
  50. package/plugin/scripts/identifier-preflight.mjs +2 -1
  51. package/plugin/scripts/kb-copy-proof.mjs +57 -9
  52. package/plugin/scripts/learn-capture.mjs +2 -1
  53. package/plugin/scripts/learning-store.mjs +62 -16
  54. package/plugin/scripts/lesson-bridge.mjs +2 -2
  55. package/plugin/scripts/lesson-promote.mjs +83 -22
  56. package/plugin/scripts/md-stamp.mjs +2 -1
  57. package/plugin/scripts/native-turn-transcript.mjs +98 -6
  58. package/plugin/scripts/nightly-scheduler.mjs +10 -5
  59. package/plugin/scripts/package-recommender.mjs +2 -2
  60. package/plugin/scripts/project-store-resolver.mjs +19 -0
  61. package/plugin/scripts/routing-outcome-capture.mjs +2 -1
  62. package/plugin/scripts/session-snapshot-hook.mjs +24 -4
  63. package/plugin/scripts/session-start-core.mjs +5 -15
  64. package/plugin/scripts/session-start-health.mjs +97 -10
  65. package/plugin/scripts/session-start-issue-alert.mjs +63 -0
  66. package/plugin/scripts/session-start-update-plane.mjs +15 -1
  67. package/plugin/scripts/signal-watch.mjs +2 -1
  68. package/plugin/scripts/spend-guard.mjs +2 -1
  69. package/plugin/scripts/substitution-wall.mjs +2 -1
  70. package/plugin/scripts/turn-outcome-capture.mjs +7 -3
  71. package/plugin/scripts/unprompted-runtime.mjs +20 -3
  72. package/plugin/scripts/update-apply.mjs +186 -15
  73. package/plugin/skills/release-proof/scripts/release-proof.mjs +2 -1
  74. package/plugin/skills/ruvnet-brain/PLAYBOOK.md +2 -2
  75. package/plugin/skills/ruvnet-brain/SKILL.md +3 -2
  76. package/scripts/adr-072-completion.mjs +2 -1
  77. package/scripts/agentdb-context.mjs +2 -1
  78. package/scripts/agentdb-fleet-doctor.mjs +30 -8
  79. package/scripts/approved-runtime.mjs +2 -1
  80. package/scripts/architecture-review-lock.mjs +2 -1
  81. package/scripts/ascii-drift.mjs +2 -1
  82. package/scripts/brain-latency-50.mjs +2 -1
  83. package/scripts/brain-novice-50.mjs +2 -16
  84. package/scripts/brain-score.mjs +13 -2
  85. package/scripts/build-bundle.mjs +2 -1
  86. package/scripts/build-concepts.mjs +2 -1
  87. package/scripts/candidate-ci-receipt.mjs +2 -1
  88. package/scripts/candidate-host-evidence.mjs +2 -1
  89. package/scripts/card-from-source.mjs +2 -1
  90. package/scripts/ci/warm-brain-models.mjs +2 -1
  91. package/scripts/claims-verify.mjs +7 -3
  92. package/scripts/claude-controlled-terminal.mjs +2 -1
  93. package/scripts/claude-terminal-mod.mjs +2 -1
  94. package/scripts/code-release-corpus.mjs +2 -1
  95. package/scripts/codex-hook-trust-reconcile.mjs +67 -1
  96. package/scripts/codex-hook-trust.mjs +40 -1
  97. package/scripts/codex-hook-wrapper-history.mjs +2 -1
  98. package/scripts/codex-host-execution-proof.mjs +2 -1
  99. package/scripts/completion-claim-replay.mjs +2 -1
  100. package/scripts/console-engine.mjs +8 -3
  101. package/scripts/corpus-canary.mjs +2 -1
  102. package/scripts/corpus-candidate.mjs +2 -2
  103. package/scripts/corpus-coverage-sidecar.mjs +2 -1
  104. package/scripts/corpus-dispatch-decision.mjs +2 -1
  105. package/scripts/corpus-dispatch-receipt.mjs +2 -1
  106. package/scripts/corpus-next-seed.mjs +2 -1
  107. package/scripts/corpus-qa.mjs +2 -1
  108. package/scripts/corpus-reconcile.mjs +2 -2
  109. package/scripts/corpus-watchdog.mjs +2 -1
  110. package/scripts/count-chunks.mjs +2 -1
  111. package/scripts/customer-state-matrix.mjs +2 -1
  112. package/scripts/derive-passage-content-map.mjs +2 -1
  113. package/scripts/development-push-check.mjs +2 -1
  114. package/scripts/dispatch-receipt.mjs +2 -1
  115. package/scripts/doc-currency.mjs +2 -1
  116. package/scripts/dream-issue-gate.mjs +2 -1
  117. package/scripts/dual-host-deliberation.mjs +2 -16
  118. package/scripts/dual-host-suggest.mjs +2 -16
  119. package/scripts/eval-brain.mjs +7 -3
  120. package/scripts/execution-policy.mjs +2 -1
  121. package/scripts/execution-preflight.mjs +2 -1
  122. package/scripts/falsify.mjs +2 -1
  123. package/scripts/fix-metaharness-memretrieve.mjs +2 -1
  124. package/scripts/fix-workstream.mjs +2 -1
  125. package/scripts/full-hints.mjs +2 -1
  126. package/scripts/full-suite-gate.mjs +2 -1
  127. package/scripts/grok-host.mjs +68 -0
  128. package/scripts/hook-qualify-core.mjs +3 -1
  129. package/scripts/hook-qualify.mjs +2 -1
  130. package/scripts/hook-retirement-check.mjs +2 -1
  131. package/scripts/host-registry.mjs +2 -1
  132. package/scripts/independent-review-receipt.mjs +2 -1
  133. package/scripts/ingest-new-repos.mjs +2 -1
  134. package/scripts/ingest-repo.mjs +12 -2
  135. package/scripts/integration-evidence.mjs +2 -1
  136. package/scripts/issue-fix.mjs +7 -24
  137. package/scripts/issue-watch.mjs +116 -40
  138. package/scripts/job-heartbeat.sh +54 -19
  139. package/scripts/key-canary.mjs +9 -3
  140. package/scripts/latency-to-surface.mjs +2 -1
  141. package/scripts/learning-replay-cli.mjs +97 -19
  142. package/scripts/learning-replay-execution.mjs +2 -0
  143. package/scripts/learning-replay-fixture.mjs +3 -0
  144. package/scripts/learning-replay-proof.mjs +14 -13
  145. package/scripts/learning-replay.mjs +3 -3
  146. package/scripts/learnings.mjs +2 -1
  147. package/scripts/lesson-ratify.mjs +88 -40
  148. package/scripts/loop-checkpoint.mjs +2 -1
  149. package/scripts/metaharness-receipts.mjs +2 -1
  150. package/scripts/model-catalog.mjs +2 -1
  151. package/scripts/model-currency-evidence.mjs +6 -4
  152. package/scripts/model-currency.mjs +33 -3
  153. package/scripts/model-native-catalog.mjs +2 -1
  154. package/scripts/model-router-agent-hook.mjs +2 -1
  155. package/scripts/model-router-dispatch.mjs +2 -1
  156. package/scripts/model-router-engine.mjs +2 -1
  157. package/scripts/model-router-outcome.mjs +2 -1
  158. package/scripts/model-router-setup.mjs +2 -1
  159. package/scripts/model-routing-eval.mjs +2 -1
  160. package/scripts/model-routing-gateway.mjs +2 -1
  161. package/scripts/model-routing-launchers.mjs +4 -1
  162. package/scripts/model-terminal-gateway.mjs +2 -1
  163. package/scripts/model-terminal-launchers.mjs +2 -1
  164. package/scripts/model-weekly-analyst.mjs +2 -1
  165. package/scripts/model-weekly-cycle.mjs +2 -1
  166. package/scripts/model-weekly-qualification.mjs +2 -1
  167. package/scripts/nightly-gists.sh +26 -20
  168. package/scripts/nightly-two-run-proof.mjs +2 -1
  169. package/scripts/nightly-watchdog.mjs +158 -47
  170. package/scripts/no-silent-substitution.mjs +2 -1
  171. package/scripts/notify.sh +11 -6
  172. package/scripts/ntfy-inbox.mjs +41 -18
  173. package/scripts/onboarding-console.mjs +47 -8
  174. package/scripts/oracle/abstain-threshold-sweep.mjs +2 -1
  175. package/scripts/oracle/abstain-trace.mjs +2 -1
  176. package/scripts/oracle/doc2query-generate.mjs +2 -1
  177. package/scripts/oracle/doc2query-reach.mjs +2 -1
  178. package/scripts/oracle/judge-train.mjs +2 -1
  179. package/scripts/oracle/need-set-split.mjs +2 -1
  180. package/scripts/oracle/produce-questions.mjs +2 -16
  181. package/scripts/oracle/repo-recall.mjs +2 -2
  182. package/scripts/oracle/retrieval-accuracy.mjs +2 -2
  183. package/scripts/oracle/sona-query-adapter-eval.mjs +2 -1
  184. package/scripts/oracle/source-tree.mjs +2 -15
  185. package/scripts/oracle/source-units.mjs +2 -16
  186. package/scripts/oracle/spike-run.mjs +2 -16
  187. package/scripts/oracle/validate-labels.mjs +2 -16
  188. package/scripts/org-repo-count.mjs +2 -1
  189. package/scripts/package-cards.mjs +2 -1
  190. package/scripts/prepublication-evidence.mjs +2 -1
  191. package/scripts/private-overlay.mjs +2 -1
  192. package/scripts/product-integrity-contract.mjs +2 -1
  193. package/scripts/protected-release-invocation.mjs +2 -1
  194. package/scripts/public-verification-abandon.mjs +2 -1
  195. package/scripts/public-verification-aggregate.mjs +2 -1
  196. package/scripts/public-verification-finalizer.mjs +2 -1
  197. package/scripts/public-verification-inputs.mjs +2 -1
  198. package/scripts/public-verification-lane.mjs +2 -1
  199. package/scripts/publication-receipt.mjs +2 -1
  200. package/scripts/published-surface-probe.mjs +2 -1
  201. package/scripts/qe/card-lane-gate.mjs +2 -16
  202. package/scripts/qe/session-start-gate.mjs +2 -16
  203. package/scripts/qe/ux-suite.mjs +2 -1
  204. package/scripts/qualified-candidate-check.mjs +2 -1
  205. package/scripts/rebuild-gists-from-receipts.mjs +2 -1
  206. package/scripts/recommendation-eval.mjs +2 -1
  207. package/scripts/recommendation-floor.mjs +2 -1
  208. package/scripts/recommendation-judge-score.mjs +2 -1
  209. package/scripts/recommendation-real-host-score.mjs +2 -1
  210. package/scripts/recommendation-real-host.mjs +2 -1
  211. package/scripts/refresh-capability-only-store.mjs +2 -1
  212. package/scripts/refresh-model-catalog.mjs +2 -1
  213. package/scripts/rehearse-corpus-pipeline.mjs +2 -1
  214. package/scripts/release-authority.mjs +2 -1
  215. package/scripts/release-evidence-aggregate.mjs +2 -1
  216. package/scripts/release-payload.mjs +2 -1
  217. package/scripts/release-projection.mjs +2 -1
  218. package/scripts/release-proof.mjs +2 -1
  219. package/scripts/release-qualification-contract.mjs +64 -28
  220. package/scripts/release-qualification.mjs +8 -1
  221. package/scripts/release-vector.mjs +2 -1
  222. package/scripts/restore-local-ingests.mjs +2 -1
  223. package/scripts/retrieval-canary.mjs +2 -1
  224. package/scripts/route-cheap.mjs +2 -1
  225. package/scripts/route-gold-rank.mjs +2 -1
  226. package/scripts/route-index-memory.mjs +2 -1
  227. package/scripts/route-latency-warm.mjs +2 -1
  228. package/scripts/router-utilization.mjs +2 -1
  229. package/scripts/routing-flywheel.mjs +2 -1
  230. package/scripts/run-operational-benchmark.mjs +2 -1
  231. package/scripts/run-operational-benchmark.v3.mjs +2 -1
  232. package/scripts/rvf-index-audit.mjs +2 -16
  233. package/scripts/seal-gist-receipt.mjs +2 -1
  234. package/scripts/security-guidance-codex-compat.mjs +2 -1
  235. package/scripts/selfcheck.mjs +2 -1
  236. package/scripts/signal-watch.mjs +2 -1
  237. package/scripts/source-coverage.mjs +2 -1
  238. package/scripts/stabilization-receipt.mjs +2 -1
  239. package/scripts/stamp-sweep.mjs +2 -1
  240. package/scripts/status-honesty.mjs +2 -1
  241. package/scripts/sync-commands.mjs +2 -2
  242. package/scripts/top100-benchmark.mjs +2 -1
  243. package/scripts/top100-corpus.mjs +2 -1
  244. package/scripts/user-model-hook-install.mjs +2 -1
  245. package/scripts/user-model-prompt-hook.mjs +2 -1
  246. package/scripts/verify-bundle.mjs +3 -1
  247. package/scripts/verify-model-catalog.mjs +2 -1
  248. package/scripts/version.mjs +2 -1
  249. package/scripts/wired-check.mjs +11 -5
  250. package/scripts/worktree-integrity.mjs +2 -2
@@ -52,6 +52,7 @@ import os from 'node:os';
52
52
  import path from 'node:path';
53
53
  import { fileURLToPath } from 'node:url';
54
54
  import { fireHook, resolveInstalledSurface, readInstalledRegistrations } from '../selfcheck.mjs';
55
+ import { isDirectInvocation } from '../../plugin/scripts/entrypoint.mjs';
55
56
 
56
57
  const HERE = path.dirname(fileURLToPath(import.meta.url));
57
58
  export const REPO_ROOT = path.resolve(HERE, '../..');
@@ -225,20 +226,5 @@ async function main() {
225
226
  process.exit(1);
226
227
  }
227
228
 
228
- // Entry-point guard. Compares REALPATHS on both sides: path.resolve() normalizes a path but does
229
- // NOT follow symlinks, while import.meta.url IS symlink-resolved by Node. Through a symlink (npm bin
230
- // shims, wrapper scripts, and every os.tmpdir() path on macOS) the two sides disagree, so main()
231
- // never runs -- and because nothing throws, the process exits 0. A silent exit 0 is indistinguishable
232
- // from "ran, found nothing", which is how prepareCorpusCandidate once reported SUCCESS with no
233
- // archive on disk. Reproduced live 2026-07-27; pinned by tests/unit/entrypoint-symlink.test.mjs.
234
- function isDirectInvocation() {
235
- try {
236
- if (!process.argv[1]) return false;
237
- return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url));
238
- } catch {
239
- return false;
240
- }
241
- }
242
-
243
- const invokedDirectly = isDirectInvocation();
229
+ const invokedDirectly = isDirectInvocation(import.meta.url);
244
230
  if (invokedDirectly) main();
@@ -33,6 +33,7 @@ import { runCommandProbe } from '../../tests/ux/command-probe.mjs';
33
33
  import { runCardLaneGate } from './card-lane-gate.mjs';
34
34
  import { runSessionStartGate } from './session-start-gate.mjs';
35
35
  import { automaticHookRetirementStatus } from '../../bin/install.mjs';
36
+ import { isDirectInvocation } from '../../plugin/scripts/entrypoint.mjs';
36
37
 
37
38
  const HERE = path.dirname(fileURLToPath(import.meta.url));
38
39
  const RENDER_PROBE = path.resolve(HERE, '../../tests/ux/render-probe.mjs');
@@ -394,7 +395,7 @@ export async function runUxSuite() {
394
395
  throw error;
395
396
  }
396
397
 
397
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
398
+ if (isDirectInvocation(import.meta.url)) {
398
399
  runUxSuite().catch((e) => {
399
400
  if (!e.receipt) console.error(' ux-suite crashed:', e.message);
400
401
  process.exit(e.receipt ? 1 : 2);
@@ -10,6 +10,7 @@ import { evaluateCandidateReceipt } from './release-proof.mjs';
10
10
  import { aggregateEvidence } from './release-evidence-aggregate.mjs';
11
11
  import { payloadIdFor } from './release-payload.mjs';
12
12
  import { canonicalJson } from './release-transaction.mjs';
13
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
13
14
 
14
15
  const REPO = 'stuinfla/ruvnet-brain';
15
16
  const WORKFLOW = '.github/workflows/release-candidate-preflight.yml';
@@ -109,7 +110,7 @@ export async function checkQualifiedCandidate({ sha, requiredCheck, timeoutMs =
109
110
  await pause(Math.min(pollMs, remaining));
110
111
  }
111
112
  }
112
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
113
+ if (isDirectInvocation(import.meta.url)) {
113
114
  try {
114
115
  if (process.env.GITHUB_REPOSITORY !== REPO) throw new Error('unexpected qualification repository');
115
116
  const args = process.argv.slice(2), options = {};
@@ -25,6 +25,7 @@ import {
25
25
  sealGistReceipt,
26
26
  sealGistReceiptSet,
27
27
  } from './gist-receipts.mjs';
28
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
28
29
 
29
30
  export { buildGistAggregate, paragraphChunks, provenanceBanner, rawUrlFor };
30
31
 
@@ -263,7 +264,7 @@ export async function main(argv = process.argv.slice(2), {
263
264
  return 0;
264
265
  }
265
266
 
266
- if (((() => { try { return process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })())) {
267
+ if (isDirectInvocation(import.meta.url)) {
267
268
  main().then((code) => { process.exitCode = code; }).catch((error) => {
268
269
  console.error(error.message);
269
270
  process.exitCode = 1;
@@ -13,6 +13,7 @@ import fs from 'node:fs';
13
13
  import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { indexCards, rank, SNAPSHOT_FILE } from '../plugin/scripts/package-recommender.mjs';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
18
19
 
@@ -76,7 +77,7 @@ export function evaluate(items, index) {
76
77
  };
77
78
  }
78
79
 
79
- const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
80
+ const isMain = isDirectInvocation(import.meta.url);
80
81
  if (isMain) {
81
82
  const sets = [];
82
83
  let cards = SNAPSHOT_FILE;
@@ -14,6 +14,7 @@ import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { judgeScore } from './recommendation-judge-score.mjs';
16
16
  import { wilson } from './recommendation-eval.mjs';
17
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
17
18
 
18
19
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
19
20
  const POS = new Set(['design', 'diagnosis']);
@@ -31,7 +32,7 @@ export function applyFloor(key, picks, floor) {
31
32
  return Object.fromEntries(key.map((k) => [k.qid, k.lane === 'semantic' && !(k.topSimilarity >= floor) ? null : picks[k.qid] ?? null]));
32
33
  }
33
34
 
34
- const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
35
+ const isMain = isDirectInvocation(import.meta.url);
35
36
  if (isMain) {
36
37
  const arg = (n, d) => { const i = process.argv.indexOf(n); return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : d; };
37
38
  const dir = arg('--dir', null);
@@ -13,6 +13,7 @@ import fs from 'node:fs';
13
13
  import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { wilson } from './recommendation-eval.mjs';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
18
19
  const POS = new Set(['design', 'diagnosis']);
@@ -57,7 +58,7 @@ export function judgeScore(key, picks, cards, { familyAware = false } = {}) {
57
58
  };
58
59
  }
59
60
 
60
- const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
61
+ const isMain = isDirectInvocation(import.meta.url);
61
62
  if (isMain) {
62
63
  const arg = (n, d) => { const i = process.argv.indexOf(n); return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : d; };
63
64
  const dir = arg('--dir', null);
@@ -15,6 +15,7 @@ import path from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
16
  import { wilson } from './recommendation-eval.mjs';
17
17
  import { applyFloor } from './recommendation-floor.mjs';
18
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
18
19
 
19
20
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
20
21
  const POS = new Set(['design', 'diagnosis']);
@@ -55,7 +56,7 @@ export function scoreRealHost(real, key, simPicks, cards) {
55
56
  };
56
57
  }
57
58
 
58
- const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
59
+ const isMain = isDirectInvocation(import.meta.url);
59
60
  if (isMain) {
60
61
  const arg = (n, d) => { const i = process.argv.indexOf(n); return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : d; };
61
62
  const real = JSON.parse(fs.readFileSync(arg('--real'), 'utf8'));
@@ -21,6 +21,7 @@ import os from 'node:os';
21
21
  import path from 'node:path';
22
22
  import readline from 'node:readline';
23
23
  import { fileURLToPath } from 'node:url';
24
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
24
25
 
25
26
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
26
27
  const arg = (n, d) => { const i = process.argv.indexOf(n); return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : d; };
@@ -53,7 +54,7 @@ export function mentioned(answer, offered) {
53
54
  return null;
54
55
  }
55
56
 
56
- const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
57
+ const isMain = isDirectInvocation(import.meta.url);
57
58
  if (isMain) {
58
59
  const outDir = arg('--out', null);
59
60
  if (!outDir || !arg('--key', null)) { console.error('--key and --out are required'); process.exit(2); }
@@ -8,6 +8,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
8
8
  import { buildCorpus } from '../kb/forge-corpus.mjs';
9
9
  import { loadRvf } from '../kb/resolve-deps.mjs';
10
10
  import { CAPABILITY_RETIRED_SUFFIXES, isCapabilityOnly } from '../kb/capability-only.mjs';
11
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
11
12
 
12
13
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
13
14
  const NAME = 'cognitum-ruos';
@@ -138,6 +139,6 @@ async function main(argv) {
138
139
  console.log(JSON.stringify({ store: NAME, ...result }));
139
140
  }
140
141
 
141
- if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) {
142
+ if (isDirectInvocation(import.meta.url)) {
142
143
  try { await main(process.argv.slice(2)); } catch (error) { console.error(`[capability-store] ${error.message}`); process.exitCode = 1; }
143
144
  }
@@ -15,6 +15,7 @@
15
15
  import fs from 'node:fs';
16
16
  import path from 'node:path';
17
17
  import { fileURLToPath } from 'node:url';
18
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
18
19
 
19
20
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
21
  const ROOT = path.resolve(__dirname, '..');
@@ -123,6 +124,6 @@ async function main() {
123
124
  }
124
125
  }
125
126
 
126
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
127
+ if (isDirectInvocation(import.meta.url)) {
127
128
  main().catch((e) => { console.error('refresh-model-catalog FAILED:', e.message); process.exit(1); });
128
129
  }
@@ -68,6 +68,7 @@ import os from 'node:os';
68
68
  import path from 'node:path';
69
69
  import { spawnSync } from 'node:child_process';
70
70
  import { fileURLToPath, pathToFileURL } from 'node:url';
71
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
71
72
 
72
73
  const HERE = path.dirname(fileURLToPath(import.meta.url));
73
74
  export const REAL_ROOT = path.resolve(HERE, '..');
@@ -1591,7 +1592,7 @@ export async function main(argv = process.argv.slice(2)) {
1591
1592
  return receipt.verdict === 'PASS' ? 0 : 1;
1592
1593
  }
1593
1594
 
1594
- if (((() => { try { return process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })())) {
1595
+ if (isDirectInvocation(import.meta.url)) {
1595
1596
  main().then((code) => { process.exitCode = code; }).catch((error) => {
1596
1597
  console.error(error?.message || error);
1597
1598
  process.exitCode = 1;
@@ -5,6 +5,7 @@
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
8
9
 
9
10
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
10
11
  const CANONICAL_PUBLISHERS = new Set([
@@ -203,7 +204,7 @@ export function main(root = ROOT) {
203
204
  // spellings of one file, so the guard silently reads false and the CLI exits 0 having done nothing —
204
205
  // the same defect 6eead7bc fixed in release-projection.mjs, which is a gate this repo relies on.
205
206
  if (((() => {
206
- try { return process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; }
207
+ try { return isDirectInvocation(import.meta.url); } catch { return false; }
207
208
  })())) {
208
209
  process.exitCode = main();
209
210
  }
@@ -4,6 +4,7 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { canonicalJson } from './release-transaction.mjs';
7
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
7
8
 
8
9
  export const REQUIRED_RELEASE_LEAVES = Object.freeze([
9
10
  'source-quality',
@@ -38,7 +39,7 @@ export function aggregateEvidence({ sha, payloadId, leaves }) {
38
39
  return { ...envelope, evidenceDigest: crypto.createHash('sha256').update(canonicalJson(envelope)).digest('hex') };
39
40
  }
40
41
 
41
- const isCli = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
42
+ const isCli = isDirectInvocation(import.meta.url);
42
43
  if (isCli) {
43
44
  const arg = (name) => {
44
45
  const index = process.argv.indexOf(name);
@@ -4,6 +4,7 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { canonicalJson } from './release-transaction.mjs';
7
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
7
8
 
8
9
  const sha256 = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex');
9
10
  const digestFile = (file) => sha256(fs.readFileSync(file));
@@ -51,7 +52,7 @@ const arg = (name) => {
51
52
  const index = process.argv.indexOf(name);
52
53
  return index >= 0 ? process.argv[index + 1] : null;
53
54
  };
54
- const command = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
55
+ const command = isDirectInvocation(import.meta.url)
55
56
  ? process.argv[2]
56
57
  : null;
57
58
 
@@ -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
  },
@@ -358,10 +393,11 @@ export const RELEASE_REQUIREMENTS = Object.freeze({
358
393
  },
359
394
  {
360
395
  "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",
396
+ "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
397
  "files": [
363
398
  "tests/unit/model-router-update-convergence.test.mjs",
364
- "tests/unit/codex-hook-trust-reconcile.test.mjs"
399
+ "tests/unit/codex-hook-trust-reconcile.test.mjs",
400
+ "tests/unit/codex-shared-host-refresh.test.mjs"
365
401
  ]
366
402
  },
367
403
  {
@@ -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();