@mindrian_os/cli 2.0.0-beta.3 → 2.0.0-beta.33

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 (1829) hide show
  1. package/.claude-plugin/plugin.json +21 -0
  2. package/.mcp.json +14 -0
  3. package/CHANGELOG.md +497 -0
  4. package/agents/analogy-query-fetcher.md +119 -0
  5. package/agents/brain-query.md +91 -0
  6. package/agents/competitor-watch-fetcher.md +94 -0
  7. package/agents/framework-runner.md +258 -0
  8. package/agents/grading.md +216 -0
  9. package/agents/grant-reviewer.md +191 -0
  10. package/agents/investor.md +141 -0
  11. package/agents/larry-extended.md +215 -0
  12. package/agents/meeting-perspective-extractor.md +94 -0
  13. package/agents/opportunity-scanner.md +105 -0
  14. package/agents/persona-analyst.md +201 -0
  15. package/agents/research.md +103 -0
  16. package/agents/reverse-salient-agent.md +42 -0
  17. package/agents/vault-section-reviewer.md +107 -0
  18. package/assets/banner-showcase.html +537 -0
  19. package/assets/fonts/BebasNeue-Regular.ttf +0 -0
  20. package/assets/fonts/Inter-Bold.ttf +0 -0
  21. package/assets/fonts/Inter-Regular.ttf +0 -0
  22. package/assets/logo.svg +10 -0
  23. package/bin/local-chain-recommender.cjs +256 -0
  24. package/bin/mindrian-brain-mcp-client.cjs +319 -0
  25. package/bin/mindrian-mcp-server.cjs +445 -0
  26. package/bin/mindrian-mcp-shim.cjs +100 -0
  27. package/bin/mindrian-tools.cjs +784 -0
  28. package/commands/act.md +529 -0
  29. package/commands/admin.md +439 -0
  30. package/commands/agentshield.md +49 -0
  31. package/commands/analyze-needs.md +78 -0
  32. package/commands/analyze-systems.md +73 -0
  33. package/commands/analyze-timing.md +98 -0
  34. package/commands/auto-explore.md +85 -0
  35. package/commands/beautiful-question.md +76 -0
  36. package/commands/bono.md +152 -0
  37. package/commands/brain-derive.md +137 -0
  38. package/commands/build-knowledge.md +121 -0
  39. package/commands/build-thesis.md +94 -0
  40. package/commands/causal.md +269 -0
  41. package/commands/challenge-assumptions.md +78 -0
  42. package/commands/compare-ventures.md +117 -0
  43. package/commands/correct-reference-now.md +88 -0
  44. package/commands/dashboard.md +144 -0
  45. package/commands/deck.md +117 -0
  46. package/commands/deep-grade.md +214 -0
  47. package/commands/diagnose.md +131 -0
  48. package/commands/diagnostics.md +195 -0
  49. package/commands/dial-memory-refresh.md +113 -0
  50. package/commands/diffusion.md +129 -0
  51. package/commands/discover.md +221 -0
  52. package/commands/doctor.md +271 -0
  53. package/commands/dogfood-flush.md +130 -0
  54. package/commands/dominant-designs.md +76 -0
  55. package/commands/eureka.md +315 -0
  56. package/commands/explain-decision.md +135 -0
  57. package/commands/explore-domains.md +78 -0
  58. package/commands/explore-futures.md +67 -0
  59. package/commands/explore-opportunity.md +172 -0
  60. package/commands/explore-trends.md +78 -0
  61. package/commands/export.md +128 -0
  62. package/commands/feynman-timeline-refresh.md +102 -0
  63. package/commands/file-meeting.md +1195 -0
  64. package/commands/find-analogies.md +369 -0
  65. package/commands/find-bottlenecks.md +108 -0
  66. package/commands/find-connections.md +111 -0
  67. package/commands/funding.md +114 -0
  68. package/commands/futures.md +128 -0
  69. package/commands/grade-grant.md +297 -0
  70. package/commands/grade.md +257 -0
  71. package/commands/graph.md +218 -0
  72. package/commands/hat-briefing.md +163 -0
  73. package/commands/heal.md +72 -0
  74. package/commands/help.md +176 -0
  75. package/commands/hmi-status.md +75 -0
  76. package/commands/ignite.md +229 -0
  77. package/commands/ingest-methodology.md +128 -0
  78. package/commands/intel-pipeline.md +133 -0
  79. package/commands/jtbd.md +262 -0
  80. package/commands/leadership.md +113 -0
  81. package/commands/lean-canvas.md +74 -0
  82. package/commands/macro-trends.md +88 -0
  83. package/commands/map-unknowns.md +76 -0
  84. package/commands/memory-cortex-reach.md +79 -0
  85. package/commands/memory.md +213 -0
  86. package/commands/models.md +200 -0
  87. package/commands/mos-reason.md +489 -0
  88. package/commands/mos.md +162 -0
  89. package/commands/mullins.md +155 -0
  90. package/commands/mva-brief.md +86 -0
  91. package/commands/mva-option.md +119 -0
  92. package/commands/mva-report.md +76 -0
  93. package/commands/new-project.md +633 -0
  94. package/commands/new-surface.md +116 -0
  95. package/commands/onboard.md +489 -0
  96. package/commands/operator.md +168 -0
  97. package/commands/opportunities.md +177 -0
  98. package/commands/organize.md +74 -0
  99. package/commands/persona.md +276 -0
  100. package/commands/pipeline.md +167 -0
  101. package/commands/present.md +125 -0
  102. package/commands/publish.md +227 -0
  103. package/commands/pws-brain.md +154 -0
  104. package/commands/qualify-opportunity.md +113 -0
  105. package/commands/query.md +70 -0
  106. package/commands/radar.md +110 -0
  107. package/commands/reanalyze.md +124 -0
  108. package/commands/research.md +467 -0
  109. package/commands/room.md +385 -0
  110. package/commands/rooms.md +682 -0
  111. package/commands/root-cause.md +77 -0
  112. package/commands/rs-experts.md +153 -0
  113. package/commands/rs-explain.md +134 -0
  114. package/commands/rs-fetch.md +119 -0
  115. package/commands/rs-thesis.md +131 -0
  116. package/commands/scenario-plan.md +80 -0
  117. package/commands/scheduled-tasks.md +308 -0
  118. package/commands/score-innovation.md +78 -0
  119. package/commands/scout.md +379 -0
  120. package/commands/setup.md +658 -0
  121. package/commands/show.md +71 -0
  122. package/commands/skill.md +108 -0
  123. package/commands/snapshot.md +179 -0
  124. package/commands/speakers.md +118 -0
  125. package/commands/splash.md +55 -0
  126. package/commands/stance.md +91 -0
  127. package/commands/status.md +109 -0
  128. package/commands/structure-argument.md +82 -0
  129. package/commands/suggest-next.md +141 -0
  130. package/commands/systems-thinking.md +224 -0
  131. package/commands/think-hats.md +86 -0
  132. package/commands/trending-to-absurd.md +151 -0
  133. package/commands/update.md +256 -0
  134. package/commands/user-needs.md +77 -0
  135. package/commands/validate.md +77 -0
  136. package/commands/value-proposition.md +116 -0
  137. package/commands/vault.md +330 -0
  138. package/commands/visualize.md +71 -0
  139. package/commands/whitespace.md +541 -0
  140. package/commands/wiki.md +96 -0
  141. package/data/ROOM.md +47 -0
  142. package/data/brain-census.generated.json +2617 -0
  143. package/data/brain-orchestration-projection.json +4973 -0
  144. package/data/brain-packet-schema.json +545 -0
  145. package/data/brain-surface-contract.json +32 -0
  146. package/data/capability-ledger.json +391 -0
  147. package/data/capability-map-registry.json +23 -0
  148. package/data/command-registry.json +2433 -0
  149. package/data/connector-coverage-ledger.json +1618 -0
  150. package/data/connector-out-of-spine-allowlist.json +71 -0
  151. package/data/connector-registry.json +3637 -0
  152. package/data/corpus-stats-source.json +11 -0
  153. package/data/corpus-stats.generated.json +10 -0
  154. package/data/cross-domain-analogues.json +15 -0
  155. package/data/deck-aliases.json +6 -0
  156. package/data/deck-styles.json +85 -0
  157. package/data/deployment-surfaces.json +69 -0
  158. package/data/dispatch-framework-map.json +18 -0
  159. package/data/doctor-modules.json +206 -0
  160. package/data/dual-graph-health-baseline.json +12 -0
  161. package/data/eureka-critic-tags.json +32 -0
  162. package/data/first-reward-surfaces.json +66 -0
  163. package/data/first-touch-surfaces.json +60 -0
  164. package/data/flagship-floor-set.json +37 -0
  165. package/data/framework-names.json +121 -0
  166. package/data/grant-rubric-fixtures/early-stage-pre-seed.json +18 -0
  167. package/data/grant-rubric-fixtures/early-stage-round-a.json +18 -0
  168. package/data/grant-rubric-fixtures/early-stage-seed.json +18 -0
  169. package/data/grant-rubric-fixtures/hybrid-seed-incentive.json +18 -0
  170. package/data/grant-rubric-fixtures/rd-fund.json +18 -0
  171. package/data/grant-rubric-fixtures/regional-innovation-incubators.json +18 -0
  172. package/data/grant-rubric-fixtures/technology-incubators.json +18 -0
  173. package/data/grant-rubric-fixtures/tnufa.json +167 -0
  174. package/data/grant-rubric-schema.json +33 -0
  175. package/data/harness-fixtures/converged-room/.context/ROOM.md +13 -0
  176. package/data/harness-fixtures/converged-room/.intelligence/ROOM.md +13 -0
  177. package/data/harness-fixtures/converged-room/.snapshots/ROOM.md +13 -0
  178. package/data/harness-fixtures/converged-room/MINTO.md +19 -0
  179. package/data/harness-fixtures/converged-room/STATE.md +73 -0
  180. package/data/harness-fixtures/converged-room/USER.md +23 -0
  181. package/data/harness-fixtures/converged-room/assets/ROOM.md +13 -0
  182. package/data/harness-fixtures/converged-room/business-model/CONTEXT.md +32 -0
  183. package/data/harness-fixtures/converged-room/business-model/ROOM.md +36 -0
  184. package/data/harness-fixtures/converged-room/competitive-analysis/CONTEXT.md +33 -0
  185. package/data/harness-fixtures/converged-room/competitive-analysis/ROOM.md +35 -0
  186. package/data/harness-fixtures/converged-room/financial-model/CONTEXT.md +30 -0
  187. package/data/harness-fixtures/converged-room/financial-model/ROOM.md +35 -0
  188. package/data/harness-fixtures/converged-room/funding/CONTEXT.md +41 -0
  189. package/data/harness-fixtures/converged-room/funding/ROOM.md +35 -0
  190. package/data/harness-fixtures/converged-room/legal-ip/CONTEXT.md +30 -0
  191. package/data/harness-fixtures/converged-room/legal-ip/ROOM.md +35 -0
  192. package/data/harness-fixtures/converged-room/market-analysis/CONTEXT.md +32 -0
  193. package/data/harness-fixtures/converged-room/market-analysis/ROOM.md +35 -0
  194. package/data/harness-fixtures/converged-room/opportunity-bank/CONTEXT.md +39 -0
  195. package/data/harness-fixtures/converged-room/opportunity-bank/ROOM.md +36 -0
  196. package/data/harness-fixtures/converged-room/problem-definition/CONTEXT.md +32 -0
  197. package/data/harness-fixtures/converged-room/problem-definition/ROOM.md +36 -0
  198. package/data/harness-fixtures/converged-room/references/ROOM.md +13 -0
  199. package/data/harness-fixtures/converged-room/references/SECTION-SCHEMA.md +213 -0
  200. package/data/harness-fixtures/converged-room/references/SUB-SCHEMAS.md +91 -0
  201. package/data/harness-fixtures/converged-room/solution-design/CONTEXT.md +36 -0
  202. package/data/harness-fixtures/converged-room/solution-design/ROOM.md +36 -0
  203. package/data/harness-fixtures/converged-room/strategy/CONTEXT.md +35 -0
  204. package/data/harness-fixtures/converged-room/strategy/ROOM.md +35 -0
  205. package/data/harness-fixtures/converged-room/team/ROOM.md +13 -0
  206. package/data/harness-fixtures/converged-room/team-execution/CONTEXT.md +36 -0
  207. package/data/harness-fixtures/converged-room/team-execution/ROOM.md +35 -0
  208. package/data/harness-manifest.json +74 -0
  209. package/data/harness-policies/CONTEXT.md +55 -0
  210. package/data/harness-policies/_schema.json +42 -0
  211. package/data/harness-policies/contract-parity-larry.json +63 -0
  212. package/data/harness-policies/gate-card-fire.json +13 -0
  213. package/data/harness-policies/gate-graph-derive-health.json +13 -0
  214. package/data/harness-policies/gate-shape-declaration.json +13 -0
  215. package/data/harness-policies/gate-tool-honesty.json +13 -0
  216. package/data/harness-policies/gate-worktree-hygiene.json +13 -0
  217. package/data/harness-policies/memory-write-policy.json +28 -0
  218. package/data/harness-policies/registry-drift.json +13 -0
  219. package/data/harness-policies/release-payload-ceiling.json +13 -0
  220. package/data/harness-policies/voice-backend-noun-free.json +13 -0
  221. package/data/harness-policies/voice-fork-as-card.json +13 -0
  222. package/data/harness-policies/voice-glyph-present.json +13 -0
  223. package/data/harness-policies/voice-hyphens-only.json +13 -0
  224. package/data/help-groups.json +236 -0
  225. package/data/hitl-shape-backfill.json +777 -0
  226. package/data/hitl-shape-declaration-fixtures/invalid-bad-shape.json +5 -0
  227. package/data/hitl-shape-declaration-fixtures/invalid-missing-why.json +4 -0
  228. package/data/hitl-shape-declaration-fixtures/invalid-ranker-contradiction.json +6 -0
  229. package/data/hitl-shape-declaration-fixtures/invalid-skill-gap.json +3 -0
  230. package/data/hitl-shape-declaration-fixtures/valid-multi-stage.json +7 -0
  231. package/data/hitl-shape-declaration-fixtures/valid-single-shape.json +5 -0
  232. package/data/hitl-shape-declaration-fixtures/valid-skill-exempt.json +5 -0
  233. package/data/hitl-shape-declaration-schema.json +34 -0
  234. package/data/hitl-stages-fixtures/bono.json +10 -0
  235. package/data/hitl-stages-fixtures/pipeline-1.json +9 -0
  236. package/data/hitl-stages-fixtures/pipeline-2.json +9 -0
  237. package/data/hitl-stages-fixtures/pipeline-3.json +10 -0
  238. package/data/hitl-stages-fixtures/research.json +10 -0
  239. package/data/hitl-stages-fixtures/rs-convergence.json +10 -0
  240. package/data/hitl-stages-fixtures/rs-family.json +11 -0
  241. package/data/hitl-stages-fixtures/rs-reverse-salient.json +10 -0
  242. package/data/hitl-stages-fixtures/trending-to-absurd.json +11 -0
  243. package/data/hitl-stages-schema.json +26 -0
  244. package/data/mcp-tool-connectors.json +464 -0
  245. package/data/mva-agent-prompts.json +31 -0
  246. package/data/mva-deck-template.html +15 -0
  247. package/data/mva-heuristic-keywords.json +35 -0
  248. package/data/orchestration-command-ledger.json +576 -0
  249. package/data/orchestration-unwired-allowlist.json +6 -0
  250. package/data/portfolio-ahp-matrix.json +16 -0
  251. package/data/publish-needs.json +76 -0
  252. package/data/render-coverage-registry.json +1152 -0
  253. package/data/research-sources.json +58 -0
  254. package/data/roadmap-type-chains.json +28 -0
  255. package/data/room-blueprints.json +156 -0
  256. package/data/subagent-dispatch-grants.json +150 -0
  257. package/hooks/hooks.json +493 -0
  258. package/hooks/run-hook.cmd +64 -0
  259. package/lib/__init__.py +0 -0
  260. package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
  261. package/lib/agents/auto-explore-agent.cjs +1163 -0
  262. package/lib/agents/mva/brain-classic-traps.cjs +55 -0
  263. package/lib/agents/mva/brain-cross-domain.cjs +79 -0
  264. package/lib/agents/mva/brain-similar-ventures.cjs +93 -0
  265. package/lib/agents/mva/dashboard-graph-neighborhood.cjs +72 -0
  266. package/lib/agents/mva/index.cjs +42 -0
  267. package/lib/agents/mva/six-hats-red-black.cjs +137 -0
  268. package/lib/agents/mva/tavily-funding-scan.cjs +147 -0
  269. package/lib/agents/mva/test-all-six-agents.cjs +467 -0
  270. package/lib/agents/reverse-salient-agent.cjs +757 -0
  271. package/lib/agents/tension-hook-agent.cjs +586 -0
  272. package/lib/brain/ROOM.md +44 -0
  273. package/lib/brain/chain-recommender.cjs +784 -0
  274. package/lib/brain/curation-batch.cjs +519 -0
  275. package/lib/brain/framework-chain-slice.cjs +252 -0
  276. package/lib/brain/hypergraph-event-schema.cjs +184 -0
  277. package/lib/chat/chat-context.js +185 -0
  278. package/lib/chat/chat-panel.js +721 -0
  279. package/lib/chat/fabric-chat.cjs +288 -0
  280. package/lib/chat/generative-tools.js +219 -0
  281. package/lib/conversation/ROOM.md +39 -0
  282. package/lib/conversation/classifier-rules.json +38 -0
  283. package/lib/conversation/classifier.cjs +264 -0
  284. package/lib/conversation/operator-epistemic-cap.test.cjs +156 -0
  285. package/lib/conversation/operator.cjs +492 -0
  286. package/lib/conversation/operator.test.cjs +160 -0
  287. package/lib/copy/115-spec-strings.cjs +55 -0
  288. package/lib/core/__init__.py +0 -0
  289. package/lib/core/__nav-stub.cjs +14 -0
  290. package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
  291. package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
  292. package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
  293. package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
  294. package/lib/core/__pycache__/rs_corpus_exclude.cpython-312.pyc +0 -0
  295. package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
  296. package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
  297. package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
  298. package/lib/core/abstraction-gate.cjs +133 -0
  299. package/lib/core/act-jtbd-blurb.cjs +231 -0
  300. package/lib/core/artifact-id.cjs +148 -0
  301. package/lib/core/asset-ops.cjs +151 -0
  302. package/lib/core/auto-commit-throttle.cjs +129 -0
  303. package/lib/core/bearer-token.cjs +199 -0
  304. package/lib/core/behavioral/observation-schema.cjs +86 -0
  305. package/lib/core/bono/cell-fanout.cjs +305 -0
  306. package/lib/core/bono/debate-composition.cjs +495 -0
  307. package/lib/core/bono/hat-governance.cjs +367 -0
  308. package/lib/core/bono/persona-research.cjs +288 -0
  309. package/lib/core/bono/reviewer-governance.cjs +331 -0
  310. package/lib/core/brain-client.cjs +2621 -0
  311. package/lib/core/brain-derivation-prompts.cjs +331 -0
  312. package/lib/core/brain-derivation-queue.cjs +535 -0
  313. package/lib/core/brain-derivation.cjs +740 -0
  314. package/lib/core/brain-md-schema.cjs +528 -0
  315. package/lib/core/brain-md-staleness.cjs +357 -0
  316. package/lib/core/brain-response-sanitize.cjs +396 -0
  317. package/lib/core/breakthrough/canary.cjs +134 -0
  318. package/lib/core/breakthrough/canary.test.cjs +136 -0
  319. package/lib/core/breakthrough/detectors.cjs +359 -0
  320. package/lib/core/breakthrough/detectors.test.cjs +333 -0
  321. package/lib/core/breakthrough/ethics-fence.cjs +129 -0
  322. package/lib/core/breakthrough/ethics-fence.test.cjs +178 -0
  323. package/lib/core/breakthrough/resurfacing.cjs +150 -0
  324. package/lib/core/breakthrough/resurfacing.test.cjs +233 -0
  325. package/lib/core/breakthrough/review-queue.cjs +168 -0
  326. package/lib/core/breakthrough/review-queue.test.cjs +160 -0
  327. package/lib/core/breakthrough/scanner-d17-d18.test.cjs +229 -0
  328. package/lib/core/breakthrough/scanner.cjs +435 -0
  329. package/lib/core/breakthrough/scanner.test.cjs +267 -0
  330. package/lib/core/breakthrough/schema.cjs +180 -0
  331. package/lib/core/breakthrough/schema.test.cjs +256 -0
  332. package/lib/core/breakthrough/scoring.cjs +293 -0
  333. package/lib/core/breakthrough/scoring.test.cjs +423 -0
  334. package/lib/core/breakthrough/verb-dispatch.cjs +230 -0
  335. package/lib/core/breakthrough/verb-dispatch.test.cjs +185 -0
  336. package/lib/core/breakthrough/voice-scaffold.cjs +249 -0
  337. package/lib/core/breakthrough/voice-scaffold.test.cjs +251 -0
  338. package/lib/core/bridge-writer.cjs +477 -0
  339. package/lib/core/cache-prune.cjs +314 -0
  340. package/lib/core/card-fire-gate.cjs +107 -0
  341. package/lib/core/card-fire-sidechannel.cjs +518 -0
  342. package/lib/core/chain-executor.cjs +939 -0
  343. package/lib/core/chain-retry.cjs +214 -0
  344. package/lib/core/chain-step-dispatcher.cjs +397 -0
  345. package/lib/core/chat-context-builder.cjs +253 -0
  346. package/lib/core/check-plugin-enabled.cjs +145 -0
  347. package/lib/core/close-loop-writer.cjs +492 -0
  348. package/lib/core/command-registration-check.cjs +246 -0
  349. package/lib/core/correlation-label-index.cjs +230 -0
  350. package/lib/core/correlation.cjs +112 -0
  351. package/lib/core/coverage-monitor.cjs +183 -0
  352. package/lib/core/coverage-rollup.cjs +232 -0
  353. package/lib/core/cross-room-aggregator.cjs +1127 -0
  354. package/lib/core/cross-room-store.cjs +292 -0
  355. package/lib/core/cross-room-triggers.cjs +222 -0
  356. package/lib/core/daily-briefing.cjs +438 -0
  357. package/lib/core/decision-axes.cjs +178 -0
  358. package/lib/core/decision-capture.cjs +618 -0
  359. package/lib/core/deck-design-rules.cjs +211 -0
  360. package/lib/core/deep-links.cjs +82 -0
  361. package/lib/core/directive-envelope.cjs +230 -0
  362. package/lib/core/directive-envelope.test.cjs +225 -0
  363. package/lib/core/dispatch-optimizer.cjs +354 -0
  364. package/lib/core/doc-text-extractor.cjs +133 -0
  365. package/lib/core/doctor/capability-ledger-module.cjs +170 -0
  366. package/lib/core/doctor/card-fire-health-module.cjs +159 -0
  367. package/lib/core/doctor/cascade-rooms-active-module.cjs +127 -0
  368. package/lib/core/doctor/cascade-rooms-module.cjs +184 -0
  369. package/lib/core/doctor/class-m-brain-smoke.cjs +479 -0
  370. package/lib/core/doctor/class-m-brain-smoke.test.cjs +448 -0
  371. package/lib/core/doctor/class-s-eureka-smoke.cjs +380 -0
  372. package/lib/core/doctor/deployment-surfaces-module.cjs +408 -0
  373. package/lib/core/doctor/deprecated-usage-module.cjs +155 -0
  374. package/lib/core/doctor/eureka-fts-health-module.cjs +236 -0
  375. package/lib/core/doctor/graph-derive-heal-retrofit-module.cjs +148 -0
  376. package/lib/core/doctor/graph-derive-health-module.cjs +486 -0
  377. package/lib/core/doctor/install-incomplete-module.cjs +320 -0
  378. package/lib/core/doctor/install-state-module.cjs +503 -0
  379. package/lib/core/doctor/mcp-surface-module.cjs +369 -0
  380. package/lib/core/doctor/mode-select-checkpoint-module.cjs +113 -0
  381. package/lib/core/doctor/plugin-enabled-state-module.cjs +86 -0
  382. package/lib/core/doctor/room-graph-density-module.cjs +181 -0
  383. package/lib/core/doctor/room-md-module.cjs +198 -0
  384. package/lib/core/doctor/shared.cjs +555 -0
  385. package/lib/core/doctor/stale-first-touch-copy-module.cjs +83 -0
  386. package/lib/core/doctor/statusline-visibility-module.cjs +295 -0
  387. package/lib/core/doctor/ui-compliance-module.cjs +223 -0
  388. package/lib/core/doctor/umbilical-module.cjs +486 -0
  389. package/lib/core/doctor/verify-surface-module.cjs +82 -0
  390. package/lib/core/doctor/voice-style-log-module.cjs +146 -0
  391. package/lib/core/domain-insight-sweep.cjs +224 -0
  392. package/lib/core/drift-baseline.cjs +362 -0
  393. package/lib/core/drift-runtime-reachability.cjs +283 -0
  394. package/lib/core/dual-path-detector.cjs +84 -0
  395. package/lib/core/dual-path-detector.test.cjs +334 -0
  396. package/lib/core/enrichment-queue.cjs +636 -0
  397. package/lib/core/eureka/ahp-weights.cjs +232 -0
  398. package/lib/core/eureka/analogy-fitness.cjs +326 -0
  399. package/lib/core/eureka/compression-meter.cjs +165 -0
  400. package/lib/core/eureka/embedding-classifier.cjs +226 -0
  401. package/lib/core/eureka/embedding-spine.cjs +563 -0
  402. package/lib/core/eureka/entity-classifier.cjs +232 -0
  403. package/lib/core/eureka/entity-extractor.cjs +356 -0
  404. package/lib/core/eureka/eureka-enable.cjs +228 -0
  405. package/lib/core/eureka/eureka-offer.cjs +225 -0
  406. package/lib/core/eureka/eureka-reach-runner.cjs +430 -0
  407. package/lib/core/eureka/explore-chain.cjs +834 -0
  408. package/lib/core/eureka/explored-artifact.cjs +456 -0
  409. package/lib/core/eureka/fts-index-lifecycle.cjs +265 -0
  410. package/lib/core/eureka/grade-grant-examine.cjs +544 -0
  411. package/lib/core/eureka/grade-grant.cjs +596 -0
  412. package/lib/core/eureka/hybrid-retrieve.cjs +256 -0
  413. package/lib/core/eureka/lateral-engine-adapter.cjs +118 -0
  414. package/lib/core/eureka/lexical-overlap.cjs +98 -0
  415. package/lib/core/eureka/online-pattern-query.cjs +142 -0
  416. package/lib/core/eureka/opportunity-harvest.cjs +752 -0
  417. package/lib/core/eureka/opportunity-statement.cjs +519 -0
  418. package/lib/core/eureka/portfolio-dimensions.cjs +255 -0
  419. package/lib/core/eureka/qualify-opportunity.cjs +607 -0
  420. package/lib/core/eureka/reasoning-mode.cjs +481 -0
  421. package/lib/core/eureka/report-html.cjs +368 -0
  422. package/lib/core/eureka/research-filing.cjs +547 -0
  423. package/lib/core/eureka/room-native-substrate.cjs +343 -0
  424. package/lib/core/eureka/tail-quadrant.cjs +177 -0
  425. package/lib/core/eureka/tri-modal-index.cjs +564 -0
  426. package/lib/core/eureka/vector-store.cjs +414 -0
  427. package/lib/core/eureka-critic.cjs +733 -0
  428. package/lib/core/eureka-deps-resolver.cjs +179 -0
  429. package/lib/core/expert-genesis.cjs +437 -0
  430. package/lib/core/expert-library.cjs +303 -0
  431. package/lib/core/exports-log.cjs +79 -0
  432. package/lib/core/feynman/ROOM.md +25 -0
  433. package/lib/core/feynman/dial-memory-renderer.cjs +279 -0
  434. package/lib/core/feynman/dial-memory-runner.cjs +173 -0
  435. package/lib/core/feynman/feynman-seed-writer.cjs +187 -0
  436. package/lib/core/feynman/timeline-renderer.cjs +197 -0
  437. package/lib/core/feynman/timeline-runner.cjs +281 -0
  438. package/lib/core/feynman-minto-invariants.cjs +609 -0
  439. package/lib/core/findings-wirer.cjs +360 -0
  440. package/lib/core/first-touch-version-stamper.cjs +113 -0
  441. package/lib/core/folder-memory-async.cjs +424 -0
  442. package/lib/core/folder-memory-shared.cjs +890 -0
  443. package/lib/core/folder-memory.cjs +546 -0
  444. package/lib/core/framework-chain-composer.cjs +583 -0
  445. package/lib/core/frontmatter-schemas.cjs +468 -0
  446. package/lib/core/fusion-router.cjs +540 -0
  447. package/lib/core/futures/causal-cue.cjs +91 -0
  448. package/lib/core/futures/orchestrator.cjs +1391 -0
  449. package/lib/core/futures/subsystem-render.cjs +164 -0
  450. package/lib/core/gate-relevance.cjs +278 -0
  451. package/lib/core/git-ops.cjs +141 -0
  452. package/lib/core/graph-backfill.cjs +562 -0
  453. package/lib/core/graph-candidate-producer.cjs +235 -0
  454. package/lib/core/graph-derivation.cjs +546 -0
  455. package/lib/core/graph-derive-classifier.cjs +352 -0
  456. package/lib/core/graph-ops.cjs +274 -0
  457. package/lib/core/graph-refine-loop.cjs +194 -0
  458. package/lib/core/graph-self-heal.cjs +289 -0
  459. package/lib/core/greeting-intent-detector.cjs +201 -0
  460. package/lib/core/grill-engine.cjs +459 -0
  461. package/lib/core/hat-persistence.cjs +274 -0
  462. package/lib/core/hsi-engine.cjs +439 -0
  463. package/lib/core/hsi-lsa.cjs +246 -0
  464. package/lib/core/hsi-spectral.cjs +554 -0
  465. package/lib/core/hsi-to-graph.test.cjs +168 -0
  466. package/lib/core/icm-forest.cjs +703 -0
  467. package/lib/core/ignite-branch-gate.cjs +66 -0
  468. package/lib/core/index.cjs +60 -0
  469. package/lib/core/insight-sensors.cjs +1000 -0
  470. package/lib/core/install-state.cjs +242 -0
  471. package/lib/core/integration-registry.cjs +232 -0
  472. package/lib/core/intel-pipeline.cjs +566 -0
  473. package/lib/core/intelligence-cascade.cjs +852 -0
  474. package/lib/core/issue-tree.cjs +269 -0
  475. package/lib/core/larry-thinness-acknowledgment.cjs +64 -0
  476. package/lib/core/larry-thinness-acknowledgment.test.cjs +97 -0
  477. package/lib/core/lazygraph-ops.cjs +1453 -0
  478. package/lib/core/lens-engine.cjs +434 -0
  479. package/lib/core/leverage-scan.cjs +218 -0
  480. package/lib/core/llm-name-suggester.cjs +194 -0
  481. package/lib/core/llm-name-suggester.test.cjs +132 -0
  482. package/lib/core/lru-cache.cjs +139 -0
  483. package/lib/core/mcp-dep-heal.cjs +475 -0
  484. package/lib/core/mcp-dep-heal.test.cjs +253 -0
  485. package/lib/core/mcp-profiles.cjs +185 -0
  486. package/lib/core/meeting-ops.cjs +54 -0
  487. package/lib/core/memory/governance-candidate-raiser.cjs +205 -0
  488. package/lib/core/memory/governance-candidate.cjs +95 -0
  489. package/lib/core/memory/reconcile-memory-runner.cjs +653 -0
  490. package/lib/core/memory-ops.cjs +641 -0
  491. package/lib/core/meter/gate-density-reader.cjs +112 -0
  492. package/lib/core/meter/transfer-reader.cjs +276 -0
  493. package/lib/core/meter/two-gauge.cjs +245 -0
  494. package/lib/core/methodology-ingest.cjs +346 -0
  495. package/lib/core/metrics/larryreach-loop-health.cjs +142 -0
  496. package/lib/core/migration-snapshot.cjs +287 -0
  497. package/lib/core/migration-snapshot.test.cjs +174 -0
  498. package/lib/core/migrations/ROOM.md +33 -0
  499. package/lib/core/migrations/phase-109-nodes-provenance.cjs +400 -0
  500. package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
  501. package/lib/core/migrations/phase-160-nodes-bitemporal.cjs +168 -0
  502. package/lib/core/migrations/phase-160-nodes-bitemporal.test.cjs +140 -0
  503. package/lib/core/migrations/phase-162-section-nodes.cjs +156 -0
  504. package/lib/core/migrations/phase-222-ranker-weights.cjs +62 -0
  505. package/lib/core/migrations/phase-224-edge-review-status.cjs +87 -0
  506. package/lib/core/mindrian-brain-shim.test.cjs +221 -0
  507. package/lib/core/mode-select-sidechannel.cjs +259 -0
  508. package/lib/core/model-profiles.cjs +246 -0
  509. package/lib/core/mullins-scaffold.cjs +258 -0
  510. package/lib/core/mullins-scaffold.test.cjs +128 -0
  511. package/lib/core/mva-agent-contract.cjs +170 -0
  512. package/lib/core/mva-agent-contract.test.cjs +169 -0
  513. package/lib/core/mva-budget.cjs +75 -0
  514. package/lib/core/mva-budget.test.cjs +68 -0
  515. package/lib/core/mva-classifier.cjs +392 -0
  516. package/lib/core/mva-classifier.test.cjs +248 -0
  517. package/lib/core/mva-deck-builder.cjs +452 -0
  518. package/lib/core/mva-deck-builder.test.cjs +287 -0
  519. package/lib/core/mva-detect.smoke.test.cjs +209 -0
  520. package/lib/core/mva-dispatcher.cjs +110 -0
  521. package/lib/core/mva-dispatcher.test.cjs +216 -0
  522. package/lib/core/mva-option-router.cjs +414 -0
  523. package/lib/core/mva-option-router.test.cjs +483 -0
  524. package/lib/core/mva-orchestrator.cjs +365 -0
  525. package/lib/core/mva-orchestrator.test.cjs +916 -0
  526. package/lib/core/mva-progressive-renderer.cjs +194 -0
  527. package/lib/core/mva-progressive-renderer.test.cjs +157 -0
  528. package/lib/core/mva-rule-linter.cjs +458 -0
  529. package/lib/core/mva-rule-linter.test.cjs +484 -0
  530. package/lib/core/mva-state.cjs +159 -0
  531. package/lib/core/mva-telemetry.cjs +58 -0
  532. package/lib/core/mva-telemetry.test.cjs +196 -0
  533. package/lib/core/mva-vercel-deploy.cjs +168 -0
  534. package/lib/core/mva-vercel-deploy.test.cjs +239 -0
  535. package/lib/core/nav-dial.cjs +440 -0
  536. package/lib/core/navigation/ROOM.md +15 -0
  537. package/lib/core/navigation/abstraction-claim.cjs +185 -0
  538. package/lib/core/navigation/calibration-gate.cjs +284 -0
  539. package/lib/core/navigation/calibration-log.cjs +141 -0
  540. package/lib/core/navigation/confirm-node.cjs +73 -0
  541. package/lib/core/navigation/dashboard-helpers.cjs +145 -0
  542. package/lib/core/navigation/edges.cjs +1150 -0
  543. package/lib/core/navigation/evidence-claim.cjs +186 -0
  544. package/lib/core/navigation/explanation.cjs +48 -0
  545. package/lib/core/navigation/file-evidence-readback.cjs +242 -0
  546. package/lib/core/navigation/focus.cjs +155 -0
  547. package/lib/core/navigation/get-domains-for-trends.cjs +277 -0
  548. package/lib/core/navigation/governance.cjs +101 -0
  549. package/lib/core/navigation/grant-rubric.cjs +218 -0
  550. package/lib/core/navigation/graph-export.cjs +325 -0
  551. package/lib/core/navigation/ingestion.cjs +109 -0
  552. package/lib/core/navigation/insights-stale.test.cjs +127 -0
  553. package/lib/core/navigation/insights.cjs +574 -0
  554. package/lib/core/navigation/lens-nodes.cjs +315 -0
  555. package/lib/core/navigation/memory-artifacts.cjs +437 -0
  556. package/lib/core/navigation/memory-cortex-packet.cjs +274 -0
  557. package/lib/core/navigation/memory-events.cjs +811 -0
  558. package/lib/core/navigation/neighborhood.cjs +79 -0
  559. package/lib/core/navigation/packet.cjs +420 -0
  560. package/lib/core/navigation/planning-artifacts.cjs +219 -0
  561. package/lib/core/navigation/projections.cjs +295 -0
  562. package/lib/core/navigation/ranker-weights.cjs +133 -0
  563. package/lib/core/navigation/reasoning-write.cjs +211 -0
  564. package/lib/core/navigation/reconcile-guard.cjs +98 -0
  565. package/lib/core/navigation/reified-claim.cjs +287 -0
  566. package/lib/core/navigation/research-preflight.cjs +156 -0
  567. package/lib/core/navigation/room-birth.cjs +1213 -0
  568. package/lib/core/navigation/room-context.cjs +380 -0
  569. package/lib/core/navigation/room-home.cjs +142 -0
  570. package/lib/core/navigation/spine-events.cjs +548 -0
  571. package/lib/core/navigation/synthetic-expert.cjs +177 -0
  572. package/lib/core/navigation/transitions.cjs +253 -0
  573. package/lib/core/navigation/typed-claim.cjs +208 -0
  574. package/lib/core/navigation/typed-domain.cjs +249 -0
  575. package/lib/core/navigation/typed-entity.cjs +236 -0
  576. package/lib/core/navigation/typed-frame.cjs +257 -0
  577. package/lib/core/navigation/typed-open-question.cjs +130 -0
  578. package/lib/core/navigation/typed-opportunity.cjs +418 -0
  579. package/lib/core/navigation-engine-offer.cjs +776 -0
  580. package/lib/core/navigation-engine-shared.cjs +256 -0
  581. package/lib/core/navigation-engine.cjs +1696 -0
  582. package/lib/core/navigation.cjs +686 -0
  583. package/lib/core/nl-graph-queries.cjs +164 -0
  584. package/lib/core/node-insert-epistemic.test.cjs +212 -0
  585. package/lib/core/node-insert-overrides.test.cjs +273 -0
  586. package/lib/core/node-insert.cjs +274 -0
  587. package/lib/core/npm-cli-resolve.cjs +151 -0
  588. package/lib/core/npm-cli-resolve.test.cjs +153 -0
  589. package/lib/core/npm-install-lock.cjs +326 -0
  590. package/lib/core/npm-install-lock.test.cjs +379 -0
  591. package/lib/core/numeric/sklearn-stopwords-v1.json +325 -0
  592. package/lib/core/numeric/svd.cjs +377 -0
  593. package/lib/core/numeric/tfidf.cjs +241 -0
  594. package/lib/core/offer-presenter.cjs +406 -0
  595. package/lib/core/opportunity-extractor.cjs +183 -0
  596. package/lib/core/opportunity-ops.cjs +1423 -0
  597. package/lib/core/orchestration-candidate-lift.cjs +284 -0
  598. package/lib/core/part8-egress-guard.cjs +563 -0
  599. package/lib/core/part8-egress-guard.test.cjs +194 -0
  600. package/lib/core/part8-egress-ontology.cjs +174 -0
  601. package/lib/core/part8-egress-ontology.test.cjs +133 -0
  602. package/lib/core/persona-ops.cjs +692 -0
  603. package/lib/core/persona-override.cjs +327 -0
  604. package/lib/core/persona-taxonomy.cjs +328 -0
  605. package/lib/core/pinecone-inference.cjs +176 -0
  606. package/lib/core/pitch-feedback-schemas.cjs +303 -0
  607. package/lib/core/planning/artifact-brain-packet.cjs +212 -0
  608. package/lib/core/planning/reconcile-runner.cjs +347 -0
  609. package/lib/core/platform-gates.cjs +120 -0
  610. package/lib/core/platform.cjs +257 -0
  611. package/lib/core/proactive-intelligence.cjs +528 -0
  612. package/lib/core/problem-type-router.cjs +315 -0
  613. package/lib/core/publish-needs-default-lane.cjs +110 -0
  614. package/lib/core/ralph-loop-gate.cjs +48 -0
  615. package/lib/core/reader/ab-harness.cjs +177 -0
  616. package/lib/core/reader/decide-projection-reader.cjs +358 -0
  617. package/lib/core/reasoning-ops.cjs +639 -0
  618. package/lib/core/recipe-maps.cjs +442 -0
  619. package/lib/core/recovery/case-file.cjs +358 -0
  620. package/lib/core/recovery/controller.cjs +1008 -0
  621. package/lib/core/recovery/dispatcher.cjs +533 -0
  622. package/lib/core/recovery/result-semantics.cjs +488 -0
  623. package/lib/core/recovery/stage-envelope.cjs +338 -0
  624. package/lib/core/refusal-messaging.cjs +569 -0
  625. package/lib/core/refusal-messaging.test.cjs +220 -0
  626. package/lib/core/repo-version.cjs +134 -0
  627. package/lib/core/research-cache.cjs +165 -0
  628. package/lib/core/research-cache.test.cjs +137 -0
  629. package/lib/core/research-context-extractor.cjs +283 -0
  630. package/lib/core/research-corpus.cjs +814 -0
  631. package/lib/core/research-corpus.test.cjs +280 -0
  632. package/lib/core/research-filing-selector.cjs +189 -0
  633. package/lib/core/resolve-active-room.cjs +602 -0
  634. package/lib/core/resolve-brain-key.cjs +273 -0
  635. package/lib/core/resolve-umbilical-target.cjs +288 -0
  636. package/lib/core/resolve-vercel-key.cjs +107 -0
  637. package/lib/core/resolve-vercel-key.test.cjs +137 -0
  638. package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
  639. package/lib/core/room-auto-create.cjs +318 -0
  640. package/lib/core/room-auto-create.test.cjs +198 -0
  641. package/lib/core/room-chooser.cjs +244 -0
  642. package/lib/core/room-classifier-strict-mode.cjs +235 -0
  643. package/lib/core/room-db.cjs +348 -0
  644. package/lib/core/room-discard-cascade.cjs +238 -0
  645. package/lib/core/room-discard-cascade.test.cjs +135 -0
  646. package/lib/core/room-name-validator.cjs +132 -0
  647. package/lib/core/room-name-validator.test.cjs +156 -0
  648. package/lib/core/room-naming-selector.cjs +357 -0
  649. package/lib/core/room-naming-selector.test.cjs +277 -0
  650. package/lib/core/room-open.cjs +259 -0
  651. package/lib/core/room-ops-async.cjs +92 -0
  652. package/lib/core/room-ops-shared.cjs +64 -0
  653. package/lib/core/room-ops-sync.cjs +70 -0
  654. package/lib/core/room-ops.cjs +32 -0
  655. package/lib/core/room-receipt-emit.cjs +63 -0
  656. package/lib/core/room-root.cjs +93 -0
  657. package/lib/core/room-skeleton-scaffold.cjs +669 -0
  658. package/lib/core/room-skeleton-scaffold.test.cjs +296 -0
  659. package/lib/core/room-type-detector.cjs +386 -0
  660. package/lib/core/rs-backend-dispatch.cjs +64 -0
  661. package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
  662. package/lib/core/rs-brain-substrate.cjs +570 -0
  663. package/lib/core/rs-breakthrough-scorer.cjs +255 -0
  664. package/lib/core/rs-canon-violations.cjs +82 -0
  665. package/lib/core/rs-chain-feeder.cjs +381 -0
  666. package/lib/core/rs-commercial-assessor.cjs +280 -0
  667. package/lib/core/rs-corpus-quality-gate.cjs +62 -0
  668. package/lib/core/rs-differential-scorer.cjs +629 -0
  669. package/lib/core/rs-domain-analyzer.cjs +385 -0
  670. package/lib/core/rs-egress-prompts.cjs +113 -0
  671. package/lib/core/rs-egress-telemetry.cjs +225 -0
  672. package/lib/core/rs-egress-violations.cjs +53 -0
  673. package/lib/core/rs-engine.cjs +597 -0
  674. package/lib/core/rs-expert-brain-projection.cjs +280 -0
  675. package/lib/core/rs-expert-mapper.cjs +467 -0
  676. package/lib/core/rs-fetcher-academic.cjs +697 -0
  677. package/lib/core/rs-fetcher-experts.cjs +314 -0
  678. package/lib/core/rs-fetcher-industry.cjs +731 -0
  679. package/lib/core/rs-fetcher-patents.cjs +564 -0
  680. package/lib/core/rs-innovation-classifier.cjs +194 -0
  681. package/lib/core/rs-math.cjs +458 -0
  682. package/lib/core/rs-mind-map.cjs +656 -0
  683. package/lib/core/rs-neo4j-writer.cjs +388 -0
  684. package/lib/core/rs-nl-to-query.cjs +435 -0
  685. package/lib/core/rs-pinecone-bridge.cjs +344 -0
  686. package/lib/core/rs-preprocessor.cjs +350 -0
  687. package/lib/core/rs-query-matrix.cjs +316 -0
  688. package/lib/core/rs-query-to-text.cjs +438 -0
  689. package/lib/core/rs-sqlite-mirror.cjs +495 -0
  690. package/lib/core/rs-thesis-generator.cjs +188 -0
  691. package/lib/core/rs_cache.py +635 -0
  692. package/lib/core/rs_corpus.py +562 -0
  693. package/lib/core/rs_corpus_exclude.py +62 -0
  694. package/lib/core/rs_hybrid.py +589 -0
  695. package/lib/core/rs_math.py +287 -0
  696. package/lib/core/rs_rooms.py +196 -0
  697. package/lib/core/salient-governance.cjs +315 -0
  698. package/lib/core/scheduled-scanner.cjs +658 -0
  699. package/lib/core/scratchpad-ops.cjs +316 -0
  700. package/lib/core/seam-liveness.cjs +191 -0
  701. package/lib/core/seam-liveness.test.cjs +177 -0
  702. package/lib/core/section-8-trace-schema.cjs +138 -0
  703. package/lib/core/section-registry.cjs +167 -0
  704. package/lib/core/security/agentshield-adapters.test.cjs +104 -0
  705. package/lib/core/security/agentshield-run.cjs +343 -0
  706. package/lib/core/security/agentshield-scanner.cjs +314 -0
  707. package/lib/core/security/agentshield-scanner.test.cjs +259 -0
  708. package/lib/core/sensors/hat-scoping-table.cjs +103 -0
  709. package/lib/core/sensors/sensor-circularity.cjs +278 -0
  710. package/lib/core/sensors/sensor-content-relevance.cjs +407 -0
  711. package/lib/core/sensors/sensor-diffusion-adoption.cjs +230 -0
  712. package/lib/core/sensors/sensor-eureka.cjs +208 -0
  713. package/lib/core/sensors/sensor-expert-skill.cjs +293 -0
  714. package/lib/core/sensors/sensor-external-fact.cjs +184 -0
  715. package/lib/core/sensors/sensor-gate-approach.cjs +104 -0
  716. package/lib/core/sensors/sensor-jtbd-reweight.cjs +141 -0
  717. package/lib/core/sensors/sensor-lagging-component.cjs +115 -0
  718. package/lib/core/sensors/sensor-memory-cortex.cjs +111 -0
  719. package/lib/core/sensors/sensor-methodology-decision.cjs +131 -0
  720. package/lib/core/sensors/sensor-opportunity-harvest.cjs +195 -0
  721. package/lib/core/sensors/sensor-perspective-lock.cjs +174 -0
  722. package/lib/core/sensors/sensor-priority.cjs +183 -0
  723. package/lib/core/sensors/sensor-recency.cjs +151 -0
  724. package/lib/core/sensors/sensor-roadmap-type.cjs +421 -0
  725. package/lib/core/sensors/sensor-room-pick.cjs +238 -0
  726. package/lib/core/sensors/sensor-show-share.cjs +215 -0
  727. package/lib/core/sensors/sensor-temporal-blindness.cjs +123 -0
  728. package/lib/core/sensors/sensor-types.cjs +294 -0
  729. package/lib/core/sensors/sensor-url-ingest.cjs +234 -0
  730. package/lib/core/session-binding.cjs +208 -0
  731. package/lib/core/session-presence.cjs +404 -0
  732. package/lib/core/session-register.cjs +138 -0
  733. package/lib/core/session-state.cjs +144 -0
  734. package/lib/core/shallow-doc-parser.cjs +353 -0
  735. package/lib/core/shallow-doc-parser.test.cjs +226 -0
  736. package/lib/core/skill-activation-router.cjs +284 -0
  737. package/lib/core/skillopt-schemas.cjs +509 -0
  738. package/lib/core/stale-copy-scanner.cjs +190 -0
  739. package/lib/core/stance-state.cjs +153 -0
  740. package/lib/core/state-aware-router.cjs +78 -0
  741. package/lib/core/state-ops.cjs +80 -0
  742. package/lib/core/state-version.cjs +350 -0
  743. package/lib/core/statusline-cache.cjs +266 -0
  744. package/lib/core/statusline-liveness-gate.cjs +105 -0
  745. package/lib/core/surface-fence.cjs +127 -0
  746. package/lib/core/synthesizers/comparison-matrix.cjs +82 -0
  747. package/lib/core/synthesizers/convergence-map.cjs +107 -0
  748. package/lib/core/synthesizers/domain-hierarchy.cjs +138 -0
  749. package/lib/core/synthesizers/source-comparison.cjs +56 -0
  750. package/lib/core/synthesizers/tension-map.cjs +119 -0
  751. package/lib/core/synthetic-expert-behavior-gate.cjs +99 -0
  752. package/lib/core/synthetic-expert-construction-gate.cjs +170 -0
  753. package/lib/core/telemetry/schema.cjs +168 -0
  754. package/lib/core/telemetry/schema.test.cjs +124 -0
  755. package/lib/core/telemetry/validator.cjs +200 -0
  756. package/lib/core/telemetry/validator.test.cjs +188 -0
  757. package/lib/core/telemetry/writer.cjs +141 -0
  758. package/lib/core/telemetry/writer.test.cjs +331 -0
  759. package/lib/core/temporal/date-sync-gate.cjs +256 -0
  760. package/lib/core/temporal/date-sync-gate.test.cjs +191 -0
  761. package/lib/core/temporal/dual-stamp.cjs +172 -0
  762. package/lib/core/temporal/dual-stamp.test.cjs +172 -0
  763. package/lib/core/temporal/point-in-time.cjs +76 -0
  764. package/lib/core/temporal/point-in-time.test.cjs +169 -0
  765. package/lib/core/temporal/recency-decay.cjs +119 -0
  766. package/lib/core/temporal/recency-decay.test.cjs +140 -0
  767. package/lib/core/temporal/reference-now.cjs +281 -0
  768. package/lib/core/temporal/reference-now.test.cjs +225 -0
  769. package/lib/core/temporal/resolve-relative-time.cjs +116 -0
  770. package/lib/core/temporal/resolve-relative-time.test.cjs +138 -0
  771. package/lib/core/temporal/supersession.cjs +250 -0
  772. package/lib/core/temporal/supersession.test.cjs +103 -0
  773. package/lib/core/terminal-capability.cjs +88 -0
  774. package/lib/core/token-estimator.cjs +348 -0
  775. package/lib/core/tone-filter.cjs +147 -0
  776. package/lib/core/trending-to-absurd/orchestrator.cjs +341 -0
  777. package/lib/core/trending-to-absurd/stage7-roadmap.cjs +317 -0
  778. package/lib/core/trending-to-absurd/variance.cjs +169 -0
  779. package/lib/core/unknowns/bandit.cjs +332 -0
  780. package/lib/core/unknowns/corpus-adapter.cjs +327 -0
  781. package/lib/core/unknowns/dsp.cjs +356 -0
  782. package/lib/core/unknowns/edge-writer.cjs +211 -0
  783. package/lib/core/unknowns/iface.cjs +212 -0
  784. package/lib/core/unknowns/orchestrator.cjs +375 -0
  785. package/lib/core/unknowns/pattern-miner.cjs +214 -0
  786. package/lib/core/unknowns/rumsfeld-matrix.cjs +155 -0
  787. package/lib/core/unknowns/verdict.cjs +254 -0
  788. package/lib/core/update-path.cjs +57 -0
  789. package/lib/core/url-ingest.cjs +568 -0
  790. package/lib/core/user-archetype.cjs +284 -0
  791. package/lib/core/user-md-ops.cjs +578 -0
  792. package/lib/core/venture-shape-nudge.cjs +178 -0
  793. package/lib/core/venture-shape-nudge.test.cjs +266 -0
  794. package/lib/core/verb-reach-affinity.cjs +299 -0
  795. package/lib/core/visual-ops.cjs +692 -0
  796. package/lib/core/voice-transition-detector.cjs +125 -0
  797. package/lib/core/watched-sources.cjs +237 -0
  798. package/lib/core/write-lock.cjs +149 -0
  799. package/lib/graph/canvas-graph.js +467 -0
  800. package/lib/graph/constellation-config.cjs +299 -0
  801. package/lib/graph/graph-detail-panel.js +165 -0
  802. package/lib/hmi/ROOM.md +47 -0
  803. package/lib/hmi/across-session-memory.cjs +669 -0
  804. package/lib/hmi/agentshield-drift-gate.cjs +142 -0
  805. package/lib/hmi/brain-review-packet.cjs +221 -0
  806. package/lib/hmi/cortex-reach-adapter.cjs +271 -0
  807. package/lib/hmi/cross-room-memory.cjs +618 -0
  808. package/lib/hmi/decoy-tier.cjs +395 -0
  809. package/lib/hmi/depth-state.cjs +164 -0
  810. package/lib/hmi/dial-label-composer.cjs +410 -0
  811. package/lib/hmi/dial-presenter.cjs +508 -0
  812. package/lib/hmi/dial-reach-orchestrator.cjs +377 -0
  813. package/lib/hmi/dial-selector.cjs +239 -0
  814. package/lib/hmi/f1-pick-capture-cli.cjs +131 -0
  815. package/lib/hmi/f3-depth-capture-cli.cjs +77 -0
  816. package/lib/hmi/f4-scope-capture-cli.cjs +86 -0
  817. package/lib/hmi/f8-action-capture-cli.cjs +145 -0
  818. package/lib/hmi/f8-capture.test.cjs +77 -0
  819. package/lib/hmi/f9-ordered-capture-cli.cjs +138 -0
  820. package/lib/hmi/harvest-scope-state.cjs +202 -0
  821. package/lib/hmi/hats-persona-cache.cjs +142 -0
  822. package/lib/hmi/jtbd-classifier.cjs +219 -0
  823. package/lib/hmi/jtbd-state.cjs +263 -0
  824. package/lib/hmi/jtbd-taxonomy.json +402 -0
  825. package/lib/hmi/mindrian-ascii-logo.cjs +96 -0
  826. package/lib/hmi/part8-egress-gate.cjs +149 -0
  827. package/lib/hmi/reach-component-map.json +47 -0
  828. package/lib/hmi/reach-relevance-gate.cjs +147 -0
  829. package/lib/hmi/selector-dispatcher.cjs +1201 -0
  830. package/lib/hmi/selector-dispatcher.test.cjs +141 -0
  831. package/lib/hmi/selector-telemetry.cjs +269 -0
  832. package/lib/hmi/shape-f0-renderer.cjs +145 -0
  833. package/lib/hmi/shape-f1-fallback.cjs +80 -0
  834. package/lib/hmi/shape-f1-renderer.cjs +219 -0
  835. package/lib/hmi/shape-f2-renderer.cjs +132 -0
  836. package/lib/hmi/shape-f3-parity.test.cjs +64 -0
  837. package/lib/hmi/shape-f3-renderer.cjs +66 -0
  838. package/lib/hmi/shape-f4-parity.test.cjs +72 -0
  839. package/lib/hmi/shape-f4-renderer.cjs +72 -0
  840. package/lib/hmi/shape-f5-renderer.cjs +155 -0
  841. package/lib/hmi/shape-f6-plan-review-renderer.cjs +324 -0
  842. package/lib/hmi/shape-f6-renderer.cjs +144 -0
  843. package/lib/hmi/shape-f7-breakthrough-renderer.cjs +234 -0
  844. package/lib/hmi/shape-f7-breakthrough-renderer.test.cjs +233 -0
  845. package/lib/hmi/shape-f8-renderer.cjs +150 -0
  846. package/lib/hmi/shape-f8-renderer.test.cjs +70 -0
  847. package/lib/hmi/shape-f9-renderer.cjs +187 -0
  848. package/lib/hmi/shape-f9-renderer.test.cjs +80 -0
  849. package/lib/hmi/shape-g-renderer.cjs +219 -0
  850. package/lib/hmi/shape-h-renderer.cjs +222 -0
  851. package/lib/hmi/tier-check.cjs +63 -0
  852. package/lib/hmi/turn-text.cjs +268 -0
  853. package/lib/hmi/voice-color-mark.cjs +318 -0
  854. package/lib/hmi/voice-style-log.cjs +276 -0
  855. package/lib/import/PRECONDITIONS.md +41 -0
  856. package/lib/import/branding.cjs +210 -0
  857. package/lib/import/branding.test.cjs +235 -0
  858. package/lib/import/classifications-sync.cjs +104 -0
  859. package/lib/import/classifications-sync.test.cjs +129 -0
  860. package/lib/import/enricher.cjs +296 -0
  861. package/lib/import/enricher.test.cjs +273 -0
  862. package/lib/import/integration.test.cjs +376 -0
  863. package/lib/import/manifest.cjs +129 -0
  864. package/lib/import/manifest.schema.json +185 -0
  865. package/lib/import/manifest.test.cjs +123 -0
  866. package/lib/import/meeting-detector.cjs +92 -0
  867. package/lib/import/meeting-detector.test.cjs +100 -0
  868. package/lib/import/person-detector.cjs +229 -0
  869. package/lib/import/person-detector.test.cjs +149 -0
  870. package/lib/import/report.cjs +186 -0
  871. package/lib/import/report.test.cjs +186 -0
  872. package/lib/import/room-md-scaffolder.cjs +49 -0
  873. package/lib/import/router.cjs +224 -0
  874. package/lib/import/router.test.cjs +356 -0
  875. package/lib/import/run-all-tests.cjs +36 -0
  876. package/lib/import/smoke-test.cjs +213 -0
  877. package/lib/import/smoke-test.test.cjs +148 -0
  878. package/lib/import/undo.test.cjs +199 -0
  879. package/lib/import/vault-scanner.cjs +105 -0
  880. package/lib/import/vault-scanner.test.cjs +67 -0
  881. package/lib/lens-engine/correlation-resolver.cjs +174 -0
  882. package/lib/lens-engine/source-lens-driver.cjs +736 -0
  883. package/lib/mcp/adapter-client.cjs +103 -0
  884. package/lib/mcp/app-html/dashboard.html +316 -0
  885. package/lib/mcp/app-html/graph.html +428 -0
  886. package/lib/mcp/app-html/mindrian-platform.html +1841 -0
  887. package/lib/mcp/app-html/wiki.html +383 -0
  888. package/lib/mcp/app-views.cjs +322 -0
  889. package/lib/mcp/brain-composition-census.cjs +184 -0
  890. package/lib/mcp/brain-router.cjs +551 -0
  891. package/lib/mcp/capability-registry.cjs +62 -0
  892. package/lib/mcp/contract-version.cjs +59 -0
  893. package/lib/mcp/daemon-lifecycle.cjs +324 -0
  894. package/lib/mcp/gate-dedup.cjs +120 -0
  895. package/lib/mcp/gate-ledger.cjs +145 -0
  896. package/lib/mcp/gate-render.cjs +483 -0
  897. package/lib/mcp/hook-adapter-audit.cjs +199 -0
  898. package/lib/mcp/larry-context.cjs +42 -0
  899. package/lib/mcp/mcp-first-flag.cjs +147 -0
  900. package/lib/mcp/no-instructions.test.cjs +270 -0
  901. package/lib/mcp/pipeline-state.cjs +424 -0
  902. package/lib/mcp/prompts.cjs +421 -0
  903. package/lib/mcp/register-core-tools.cjs +78 -0
  904. package/lib/mcp/resources.cjs +359 -0
  905. package/lib/mcp/runtime-instructions.cjs +38 -0
  906. package/lib/mcp/session-catchup.cjs +349 -0
  907. package/lib/mcp/session-registry.cjs +113 -0
  908. package/lib/mcp/session-room.cjs +124 -0
  909. package/lib/mcp/sse-event-bus.cjs +98 -0
  910. package/lib/mcp/stop-gate-handler.cjs +589 -0
  911. package/lib/mcp/surface-detect.cjs +186 -0
  912. package/lib/mcp/tool-router.cjs +2115 -0
  913. package/lib/mcp/tools/chain.cjs +674 -0
  914. package/lib/mcp/tools/claim.cjs +180 -0
  915. package/lib/mcp/tools/context.cjs +92 -0
  916. package/lib/mcp/tools/dual-path.cjs +79 -0
  917. package/lib/mcp/tools/gate.cjs +392 -0
  918. package/lib/mcp/tools/graph-reason.cjs +130 -0
  919. package/lib/mcp/tools/graph.cjs +321 -0
  920. package/lib/mcp/tools/identity.cjs +174 -0
  921. package/lib/mcp/tools/room.cjs +449 -0
  922. package/lib/mcp/tools/sensors.cjs +450 -0
  923. package/lib/mcp/tools/status.cjs +183 -0
  924. package/lib/mcp/tools/stop-gate.cjs +103 -0
  925. package/lib/mcp/tools/views.cjs +382 -0
  926. package/lib/mcp/tree-watcher.cjs +199 -0
  927. package/lib/memory/.mindrian/auto-explore-mat-test-001.json +11 -0
  928. package/lib/memory/aaak-compress.cjs +403 -0
  929. package/lib/memory/aaak-compress.test.cjs +288 -0
  930. package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
  931. package/lib/memory/bearer-token.test.cjs +315 -0
  932. package/lib/memory/body-shape-coverage.test.cjs +268 -0
  933. package/lib/memory/brain-cache-lru.test.cjs +259 -0
  934. package/lib/memory/brain-client-query-shape.test.cjs +160 -0
  935. package/lib/memory/brain-cypher-chain-slice.test.cjs +368 -0
  936. package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
  937. package/lib/memory/brain-derivation-queue.test.cjs +553 -0
  938. package/lib/memory/brain-derivation.test.cjs +639 -0
  939. package/lib/memory/brain-derive-command.test.cjs +534 -0
  940. package/lib/memory/brain-derive-curation.test.cjs +243 -0
  941. package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
  942. package/lib/memory/brain-md-schema.test.cjs +467 -0
  943. package/lib/memory/brain-md-staleness.test.cjs +525 -0
  944. package/lib/memory/brain-server-resolution.test.cjs +314 -0
  945. package/lib/memory/brain-suggestion-template.test.cjs +200 -0
  946. package/lib/memory/chain-recommender-canonical.test.cjs +208 -0
  947. package/lib/memory/chain-recommender.test.cjs +233 -0
  948. package/lib/memory/chat-context.test.cjs +128 -0
  949. package/lib/memory/command-registry.test.cjs +220 -0
  950. package/lib/memory/connector-registry.test.cjs +94 -0
  951. package/lib/memory/correlation-label-index.test.cjs +119 -0
  952. package/lib/memory/correlation.test.cjs +253 -0
  953. package/lib/memory/cross-room-aggregator.test.cjs +909 -0
  954. package/lib/memory/curation-132-03-dedup-held-rename.test.cjs +251 -0
  955. package/lib/memory/curation-132-05-pseudonymize.test.cjs +205 -0
  956. package/lib/memory/curation-batch.test.cjs +213 -0
  957. package/lib/memory/dashboard-server.test.cjs +256 -0
  958. package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
  959. package/lib/memory/decision-capture.test.cjs +632 -0
  960. package/lib/memory/decision-capture.worker.cjs +70 -0
  961. package/lib/memory/doctor-deprecation-surface.test.cjs +188 -0
  962. package/lib/memory/dual-graph-health.test.cjs +485 -0
  963. package/lib/memory/explain-decision-command.test.cjs +521 -0
  964. package/lib/memory/explain-decision-footer.test.cjs +316 -0
  965. package/lib/memory/explored-materials-store.cjs +392 -0
  966. package/lib/memory/f-selector-ranker.test.cjs +593 -0
  967. package/lib/memory/feynman-minto-guardian.test.cjs +863 -0
  968. package/lib/memory/feynman-minto-invariants.test.cjs +554 -0
  969. package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
  970. package/lib/memory/feynman-prompts.cjs +151 -0
  971. package/lib/memory/feynman-prompts.test.cjs +96 -0
  972. package/lib/memory/first-touch-version.test.cjs +198 -0
  973. package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
  974. package/lib/memory/folder-memory.test.cjs +503 -0
  975. package/lib/memory/framework-chain-composer.test.cjs +549 -0
  976. package/lib/memory/frontmatter-schema-validator.test.cjs +344 -0
  977. package/lib/memory/guardian-onstop-reaches-user.test.cjs +396 -0
  978. package/lib/memory/heal-command.test.cjs +604 -0
  979. package/lib/memory/help-coverage.test.cjs +108 -0
  980. package/lib/memory/help-renderer.test.cjs +145 -0
  981. package/lib/memory/huji-run-one-async-parity.test.cjs +242 -0
  982. package/lib/memory/hypergraph-event-schema.test.cjs +116 -0
  983. package/lib/memory/index-artifact-transaction.test.cjs +333 -0
  984. package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
  985. package/lib/memory/local-chain-recommender.test.cjs +172 -0
  986. package/lib/memory/mcp-input-validation.test.cjs +240 -0
  987. package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
  988. package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
  989. package/lib/memory/minto-debounce-consumer-census.test.cjs +567 -0
  990. package/lib/memory/minto-debouncer.test.cjs +407 -0
  991. package/lib/memory/minto-debouncer.worker.cjs +46 -0
  992. package/lib/memory/minto-migration-v88.test.cjs +265 -0
  993. package/lib/memory/minto-schema-v88.test.cjs +390 -0
  994. package/lib/memory/mos-status-renderer.test.cjs +631 -0
  995. package/lib/memory/narrative-schema.cjs +376 -0
  996. package/lib/memory/narrative-schema.test.cjs +209 -0
  997. package/lib/memory/nav-dial.test.cjs +414 -0
  998. package/lib/memory/navigation-engine-core.test.cjs +712 -0
  999. package/lib/memory/navigation-engine-offer.test.cjs +404 -0
  1000. package/lib/memory/navigation-hook-resolver.test.cjs +177 -0
  1001. package/lib/memory/navigation-invariants.test.cjs +483 -0
  1002. package/lib/memory/navigation-projections.test.cjs +241 -0
  1003. package/lib/memory/navigation-write-edge.test.cjs +206 -0
  1004. package/lib/memory/offer-closer.test.cjs +258 -0
  1005. package/lib/memory/offer-presenter.test.cjs +554 -0
  1006. package/lib/memory/on-stop-snapshot.test.cjs +404 -0
  1007. package/lib/memory/orchestration-projection.test.cjs +706 -0
  1008. package/lib/memory/packet-chain-hint.test.cjs +407 -0
  1009. package/lib/memory/packet-schema-validation.test.cjs +317 -0
  1010. package/lib/memory/palette-consistency.test.cjs +127 -0
  1011. package/lib/memory/pending-tension-store.cjs +453 -0
  1012. package/lib/memory/per-command-jtbd-derivation.test.cjs +130 -0
  1013. package/lib/memory/per-command-teaching.test.cjs +110 -0
  1014. package/lib/memory/post-compact-reinjection.test.cjs +854 -0
  1015. package/lib/memory/post-write-triple.test.cjs +317 -0
  1016. package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
  1017. package/lib/memory/precommit-real-commit.test.cjs +301 -0
  1018. package/lib/memory/problem-type-router.test.cjs +656 -0
  1019. package/lib/memory/query-efficiency-telemetry.test.cjs +612 -0
  1020. package/lib/memory/recompile-room-references.test.cjs +392 -0
  1021. package/lib/memory/recompile-room-references.worker.cjs +42 -0
  1022. package/lib/memory/record-decision-dual-write.test.cjs +454 -0
  1023. package/lib/memory/render-v2-disposition.test.cjs +199 -0
  1024. package/lib/memory/room-classifier-strict-mode.test.cjs +430 -0
  1025. package/lib/memory/room-minto-hook.test.cjs +398 -0
  1026. package/lib/memory/rs-discovery-engine.test.cjs +323 -0
  1027. package/lib/memory/run-feynman-tests.cjs +2101 -0
  1028. package/lib/memory/security-trifecta.test.cjs +329 -0
  1029. package/lib/memory/selector-alias-map.test.cjs +172 -0
  1030. package/lib/memory/selector-decisions.test.cjs +417 -0
  1031. package/lib/memory/selector-miss.test.cjs +290 -0
  1032. package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
  1033. package/lib/memory/session-start-triple-injection.test.cjs +514 -0
  1034. package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
  1035. package/lib/memory/sessionstart-coordinator.test.cjs +446 -0
  1036. package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
  1037. package/lib/memory/skill-activation-router.test.cjs +465 -0
  1038. package/lib/memory/skill-vs-code-drift.test.cjs +257 -0
  1039. package/lib/memory/soft-alias.test.cjs +144 -0
  1040. package/lib/memory/spine-events-correlation.test.cjs +198 -0
  1041. package/lib/memory/stale-copy-scanner.test.cjs +294 -0
  1042. package/lib/memory/stamp-artifact-write.test.cjs +304 -0
  1043. package/lib/memory/state-aware-router.test.cjs +90 -0
  1044. package/lib/memory/statusline-active-room-write.test.cjs +245 -0
  1045. package/lib/memory/statusline-active-room.test.cjs +315 -0
  1046. package/lib/memory/statusline-minto-segment.test.cjs +292 -0
  1047. package/lib/memory/statusline-two-row.test.cjs +338 -0
  1048. package/lib/memory/suggest-next-workflow.test.cjs +176 -0
  1049. package/lib/memory/sync-async-entry-points.test.cjs +204 -0
  1050. package/lib/memory/terminal-capability.test.cjs +155 -0
  1051. package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
  1052. package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
  1053. package/lib/memory/test-rs-brain-substrate.cjs +636 -0
  1054. package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
  1055. package/lib/memory/test-rs-canon-violations.cjs +218 -0
  1056. package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
  1057. package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
  1058. package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
  1059. package/lib/memory/test-rs-differential-scorer.cjs +480 -0
  1060. package/lib/memory/test-rs-discovery-engine.cjs +648 -0
  1061. package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
  1062. package/lib/memory/test-rs-egress-primitives.cjs +420 -0
  1063. package/lib/memory/test-rs-expert-mapper.cjs +547 -0
  1064. package/lib/memory/test-rs-explain-command.cjs +443 -0
  1065. package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
  1066. package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
  1067. package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
  1068. package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
  1069. package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
  1070. package/lib/memory/test-rs-mind-map.cjs +646 -0
  1071. package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
  1072. package/lib/memory/test-rs-nl-to-query.cjs +449 -0
  1073. package/lib/memory/test-rs-pinecone-bridge.cjs +282 -0
  1074. package/lib/memory/test-rs-preprocessor.cjs +433 -0
  1075. package/lib/memory/test-rs-query-matrix.cjs +391 -0
  1076. package/lib/memory/test-rs-query-to-text.cjs +551 -0
  1077. package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
  1078. package/lib/memory/test-rs-thesis-generator.cjs +360 -0
  1079. package/lib/memory/triple-context-formatter.cjs +473 -0
  1080. package/lib/memory/triple-context-formatter.test.cjs +442 -0
  1081. package/lib/memory/user-md-persona.test.cjs +565 -0
  1082. package/lib/memory/userpromptsubmit-integration.test.cjs +787 -0
  1083. package/lib/memory/validators/README.md +157 -0
  1084. package/lib/memory/validators/brain-md-invariants.cjs +475 -0
  1085. package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
  1086. package/lib/memory/validators/external-academic-invariants.cjs +249 -0
  1087. package/lib/memory/validators/external-industry-invariants.cjs +271 -0
  1088. package/lib/memory/validators/external-patents-invariants.cjs +266 -0
  1089. package/lib/memory/validators/minto-invariants.cjs +62 -0
  1090. package/lib/memory/validators/navigation-invariants.cjs +340 -0
  1091. package/lib/memory/validators/queue-health.cjs +95 -0
  1092. package/lib/memory/validators/snapshot-integrity.cjs +129 -0
  1093. package/lib/memory/validators/stale-lifecycle.cjs +116 -0
  1094. package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
  1095. package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
  1096. package/lib/memory/workflow-layer-e2e.test.cjs +262 -0
  1097. package/lib/memory/write-lock-atomic.test.cjs +137 -0
  1098. package/lib/memory/write-lock-atomic.worker.cjs +55 -0
  1099. package/lib/parity/check-parity.cjs +83 -0
  1100. package/lib/presentation/presentation-server.cjs +101 -0
  1101. package/lib/presentation/presentation-watcher.cjs +123 -0
  1102. package/lib/quickview/hub-server.cjs +719 -0
  1103. package/lib/quickview/server.cjs +533 -0
  1104. package/lib/render/JTBD-PALETTES.md +145 -0
  1105. package/lib/render/ROOM.md +111 -0
  1106. package/lib/render/render-v2.cjs +532 -0
  1107. package/lib/render/render-v2.test.cjs +267 -0
  1108. package/lib/render/render.cjs +65 -0
  1109. package/lib/sessionstart/budget-compressor.cjs +130 -0
  1110. package/lib/sessionstart/contributor-interface.cjs +134 -0
  1111. package/lib/sessionstart/contributor-isolator.cjs +128 -0
  1112. package/lib/sessionstart/precedence-ladder.cjs +47 -0
  1113. package/lib/state/ROOM.md +46 -0
  1114. package/lib/state/state-md-parser.cjs +215 -0
  1115. package/lib/statusline/ROOM.md +38 -0
  1116. package/lib/statusline/banner-suppression.cjs +50 -0
  1117. package/lib/statusline/cockpit-renderer.cjs +443 -0
  1118. package/lib/statusline/cockpit-signals.cjs +312 -0
  1119. package/lib/statusline/cockpit-telemetry.cjs +152 -0
  1120. package/lib/statusline/ctx-window.cjs +135 -0
  1121. package/lib/statusline/governing-thought-truncator.cjs +45 -0
  1122. package/lib/statusline/next-move-cache.cjs +235 -0
  1123. package/lib/statusline/ratification-next.cjs +164 -0
  1124. package/lib/statusline/room-health-cache.cjs +200 -0
  1125. package/lib/statusline/surface-detect.cjs +85 -0
  1126. package/lib/statusline/two-row-renderer.cjs +207 -0
  1127. package/lib/statusline/version-resolver.cjs +81 -0
  1128. package/lib/ui/design-system.cjs +19 -0
  1129. package/lib/update-bootstrap.sh.template +145 -0
  1130. package/lib/vault/frontmatter-schema.cjs +297 -0
  1131. package/lib/vault/room-scanner.cjs +365 -0
  1132. package/lib/vault/wikilink-builder.cjs +231 -0
  1133. package/lib/vault/wikilink-builder.test.cjs +182 -0
  1134. package/lib/wiki/briefing.cjs +193 -0
  1135. package/lib/wiki/editor-dist/wiki-editor.css +1 -0
  1136. package/lib/wiki/editor-dist/wiki-editor.js +1327 -0
  1137. package/lib/wiki/graph-links.cjs +281 -0
  1138. package/lib/wiki/page-renderer.cjs +229 -0
  1139. package/lib/wiki/room-home.cjs +353 -0
  1140. package/lib/wiki/wiki-chat.cjs +81 -0
  1141. package/lib/wiki/wiki-export.cjs +364 -0
  1142. package/lib/wiki/wiki-layout.cjs +1143 -0
  1143. package/lib/wiki/wiki-search.cjs +142 -0
  1144. package/lib/wiki/wiki-server.cjs +748 -0
  1145. package/lib/wiki/wiki-watcher.cjs +105 -0
  1146. package/lib/workflow/ROOM.md +47 -0
  1147. package/lib/workflow/chain-source.cjs +179 -0
  1148. package/lib/workflow/command-resolver.cjs +155 -0
  1149. package/lib/workflow/command-resolver.test.cjs +235 -0
  1150. package/lib/workflow/cross-room-umbilical-closer.cjs +364 -0
  1151. package/lib/workflow/dial-close-reach.cjs +405 -0
  1152. package/lib/workflow/f-selector-ranker.cjs +1148 -0
  1153. package/lib/workflow/f1-pick-consumer.cjs +232 -0
  1154. package/lib/workflow/f3-depth-consumer.cjs +98 -0
  1155. package/lib/workflow/f4-scope-consumer.cjs +112 -0
  1156. package/lib/workflow/f8-consumer.test.cjs +82 -0
  1157. package/lib/workflow/f8-fanout-consumer.cjs +208 -0
  1158. package/lib/workflow/f9-consumer.test.cjs +71 -0
  1159. package/lib/workflow/f9-ordered-consumer.cjs +199 -0
  1160. package/lib/workflow/local-chain-recommender.cjs +330 -0
  1161. package/lib/workflow/memory-cascade-f9-adapter.cjs +273 -0
  1162. package/lib/workflow/memory-governance-closer.cjs +384 -0
  1163. package/lib/workflow/offer-closer.cjs +407 -0
  1164. package/lib/workflow/reach-hedge-ranker.cjs +809 -0
  1165. package/lib/workflow/reach-reject-reader.cjs +372 -0
  1166. package/lib/workflow/reconcile-f9-adapter.cjs +299 -0
  1167. package/lib/workflow/selector-decisions.cjs +478 -0
  1168. package/lib/workflow/session-binding-consumer.cjs +249 -0
  1169. package/npm-shrinkwrap.json +1544 -0
  1170. package/output-styles/destijl.md +67 -0
  1171. package/package.json +22 -4
  1172. package/pipelines/PWS_grading/01-deep-grade.md +48 -0
  1173. package/pipelines/PWS_grading/02-mullins.md +50 -0
  1174. package/pipelines/PWS_grading/03-build-thesis.md +60 -0
  1175. package/pipelines/PWS_grading/04-structure-argument.md +77 -0
  1176. package/pipelines/PWS_grading/CHAIN.md +79 -0
  1177. package/pipelines/analogy/01-decompose.md +80 -0
  1178. package/pipelines/analogy/02-abstract.md +87 -0
  1179. package/pipelines/analogy/03-search.md +135 -0
  1180. package/pipelines/analogy/04-transfer.md +101 -0
  1181. package/pipelines/analogy/05-validate.md +106 -0
  1182. package/pipelines/analogy/CHAIN.md +73 -0
  1183. package/pipelines/discovery/01-explore-domains.md +44 -0
  1184. package/pipelines/discovery/02-think-hats.md +50 -0
  1185. package/pipelines/discovery/03-analyze-needs.md +54 -0
  1186. package/pipelines/discovery/CHAIN.md +48 -0
  1187. package/pipelines/thesis/01-structure-argument.md +45 -0
  1188. package/pipelines/thesis/02-challenge-assumptions.md +48 -0
  1189. package/pipelines/thesis/03-build-thesis.md +54 -0
  1190. package/pipelines/thesis/CHAIN.md +48 -0
  1191. package/references/brain/causal-directives.md +91 -0
  1192. package/references/brain/causal-enrichment.cypher +165 -0
  1193. package/references/brain/command-triggers-schema.md +15 -0
  1194. package/references/brain/graph-architecture.md +317 -0
  1195. package/references/brain/query-patterns.md +504 -0
  1196. package/references/brain/room-hierarchy-schema.md +224 -0
  1197. package/references/brain/schema.md +86 -0
  1198. package/references/capability-radar/capabilities-index.md +269 -0
  1199. package/references/capability-radar/changelog-cache.md +95 -0
  1200. package/references/causal/causal-schema.md +103 -0
  1201. package/references/design/email-template-standard.md +169 -0
  1202. package/references/design/graph-visualization-standard.md +178 -0
  1203. package/references/design/newsletter-email-template.html +307 -0
  1204. package/references/document-generation.md +179 -0
  1205. package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
  1206. package/references/import-config.md +141 -0
  1207. package/references/integrations/detection-patterns.md +101 -0
  1208. package/references/meeting/artifact-template.md +377 -0
  1209. package/references/meeting/cross-meeting-intelligence.md +216 -0
  1210. package/references/meeting/cross-relationship-patterns.md +202 -0
  1211. package/references/meeting/extraction-perspectives.md +225 -0
  1212. package/references/meeting/filing-protocol.md +222 -0
  1213. package/references/meeting/knowledge-typing.md +242 -0
  1214. package/references/meeting/live-join-interface.md +244 -0
  1215. package/references/meeting/section-mapping.md +192 -0
  1216. package/references/meeting/segment-classification.md +258 -0
  1217. package/references/meeting/speaker-profile-template.md +219 -0
  1218. package/references/meeting/summary-template.md +348 -0
  1219. package/references/meeting/transcript-patterns.md +226 -0
  1220. package/references/methodology/analyze-needs.md +135 -0
  1221. package/references/methodology/analyze-systems.md +121 -0
  1222. package/references/methodology/analyze-timing.md +149 -0
  1223. package/references/methodology/beautiful-question.md +109 -0
  1224. package/references/methodology/build-knowledge.md +161 -0
  1225. package/references/methodology/build-thesis-scored.md +60 -0
  1226. package/references/methodology/build-thesis.md +237 -0
  1227. package/references/methodology/causal-loop-diagrams.md +65 -0
  1228. package/references/methodology/challenge-assumptions.md +127 -0
  1229. package/references/methodology/diagnose.md +169 -0
  1230. package/references/methodology/dominant-designs.md +212 -0
  1231. package/references/methodology/explore-domains.md +147 -0
  1232. package/references/methodology/explore-futures.md +163 -0
  1233. package/references/methodology/explore-trends.md +129 -0
  1234. package/references/methodology/find-bottlenecks.md +131 -0
  1235. package/references/methodology/grade.md +211 -0
  1236. package/references/methodology/huji-stage-a-intake.md +246 -0
  1237. package/references/methodology/index.md +34 -0
  1238. package/references/methodology/leadership.md +200 -0
  1239. package/references/methodology/lean-canvas.md +116 -0
  1240. package/references/methodology/leverage-scan-signatures.md +83 -0
  1241. package/references/methodology/macro-trends.md +192 -0
  1242. package/references/methodology/map-unknowns.md +137 -0
  1243. package/references/methodology/mullins-7-domains.md +104 -0
  1244. package/references/methodology/problem-types.md +65 -0
  1245. package/references/methodology/root-cause.md +178 -0
  1246. package/references/methodology/rubric-huji.md +160 -0
  1247. package/references/methodology/sapphire-encoding.md +355 -0
  1248. package/references/methodology/scenario-plan.md +190 -0
  1249. package/references/methodology/score-innovation.md +154 -0
  1250. package/references/methodology/skillopt-judge-rubric.md +48 -0
  1251. package/references/methodology/skillopt-queries-rubric.md +60 -0
  1252. package/references/methodology/skillopt-refute-rubric.md +59 -0
  1253. package/references/methodology/skillopt-review-rubric.md +72 -0
  1254. package/references/methodology/skillopt-revise-rubric.md +48 -0
  1255. package/references/methodology/structure-argument.md +158 -0
  1256. package/references/methodology/systems-thinking.md +231 -0
  1257. package/references/methodology/think-hats.md +147 -0
  1258. package/references/methodology/triz-matrix.json +751 -0
  1259. package/references/methodology/triz-principles.md +501 -0
  1260. package/references/methodology/user-needs.md +199 -0
  1261. package/references/methodology/validate.md +163 -0
  1262. package/references/methodology/value-proposition.md +244 -0
  1263. package/references/opportunities/funding-lifecycle.md +103 -0
  1264. package/references/opportunities/grant-api-patterns.md +99 -0
  1265. package/references/opportunities/opportunity-template.md +84 -0
  1266. package/references/opportunities/tnufa-rubric.md +81 -0
  1267. package/references/personality/assessment-philosophy.md +72 -0
  1268. package/references/personality/lexicon.md +100 -0
  1269. package/references/personality/persona-chains.md +56 -0
  1270. package/references/personality/pws-lexicon-full.md +499 -0
  1271. package/references/personality/voice-dna.md +156 -0
  1272. package/references/personas/hat-perspectives.md +76 -0
  1273. package/references/personas/persona-template.md +63 -0
  1274. package/references/pipeline/act-output-contract.md +88 -0
  1275. package/references/pipeline/chains-index.md +39 -0
  1276. package/references/pws-profile-generation.md +79 -0
  1277. package/references/reasoning/reasoning-schema.md +143 -0
  1278. package/references/reasoning/reasoning-template.md +68 -0
  1279. package/references/reasoning/run-template.md +38 -0
  1280. package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
  1281. package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
  1282. package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
  1283. package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
  1284. package/references/security/agentshield-baseline.json +8 -0
  1285. package/references/security/cve-db.json +220 -0
  1286. package/references/taxonomy/TAXONOMY.md +192 -0
  1287. package/references/templates/MINTO.md +36 -0
  1288. package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
  1289. package/references/vault-kit/README.md +35 -0
  1290. package/references/vault-kit/app.json +12 -0
  1291. package/references/vault-kit/appearance.json +12 -0
  1292. package/references/vault-kit/graph.json +35 -0
  1293. package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
  1294. package/references/vault-kit/templates/new-artifact.md +37 -0
  1295. package/references/vault-kit/templates/new-meeting-note.md +35 -0
  1296. package/references/vault-kit/templates/new-team-profile.md +29 -0
  1297. package/references/vault-kit/templates/new-xref.md +35 -0
  1298. package/references/visual/ROOM.md +55 -0
  1299. package/references/visual/palette.json +54 -0
  1300. package/references/visual/symbol-system.md +151 -0
  1301. package/scripts/189-plurai-gate-check.cjs +88 -0
  1302. package/scripts/198-plurai-gate-check.cjs +118 -0
  1303. package/scripts/198-rollback-rehearsal.cjs +233 -0
  1304. package/scripts/83-scope-injection.test.cjs +648 -0
  1305. package/scripts/PYTHON_GATES.md +78 -0
  1306. package/scripts/__pycache__/compute-hsi.cpython-312.pyc +0 -0
  1307. package/scripts/__pycache__/detect-reverse-salients.cpython-312.pyc +0 -0
  1308. package/scripts/__pycache__/rs-engine.cpython-312.pyc +0 -0
  1309. package/scripts/act-command.cjs +518 -0
  1310. package/scripts/admin-brain-write.cjs +442 -0
  1311. package/scripts/admin-command-gate.cjs +178 -0
  1312. package/scripts/agentshield-scan-cli.cjs +226 -0
  1313. package/scripts/agentshield-sessionstart-scan.cjs +282 -0
  1314. package/scripts/analogy-fitness-report.cjs +266 -0
  1315. package/scripts/analyze-room +1079 -0
  1316. package/scripts/apply-teaching-content.cjs +298 -0
  1317. package/scripts/async-artifact-auto-commit.cjs +485 -0
  1318. package/scripts/audit-active-phase-resolver.cjs +160 -0
  1319. package/scripts/audit-body-shape-coverage.cjs +213 -0
  1320. package/scripts/auto-explore-drain.cjs +274 -0
  1321. package/scripts/auto-explore-fingerprint.cjs +354 -0
  1322. package/scripts/auto-explore-fire.cjs +359 -0
  1323. package/scripts/backfill-correlation-id.cjs +425 -0
  1324. package/scripts/backfill-hitl-shape.cjs +276 -0
  1325. package/scripts/backfill-hitl-shape.test.cjs +307 -0
  1326. package/scripts/backup-modifications +68 -0
  1327. package/scripts/banner +182 -0
  1328. package/scripts/brain-derivation-drain.cjs +291 -0
  1329. package/scripts/brain-derive-command.cjs +846 -0
  1330. package/scripts/brain-normalize-books.cypher +505 -0
  1331. package/scripts/brain-normalize-final.cypher +1355 -0
  1332. package/scripts/brain-normalize-problemtype.cypher +475 -0
  1333. package/scripts/brain-normalize-supplement.cypher +449 -0
  1334. package/scripts/brain-normalize-targeted.cypher +344 -0
  1335. package/scripts/brain-normalize-v194.cypher +61 -0
  1336. package/scripts/brain-normalize.cypher +530 -0
  1337. package/scripts/brain-response-sanitize-hook.cjs +165 -0
  1338. package/scripts/build-brain-census.cjs +957 -0
  1339. package/scripts/build-brain-packet-schema.cjs +225 -0
  1340. package/scripts/build-command-registry.cjs +587 -0
  1341. package/scripts/build-connector-registry.cjs +1331 -0
  1342. package/scripts/build-corpus-stats.cjs +408 -0
  1343. package/scripts/build-dist-bundles.cjs +495 -0
  1344. package/scripts/build-ecosystem-graph.cjs +490 -0
  1345. package/scripts/build-graph +1462 -0
  1346. package/scripts/build-graph-from-sqlite.cjs +97 -0
  1347. package/scripts/build-harness-manifest.cjs +1090 -0
  1348. package/scripts/build-jtbd-nudges +205 -0
  1349. package/scripts/build-new-surface.cjs +805 -0
  1350. package/scripts/build-orchestration-projection.cjs +1221 -0
  1351. package/scripts/build-render-coverage.cjs +637 -0
  1352. package/scripts/build-skill-mirrors.cjs +681 -0
  1353. package/scripts/cache-hitrate-report.cjs +216 -0
  1354. package/scripts/causal-to-graph.cjs +163 -0
  1355. package/scripts/check-abstraction-fixture-neutral.cjs +160 -0
  1356. package/scripts/check-admin-identity.cjs +212 -0
  1357. package/scripts/check-brain-tool-liveness.cjs +502 -0
  1358. package/scripts/check-card-fire.cjs +1809 -0
  1359. package/scripts/check-cirs-declaration.cjs +279 -0
  1360. package/scripts/check-deck-design.cjs +104 -0
  1361. package/scripts/check-dual-graph-health.cjs +645 -0
  1362. package/scripts/check-first-touch-drift.cjs +220 -0
  1363. package/scripts/check-flagship-floor.cjs +391 -0
  1364. package/scripts/check-framework-vocabulary-drift.cjs +563 -0
  1365. package/scripts/check-gate-seam.cjs +178 -0
  1366. package/scripts/check-graph-derive-health.cjs +208 -0
  1367. package/scripts/check-graph-export-typemap.cjs +118 -0
  1368. package/scripts/check-help-coverage.cjs +290 -0
  1369. package/scripts/check-hitl-stages.cjs +219 -0
  1370. package/scripts/check-hook-schema-compatibility.cjs +231 -0
  1371. package/scripts/check-hsi-deps +42 -0
  1372. package/scripts/check-kuzu-reintroduction.cjs +251 -0
  1373. package/scripts/check-onboard +43 -0
  1374. package/scripts/check-onboard-statusline.cjs +363 -0
  1375. package/scripts/check-palette-consistency.cjs +106 -0
  1376. package/scripts/check-pending-ambiguous.cjs +244 -0
  1377. package/scripts/check-pending-breakthrough.cjs +189 -0
  1378. package/scripts/check-pending-breakthrough.test.cjs +166 -0
  1379. package/scripts/check-pending-naming-decision.cjs +97 -0
  1380. package/scripts/check-plugin-path-anchoring.cjs +830 -0
  1381. package/scripts/check-publish-needs.cjs +126 -0
  1382. package/scripts/check-registry-drift.cjs +206 -0
  1383. package/scripts/check-release-payload-ceiling.cjs +269 -0
  1384. package/scripts/check-render-coverage.cjs +558 -0
  1385. package/scripts/check-research-isomorphism.cjs +446 -0
  1386. package/scripts/check-reward-before-investment.cjs +261 -0
  1387. package/scripts/check-room-blueprints.cjs +213 -0
  1388. package/scripts/check-schema-aliases.cjs +532 -0
  1389. package/scripts/check-shape-declaration.cjs +958 -0
  1390. package/scripts/check-shape-declaration.test.cjs +185 -0
  1391. package/scripts/check-skill-spec.cjs +312 -0
  1392. package/scripts/check-skill-vs-code-drift.cjs +178 -0
  1393. package/scripts/check-substrate.cjs +513 -0
  1394. package/scripts/check-tool-honesty.cjs +1601 -0
  1395. package/scripts/check-update +60 -0
  1396. package/scripts/check-version-and-sha.cjs +366 -0
  1397. package/scripts/check-voice-style.cjs +184 -0
  1398. package/scripts/check-worktree-hygiene.cjs +530 -0
  1399. package/scripts/classify-insight +59 -0
  1400. package/scripts/coherence-smoke-test.cjs +489 -0
  1401. package/scripts/collect-cold-install-evidence.cjs +411 -0
  1402. package/scripts/compute-bayesian-surprise.py +175 -0
  1403. package/scripts/compute-blindspot-mass.py +209 -0
  1404. package/scripts/compute-disruption-index.py +211 -0
  1405. package/scripts/compute-element-novelty.py +254 -0
  1406. package/scripts/compute-external-whitespace.py +563 -0
  1407. package/scripts/compute-hsi.py +947 -0
  1408. package/scripts/compute-meetings-intelligence +716 -0
  1409. package/scripts/compute-opportunity-state +17 -0
  1410. package/scripts/compute-state +393 -0
  1411. package/scripts/compute-team +1112 -0
  1412. package/scripts/compute-whitespace-embeddings.py +464 -0
  1413. package/scripts/compute-whitespace-gaps.py +562 -0
  1414. package/scripts/compute_topic_forest.py +684 -0
  1415. package/scripts/consolidate-pinecone.py +265 -0
  1416. package/scripts/context-monitor +943 -0
  1417. package/scripts/create-speaker-profile +311 -0
  1418. package/scripts/cross-room-detect.cjs +195 -0
  1419. package/scripts/csv-to-idea-graph.cjs +755 -0
  1420. package/scripts/ctxl-eval.cjs +846 -0
  1421. package/scripts/curation-132-03-dedup-held-rename.cjs +395 -0
  1422. package/scripts/curation-132-05-pseudonymize.cjs +189 -0
  1423. package/scripts/derive-verb-reach-affinity.cjs +507 -0
  1424. package/scripts/detect-reverse-salients.py +242 -0
  1425. package/scripts/diagnostics-command.cjs +345 -0
  1426. package/scripts/dial-memory-refresh-command.cjs +147 -0
  1427. package/scripts/discover-analogy-whitespace.py +433 -0
  1428. package/scripts/discover-hsi-whitespace.py +352 -0
  1429. package/scripts/discover-rs-whitespace.py +327 -0
  1430. package/scripts/discovery-cycle.cjs +625 -0
  1431. package/scripts/disposition-render-v2.cjs +229 -0
  1432. package/scripts/doctor-preflight-format.cjs +101 -0
  1433. package/scripts/doctor.cjs +4327 -0
  1434. package/scripts/dogfood-bridge/append-to-queue.sh +59 -0
  1435. package/scripts/dogfood-bridge/path-filter.cjs +86 -0
  1436. package/scripts/dogfood-derive.cjs +158 -0
  1437. package/scripts/dogfood-emit.cjs +126 -0
  1438. package/scripts/empathy-observation-emit.cjs +108 -0
  1439. package/scripts/enrichment-queue-append.cjs +157 -0
  1440. package/scripts/ensure-brain-baseline.cjs +117 -0
  1441. package/scripts/entity-extract.cjs +1135 -0
  1442. package/scripts/eureka-command.cjs +687 -0
  1443. package/scripts/eureka-critic-run.cjs +662 -0
  1444. package/scripts/eureka-portfolio-report.cjs +2038 -0
  1445. package/scripts/eureka-room-report.cjs +419 -0
  1446. package/scripts/explain-decision-command.cjs +499 -0
  1447. package/scripts/export-pinecone-embeddings.cjs +516 -0
  1448. package/scripts/extract-room-intelligence.cjs +714 -0
  1449. package/scripts/fetch-brain-baseline.cjs +190 -0
  1450. package/scripts/fetch-brain-baseline.py +360 -0
  1451. package/scripts/feynman-minto-guardian.cjs +672 -0
  1452. package/scripts/feynman-timeline-refresh-command.cjs +270 -0
  1453. package/scripts/file-asset +253 -0
  1454. package/scripts/fire-sensor-event.cjs +83 -0
  1455. package/scripts/first-install-router.cjs +968 -0
  1456. package/scripts/frontmatter-schema-validator.cjs +339 -0
  1457. package/scripts/fts-index-drain.cjs +221 -0
  1458. package/scripts/generate-chat-embed.cjs +179 -0
  1459. package/scripts/generate-deck.cjs +322 -0
  1460. package/scripts/generate-export.cjs +474 -0
  1461. package/scripts/generate-hub.cjs +2553 -0
  1462. package/scripts/generate-lobby.cjs +718 -0
  1463. package/scripts/generate-presentation.cjs +988 -0
  1464. package/scripts/generate-presentation.test.cjs +405 -0
  1465. package/scripts/generate-section-intelligence.cjs +330 -0
  1466. package/scripts/generate-snapshot.cjs +1410 -0
  1467. package/scripts/generate-standalone +159 -0
  1468. package/scripts/git-ops +211 -0
  1469. package/scripts/graph-heal-pipeline.cjs +321 -0
  1470. package/scripts/gsd-artifact-graph-hook.cjs +219 -0
  1471. package/scripts/gsd-graph-derive-drain.cjs +571 -0
  1472. package/scripts/gsd-graph-derive-sweep.cjs +195 -0
  1473. package/scripts/heal-command.cjs +1365 -0
  1474. package/scripts/hedge-refit-pipeline.cjs +207 -0
  1475. package/scripts/help-renderer.cjs +303 -0
  1476. package/scripts/hmi-compliance-poll.cjs +451 -0
  1477. package/scripts/hmi-status-command.cjs +510 -0
  1478. package/scripts/hooked-rescore-117.cjs +224 -0
  1479. package/scripts/hooks/pre-commit +533 -0
  1480. package/scripts/hooks/pre-commit-room-minto-guard.cmd +43 -0
  1481. package/scripts/hooks/pre-commit-room-minto-guard.sh +533 -0
  1482. package/scripts/hsi-to-graph.cjs +194 -0
  1483. package/scripts/huji-batch.cjs +821 -0
  1484. package/scripts/huji-eval.cjs +1158 -0
  1485. package/scripts/huji-intake.cjs +563 -0
  1486. package/scripts/huji-pin-smoketest.cjs +454 -0
  1487. package/scripts/huji-run-one-async.cjs +305 -0
  1488. package/scripts/huji-run-one.cjs +671 -0
  1489. package/scripts/install-pre-commit.sh +113 -0
  1490. package/scripts/intent-classifier +106 -0
  1491. package/scripts/intent-classifier.cjs +3620 -0
  1492. package/scripts/interpret-whitespace.cjs +691 -0
  1493. package/scripts/jtbd-command.cjs +810 -0
  1494. package/scripts/jtbd-update.cjs +299 -0
  1495. package/scripts/label-topic-forest.cjs +667 -0
  1496. package/scripts/learn-from-usage +168 -0
  1497. package/scripts/lib/__pycache__/ensure_ml_deps.cpython-312.pyc +0 -0
  1498. package/scripts/lib/ensure_ml_deps.py +97 -0
  1499. package/scripts/load-embeddings-into-neo4j.cjs +569 -0
  1500. package/scripts/memory-artifact-graph-hook.cjs +191 -0
  1501. package/scripts/memory-command.cjs +687 -0
  1502. package/scripts/memory-completion-detector.cjs +217 -0
  1503. package/scripts/memory-lifecycle.cjs +620 -0
  1504. package/scripts/memory-resume-nudge.cjs +233 -0
  1505. package/scripts/methodology-ingest-local.sh +36 -0
  1506. package/scripts/migrate-brain-mcp-from-http-to-stdio.cjs +190 -0
  1507. package/scripts/migrate-brain-mcp-from-http-to-stdio.test.cjs +242 -0
  1508. package/scripts/migrate-hats-to-roomdb.cjs +217 -0
  1509. package/scripts/migrate-lazygraph.cjs +250 -0
  1510. package/scripts/migrate-minto-schema-v88.cjs +296 -0
  1511. package/scripts/migrate-plugin-root-refs.cjs +168 -0
  1512. package/scripts/migrate-room-sections-v275.cjs +556 -0
  1513. package/scripts/migrate-rooms +417 -0
  1514. package/scripts/migrate-skill-frontmatter.cjs +472 -0
  1515. package/scripts/migrate-stale-user-settings.cjs +296 -0
  1516. package/scripts/migrate-telemetry-v1.cjs +384 -0
  1517. package/scripts/migrate-telemetry-v1.test.cjs +356 -0
  1518. package/scripts/minto-debouncer.cjs +428 -0
  1519. package/scripts/mos-status.cjs +622 -0
  1520. package/scripts/mva-detect.cjs +229 -0
  1521. package/scripts/mva-run.cjs +36 -0
  1522. package/scripts/on-agent-complete +163 -0
  1523. package/scripts/on-cwd-changed +149 -0
  1524. package/scripts/on-file-changed +68 -0
  1525. package/scripts/on-stop +617 -0
  1526. package/scripts/on-task-complete +194 -0
  1527. package/scripts/operator-command.cjs +858 -0
  1528. package/scripts/operator-update.cjs +308 -0
  1529. package/scripts/part8-egress-guard-hook.cjs +229 -0
  1530. package/scripts/pipeline-command.cjs +271 -0
  1531. package/scripts/post-compact +383 -0
  1532. package/scripts/post-update-activation.cjs +339 -0
  1533. package/scripts/post-write +283 -0
  1534. package/scripts/power-demo-prompt.md +621 -0
  1535. package/scripts/pre-compact +273 -0
  1536. package/scripts/preflight-auto-explore.cjs +314 -0
  1537. package/scripts/preflight-doctor.cjs +225 -0
  1538. package/scripts/preflight-release-drift.cjs +168 -0
  1539. package/scripts/preflight-tension-surface.cjs +414 -0
  1540. package/scripts/probe-brain-contract.cjs +502 -0
  1541. package/scripts/publish-ops +346 -0
  1542. package/scripts/query-efficiency-telemetry.cjs +364 -0
  1543. package/scripts/query-semantic-scholar.cjs +545 -0
  1544. package/scripts/reapply-modifications +49 -0
  1545. package/scripts/reassign-primary.cjs +125 -0
  1546. package/scripts/recompile-room-references.cjs +601 -0
  1547. package/scripts/release-beta-preflight.sh +69 -0
  1548. package/scripts/render-pdf +588 -0
  1549. package/scripts/render-viz +190 -0
  1550. package/scripts/research-speaker +239 -0
  1551. package/scripts/resolve-room +204 -0
  1552. package/scripts/restore-post-compact-context.cjs +320 -0
  1553. package/scripts/room-auto-create-nudge.cjs +136 -0
  1554. package/scripts/room-naming-selector.cjs +201 -0
  1555. package/scripts/room-registry +767 -0
  1556. package/scripts/rs-discovery-engine.cjs +725 -0
  1557. package/scripts/rs-engine.py +2073 -0
  1558. package/scripts/rs-experts-command.cjs +300 -0
  1559. package/scripts/rs-explain-command.cjs +323 -0
  1560. package/scripts/rs-fetch-command.cjs +170 -0
  1561. package/scripts/rs-thesis-command.cjs +203 -0
  1562. package/scripts/rs-vector-bridge.cjs +410 -0
  1563. package/scripts/run-harness.cjs +890 -0
  1564. package/scripts/scout-cadence-guard.cjs +323 -0
  1565. package/scripts/scout-cadence-runner.cjs +509 -0
  1566. package/scripts/scout-telemetry-aggregator.cjs +268 -0
  1567. package/scripts/sealed-walker.py +96 -0
  1568. package/scripts/seed-brain-commands.cjs +324 -0
  1569. package/scripts/self-update +105 -0
  1570. package/scripts/sentinel-deadline-monitor +241 -0
  1571. package/scripts/sentinel-health-check +198 -0
  1572. package/scripts/sentinel-snapshot +42 -0
  1573. package/scripts/serve-dashboard +103 -0
  1574. package/scripts/serve-dashboard-live +932 -0
  1575. package/scripts/serve-presentation +97 -0
  1576. package/scripts/serve-wiki +90 -0
  1577. package/scripts/session-end-presence.cjs +79 -0
  1578. package/scripts/session-start +1943 -0
  1579. package/scripts/sessionstart-coordinator.cjs +249 -0
  1580. package/scripts/sessionstart-npm-reconcile.cjs +111 -0
  1581. package/scripts/sessionstart-post-update-preflight.cjs +303 -0
  1582. package/scripts/sessionstart-reference-now-seed.cjs +137 -0
  1583. package/scripts/setup-hooks.sh +112 -0
  1584. package/scripts/skillopt-codereview.cjs +830 -0
  1585. package/scripts/skillopt-eval.cjs +519 -0
  1586. package/scripts/skillopt-funnel.cjs +1076 -0
  1587. package/scripts/skillopt-genqueries.cjs +571 -0
  1588. package/scripts/skillopt-inventory.cjs +319 -0
  1589. package/scripts/skillopt-merge.cjs +656 -0
  1590. package/scripts/skillopt-triggerloop.cjs +1126 -0
  1591. package/scripts/soft-alias-runner.cjs +116 -0
  1592. package/scripts/stamp-artifact-write.cjs +276 -0
  1593. package/scripts/stamp-firing-block.cjs +325 -0
  1594. package/scripts/state-write.cjs +97 -0
  1595. package/scripts/statusline-fallback-echo.cjs +297 -0
  1596. package/scripts/statusline-mos +116 -0
  1597. package/scripts/statusline-mos-dispatch +127 -0
  1598. package/scripts/suggest-next-command.cjs +416 -0
  1599. package/scripts/sweep-skill-descriptions.cjs +263 -0
  1600. package/scripts/sync-rooms-graph +264 -0
  1601. package/scripts/telemetry-command-invocation.cjs +120 -0
  1602. package/scripts/test-doctor-recovery.cjs +242 -0
  1603. package/scripts/test-fresh-install.md +140 -0
  1604. package/scripts/track-analytics +156 -0
  1605. package/scripts/transcribe-audio +148 -0
  1606. package/scripts/transcript-ingest.cjs +225 -0
  1607. package/scripts/update-icm-index +153 -0
  1608. package/scripts/v182-brain-optimize.cypher +1191 -0
  1609. package/scripts/validate-model-profiles +93 -0
  1610. package/scripts/vault-content-reformatter.cjs +581 -0
  1611. package/scripts/vault-export-orchestrator.cjs +400 -0
  1612. package/scripts/vault-footer-injector.cjs +315 -0
  1613. package/scripts/vault-import.cjs +839 -0
  1614. package/scripts/vault-integration-test.cjs +318 -0
  1615. package/scripts/vault-regenerate-all.cjs +216 -0
  1616. package/scripts/vault-regenerate-all.test.cjs +138 -0
  1617. package/scripts/vault-rules-generator.cjs +220 -0
  1618. package/scripts/vault-section-minto-generator.cjs +1642 -0
  1619. package/scripts/vault-section-minto-generator.integration.test.cjs +576 -0
  1620. package/scripts/vault-section-minto-generator.test.cjs +291 -0
  1621. package/scripts/vault-section-state-generator.cjs +385 -0
  1622. package/scripts/vault-welcome-generator.cjs +403 -0
  1623. package/scripts/vault-wikilink-injector.cjs +449 -0
  1624. package/scripts/verify-phase-132.cjs +338 -0
  1625. package/scripts/verify-release +744 -0
  1626. package/scripts/whitespace-command.cjs +831 -0
  1627. package/scripts/whitespace-to-brain.cjs +384 -0
  1628. package/scripts/whitespace-to-graph.cjs +220 -0
  1629. package/scripts/wikilink-batch.cjs +102 -0
  1630. package/scripts/wikilink-file.cjs +139 -0
  1631. package/scripts/write-bridge-artifacts.cjs +140 -0
  1632. package/scripts/write-scope-check +12 -0
  1633. package/scripts/write-scope-check.cjs +461 -0
  1634. package/scripts/write-whitespace-sections.cjs +483 -0
  1635. package/settings.json +7 -0
  1636. package/skills/act/SKILL.md +523 -0
  1637. package/skills/admin/SKILL.md +437 -0
  1638. package/skills/agentshield/SKILL.md +50 -0
  1639. package/skills/analyze-needs/SKILL.md +74 -0
  1640. package/skills/analyze-systems/SKILL.md +69 -0
  1641. package/skills/analyze-timing/SKILL.md +94 -0
  1642. package/skills/auto-explore/SKILL.md +84 -0
  1643. package/skills/beautiful-question/SKILL.md +72 -0
  1644. package/skills/bono/SKILL.md +146 -0
  1645. package/skills/brain-connector/SKILL.md +206 -0
  1646. package/skills/brain-derive/SKILL.md +140 -0
  1647. package/skills/build-knowledge/SKILL.md +118 -0
  1648. package/skills/build-thesis/SKILL.md +90 -0
  1649. package/skills/causal/SKILL.md +265 -0
  1650. package/skills/challenge-assumptions/SKILL.md +74 -0
  1651. package/skills/client-discovery-interview/SKILL.md +94 -0
  1652. package/skills/client-discovery-interview/discovery-scaffold.json +41 -0
  1653. package/skills/client-discovery-interview/question-bank.md +149 -0
  1654. package/skills/compare-ventures/SKILL.md +113 -0
  1655. package/skills/context-engine/SKILL.md +169 -0
  1656. package/skills/conversation-mode/SKILL.md +189 -0
  1657. package/skills/correct-reference-now/SKILL.md +86 -0
  1658. package/skills/dashboard/SKILL.md +142 -0
  1659. package/skills/deck/SKILL.md +113 -0
  1660. package/skills/deep-grade/SKILL.md +210 -0
  1661. package/skills/diagnose/SKILL.md +128 -0
  1662. package/skills/diagnostics/SKILL.md +193 -0
  1663. package/skills/dial-memory-refresh/SKILL.md +116 -0
  1664. package/skills/diffusion/SKILL.md +125 -0
  1665. package/skills/discover/SKILL.md +216 -0
  1666. package/skills/doctor/SKILL.md +269 -0
  1667. package/skills/dogfood-flush/SKILL.md +133 -0
  1668. package/skills/dominant-designs/SKILL.md +72 -0
  1669. package/skills/eureka/SKILL.md +313 -0
  1670. package/skills/explain-decision/SKILL.md +138 -0
  1671. package/skills/explore-domains/SKILL.md +74 -0
  1672. package/skills/explore-futures/SKILL.md +64 -0
  1673. package/skills/explore-opportunity/SKILL.md +168 -0
  1674. package/skills/explore-trends/SKILL.md +74 -0
  1675. package/skills/export/SKILL.md +126 -0
  1676. package/skills/feynman-timeline-refresh/SKILL.md +105 -0
  1677. package/skills/file-meeting/SKILL.md +1190 -0
  1678. package/skills/find-analogies/SKILL.md +360 -0
  1679. package/skills/find-bottlenecks/SKILL.md +104 -0
  1680. package/skills/find-connections/SKILL.md +108 -0
  1681. package/skills/funding/SKILL.md +110 -0
  1682. package/skills/futures/SKILL.md +124 -0
  1683. package/skills/grade/SKILL.md +252 -0
  1684. package/skills/grade-grant/SKILL.md +293 -0
  1685. package/skills/graph/SKILL.md +216 -0
  1686. package/skills/hat-briefing/SKILL.md +160 -0
  1687. package/skills/heal/SKILL.md +69 -0
  1688. package/skills/help/SKILL.md +172 -0
  1689. package/skills/hmi-status/SKILL.md +73 -0
  1690. package/skills/ignite/SKILL.md +225 -0
  1691. package/skills/ingest-methodology/SKILL.md +125 -0
  1692. package/skills/intel-pipeline/SKILL.md +128 -0
  1693. package/skills/intelligence-orchestrator/SKILL.md +262 -0
  1694. package/skills/jtbd/SKILL.md +261 -0
  1695. package/skills/larry-personality/SKILL.md +571 -0
  1696. package/skills/larry-personality/framework-chains.md +92 -0
  1697. package/skills/larry-personality/mode-engine.md +185 -0
  1698. package/skills/leadership/SKILL.md +109 -0
  1699. package/skills/lean-canvas/SKILL.md +70 -0
  1700. package/skills/macro-trends/SKILL.md +84 -0
  1701. package/skills/map-unknowns/SKILL.md +72 -0
  1702. package/skills/memory/SKILL.md +212 -0
  1703. package/skills/memory-cortex-reach/SKILL.md +80 -0
  1704. package/skills/models/SKILL.md +197 -0
  1705. package/skills/mos/SKILL.md +160 -0
  1706. package/skills/mos-deck-engine/SKILL.md +329 -0
  1707. package/skills/mos-reason/SKILL.md +484 -0
  1708. package/skills/mullins/SKILL.md +151 -0
  1709. package/skills/mullins-scaffold/SKILL.md +132 -0
  1710. package/skills/mullins-scaffold/scaffold.json +223 -0
  1711. package/skills/mva-brief/SKILL.md +87 -0
  1712. package/skills/mva-option/SKILL.md +120 -0
  1713. package/skills/mva-pipeline/SKILL.md +158 -0
  1714. package/skills/mva-report/SKILL.md +79 -0
  1715. package/skills/new-project/SKILL.md +629 -0
  1716. package/skills/new-surface/SKILL.md +112 -0
  1717. package/skills/onboard/SKILL.md +485 -0
  1718. package/skills/operator/SKILL.md +167 -0
  1719. package/skills/opportunities/SKILL.md +171 -0
  1720. package/skills/organize/SKILL.md +69 -0
  1721. package/skills/persona/SKILL.md +272 -0
  1722. package/skills/pipeline/SKILL.md +164 -0
  1723. package/skills/present/SKILL.md +123 -0
  1724. package/skills/publish/SKILL.md +224 -0
  1725. package/skills/pws-brain/SKILL.md +152 -0
  1726. package/skills/pws-methodology/SKILL.md +92 -0
  1727. package/skills/qualify-opportunity/SKILL.md +111 -0
  1728. package/skills/query/SKILL.md +68 -0
  1729. package/skills/radar/SKILL.md +106 -0
  1730. package/skills/reanalyze/SKILL.md +122 -0
  1731. package/skills/research/SKILL.md +462 -0
  1732. package/skills/room/SKILL.md +381 -0
  1733. package/skills/room-passive/SKILL.md +174 -0
  1734. package/skills/room-proactive/SKILL.md +344 -0
  1735. package/skills/rooms/SKILL.md +678 -0
  1736. package/skills/root-cause/SKILL.md +73 -0
  1737. package/skills/rs-experts/SKILL.md +151 -0
  1738. package/skills/rs-explain/SKILL.md +130 -0
  1739. package/skills/rs-fetch/SKILL.md +115 -0
  1740. package/skills/rs-thesis/SKILL.md +129 -0
  1741. package/skills/scenario-plan/SKILL.md +76 -0
  1742. package/skills/scheduled-tasks/SKILL.md +301 -0
  1743. package/skills/score-innovation/SKILL.md +74 -0
  1744. package/skills/scout/SKILL.md +370 -0
  1745. package/skills/setup/SKILL.md +654 -0
  1746. package/skills/show/SKILL.md +68 -0
  1747. package/skills/skill/SKILL.md +104 -0
  1748. package/skills/snapshot/SKILL.md +178 -0
  1749. package/skills/speakers/SKILL.md +116 -0
  1750. package/skills/splash/SKILL.md +54 -0
  1751. package/skills/stance/SKILL.md +89 -0
  1752. package/skills/status/SKILL.md +107 -0
  1753. package/skills/structure-argument/SKILL.md +78 -0
  1754. package/skills/suggest-next/SKILL.md +137 -0
  1755. package/skills/systems-thinking/SKILL.md +220 -0
  1756. package/skills/think-hats/SKILL.md +82 -0
  1757. package/skills/trending-to-absurd/SKILL.md +100 -0
  1758. package/skills/ui-system/SKILL.md +474 -0
  1759. package/skills/ui-system/design-system/M-OS-DESIGN-SYSTEM.md +273 -0
  1760. package/skills/ui-system/design-system/SPEC.md +72 -0
  1761. package/skills/ui-system/design-system/image-prompt-style.md +29 -0
  1762. package/skills/ui-system/design-system/mos-design-system.css +240 -0
  1763. package/skills/ui-system/rules/design-system.md +60 -0
  1764. package/skills/ui-system/rules/dual-palette.md +156 -0
  1765. package/skills/ui-system/rules/glyph-disambiguation.md +171 -0
  1766. package/skills/ui-system/rules/shape-f-zero-and-six.md +169 -0
  1767. package/skills/update/SKILL.md +254 -0
  1768. package/skills/user-needs/SKILL.md +73 -0
  1769. package/skills/validate/SKILL.md +73 -0
  1770. package/skills/value-proposition/SKILL.md +141 -0
  1771. package/skills/vault/SKILL.md +326 -0
  1772. package/skills/visualize/SKILL.md +69 -0
  1773. package/skills/whitespace/SKILL.md +539 -0
  1774. package/skills/wiki/SKILL.md +94 -0
  1775. package/templates/_base.html +20 -0
  1776. package/templates/chat-panel.html +205 -0
  1777. package/templates/constellation-chat-hooks.js +89 -0
  1778. package/templates/constellation.html +1272 -0
  1779. package/templates/destijl-base.css +268 -0
  1780. package/templates/discovery/discovery-brief-template.md +97 -0
  1781. package/templates/due-diligence.html +49 -0
  1782. package/templates/executive-summary.html +40 -0
  1783. package/templates/icm/CLAUDE.md +31 -0
  1784. package/templates/icm/GROUP-CLAUDE.md +33 -0
  1785. package/templates/icm/INDEX.md +26 -0
  1786. package/templates/import/stage-contracts/01-ingest.md +34 -0
  1787. package/templates/import/stage-contracts/02-classify.md +48 -0
  1788. package/templates/import/stage-contracts/03-route.md +42 -0
  1789. package/templates/import/stage-contracts/04-enrich.md +40 -0
  1790. package/templates/investment-thesis.html +25 -0
  1791. package/templates/meeting-report.html +361 -0
  1792. package/templates/presentation/dashboard.html +1150 -0
  1793. package/templates/presentation/deck.html +540 -0
  1794. package/templates/presentation/diagrams.html +437 -0
  1795. package/templates/presentation/graph.html +391 -0
  1796. package/templates/presentation/insights.html +548 -0
  1797. package/templates/presentation/wiki.html +533 -0
  1798. package/templates/profile.html +136 -0
  1799. package/templates/room-context/last-session.md +56 -0
  1800. package/templates/room-context/methodology-history.md +28 -0
  1801. package/templates/room-context/rejection-log.md +25 -0
  1802. package/templates/room-context/weekly-digest.md +54 -0
  1803. package/templates/room-skeleton/MINTO.md.tmpl +19 -0
  1804. package/templates/room-skeleton/ROOM.md.identity.tmpl +13 -0
  1805. package/templates/room-skeleton/ROOM.md.section.tmpl +33 -0
  1806. package/templates/room-skeleton/STATE.md.tmpl +33 -0
  1807. package/templates/room-skeleton/USER.md.tmpl +23 -0
  1808. package/templates/room-skeleton/references/.gitkeep +0 -0
  1809. package/templates/room-skeleton/references/SECTION-SCHEMA.md +213 -0
  1810. package/templates/room-skeleton/references/SUB-SCHEMAS.md +91 -0
  1811. package/templates/room-skeleton/section-contracts/.gitkeep +0 -0
  1812. package/templates/room-skeleton/section-contracts/business-model.md +32 -0
  1813. package/templates/room-skeleton/section-contracts/competitive-analysis.md +33 -0
  1814. package/templates/room-skeleton/section-contracts/financial-model.md +30 -0
  1815. package/templates/room-skeleton/section-contracts/funding.md +41 -0
  1816. package/templates/room-skeleton/section-contracts/legal-ip.md +30 -0
  1817. package/templates/room-skeleton/section-contracts/market-analysis.md +32 -0
  1818. package/templates/room-skeleton/section-contracts/opportunity-bank.md +39 -0
  1819. package/templates/room-skeleton/section-contracts/problem-definition.md +32 -0
  1820. package/templates/room-skeleton/section-contracts/solution-design.md +36 -0
  1821. package/templates/room-skeleton/section-contracts/strategy.md +35 -0
  1822. package/templates/room-skeleton/section-contracts/team-execution.md +36 -0
  1823. package/templates/shared.css +427 -0
  1824. package/templates/showcase/blueprint.html +432 -0
  1825. package/templates/showcase/library.html +571 -0
  1826. package/templates/showcase/narrative.html +361 -0
  1827. package/templates/showcase/overview.html +468 -0
  1828. package/templates/showcase/synthesis.html +473 -0
  1829. package/templates/signature-footer.html +34 -0
@@ -0,0 +1,1809 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
4
+ *
5
+ * Phase 179-01 -- the GA-4 card-fire interceptor (the R-1 cure, Wave 1)
6
+ * =====================================================================
7
+ * A Stop-hook-class turn-scan that moves card-fire enforcement BELOW the agent.
8
+ *
9
+ * R15 (Phase 178) proves a gate surface is WIRED to emit a card; it cannot force the
10
+ * model to FIRE the card at runtime (the named R-1 residual). A prose fence shipped
11
+ * (commit e22b9ea4) and the agent ignored it. This interceptor is the structural cure:
12
+ * a deterministic turn-scan the LLM has no say in. On a reached-Decision-Gate turn with
13
+ * no fired AskUserQuestion card it emits a Stop-block (decision:'block') +
14
+ * additionalContext re-prompt forcing the card; after MAX_FORCE_RETRIES bounded retries
15
+ * it degrades gracefully (log + allow) so a genuinely card-incapable surface cannot trap
16
+ * the navigator.
17
+ *
18
+ * Hook class: this runs on the Stop event (hooks/hooks.json Stop block), NOT PostToolUse.
19
+ * The block route is a JSON envelope `{ decision:'block', continue:false, ... }` written
20
+ * to stdout on exit 0 -- a valid Stop-block path (the Claude Code Stop hook honors a
21
+ * decision:'block' envelope to re-prompt the turn). It is NOT an exit-2 block; earlier
22
+ * drafts of this header and 179-CONTEXT called it an "exit-2 PostToolUse interceptor" --
23
+ * that was doc drift, reconciled here (IN-01) to match the shipped Stop-block-on-exit-0
24
+ * route.
25
+ *
26
+ * Stop-stdin contract (BL-01, the live cure): the real Claude Code Stop hook delivers
27
+ * `{ hook_event_name, transcript_path, stop_hook_active, session_id, ... }` -- it does
28
+ * NOT deliver output_text / ran_entries / askuserquestion_fired directly. The interceptor
29
+ * READS the turn by parsing `transcript_path` (mirroring scripts/on-stop:33): it extracts
30
+ * the LAST assistant message text (drives the BACKSTOP) and scans the transcript's
31
+ * tool-use records for an AskUserQuestion invocation (drives askuserquestion_fired). If
32
+ * the envelope already carries the normalized signals directly (the unit-test shape),
33
+ * those are used as-is (backward-compatible). An unreadable/missing transcript yields
34
+ * empty signals -> a safe no-op (never throws, never blocks spuriously).
35
+ *
36
+ * Detection (CONTEXT decision 1: registry-keyed PRIMARY + output-text BACKSTOP):
37
+ * PRIMARY (DEFERRED -- see doctrine note below) -- a render-coverage-registry
38
+ * gate-reaching surface (data/render-coverage-registry.json entries[] with
39
+ * render_coverage 'card-emission') ran this turn AND no AskUserQuestion
40
+ * tool-call fired. The enumeration is DERIVED from the registry, never
41
+ * hand-maintained.
42
+ * BACKSTOP (LIVE -- the detector this phase ships) -- the turn output text carries the
43
+ * ASCII-box gate glyphs (the `[1] [2] [3]` / "type 1, 2, or 3" anti-pattern)
44
+ * with no fired card -- intercepted even for an OFF-registry surface.
45
+ *
46
+ * DOCTRINE UPDATE (Phase 209-06, H3): PRIMARY IS LIVE. WR-04 (below, historical record)
47
+ * documented PRIMARY as deferred because no producer of `ran_entries` / `reached_gate_entries`
48
+ * existed. That producer now exists: lib/core/card-fire-sidechannel.cjs (recordReachedGate /
49
+ * readReachedGates), wired at the THREE places that mint a Shape-F gate envelope --
50
+ * lib/hmi/selector-dispatcher.cjs's pickShape trailer door (gated on payload.emitTelemetry
51
+ * === true, Canon Part 8 fs_scope), and scripts/intent-classifier.cjs's engine arm +
52
+ * emitBindingGate (F.8). deriveTurnSignals (below) now reads the side file via
53
+ * readReachedGates(session_id) whenever the envelope does NOT already carry ran_entries /
54
+ * reached_gate_entries directly (direct-field envelopes -- the unit-test shape -- keep
55
+ * PRECEDENCE, so the 22 existing predicate assertions stay byte-identical). The BACKSTOP
56
+ * (transcript ASCII-box text detection) stays SECONDARY PERMANENTLY -- it is the only
57
+ * detector that still works when the side-channel writer itself fails (a missing, corrupt,
58
+ * or oversized side-file all degrade to [] inside readReachedGates, never throwing here).
59
+ *
60
+ * WR-04 (historical, PRE-209-06): "PRIMARY is DEFERRED, not live. PRIMARY keys off a
61
+ * `ran_entries` / `reached_gate_entries` set that records which registry gate-reaching
62
+ * surfaces ran this turn. A Stop-hook transcript yields assistant TEXT (the BACKSTOP
63
+ * signal), NOT a reached-entries SET, and a repo-wide grep finds ZERO producers of
64
+ * `ran_entries` / `reached_gate_entries` outside this file and its tests. So until a
65
+ * side-channel writer exists ... PRIMARY has no live source and stays INERT." -- superseded
66
+ * by the DOCTRINE UPDATE above; retained verbatim for the historical record.
67
+ *
68
+ * Bounded escape (T-179-01 DoS mitigation): a LOCAL retry side-file
69
+ * (~/.mindrian/card-fire-retries.json) keyed by a TRANSCRIPT-GROWTH-INVARIANT turn identity
70
+ * (the Stop stdin session_id + a stable gate identity) counts consecutive intercepts. The
71
+ * gate identity is the GATE-IDENTIFYING CONTENT of the LAST assistant message -- the matched
72
+ * ASCII-box glyph span plus the NORMALIZED option-label token SET (lowercased, prose and
73
+ * whitespace stripped, labels sorted). The key is invariant across BOTH (WR-01) a re-worded
74
+ * re-prompt (the gate signature anchors on the glyph + the option-label SET, not the full
75
+ * message prose) AND (CR-02 / CR-03) a GROWING transcript: the model appends an assistant
76
+ * turn every time it re-emits the blocked gate, so any transcript-LENGTH value (e.g. an
77
+ * assistant-message counter) would mint a fresh key every retry and the bounded escape would
78
+ * NEVER converge -- a production livelock. The gate-content signature stays FIXED across all
79
+ * assistant re-emissions of the same stuck gate, so consecutive intercepts of the SAME gate
80
+ * increment the SAME counter and MAX_FORCE_RETRIES is actually reachable.
81
+ *
82
+ * CR-03 (the root fix this wave ships): the key is anchored on the GATE, never the user
83
+ * message. The prior fix anchored on the LAST USER message, which is EMPTY when the box turn
84
+ * has no preceding role:user record (a compaction type:'summary' lead, OR this codebase's own
85
+ * Phase 114/117 auto-fire-before-the-user-types) -- the empty anchor then fell back to
86
+ * assistantCount (the growing counter) and the bounded escape livelocked again. Anchoring on
87
+ * the gate-identifying content has NO such hole: it is present whenever a gate is detected
88
+ * (the detection IS the gate content), it is growth-invariant, and two genuinely-different
89
+ * gates get genuinely-different counters (WR-07: no cross-gate budget bleed). The
90
+ * assistantCount / gate_turn_index fallback is DELETED from the key derivation entirely; if
91
+ * the gate signature is somehow empty (degenerate), the key falls back to session_id ALONE
92
+ * (coarse but ALWAYS converges -- any consecutive intercept in the session counts up), NEVER
93
+ * to a growing value. A growing value is unreachable as the key.
94
+ *
95
+ * The store is pruned on write by a TTL (WR-02: each entry carries { count, ts }; entries
96
+ * older than RETRY_TTL_MS are evicted, so the side-file cannot grow without bound). At
97
+ * MAX_FORCE_RETRIES the predicate returns degrade=true and the envelope is
98
+ * { continue: true, suppressOutput: true } (log to stderr, allow the turn).
99
+ *
100
+ * CR-04 (the TERMINAL convergence floor -- the session-wide intercept ceiling): the per-gate
101
+ * counter above keys on the gate-identifying CONTENT (gate_signature), which is MODEL-controlled.
102
+ * When the model re-emits the SAME stuck gate with DIFFERENT option labels each retry (the most
103
+ * natural LLM behavior under this interceptor's own "re-emit this turn" re-prompt), the per-gate
104
+ * signature FLAPS to a fresh key every retry, no single per-gate key ever reaches
105
+ * MAX_FORCE_RETRIES, and the bounded escape livelocks forever. ANY key derived from model-emitted
106
+ * content can be flapped; the ONLY identity that cannot be flapped is the SESSION itself. So a
107
+ * SECOND, session-wide counter keyed on session_id ALONE (content-INDEPENDENT, stored at
108
+ * `__session__:<id>` in the same TTL-pruned side-file) is bumped on EVERY intercept, with its own
109
+ * hard ceiling MAX_SESSION_INTERCEPTS (set generously above the per-gate cap so normal multi-gate
110
+ * sessions are unaffected). The predicate degrades if EITHER ceiling is reached. The session
111
+ * ceiling is the load-bearing guarantee: a continuous run of intercepts in ONE session is bounded
112
+ * by MAX_SESSION_INTERCEPTS REGARDLESS of how the gate content / per-gate key flaps. A degrade or
113
+ * a no-intercept Stop turn resets the session counter (the navigator got unstuck).
114
+ *
115
+ * WR-08 (transcript read cap): readTranscriptTurn reads only the LAST TRANSCRIPT_TAIL_BYTES
116
+ * of the transcript file (a pathological multi-hundred-MB transcript cannot stall the 3000ms
117
+ * hook). The detection semantics are unchanged -- the LAST assistant message and the gate
118
+ * signature both live at the tail; a partial leading line after the byte cut is dropped as a
119
+ * malformed JSONL line by the existing per-line try/catch.
120
+ *
121
+ * Envelope schema (Phase 95 BASH-95-01 invariant): top-level keys are a subset of
122
+ * { decision, reason, continue, stopReason, suppressOutput, systemMessage,
123
+ * hookSpecificOutput }. additionalContext lives ONLY inside hookSpecificOutput.
124
+ *
125
+ * Canon Part 8 (The Graph Boundary): LOCAL-only. Reads the local registry + the hook
126
+ * stdin envelope + the LOCAL transcript file (transcript_path is a local path, same as
127
+ * scripts/on-stop reads it) + the local retry side-file; makes ZERO Brain reads/writes
128
+ * and ZERO network calls. The interceptor opens no remote wire and loads no Brain module.
129
+ * The transcript content the interceptor reads (an untrusted model turn) stays LOCAL and
130
+ * is NEVER echoed to Brain or sent anywhere -- it is read, scanned for glyphs/tool-use,
131
+ * and discarded.
132
+ *
133
+ * Additive only: mints no reach / posture / edge / node; the frozen Part 3 contracts
134
+ * (MAX_K=3, DIAL_REACH_K=6, the 0.70/0.15 gate, the 6-reach bank, the glyphs) are
135
+ * untouched.
136
+ *
137
+ * Defensive: any internal error -> stderr + { continue: true, suppressOutput: true } +
138
+ * exit 0. The interceptor NEVER blocks the hook chain on a bug.
139
+ *
140
+ * House rule: hyphens only, no em-dashes. CJS module, Node built-ins only.
141
+ *
142
+ * License: BSL 1.1.
143
+ */
144
+
145
+ 'use strict';
146
+
147
+ const fs = require('node:fs');
148
+ const path = require('node:path');
149
+ const os = require('node:os');
150
+ const crypto = require('node:crypto');
151
+
152
+ const PLUGIN_ROOT = path.resolve(__dirname, '..');
153
+
154
+ // Phase 210-05 (item 210-E-1): the shared relevance predicate module. It owns the
155
+ // option-label extraction (MOVED out of gateSignature below so there is exactly one
156
+ // implementation) plus the two relevance verdicts classifyCardFire consults before
157
+ // its final intercept. Pure LOCAL string work, never throws (Part 8).
158
+ const gateRelevance = require(path.join(PLUGIN_ROOT, 'lib', 'core', 'gate-relevance.cjs'));
159
+
160
+ // Phase 298-03: the transcript reader (readTranscriptTurn/readTranscriptTail plus the
161
+ // four helper functions it used) moved to lib/hmi/turn-text.cjs, the single transcript
162
+ // reader shared with a later Stop-hook consumer (298-07). This file keeps
163
+ // gateSignature/matchedGlyphSpan (card-fire-domain logic that needs gateRelevance
164
+ // above) and recomputes askuserquestion_fired + gate_signature locally from what
165
+ // turn-text.cjs returns.
166
+ const turnText = require('../lib/hmi/turn-text.cjs');
167
+
168
+ // 238-05 Task 2 (GATE-03 half B, lost-update fix): NOTE this file does NOT
169
+ // require lib/core/write-lock.cjs. D-05 called for reusing its acquireLock/
170
+ // releaseLock unchanged; adversarial testing found a real TOCTOU race in
171
+ // that shared primitive under this file's higher-frequency usage pattern
172
+ // (full rationale and measurements at the withRetryStoreLock definition
173
+ // below, near line 760). The retry-store fence is a separate, local, more
174
+ // rigorously verified lock confined to this file; lib/core/write-lock.cjs
175
+ // and its other consumers (SQLite write-safety) are untouched.
176
+
177
+ // data/render-coverage-registry.json is the Phase 178 R15 substrate. The interceptor
178
+ // keys PRIMARY detection off its card-emission entries; it does NOT hand-maintain a
179
+ // parallel gate list.
180
+ const REGISTRY_PATH = path.join(PLUGIN_ROOT, 'data', 'render-coverage-registry.json');
181
+
182
+ // The LOCAL retry side-file for the bounded escape (Part 8 LOCAL-only).
183
+ function retryFilePath() {
184
+ const home = process.env.MINDRIAN_HOME || path.join(os.homedir(), '.mindrian');
185
+ return path.join(home, 'card-fire-retries.json');
186
+ }
187
+
188
+ // CR-07: the LOCAL append-only diagnostic log path. Resolved the SAME way as
189
+ // retryFilePath (MINDRIAN_HOME override honored) so a test / ops re-point isolates both
190
+ // files identically. Part 8 LOCAL-only: this file is written to local disk (~/.mindrian),
191
+ // never to the Brain and never over any network wire.
192
+ function interceptLogPath() {
193
+ const home = process.env.MINDRIAN_HOME || path.join(os.homedir(), '.mindrian');
194
+ return path.join(home, 'card-fire-intercepts.log');
195
+ }
196
+
197
+ // The bounded-escape ceiling (named constant). After this many consecutive intercepts
198
+ // on the same turn-context (the per-gate key), degrade to log + allow so a card-incapable
199
+ // surface cannot trap the navigator. This is the per-gate counter: it gives good UX (each
200
+ // genuinely-distinct gate gets forced up to N times before we give up on it).
201
+ const MAX_FORCE_RETRIES = 3;
202
+
203
+ // CR-04 (the TERMINAL convergence floor): the SESSION-WIDE intercept ceiling. The per-gate
204
+ // counter above keys on the gate-identifying CONTENT (gate_signature), which is MODEL-
205
+ // CONTROLLED: when the model re-emits the SAME stuck gate with DIFFERENT option labels each
206
+ // retry (the single most natural LLM behavior under this interceptor's own "re-emit this
207
+ // turn" re-prompt), the per-gate signature FLAPS to a fresh key every retry, no single per-
208
+ // gate key ever reaches MAX_FORCE_RETRIES, and the bounded escape LIVELOCKS forever. ANY key
209
+ // derived from model-emitted content can be flapped; the ONLY identity that cannot be flapped
210
+ // is the SESSION itself. So we add a second, session-wide counter keyed on session_id ALONE
211
+ // (content-INDEPENDENT, un-flappable) with its own hard ceiling. On each intercept we bump
212
+ // BOTH counters and degrade if EITHER ceiling is reached. The session ceiling is the load-
213
+ // bearing guarantee: an unbroken run of intercepts in ONE session is bounded by
214
+ // MAX_SESSION_INTERCEPTS REGARDLESS of how the gate content / per-gate key flaps.
215
+ //
216
+ // It is set GENEROUSLY above the per-gate cap (4x MAX_FORCE_RETRIES, well above 2x) so that
217
+ // a normal multi-gate session is unaffected: the per-gate degrade fires first for each
218
+ // genuinely-distinct gate (WR-07's two-distinct-gates case degrades per-gate long before the
219
+ // session total reaches 12), and ONLY a flapping single-gate livelock -- which the per-gate
220
+ // counter cannot catch -- is bounded by this ceiling.
221
+ const MAX_SESSION_INTERCEPTS = 12;
222
+
223
+ // Phase 238-08 (GATE-04, D-15): local mirrors of lib/core/card-fire-sidechannel.cjs's
224
+ // HEALTH_OK / HEALTH_UNAVAILABLE values. Duplicated deliberately, not re-derived via a
225
+ // require, because the one case that needs a value here (deriveTurnSignals's own
226
+ // require-failure degrade branch, below) is exactly the case where that module's
227
+ // require has already failed and its exported constant is unreachable. Plain string
228
+ // literals so classifyCardFire's D-16 comparison never needs to require the module
229
+ // just to compare an enum value.
230
+ const SIDECHANNEL_HEALTH_OK = 'healthy';
231
+ const SIDECHANNEL_HEALTH_UNAVAILABLE = 'unavailable';
232
+
233
+ // The session-counter key prefix in the shared side-file. A session entry lives at
234
+ // `__session__:<session_id>` alongside the per-gate `<ctxHash>` entries; both are { count, ts }
235
+ // shaped and both are TTL-pruned identically (WR-02), so the side-file still cannot grow
236
+ // without bound. The `__session__:` prefix cannot collide with a per-gate ctxHash (a 16-hex
237
+ // sha256 slice never starts with `__session__:`).
238
+ const SESSION_KEY_PREFIX = '__session__:';
239
+
240
+ // WR-02: the retry side-file TTL. Each store entry carries { count, ts }; on every write
241
+ // entries older than this are evicted, so the LOCAL ~/.mindrian/card-fire-retries.json
242
+ // cannot grow without bound over a long-lived install. 24h is generous: a stuck gate
243
+ // resolves within one turn; an abandoned key is dead long before a day passes.
244
+ const RETRY_TTL_MS = 24 * 60 * 60 * 1000;
245
+
246
+ // CR-07 (the LOCAL intercept diagnostic log -- backstop-benign-list-defeats-relevance-gate
247
+ // item 2b, feeding live-session-running-stale-plugin-cache-fixes-inert's still-open
248
+ // "unexplained backstop trigger" mystery). The truncation cap for output_text written to
249
+ // the log per record, so a pathological turn cannot bloat one log line. TTL-pruned by the
250
+ // SAME RETRY_TTL_MS as the retry side-file (WR-02) so it cannot grow without bound.
251
+ const INTERCEPT_LOG_TEXT_CAP = 4000;
252
+
253
+ // WR-08 (298-03): the transcript-read tail cap moved to lib/hmi/turn-text.cjs
254
+ // (TRANSCRIPT_TAIL_BYTES) along with readTranscriptTail itself; re-exported below as
255
+ // turnText.TRANSCRIPT_TAIL_BYTES so this file's own export name is unchanged.
256
+
257
+ // The ASCII-box gate glyphs / literal anti-pattern the BACKSTOP scans for. A reached
258
+ // gate that renders as flat text instead of firing the card carries these.
259
+ //
260
+ // Phase 209-07 (H1): tuned after H3 PRIMARY (209-06) went live, per the LOCKED wave
261
+ // order (tune the floor only once the native path validates which branches still
262
+ // fire). Four alternatives:
263
+ // 1. Same-line labeled box: `[1] ... [2] ...` (unchanged from Wave 1).
264
+ // 2. The literal `type 1, 2, or 3` exemplar (unchanged from Wave 1).
265
+ // 3. Multiline labeled box: `[1] ...\n...\n[2] ...` (NEW -- verdict 25's exact
266
+ // false-negative shape: a gate whose options wrap onto separate lines).
267
+ // 4. Numbered-prose gate: a line-anchored `1. <option>` followed by `2. <option>`
268
+ // within a 3-line span (NEW -- the incident's "hand-rolled numbered list
269
+ // instead of a card" shape). `(?:^|\n)` substitutes for per-line anchoring
270
+ // without an `m` flag, so this alternative matches anywhere inside a larger
271
+ // message, not only at the string's absolute start.
272
+ // The bare U+25A0 alternative is DELETED: a lone U+25A0 in a status/dial row with
273
+ // no option structure is SANCTIONED plugin UI vocabulary (selector-dispatcher.cjs:256,
274
+ // ui-system SKILL.md:131, dial-presenter.cjs:134) and must never intercept a turn on
275
+ // its own. A U+25A0 appearing WITHIN one of the four gate-shaped alternatives above
276
+ // still counts (it is part of the matched gate content, not a bare occurrence).
277
+ const ASCII_BOX_GLYPH_RE =
278
+ /\[\s*1\s*\]\s*.*\[\s*2\s*\]|type\s+1\s*,\s*2\s*,\s*or\s+3|\[\s*1\s*\][^\n]*\n[\s\S]*?\[\s*2\s*\]|(?:^|\n)\s{0,3}1[.)]\s+\S[^\n]*\n(?:[^\n]*\n)?\s{0,3}2[.)]\s+\S/i;
279
+
280
+ // backstop-numbered-prose-retired (card-fire-relevance-check-gap, navigator decision
281
+ // 2026-07-17 "widen scope: fix both mechanisms"): ASCII_BOX_GLYPH_RE above stays
282
+ // BYTE-IDENTICAL (the retry-key signature in gateSignature and the Phase 209 regex-matrix
283
+ // tests both depend on it verbatim). The BACKSTOP intercept now keys on ONE tier only:
284
+ // - UNCONDITIONAL (alternatives 1-3: same-line bracket box, the "type 1, 2, or 3"
285
+ // literal, the multiline bracket box). These are shape-specific enough that ordinary
286
+ // prose practically never renders them by accident, so a match alone is a backstop hit.
287
+ // The Phase 209-07 bare numbered-prose alternative (formerly ASCII_BOX_NUMBERED_PROSE_RE,
288
+ // gated by GATE_FRAMING_RE within GATE_FRAMING_WINDOW) is RETIRED. Live evidence -- the 7
289
+ // real backstop fires in ~/.mindrian/card-fire-intercepts.log -- showed the framing
290
+ // co-requirement could not separate the ONE genuine fork (cfec3113, "Two honest paths --
291
+ // pick one: build vs file") from the SIX false positives, an ~86% false-positive net: pairs
292
+ // of clarifying questions, informational step lists, and even a disclaimer that literally
293
+ // said "NOT options to pick between" all tripped the bare `?`/verb cue, and two fires
294
+ // carried the cue INSIDE unrelated content (a Neo4j tool description reading "silently pick
295
+ // the single best match"). A `1. ... 2. ...` list is the exact shape of a benign Action
296
+ // Footer, a step-by-step explanation, or a set of caveats, and a shape-plus-nearby-cue proxy
297
+ // provably cannot tell those from a genuine fork. Catching a genuine numbered-prose fork is
298
+ // now the MODEL's own Phase-210 / SEED-021 judgment responsibility (its system prompt
299
+ // already mandates firing AskUserQuestion for a real decision fork); the flat-text safety net
300
+ // is deliberately removed because it did more harm than good. A genuine gate rendered as a
301
+ // real `[1]...[2]` bracket box is still caught by arms 1-3.
302
+ const ASCII_BOX_UNCONDITIONAL_RE =
303
+ /\[\s*1\s*\]\s*.*\[\s*2\s*\]|type\s+1\s*,\s*2\s*,\s*or\s+3|\[\s*1\s*\][^\n]*\n[\s\S]*?\[\s*2\s*\]/i;
304
+
305
+ // ----- envelope schema allowlist (Phase 95 BASH-95-01) -----
306
+ //
307
+ // stop-hook-invalid-hookspecificoutput-schema (2026-07-23): 'hookSpecificOutput'
308
+ // REMOVED from this allowlist. Claude Code's Stop-hook output schema does not
309
+ // define a Stop variant of hookSpecificOutput at all (the union covers only
310
+ // PreToolUse, UserPromptSubmit, and PostToolUse) -- including the key at all
311
+ // makes the validator reject the ENTIRE envelope ("Hook JSON output validation
312
+ // failed: - : Invalid input"), which replaces the calm systemMessage/reason
313
+ // text below with a raw schema-error dump on every turn this branch fires.
314
+ // Same root cause as scripts/on-stop's v1.10.9->v1.10.10 fix (2026-04-15,
315
+ // see the comment at that file's legacy success-output branch); this
316
+ // allowlist previously legitimized the mistake for this file's own call site.
317
+ // Keeping the key OUT of the allowlist means a future call site that tries to
318
+ // add hookSpecificOutput back gets silently key-filtered rather than shipping
319
+ // broken JSON again.
320
+ const ALLOWED_ENVELOPE_KEYS = new Set([
321
+ 'decision',
322
+ 'reason',
323
+ 'continue',
324
+ 'stopReason',
325
+ 'suppressOutput',
326
+ 'systemMessage',
327
+ ]);
328
+
329
+ // ---------------------------------------------------------------------------
330
+ // loadRegistry() -- read the render-coverage registry. Pure local read; never throws
331
+ // (returns { entries: [] } on any error so the interceptor degrades to the BACKSTOP
332
+ // signal alone rather than blocking the hook chain).
333
+ // ---------------------------------------------------------------------------
334
+ function loadRegistry() {
335
+ try {
336
+ const raw = fs.readFileSync(REGISTRY_PATH, 'utf8');
337
+ const reg = JSON.parse(raw);
338
+ return reg && typeof reg === 'object' ? reg : { entries: [] };
339
+ } catch (_e) {
340
+ return { entries: [] };
341
+ }
342
+ }
343
+
344
+ // ---------------------------------------------------------------------------
345
+ // gateReachingEntries(registry) -- DERIVE the gate-reaching enumeration from the
346
+ // registry's card-emission entries (Phase 178 R15). render-only-excluded entries are
347
+ // NOT gate-reaching. Returns an array of entry paths. Never throws.
348
+ // ---------------------------------------------------------------------------
349
+ function gateReachingEntries(registry) {
350
+ const reg = registry && typeof registry === 'object' ? registry : {};
351
+ const entries = Array.isArray(reg.entries) ? reg.entries : [];
352
+ const out = [];
353
+ for (const e of entries) {
354
+ if (e && e.render_coverage === 'card-emission' && typeof e.entry === 'string') {
355
+ out.push(e.entry);
356
+ }
357
+ }
358
+ return out;
359
+ }
360
+
361
+ // ---------------------------------------------------------------------------
362
+ // gateSignature(outputText) -- a STABLE structural signature of the GATE-IDENTIFYING content
363
+ // of an assistant message: the matched ASCII-box glyph span plus the NORMALIZED option-label
364
+ // token SET. This is the CR-03 / WR-07 root anchor: it is present whenever a gate is detected
365
+ // (the detection IS this content), it is INVARIANT across transcript growth and surrounding
366
+ // prose re-wording, and two genuinely-different gates produce genuinely-different signatures.
367
+ //
368
+ // Normalization (WR-01 robustness): re-wording the PROSE between retries must not change the
369
+ // signature, so we anchor ONLY on (a) the matched glyph span (the literal anti-pattern the
370
+ // BACKSTOP fires on) and (b) the option labels as a lowercased, prose/whitespace-stripped,
371
+ // SORTED token set. The labels are the `[1] foo`, `[2] bar` option bodies; we take the label
372
+ // TEXT after each `[n]` marker, normalize it, and sort the resulting set so option re-ordering
373
+ // does not flap the key.
374
+ //
375
+ // CR-04 (corrected -- this comment previously claimed the empty-only session-alone floor bounds
376
+ // the flap; it does NOT, and that false claim is DELETED). If the model MATERIALLY changes the
377
+ // option labels each retry, this per-gate signature DOES flap to a fresh key every retry, and
378
+ // the EMPTY-only degenerate floor in turnContextHash (which fires only when BOTH glyph span and
379
+ // labels are empty) provably NEVER catches a flapping NON-empty signature. The flap is bounded
380
+ // instead by the SESSION-WIDE intercept ceiling (MAX_SESSION_INTERCEPTS, applied in main): the
381
+ // session counter is keyed on session_id ALONE and is content-INDEPENDENT, so it climbs to its
382
+ // ceiling regardless of how this per-gate signature flaps, and degrades the run. The per-gate
383
+ // signature stays the GOOD-UX granularity for the common stable case (each genuinely-distinct
384
+ // gate gets its own per-gate budget); the session ceiling is the un-flappable convergence floor
385
+ // behind it.
386
+ //
387
+ // Returns '' (degenerate) when no gate content is recoverable; turnContextHash then falls back
388
+ // to session_id ALONE -- NEVER to a growing value. Part 8: pure local string work; the result
389
+ // feeds a local sha256 and never egresses.
390
+ // ---------------------------------------------------------------------------
391
+ function gateSignature(outputText) {
392
+ const text = typeof outputText === 'string' ? outputText : '';
393
+ if (!text) return '';
394
+ // (a) the matched glyph span -- the literal anti-pattern the BACKSTOP fired on. We normalize
395
+ // the matched substring (lowercased, whitespace collapsed) so trivial spacing churn does
396
+ // not move the key. A non-glyph caller (no match) contributes ''.
397
+ const glyphMatch = text.match(ASCII_BOX_GLYPH_RE);
398
+ const glyphSpan = glyphMatch
399
+ ? glyphMatch[0].toLowerCase().replace(/\s+/g, ' ').trim()
400
+ : '';
401
+ // (b) the option-label token SET. Pull the label TEXT after each `[n]` (or `n)` / `n.`)
402
+ // option marker, normalize each (lowercased, non-alphanumeric stripped), drop empties,
403
+ // dedupe, and SORT so option re-ordering does not flap the signature.
404
+ // Phase 210-05: the extraction itself (the OPTION_LABEL_RE loop, including its
405
+ // load-bearing whitespace-separator requirement) MOVED verbatim to
406
+ // lib/core/gate-relevance.cjs::extractOptionLabels so the retry-key signature and
407
+ // the relevance predicate share exactly ONE implementation. Same regex, same
408
+ // normalization, same encounter-order dedupe -- the signature output is
409
+ // byte-equivalent across the move, so retry keys do not change.
410
+ const labelSet = gateRelevance.extractOptionLabels(text);
411
+ labelSet.sort();
412
+ const sig = 'glyph:' + glyphSpan + '|labels:' + labelSet.join(',');
413
+ // Degenerate: no glyph span AND no labels recovered -> '' so the key floors to session alone.
414
+ if (!glyphSpan && labelSet.length === 0) return '';
415
+ return crypto.createHash('sha256').update(sig).digest('hex').slice(0, 24);
416
+ }
417
+
418
+ // ---------------------------------------------------------------------------
419
+ // turnContextHash(turn) -- a STABLE LOCAL key for the bounded-escape retry counter.
420
+ //
421
+ // WR-01 + CR-02 + CR-03: the key MUST be stable across re-PROMPTS on the SAME stuck gate, or
422
+ // MAX_FORCE_RETRIES is never reachable. There are ways the key can drift, and each is fatal to
423
+ // convergence:
424
+ // - WR-01 (re-worded prose): the model re-emits the same gate with different PROSE, so an
425
+ // output_text-derived key would mint a fresh key every retry.
426
+ // - CR-02 / CR-03 (transcript GROWTH): on the LIVE BACKSTOP path the model APPENDS one
427
+ // assistant turn every time the interceptor blocks and it re-emits, so ANY
428
+ // transcript-LENGTH-derived identity (an assistant-message counter, OR a last-USER-message
429
+ // anchor that is EMPTY on a no-role:user transcript and falls back to that counter) mints a
430
+ // fresh key every retry -- a production livelock.
431
+ // ROOT FIX: anchor the gate identity on the GATE-IDENTIFYING CONTENT itself (gate_signature):
432
+ // - session_id : the Stop stdin session_id (the same conversation across retries).
433
+ // - gate identity (in precedence order, each transcript-growth-INVARIANT):
434
+ // 1. the reached-gate entry SET when present (PRIMARY signal -- deferred, no producer).
435
+ // 2. the GATE SIGNATURE (gate_signature): the matched glyph span + normalized option-label
436
+ // SET of the LAST assistant message. Present whenever a gate is detected, invariant
437
+ // across transcript growth and prose re-wording, per-gate (two different gates ->
438
+ // different signatures -> different counters; WR-07).
439
+ // DEGENERATE FLOOR: if BOTH are empty, the key is session_id ALONE -- coarse but ALWAYS
440
+ // converges. NEVER the output text (WR-01), NEVER assistantCount / gate_turn_index / any
441
+ // transcript-length value (CR-02 / CR-03). A growing value is UNREACHABLE as the key.
442
+ // Part 8: a local sha256 over local stable identity scalars; never egresses.
443
+ // ---------------------------------------------------------------------------
444
+ function turnContextHash(turn) {
445
+ const t = turn && typeof turn === 'object' ? turn : {};
446
+ const session = typeof t.session_id === 'string' ? t.session_id : '';
447
+ // Gate identity, in precedence order. Each candidate is invariant across BOTH a re-worded
448
+ // re-prompt (WR-01) AND a growing transcript (CR-02 / CR-03).
449
+ const ran = Array.isArray(t.ran_entries) && t.ran_entries.length > 0
450
+ ? t.ran_entries.slice().sort().join('|')
451
+ : '';
452
+ // gate_signature: the transcript-growth-INVARIANT, per-gate identity for the LIVE BACKSTOP
453
+ // path (CR-03 / WR-07 root anchor). It is derived from the GATE CONTENT, never the user
454
+ // message and never a transcript-length counter, so the no-role:user path has no livelock
455
+ // hole and distinct gates never share a counter.
456
+ const gateSig = typeof t.gate_signature === 'string' ? t.gate_signature : '';
457
+ const gateIdentity = ran || gateSig;
458
+ // DEGENERATE FLOOR (gateIdentity empty): key on session_id ALONE. This always converges (any
459
+ // consecutive intercept in the session increments the same counter). It is NEVER a growing
460
+ // value -- the assistantCount / gate_turn_index fallback is DELETED.
461
+ return crypto
462
+ .createHash('sha256')
463
+ .update('s:' + session + '|g:' + gateIdentity)
464
+ .digest('hex')
465
+ .slice(0, 16);
466
+ }
467
+
468
+ // ---------------------------------------------------------------------------
469
+ // computeBackstopHit(outputText) -- the BACKSTOP signal. A hit ONLY on the shape-specific
470
+ // alternatives 1-3 (ASCII_BOX_UNCONDITIONAL_RE: same-line bracket box, the "type 1, 2, or 3"
471
+ // literal, the multiline bracket box). The Phase 209-07 bare numbered-prose alternative is
472
+ // RETIRED (see the retirement note above ASCII_BOX_UNCONDITIONAL_RE): it was an ~86%
473
+ // false-positive net in the live log, and a shape-plus-nearby-cue proxy cannot separate a
474
+ // benign numbered list from a genuine fork. A real numbered-prose fork is now the model's own
475
+ // Phase-210 / SEED-021 judgment. Pure LOCAL string work; never throws.
476
+ // ---------------------------------------------------------------------------
477
+ function computeBackstopHit(outputText) {
478
+ const text = typeof outputText === 'string' ? outputText : '';
479
+ if (!text) return false;
480
+ // Arms 1-3 only: a literal `[1] ... [2]` bracket box or the "type 1, 2, or 3" literal.
481
+ // Numbered-prose shape alone no longer counts (retired -- model judgment owns the fork).
482
+ return ASCII_BOX_UNCONDITIONAL_RE.test(text);
483
+ }
484
+
485
+ // ---------------------------------------------------------------------------
486
+ // matchedGlyphSpan(outputText) -- CR-07 diagnostic helper: return the ACTUAL text of the
487
+ // ASCII_BOX_GLYPH_RE match (not just a boolean), so the LOCAL intercept log records exactly
488
+ // which glyph span tripped the scan. '' when nothing matched. Never throws. Part 8: pure
489
+ // local string work; the span is written only to the local diagnostic log, never egressed.
490
+ // ---------------------------------------------------------------------------
491
+ function matchedGlyphSpan(outputText) {
492
+ const text = typeof outputText === 'string' ? outputText : '';
493
+ if (!text) return '';
494
+ const mm = text.match(ASCII_BOX_GLYPH_RE);
495
+ return mm ? mm[0] : '';
496
+ }
497
+
498
+ // ---------------------------------------------------------------------------
499
+ // classifyCardFire(turn, registry) -- THE deterministic predicate.
500
+ //
501
+ // Returns { intercept, reason, degrade }:
502
+ // - intercept=true : a reached gate fired no card; force it (decision:block-on-exit-0 re-prompt).
503
+ // - intercept=false : ordinary turn, card already fired, or degraded.
504
+ // - degrade=true : the bounded escape released (retry_count >= MAX_FORCE_RETRIES);
505
+ // stop forcing, log + allow.
506
+ //
507
+ // turn shape (the normalized turn signals a Stop hook derives):
508
+ // { ran_entries: string[], askuserquestion_fired: bool, output_text: string,
509
+ // retry_count?: number, session_count?: number }
510
+ //
511
+ // Bounded escape (CR-04): degrade when EITHER ceiling is reached --
512
+ // - retry_count >= MAX_FORCE_RETRIES (the per-gate counter; good UX, per-gate granularity)
513
+ // - session_count >= MAX_SESSION_INTERCEPTS (the SESSION-wide ceiling; the content-INDEPENDENT,
514
+ // un-flappable convergence floor that catches a
515
+ // flapping per-gate key the per-gate counter cannot).
516
+ // The session ceiling is the load-bearing guarantee: an unbroken run of intercepts in ONE
517
+ // session cannot exceed MAX_SESSION_INTERCEPTS regardless of how the gate content / per-gate key
518
+ // flaps. Both ceilings are checked; the session ceiling is reported distinctly so the degrade
519
+ // reason names WHICH floor fired.
520
+ //
521
+ // Pure code, deterministic, no network, no clock, no random. Never throws.
522
+ // ---------------------------------------------------------------------------
523
+ function classifyCardFire(turn, registry) {
524
+ try {
525
+ const t = turn && typeof turn === 'object' ? turn : {};
526
+ const ran = Array.isArray(t.ran_entries) ? t.ran_entries : [];
527
+ const cardFired = t.askuserquestion_fired === true;
528
+ const outputText = typeof t.output_text === 'string' ? t.output_text : '';
529
+
530
+ // If the card already fired, there is nothing to force.
531
+ if (cardFired) {
532
+ return { intercept: false, reason: 'card-fired', degrade: false };
533
+ }
534
+
535
+ // PRIMARY signal: did a render-coverage-registry gate-reaching surface run?
536
+ const reaching = new Set(gateReachingEntries(registry));
537
+ const primaryHit = ran.some(function (e) { return reaching.has(e); });
538
+
539
+ // BACKSTOP signal: does the turn output carry the ASCII-box gate glyphs? Catches
540
+ // the literal anti-pattern even for an off-registry surface. CR-05: a bare
541
+ // numbered-prose list (alternative 4) is a hit ONLY when it carries a choice-framing
542
+ // cue nearby, so a benign Action Footer / step-by-step list no longer force-fires.
543
+ const backstopHit = computeBackstopHit(outputText);
544
+
545
+ if (!primaryHit && !backstopHit) {
546
+ // No gate-reaching signal on this turn -> zero forced cards (ordinary turn).
547
+ return { intercept: false, reason: 'no-gate-signal', degrade: false };
548
+ }
549
+
550
+ // Phase 238-08 (GATE-04, D-15): the backstop-corroboration gate. `238-RESEARCH.md`
551
+ // measured that pure regex provably cannot separate a footnote reference list from
552
+ // a bracket-box gate -- `[1] Simon 1962.` / `[2] Rittel and Webber 1973.` and
553
+ // `[1] Build the plan` / `[2] File the evidence` are the SAME string shape. Both
554
+ // candidate replacement patterns still fired on the footnote list, and
555
+ // line-anchoring additionally lost the same-line bracket-box true positive (both
556
+ // measured, not assumed). Evidence: 5 of 6 authored false-positive fixtures fire on
557
+ // the shipped ASCII_BOX_UNCONDITIONAL_RE pattern today; 0 of 38 live
558
+ // ~/.mindrian/card-fire-intercepts.log records are backstop fires (37 of 38 are
559
+ // PRIMARY-arm, 1 of 38 is neither arm); the backstop's live false-positive rate on
560
+ // ordinary prose is real, not hypothetical. A regex cannot close this: a footnote
561
+ // reference list and a bracket-box gate are the same string shape, and a
562
+ // shape-plus-nearby-cue proxy was already tried and retired once at roughly an 86
563
+ // percent false-positive rate (see the retirement note above
564
+ // ASCII_BOX_UNCONDITIONAL_RE) -- this branch does NOT re-introduce that proxy under
565
+ // a new name. The remedy is architectural instead: a structural signal a citation
566
+ // cannot have, a corroborating side-channel reach record for THIS session. Decision
567
+ // ruled on 2026-07-29 (D-15, 238-08-PLAN.md).
568
+ //
569
+ // Condition: the PRIMARY arm did not hit (this branch is BACKSTOP-only), the
570
+ // BACKSTOP arm did hit, sidechannel_health is EXPLICITLY the healthy value (D-16:
571
+ // a turn carrying NEITHER new field -- the direct-field unit-test envelope shape --
572
+ // does not satisfy this and falls through unchanged, keeping every existing
573
+ // predicate assertion byte-stable), and reach_corroborated is not true. When all
574
+ // four hold, the backstop hit is UNCORROBORATED on a HEALTHY side channel: suppress
575
+ // the intercept and report degrade:false (this was never a real gate, so it must
576
+ // not consume retry budget -- placing this branch BEFORE the ceiling checks below
577
+ // is deliberate for exactly that reason).
578
+ //
579
+ // ACCEPTED RESIDUAL, stated plainly, not hidden (D-15): a genuine unrendered
580
+ // bracket-box gate from an OFF-REGISTRY surface, with a healthy side channel and NO
581
+ // reach record, no longer intercepts here. That is a real reduction in coverage,
582
+ // accepted because the PRIMARY arm handles the overwhelming majority of real fires
583
+ // (37 of 38 in the live log) and the alternative is a classifier that fires on
584
+ // ordinary technical prose in a dev repo. When the side channel is UNAVAILABLE
585
+ // (sidechannel_health is not explicitly healthy), this branch does not fire and the
586
+ // backstop keeps its full pre-238-08 independent authority -- the "detector of last
587
+ // resort" its own doctrine header claims, preserved rather than deleted.
588
+ if (
589
+ !primaryHit &&
590
+ backstopHit &&
591
+ t.sidechannel_health === SIDECHANNEL_HEALTH_OK &&
592
+ t.reach_corroborated !== true
593
+ ) {
594
+ return { intercept: false, degrade: false, reason: 'backstop-uncorroborated-by-side-channel' };
595
+ }
596
+
597
+ // A reached gate with no fired card is a candidate intercept. Apply the bounded escape:
598
+ // degrade if EITHER the per-gate counter OR the SESSION-wide counter has hit its ceiling.
599
+ const sessionCount = Number.isFinite(t.session_count) ? t.session_count : 0;
600
+ if (sessionCount >= MAX_SESSION_INTERCEPTS) {
601
+ // The CR-04 convergence floor: the session ceiling catches a flapping per-gate key that
602
+ // the per-gate counter never reaches. Content-INDEPENDENT, so it ALWAYS converges.
603
+ return {
604
+ intercept: false,
605
+ degrade: true,
606
+ reason: 'session-intercept-ceiling-reached-after-' + MAX_SESSION_INTERCEPTS + '-intercepts',
607
+ };
608
+ }
609
+
610
+ const retryCount = Number.isFinite(t.retry_count) ? t.retry_count : 0;
611
+ if (retryCount >= MAX_FORCE_RETRIES) {
612
+ return {
613
+ intercept: false,
614
+ degrade: true,
615
+ reason: 'bounded-escape-released-after-' + MAX_FORCE_RETRIES + '-retries',
616
+ };
617
+ }
618
+
619
+ // Phase 210-05 (item 210-E-1): the RELEVANCE GATE, inserted between the bounded
620
+ // escape above and the final intercept below. Two NARROW pass reasons only:
621
+ // - 'gate-already-answered' : the preceding user turn already plainly answered
622
+ // the gate (the 2026-07-02 live incident: a plain-text "yes" to the question
623
+ // the gate would re-ask).
624
+ // - 'gate-irrelevant-to-turn': the gate's subject matter has ZERO token overlap
625
+ // with the current conversation (the stale-artifact pattern).
626
+ // Empty/uncertain user text takes NEITHER pass (the conservative verdict inside
627
+ // gate-relevance.cjs) and falls through to the existing intercept -- the Phase 209
628
+ // guarantee (a genuine, relevant, unanswered fork still force-fires) is preserved.
629
+ // CR-03: preceding_user_text feeds ONLY this verdict, never the retry key.
630
+ //
631
+ // 2026-07-05 relevance-gate PRIMARY-path fix (kept): gateAlreadyAnswered's gateLabels
632
+ // (derived from outputText) is UNTOUCHED below -- only the relevance comparison's second
633
+ // argument (the gate subject) is path-specific. WHY: on the PRIMARY path, outputText is
634
+ // the CURRENT TURN's assistant reply, and the model naturally echoes the user's current
635
+ // topic back when answering it -- so comparing precedingUserText against outputText almost
636
+ // always looked "relevant" no matter what the stale reach was actually about (it compared
637
+ // the user's turn against the assistant's OWN reply, never against the reach's real
638
+ // subject).
639
+ //
640
+ // card-fire-relevance-check-gap (2026-07-17) PRIMARY-path gate-existence guard: a PRIMARY
641
+ // hit means a registry gate-reaching surface (lib/hmi/selector-dispatcher.cjs) appears in
642
+ // ran_entries -- but the side-channel's NO_SESSION_KEY union + ~10-min TTL bleeds ONE real
643
+ // gate-mint into EVERY turn's ran_entries for the next ten minutes across all sessions (the
644
+ // live log shows 10 consecutive false fires on status / "building" / "boot the real one"
645
+ // turns spanning ~21 min and 4 session_ids). So ran_entries alone is NOT proof a gate was
646
+ // reached THIS turn. Require CONFIRMED gate-existence: a non-empty reach-recorded subject
647
+ // (t.gate_subject_text -- the gate's own recorded content from the side-channel). With no
648
+ // subject there is no gate this turn -> 'primary-gate-existence-unconfirmed', no intercept.
649
+ // Relevance on the primary path compares the preceding user turn against the reach's OWN
650
+ // recorded subject ONLY, never the outputText fallback (which compares the user turn against
651
+ // the assistant's own reply and almost always reads "relevant" -- the exact defect this
652
+ // closes). This guard is PRIMARY-only; the BACKSTOP path carries its gate content in
653
+ // outputText and keeps the outputText fallback below.
654
+ const precedingUserText = typeof t.preceding_user_text === 'string'
655
+ ? t.preceding_user_text
656
+ : '';
657
+ if (primaryHit && !backstopHit) {
658
+ const primarySubject = (typeof t.gate_subject_text === 'string' && t.gate_subject_text)
659
+ ? t.gate_subject_text
660
+ : '';
661
+ if (!primarySubject) {
662
+ return { intercept: false, reason: 'primary-gate-existence-unconfirmed', degrade: false };
663
+ }
664
+ // room-bind-gate-fires-on-notification-only-turns (2026-07-23): refines
665
+ // card-fire-over-enforcement (2026-07-20) fix (B) above. That fix distinguished a
666
+ // FRESH gate from a STALE one; it did NOT distinguish WHY precedingUserText is empty.
667
+ // gateTopicallyRelevant's low-signal branch conflates two very different '' causes:
668
+ // (1) a genuinely short/terse HUMAN turn ("ok", "go on") -- KEEP forcing here, a
669
+ // human really was there and might be dismissively engaging with the gate
670
+ // (the WR-06/CR-06 floor, unchanged).
671
+ // (2) the preceding transcript record is a SYNTHETIC tool_result / task-notification
672
+ // envelope with NO human-authored text field at all (a background subagent
673
+ // finishing, an automated task notification) -- there was no human turn to be
674
+ // relevant or irrelevant to, so forcing a Decision Gate card here is never
675
+ // correct. Confirmed live: the F.8 room-binding gate force-fired three
676
+ // consecutive times on notification-only turns in one session (see
677
+ // .planning/debug/resolved/room-bind-gate-fires-on-notification-only-turns.md).
678
+ // classifyPrecedingUserContentSource (readTranscriptTurn) is the ONLY producer of
679
+ // 'tool_result' -- an unexplained/absent preceding record still resolves to 'none' and
680
+ // stays on the pre-fix conservative floor below. This check is PRIMARY-path ONLY (per
681
+ // the confirmed mechanism); the BACKSTOP path already forces unconditionally on a terse
682
+ // turn (gateStale:false, unchanged) and is out of scope for this fix.
683
+ if (t.preceding_user_text_source === 'tool_result') {
684
+ return { intercept: false, reason: 'preceding-turn-synthetic-no-user-engagement', degrade: false };
685
+ }
686
+ // card-fire-over-enforcement (2026-07-20) fix (B): a STALE side-channel
687
+ // gate (bled forward by the file TTL) plus a low-signal terse turn is the
688
+ // dominant over-enforcement class. Pass the gate's staleness so the
689
+ // low-signal relevance branch stops defaulting to force. A FRESH gate
690
+ // (gate_is_fresh !== false) keeps the conservative force floor unchanged.
691
+ if (!gateRelevance.gateTopicallyRelevant(precedingUserText, primarySubject,
692
+ { gateStale: t.gate_is_fresh === false })) {
693
+ return { intercept: false, reason: 'gate-irrelevant-to-turn', degrade: false };
694
+ }
695
+ }
696
+ const gateLabels = gateRelevance.extractOptionLabels(outputText);
697
+ if (gateRelevance.gateAlreadyAnswered(precedingUserText, gateLabels)) {
698
+ return { intercept: false, reason: 'gate-already-answered', degrade: false };
699
+ }
700
+ if (!(primaryHit && !backstopHit)) {
701
+ // BACKSTOP path: outputText legitimately IS the gate content, so the fallback to
702
+ // outputText is preserved here (and ONLY here).
703
+ const gateSubjectText = (typeof t.gate_subject_text === 'string' && t.gate_subject_text)
704
+ ? t.gate_subject_text
705
+ : outputText;
706
+ // BACKSTOP path: the gate content is THIS turn's own output_text, so the
707
+ // gate is always fresh here -- gateStale:false preserves the WR-06 floor
708
+ // (a terse turn against a freshly rendered box still force-fires).
709
+ if (!gateRelevance.gateTopicallyRelevant(precedingUserText, gateSubjectText,
710
+ { gateStale: false })) {
711
+ return { intercept: false, reason: 'gate-irrelevant-to-turn', degrade: false };
712
+ }
713
+ }
714
+
715
+ // Navigator decision (2026-07-05): a plain 2-option yes/no closer is a SIMPLE
716
+ // BINARY, not a genuine multi-option Decision Gate, and is EXEMPT from the
717
+ // card-fire requirement -- only genuine 3+-option forks force-fire. This pass-
718
+ // reason sits AFTER the two relevance checks on purpose: placing it before
719
+ // gate-already-answered would relabel an already-answered 2-option gate (the
720
+ // relevance test's RELEASE_GATE is also 2-option) as gate-is-simple-binary and
721
+ // change that pass-reason's precedence. Reuse the gateLabels already extracted
722
+ // above (per the RCA: no new option-extraction path).
723
+ //
724
+ // intern-w1-card-discipline-decay (2026-07-11): the original condition was a
725
+ // BARE `gateLabels.length === 2` cardinality check, which cannot distinguish a
726
+ // trivial yes/no confirmation closer ("Want those?") from a genuine two-way
727
+ // FORCED-CHOICE strategic fork ("run research vs build the plan" / "build the
728
+ // plan now vs file evidence first"). All 3 of an intern's missed forks in one
729
+ // QA session carried exactly 2 option labels and were swallowed by this
730
+ // exemption regardless of content. Fixed by requiring the labels to be
731
+ // YES/NO-SHAPED (gateRelevance.isYesNoShapedGate -- the SAME semantic test
732
+ // gateAlreadyAnswered already uses for its own 2-option yes/no answer-matching,
733
+ // reused here per Part 7 rather than re-implemented), not merely 2-in-number.
734
+ // A genuine 2-option fork whose labels are NOT yes/no-shaped now falls through
735
+ // to the final intercept below and force-fires, exactly like a 3+-way fork; a
736
+ // real yes/no closer stays exempt.
737
+ if (gateRelevance.isYesNoShapedGate(gateLabels)) {
738
+ return { intercept: false, reason: 'gate-is-simple-binary', degrade: false };
739
+ }
740
+
741
+ const reason = primaryHit
742
+ ? 'reached-registry-gate-no-card'
743
+ : 'ascii-box-backstop-no-card';
744
+ return { intercept: true, reason: reason, degrade: false };
745
+ } catch (_e) {
746
+ // Defensive: never throw out of the predicate.
747
+ return { intercept: false, reason: 'predicate-error', degrade: false };
748
+ }
749
+ }
750
+
751
+ // ---------------------------------------------------------------------------
752
+ // buildEnforcementEnvelope(verdict) -- shape the Stop-hook output envelope from a
753
+ // classifyCardFire verdict.
754
+ // - degrade -> { continue: true, suppressOutput: true } (log + allow; no loop).
755
+ // - intercept-> the decision:block-on-exit-0 block: { decision:'block', reason,
756
+ // systemMessage, continue:false }.
757
+ // - neither -> { continue: true, suppressOutput: true } (nothing to do).
758
+ // Returns a key-filtered envelope. Never throws.
759
+ //
760
+ // CR-06 (2026-07-11, backstop-benign-list-defeats-relevance-gate reopen of
761
+ // card-fire-block-surface Finding 1): the ORIGINAL fix added a systemMessage on the
762
+ // premise that Claude Code surfaces `reason` as "Stop hook error: <reason>" ONLY when no
763
+ // systemMessage override is present. Live observation (v1.15.3-beta.12) proved that premise
764
+ // FALSE -- Claude Code renders "Stop hook error: <reason>" REGARDLESS of systemMessage, so
765
+ // the internal slug (e.g. ascii-box-backstop-no-card) still reached the user looking like a
766
+ // crash. The only lever left is the `reason` CONTENT itself: on BOTH the intercept branch
767
+ // and the degrade branch it is now a calm, human-safe phrase, never the internal slug. The
768
+ // slug is PRESERVED for telemetry in the LOCAL intercept log (appendInterceptLog), not
769
+ // deleted. systemMessage stays on the intercept branch. The else branch keeps
770
+ // suppressOutput: true and carries no systemMessage.
771
+ //
772
+ // stop-hook-invalid-hookspecificoutput-schema (2026-07-23, 4th occurrence of this
773
+ // defect class): the intercept branch previously ALSO carried a hookSpecificOutput
774
+ // envelope (event name Stop, plus an additionalContext re-prompt string). Stop is
775
+ // not one of the three event types Claude Code's schema defines a
776
+ // hookSpecificOutput variant for (PreToolUse / UserPromptSubmit / PostToolUse only),
777
+ // so that key made the validator reject the WHOLE envelope -- the user saw a raw
778
+ // "Hook JSON output validation failed: Invalid input" dump instead of the calm
779
+ // `reason`/`systemMessage` text above, on every turn this branch fired. REMOVED
780
+ // outright. The `additionalContext` re-prompt text it carried ("You MUST fire the
781
+ // AskUserQuestion card NOW...") has no valid Stop-hook delivery channel in the
782
+ // current schema (additionalContext is UserPromptSubmit/PostToolUse-only) and per
783
+ // CR-06 must not be smuggled into `reason`/`systemMessage` either (those are
784
+ // human-facing and must stay calm, never carry model-directive/internal-mechanism
785
+ // text) -- so it is dropped, not relocated. See
786
+ // .planning/debug/resolved/stop-hook-invalid-hookspecificoutput-schema.md.
787
+ // ---------------------------------------------------------------------------
788
+ function buildEnforcementEnvelope(verdict) {
789
+ const v = verdict && typeof verdict === 'object' ? verdict : {};
790
+
791
+ let raw;
792
+ if (v.degrade === true) {
793
+ raw = {
794
+ continue: true,
795
+ suppressOutput: true,
796
+ // CR-06: calm, human-safe `reason` (never the internal slug). Claude Code surfaces
797
+ // `reason` as "Stop hook error: <reason>" regardless of systemMessage, so the slug
798
+ // must not live here. It is preserved for telemetry in the LOCAL intercept log.
799
+ reason: 'continuing this turn',
800
+ };
801
+ } else if (v.intercept === true) {
802
+ raw = {
803
+ decision: 'block',
804
+ // CR-06: calm, human-safe `reason` (never the internal slug -- see the branch note
805
+ // above). The slug is preserved for telemetry in the LOCAL intercept log instead.
806
+ reason: 'rendering your choices as a selectable card',
807
+ // FIXED human-facing line (never interpolated from transcript content or the reason
808
+ // slug; T-m9g-01). Retained from the original Finding 1 fix as the second calm surface.
809
+ systemMessage: 'Re-rendering your choices as a selectable card...',
810
+ continue: false,
811
+ };
812
+ } else {
813
+ raw = { continue: true, suppressOutput: true };
814
+ }
815
+
816
+ const filtered = {};
817
+ for (const k of Object.keys(raw)) {
818
+ if (ALLOWED_ENVELOPE_KEYS.has(k)) filtered[k] = raw[k];
819
+ }
820
+ if (filtered.continue === undefined && filtered.decision === undefined) {
821
+ filtered.continue = true;
822
+ }
823
+ return filtered;
824
+ }
825
+
826
+ // ---------------------------------------------------------------------------
827
+ // 238-05 Task 2 (GATE-03 half B, the LOST-UPDATE fix): withRetryStoreLock, the
828
+ // bounded-wait fence around the retry-store read-modify-write.
829
+ //
830
+ // Measured pre-fix (238-RESEARCH.md Finding 4): 20 forked processes each doing
831
+ // 10 bumpRetryCount calls against an isolated MINDRIAN_HOME landed a final
832
+ // count of 3, not 200 -- 197 lost updates. Task 1's tmp-and-rename write fixes
833
+ // torn READS; it does NOT fix this. The defect is a read-modify-write with no
834
+ // fence: every concurrent writer reads the same pre-state and the last writer
835
+ // wins, discarding every increment that landed between its own read and write.
836
+ //
837
+ // DEVIATION FROM D-05, recorded here and in 238-05-SUMMARY.md: D-05 called
838
+ // for reusing lib/core/write-lock.cjs's acquireLock/releaseLock UNCHANGED.
839
+ // Adversarial testing during this task (20 forked processes doing 200 total
840
+ // acquire/release cycles, not the single simultaneous-storm shape Phase
841
+ // 87-02's own precedent test exercises) found that acquireLock has a REAL
842
+ // TOCTOU race under this higher-frequency usage: its create step is
843
+ // open-then-SEPARATELY-write (a reader can observe an empty file mid-create
844
+ // and misclassify it as corrupt), and its corrupt/stale/dead-PID cleanup
845
+ // branches unconditionally unlink whatever is CURRENTLY at the lock path
846
+ // without verifying it is still the same file they read moments earlier --
847
+ // so a slow contender can destroy a DIFFERENT, already-valid lock a faster
848
+ // contender just created, breaking mutual exclusion. Measured: repeated
849
+ // 20x10 runs against the unmodified primitive landed 148-197 of 200, never a
850
+ // reliable 200, with zero fence-exhaustion events (so the loss is a true
851
+ // double-hold, not a wait-budget problem). Root-caused with a custom
852
+ // nanosecond-precision trace (hrtime.bigint on ACQ/REL boundaries across all
853
+ // 20 children) that caught two live overlapping "holds" of the same lock
854
+ // path in the act.
855
+ //
856
+ // scripts/check-card-fire.cjs is the ONLY file this plan may modify
857
+ // (files_modified). lib/core/write-lock.cjs is shared by other subsystems
858
+ // (SQLite write-safety) and is NOT touched here -- fixing its cleanup
859
+ // protocol correctly is real distributed-systems work (verified by writing
860
+ // and discarding two intermediate fix attempts that each introduced their
861
+ // own new race or performance regression before landing on the design
862
+ // below) and belongs to a dedicated follow-up, not a plan whose declared
863
+ // scope is this file alone. Instead, the retry-store fence below is a
864
+ // SEPARATE, purpose-built lock local to this file, using two idioms already
865
+ // proven correct in this session:
866
+ // 1. Atomic CREATE: write full content to a unique temp path, then
867
+ // fs.linkSync(tmpPath, lockPath). link() only ever makes an ALREADY-
868
+ // FULLY-WRITTEN inode visible under the final name -- there is no
869
+ // window where a reader can see empty/partial content, unlike
870
+ // open('wx') followed by a separate write.
871
+ // 2. Inode-VERIFIED cleanup: before removing a lock judged corrupt/stale/
872
+ // dead-PID, open it, fstat it, and only unlink if the inode still
873
+ // matches what was read. A concurrent contender who has already
874
+ // replaced the file with a fresh, valid lock can never have that lock
875
+ // destroyed by a decision based on a now-stale snapshot.
876
+ // Empirically verified: 20+ consecutive 20-process x 10-bump runs against
877
+ // this design landed exactly 200 every time (see 238-05-SUMMARY.md for the
878
+ // full trial log). The external behavior this plan's callers need is
879
+ // unchanged: bump/clear still best-effort, still swallow write faults, still
880
+ // degrade to an unfenced write on fence exhaustion (D-12).
881
+ // ---------------------------------------------------------------------------
882
+
883
+ // retryStoreLockPath() -- a dedicated lock file sitting NEXT TO the retry
884
+ // store itself (a sibling path, not nested under a room-shaped '.mindrian'
885
+ // directory the way the shared write-lock.cjs primitive would have used).
886
+ // Since this lock is purpose-built for exactly one file, it needs no
887
+ // borrowed room-directory convention.
888
+ function retryStoreLockPath() {
889
+ return retryFilePath() + '.lock';
890
+ }
891
+
892
+ // The bounded-wait sizing. Named constants, not magic numbers, so the total
893
+ // worst-case wait is legible at a glance: 300 attempts * 20ms = ~6000ms.
894
+ //
895
+ // Justification for affording the wait at all: Phase 241 verified against
896
+ // real Claude Code documentation that the platform's default Stop-hook
897
+ // timeout is 600 SECONDS per hook command, not the ~3000ms this file's own
898
+ // older comments assumed and never checked. A worst-case wait of about six
899
+ // seconds sits comfortably (~100x) inside the real budget, so fencing here
900
+ // is never a latency risk in production.
901
+ //
902
+ // Tuning note: an initial 50-attempt (~1s) budget, sized before this file's
903
+ // own concurrency was measured, produced occasional (D-12) fence-exhaustion
904
+ // degrades under 20-process x 10-bump real contention (2-3 exhaustions per
905
+ // run, each landing one increment via the unfenced path instead of the
906
+ // fenced one -- safe per D-12, but not exact). Widening to 300 attempts
907
+ // (~6s) was verified against 24+ consecutive 20x10 runs with zero
908
+ // exhaustions and an exact count every time (238-05-SUMMARY.md has the
909
+ // trial log). 6s worst case is still far inside the 600s hook budget.
910
+ const RETRY_LOCK_MAX_ATTEMPTS = 300;
911
+ const RETRY_LOCK_SLEEP_MS = 20;
912
+
913
+ // RETRY_LOCK_STALE_THRESHOLD_MS -- mirrors lib/core/write-lock.cjs's own
914
+ // STALE_THRESHOLD_MS (5s) for consistency of expectations across the
915
+ // codebase's lock files: a lock older than this is presumed abandoned by a
916
+ // crashed holder and is safe to reclaim (after inode verification).
917
+ const RETRY_LOCK_STALE_THRESHOLD_MS = 5000;
918
+
919
+ // safeVerifiedDelete(lockPath, expectedIno, expectedDev) -- remove lockPath
920
+ // ONLY if it is still the exact inode we already inspected. Opens the file
921
+ // (not just statSync on the path) so the inode check and the unlink discuss
922
+ // the SAME file handle's identity, closing the gap a path-based re-check
923
+ // would still leave.
924
+ function safeVerifiedDelete(lockPath, expectedIno, expectedDev) {
925
+ let fd;
926
+ try {
927
+ fd = fs.openSync(lockPath, 'r');
928
+ } catch (_e) {
929
+ return; // already gone; nothing to clean up
930
+ }
931
+ try {
932
+ const st = fs.fstatSync(fd);
933
+ if (st.ino !== expectedIno || st.dev !== expectedDev) {
934
+ // A different, presumably newer file now lives at this path. Not ours
935
+ // to delete -- deleting it would destroy someone else's valid lock.
936
+ return;
937
+ }
938
+ fs.unlinkSync(lockPath);
939
+ } catch (_e) {
940
+ /* best-effort cleanup; never throw out of the fence */
941
+ } finally {
942
+ try { fs.closeSync(fd); } catch (_e) { /* best-effort */ }
943
+ }
944
+ }
945
+
946
+ // tryAtomicCreate(lockPath, payload) -- write-then-link. Throws EEXIST (same
947
+ // error code openSync('wx') would throw) if the name is already taken, so
948
+ // callers can treat it identically to a failed exclusive-create.
949
+ function tryAtomicCreate(lockPath, payload) {
950
+ const tmpPath = lockPath + '.tmp-' + process.pid + '-' + Date.now() + '-' + Math.random().toString(36).slice(2);
951
+ fs.writeFileSync(tmpPath, payload);
952
+ try {
953
+ fs.linkSync(tmpPath, lockPath);
954
+ } finally {
955
+ try { fs.unlinkSync(tmpPath); } catch (_e) { /* best-effort */ }
956
+ }
957
+ }
958
+
959
+ // acquireRetryLock() -- one attempt to claim the retry-store lock. Throws on
960
+ // failure (live holder or a pathological double-failure after cleanup);
961
+ // withRetryStoreLock below is what turns this into a bounded WAIT.
962
+ function acquireRetryLock() {
963
+ const lockPath = retryStoreLockPath();
964
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true });
965
+ const payload = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
966
+
967
+ for (let attempt = 0; attempt < 2; attempt += 1) {
968
+ // Cheap pre-check: only pay for the tmp-write-then-link dance when the
969
+ // path looks free. Under contention the lock is usually held, so this
970
+ // check saves a wasted disk write on nearly every failed attempt; if it
971
+ // races (looks free but is not by the time we act), linkSync's own
972
+ // EEXIST still catches it correctly -- this is a performance hint only,
973
+ // never relied on for correctness.
974
+ if (!fs.existsSync(lockPath)) {
975
+ try {
976
+ tryAtomicCreate(lockPath, payload);
977
+ return;
978
+ } catch (createErr) {
979
+ if (createErr.code !== 'EEXIST') throw createErr;
980
+ // fall through to inspection below
981
+ }
982
+ }
983
+
984
+ let fd;
985
+ try {
986
+ fd = fs.openSync(lockPath, 'r');
987
+ } catch (_openErr) {
988
+ // Vanished between the existsSync check and open -- someone else is
989
+ // racing; retry from the top of this attempt.
990
+ continue;
991
+ }
992
+ let st, raw;
993
+ try {
994
+ st = fs.fstatSync(fd);
995
+ raw = fs.readFileSync(fd, 'utf-8');
996
+ } finally {
997
+ try { fs.closeSync(fd); } catch (_e) { /* best-effort */ }
998
+ }
999
+
1000
+ let data;
1001
+ try {
1002
+ data = JSON.parse(raw);
1003
+ } catch (_parseErr) {
1004
+ safeVerifiedDelete(lockPath, st.ino, st.dev);
1005
+ continue;
1006
+ }
1007
+ const age = Date.now() - data.timestamp;
1008
+ if (age > RETRY_LOCK_STALE_THRESHOLD_MS) {
1009
+ safeVerifiedDelete(lockPath, st.ino, st.dev);
1010
+ continue;
1011
+ }
1012
+ if (data.pid === process.pid) {
1013
+ // Same-process re-acquire: no cross-process race is possible here
1014
+ // (single-threaded, same PID owns it by definition).
1015
+ fs.writeFileSync(lockPath, payload);
1016
+ return;
1017
+ }
1018
+ try {
1019
+ process.kill(data.pid, 0);
1020
+ throw new Error('retry-store lock held by PID ' + data.pid);
1021
+ } catch (killErr) {
1022
+ if (killErr.message && killErr.message.indexOf('retry-store lock held') === 0) throw killErr;
1023
+ // Dead PID -- clean up (inode-verified) and retry.
1024
+ safeVerifiedDelete(lockPath, st.ino, st.dev);
1025
+ continue;
1026
+ }
1027
+ }
1028
+ throw new Error('retry-store lock could not be acquired after retry');
1029
+ }
1030
+
1031
+ function releaseRetryLock() {
1032
+ try {
1033
+ fs.unlinkSync(retryStoreLockPath());
1034
+ } catch (_e) {
1035
+ /* ENOENT or other errors -- silent, matches releaseLock's contract */
1036
+ }
1037
+ }
1038
+
1039
+ // withRetryStoreLock(fn) -- run fn() with the retry-store file lock held.
1040
+ //
1041
+ // A bare single-shot acquire THROWS when a live holder exists; it does not
1042
+ // wait. The bounded spin below is the whole point of this function, not an
1043
+ // optimization: it retries the acquire up to RETRY_LOCK_MAX_ATTEMPTS times,
1044
+ // sleeping RETRY_LOCK_SLEEP_MS (via a real synchronous Atomics.wait sleep,
1045
+ // never a busy spin) between attempts.
1046
+ //
1047
+ // D-12 (degrade direction on fence exhaustion): if every attempt fails to
1048
+ // acquire, run fn() UNFENCED anyway rather than dropping the increment. That
1049
+ // is exactly today's (pre-238-05) behavior, so this change can never be worse
1050
+ // than the status quo on any path -- dropping the increment is the defect
1051
+ // being fixed, not an acceptable fallback. Nothing is swallowed silently on
1052
+ // this path beyond an optional stderr line (this runs inside a Stop hook, so
1053
+ // it must never throw or print to stdout).
1054
+ function withRetryStoreLock(fn) {
1055
+ for (let attempt = 0; attempt < RETRY_LOCK_MAX_ATTEMPTS; attempt += 1) {
1056
+ try {
1057
+ acquireRetryLock();
1058
+ } catch (_acquireErr) {
1059
+ // Did not win the fence this attempt. Sleep synchronously and retry.
1060
+ // Atomics.wait on a one-element Int32Array backed by a SharedArrayBuffer
1061
+ // is a real blocking sleep Node permits on the main thread, needs no
1062
+ // dependency, and is not a CPU-spinning busy loop.
1063
+ const sab = new SharedArrayBuffer(4);
1064
+ const ia = new Int32Array(sab);
1065
+ Atomics.wait(ia, 0, 0, RETRY_LOCK_SLEEP_MS);
1066
+ continue;
1067
+ }
1068
+ try {
1069
+ return fn();
1070
+ } finally {
1071
+ releaseRetryLock();
1072
+ }
1073
+ }
1074
+ // Fence exhausted (D-12): degrade to the unfenced read-modify-write rather
1075
+ // than dropping the increment. Never worse than pre-238-05 behavior.
1076
+ try {
1077
+ process.stderr.write('[check-card-fire] retry-store lock fence exhausted; writing unfenced\n');
1078
+ } catch (_e) {
1079
+ /* stderr write must never throw the hook */
1080
+ }
1081
+ return fn();
1082
+ }
1083
+
1084
+ // readRetryCount(ctxHash) / bumpRetryCount(ctxHash) / clearRetryCount(ctxHash) --
1085
+ // the LOCAL bounded-escape side-file (Part 8 LOCAL-only). Best-effort: any error is
1086
+ // swallowed (a missing/corrupt side-file degrades to a fresh count of 0, never blocks).
1087
+ // ---------------------------------------------------------------------------
1088
+ function readRetryStore() {
1089
+ try {
1090
+ const raw = fs.readFileSync(retryFilePath(), 'utf8');
1091
+ const obj = JSON.parse(raw);
1092
+ return obj && typeof obj === 'object' ? obj : {};
1093
+ } catch (_e) {
1094
+ return {};
1095
+ }
1096
+ }
1097
+
1098
+ // pruneRetryStore(store, now) -- WR-02: evict entries older than RETRY_TTL_MS so the
1099
+ // side-file cannot grow without bound. Each entry is { count, ts }; a legacy bare-integer
1100
+ // entry (pre-WR-02 format) is normalized to { count, ts: now } on read so it is not lost
1101
+ // but does become subject to the TTL going forward. Pure; returns a fresh pruned store.
1102
+ function pruneRetryStore(store, now) {
1103
+ const t = Number.isFinite(now) ? now : Date.now();
1104
+ const out = {};
1105
+ const src = store && typeof store === 'object' ? store : {};
1106
+ for (const k of Object.keys(src)) {
1107
+ const e = normalizeRetryEntry(src[k], t);
1108
+ if (e && (t - e.ts) <= RETRY_TTL_MS) {
1109
+ out[k] = e;
1110
+ }
1111
+ }
1112
+ return out;
1113
+ }
1114
+
1115
+ // normalizeRetryEntry(v, now) -- coerce a store value to { count, ts }. Tolerates the
1116
+ // legacy bare-integer shape (pre-WR-02) and the { count, ts } shape; anything else -> null.
1117
+ function normalizeRetryEntry(v, now) {
1118
+ const t = Number.isFinite(now) ? now : Date.now();
1119
+ if (Number.isFinite(v)) return { count: v, ts: t };
1120
+ if (v && typeof v === 'object' && Number.isFinite(v.count)) {
1121
+ return { count: v.count, ts: Number.isFinite(v.ts) ? v.ts : t };
1122
+ }
1123
+ return null;
1124
+ }
1125
+
1126
+ // 238-05 Task 1 (GATE-03 half B, torn-read fix): writeRetryStore writes via a
1127
+ // tmp-file-plus-renameSync in the SAME directory as the target, mirroring the
1128
+ // sibling side-file's idiom (lib/core/card-fire-sidechannel.cjs::writeStoreAtomic).
1129
+ // Rename is atomic on the same filesystem, which is why the temp file must live
1130
+ // next to the target and never in os.tmpdir().
1131
+ //
1132
+ // What this fixes: a concurrent READER can never observe a partial or
1133
+ // half-written file, because the target path only ever transitions from "old
1134
+ // complete content" to "new complete content" in one atomic filesystem op.
1135
+ //
1136
+ // What this does NOT fix: lost updates. This function still overwrites
1137
+ // whatever `store` it is handed; if two callers both read the pre-state and
1138
+ // both call this with their own read-modify-write, the last rename wins and
1139
+ // the other caller's increment is gone. Closing THAT defect is Task 2's job
1140
+ // (withRetryStoreLock, the bounded-wait fence around the read-modify-write).
1141
+ // Do not mistake one fix for the other.
1142
+ function writeRetryStore(store) {
1143
+ try {
1144
+ const fp = retryFilePath();
1145
+ const dir = path.dirname(fp);
1146
+ fs.mkdirSync(dir, { recursive: true });
1147
+ // WR-02: prune on every write.
1148
+ const now = Date.now();
1149
+ const tmp = fp + '.tmp-' + process.pid + '-' + now;
1150
+ fs.writeFileSync(tmp, JSON.stringify(pruneRetryStore(store, now)), 'utf8');
1151
+ fs.renameSync(tmp, fp);
1152
+ } catch (_e) {
1153
+ /* best-effort; never block on a side-file write */
1154
+ }
1155
+ }
1156
+
1157
+ function readRetryCount(ctxHash) {
1158
+ const store = readRetryStore();
1159
+ const e = normalizeRetryEntry(store[ctxHash], Date.now());
1160
+ return e ? e.count : 0;
1161
+ }
1162
+
1163
+ // 238-05 Task 2: the read is moved INSIDE the fence. A read taken before the
1164
+ // lock reintroduces the exact lost-update race being fixed (a reader outside
1165
+ // the lock can still see a stale pre-state that a concurrent writer is about
1166
+ // to overwrite with its own stale-based next value).
1167
+ function bumpRetryCount(ctxHash) {
1168
+ return withRetryStoreLock(function () {
1169
+ const store = readRetryStore();
1170
+ const now = Date.now();
1171
+ const e = normalizeRetryEntry(store[ctxHash], now);
1172
+ const next = (e ? e.count : 0) + 1;
1173
+ store[ctxHash] = { count: next, ts: now };
1174
+ writeRetryStore(store);
1175
+ return next;
1176
+ });
1177
+ }
1178
+
1179
+ function clearRetryCount(ctxHash) {
1180
+ withRetryStoreLock(function () {
1181
+ const store = readRetryStore();
1182
+ if (ctxHash in store) {
1183
+ delete store[ctxHash];
1184
+ writeRetryStore(store);
1185
+ }
1186
+ });
1187
+ }
1188
+
1189
+ // ---------------------------------------------------------------------------
1190
+ // CR-04 SESSION-WIDE intercept ceiling -- the content-INDEPENDENT convergence floor.
1191
+ //
1192
+ // sessionKey(sessionId) / readSessionCount(sessionId) / bumpSessionCount(sessionId) /
1193
+ // clearSessionCount(sessionId) -- the session counter lives in the SAME side-file as the per-
1194
+ // gate entries, at `__session__:<sessionId>`, { count, ts } shaped, TTL-pruned identically
1195
+ // (WR-02). It is keyed on the OPAQUE session_id ALONE (no model-emitted content), so it cannot
1196
+ // be flapped: a continuous run of intercepts in ONE session climbs the SAME session counter
1197
+ // REGARDLESS of how the per-gate signature moves, and MAX_SESSION_INTERCEPTS hard-bounds it.
1198
+ //
1199
+ // Part 8: session_id is an opaque conversation identifier (not user content / not artifact
1200
+ // text). The key is `__session__:<opaque-id>`; the value is a scalar count + timestamp. No raw
1201
+ // text egress; the side-file is LOCAL (~/.mindrian) only. Best-effort like the per-gate helpers.
1202
+ // ---------------------------------------------------------------------------
1203
+ function sessionKey(sessionId) {
1204
+ const s = typeof sessionId === 'string' ? sessionId : '';
1205
+ return SESSION_KEY_PREFIX + s;
1206
+ }
1207
+
1208
+ function readSessionCount(sessionId) {
1209
+ const store = readRetryStore();
1210
+ const e = normalizeRetryEntry(store[sessionKey(sessionId)], Date.now());
1211
+ return e ? e.count : 0;
1212
+ }
1213
+
1214
+ // 238-05 Task 2: routed through withRetryStoreLock, same read-inside-the-fence
1215
+ // discipline as bumpRetryCount/clearRetryCount above. This counter shares the
1216
+ // SAME file and the SAME write path as the per-gate entries, so a fence
1217
+ // applied to only one accessor family would still lose the other's updates.
1218
+ function bumpSessionCount(sessionId) {
1219
+ return withRetryStoreLock(function () {
1220
+ const store = readRetryStore();
1221
+ const now = Date.now();
1222
+ const key = sessionKey(sessionId);
1223
+ const e = normalizeRetryEntry(store[key], now);
1224
+ const next = (e ? e.count : 0) + 1;
1225
+ store[key] = { count: next, ts: now };
1226
+ writeRetryStore(store);
1227
+ return next;
1228
+ });
1229
+ }
1230
+
1231
+ function clearSessionCount(sessionId) {
1232
+ withRetryStoreLock(function () {
1233
+ const store = readRetryStore();
1234
+ const key = sessionKey(sessionId);
1235
+ if (key in store) {
1236
+ delete store[key];
1237
+ writeRetryStore(store);
1238
+ }
1239
+ });
1240
+ }
1241
+
1242
+ // ---------------------------------------------------------------------------
1243
+ // CR-07 -- the LOCAL append-only intercept diagnostic log. Written whenever
1244
+ // classifyCardFire returns intercept:true OR degrade:true, so the NEXT occurrence of the
1245
+ // still-unexplained backstop trigger (live-session-running-stale-plugin-cache-fixes-inert)
1246
+ // is a one-log-read diagnosis instead of a multi-hour forensic reconstruction. Each record
1247
+ // preserves the ORIGINAL classification slug (verdict.reason) even though the user-facing
1248
+ // envelope `reason` is now a calm phrase (CR-06), so telemetry survives the calming.
1249
+ //
1250
+ // TTL-pruned on every write by the SAME RETRY_TTL_MS the retry side-file uses (WR-02), so
1251
+ // the JSONL cannot grow without bound. Best-effort like the retry helpers: any error is
1252
+ // swallowed -- a diagnostic log write must NEVER block or throw the Stop hook.
1253
+ //
1254
+ // Part 8 (Graph Boundary): LOCAL-only. The record (including the truncated output_text,
1255
+ // an untrusted model turn already on local disk in the transcript) is written to
1256
+ // ~/.mindrian on local disk, never to the Brain and never over any network wire.
1257
+ // ---------------------------------------------------------------------------
1258
+ function readInterceptLogLines(fp, now) {
1259
+ const out = [];
1260
+ try {
1261
+ const raw = fs.readFileSync(fp, 'utf8');
1262
+ const lines = raw.split('\n');
1263
+ for (const line of lines) {
1264
+ const trimmed = line.trim();
1265
+ if (!trimmed) continue;
1266
+ let obj;
1267
+ try { obj = JSON.parse(trimmed); } catch (_e) { continue; }
1268
+ // TTL-prune: keep only records younger than RETRY_TTL_MS (WR-02 parity).
1269
+ if (obj && Number.isFinite(obj.ts) && (now - obj.ts) <= RETRY_TTL_MS) {
1270
+ out.push(trimmed);
1271
+ }
1272
+ }
1273
+ } catch (_e) {
1274
+ /* missing / unreadable -> fresh log */
1275
+ }
1276
+ return out;
1277
+ }
1278
+
1279
+ function appendInterceptLog(turn, verdict) {
1280
+ try {
1281
+ const t = turn && typeof turn === 'object' ? turn : {};
1282
+ const v = verdict && typeof verdict === 'object' ? verdict : {};
1283
+ const now = Date.now();
1284
+ const outputText = typeof t.output_text === 'string' ? t.output_text : '';
1285
+ const record = {
1286
+ ts: now,
1287
+ timestamp: new Date(now).toISOString(),
1288
+ session_id: typeof t.session_id === 'string' ? t.session_id : '',
1289
+ // The ORIGINAL classification slug -- preserved here even though the user-facing
1290
+ // envelope `reason` changes to a calm phrase (CR-06). This is the telemetry sink.
1291
+ reason: typeof v.reason === 'string' ? v.reason : '',
1292
+ gate_signature: typeof t.gate_signature === 'string' ? t.gate_signature : '',
1293
+ ran_entries: Array.isArray(t.ran_entries) ? t.ran_entries : [],
1294
+ matched_glyph_span: matchedGlyphSpan(outputText),
1295
+ output_text: outputText.slice(0, INTERCEPT_LOG_TEXT_CAP),
1296
+ };
1297
+ const fp = interceptLogPath();
1298
+ fs.mkdirSync(path.dirname(fp), { recursive: true });
1299
+ const kept = readInterceptLogLines(fp, now);
1300
+ kept.push(JSON.stringify(record));
1301
+ fs.writeFileSync(fp, kept.join('\n') + '\n', 'utf8');
1302
+ } catch (_e) {
1303
+ /* best-effort; never block the hook on a diagnostic-log write */
1304
+ }
1305
+ }
1306
+
1307
+ // ---------------------------------------------------------------------------
1308
+ // consumeReachedGatesForVerdict(turn, verdict) -- card-fire-answered-gate-refires-
1309
+ // within-ttl-window (2026-07-28). THE record-lifecycle wire: spend the side-channel
1310
+ // reached-gate records once this Stop evaluation has reached a TERMINAL verdict on
1311
+ // them, so a single gate mint can never be re-litigated on a LATER turn.
1312
+ //
1313
+ // THE GAP THIS CLOSES (confirmed from source + the live ~/.mindrian/card-fire-
1314
+ // intercepts.log, 6 real records, every one of them reason 'reached-registry-gate-
1315
+ // no-card' with ran_entries ["scripts/intent-classifier.cjs"] and an empty/benign
1316
+ // matched_glyph_span -- i.e. every one a PRIMARY-arm hit on a turn whose own output
1317
+ // could not possibly match ASCII_BOX_UNCONDITIONAL_RE): the side-channel record had
1318
+ // no lifecycle at all. Its ONLY exit was the 10-minute TTL. So the PRIMARY arm kept
1319
+ // asserting "a gate was reached, force the card" on EVERY Stop evaluation inside the
1320
+ // 2-minute TURN_FRESH_MS window -- including the turns AFTER the navigator had
1321
+ // already fired the card and answered it.
1322
+ //
1323
+ // WHY THE EXISTING ESCAPES CANNOT COVER IT (each was checked against this shape):
1324
+ // - askuserquestion_fired is CURRENT-TURN scoped (readTranscriptTurn resets its
1325
+ // window at every role:user boundary), so a card fired and answered in turn N is
1326
+ // structurally invisible to turn N+1's Stop hook.
1327
+ // - gate-already-answered derives gateLabels from THIS turn's outputText, which is
1328
+ // EMPTY on a no-card prose turn, so that branch returns false before it can help.
1329
+ // - gate_is_fresh encodes elapsed time since mint, never still-pending state; a
1330
+ // gate answered 30 seconds ago and a gate still sitting unanswered 30 seconds ago
1331
+ // are byte-identical to it.
1332
+ // - preceding-turn-synthetic-no-user-engagement only fires on a CONFIRMED
1333
+ // 'tool_result' record; a background task-notification carrying a real text block
1334
+ // classifies as 'typed' and falls straight through.
1335
+ //
1336
+ // TERMINAL vs ACTIVE (the load-bearing distinction): consume on card-fired /
1337
+ // no-gate-signal / any relevance pass / a bounded-escape degrade. NEVER consume on
1338
+ // intercept:true -- an intercept means the force-loop is still ACTIVE, the model is
1339
+ // about to be re-prompted, and the record must survive so the re-prompted turn is
1340
+ // re-checked. Consuming there would make MAX_FORCE_RETRIES unreachable and silently
1341
+ // turn the force-fire into a single-shot -- a reverse regression on the Phase 209
1342
+ // guarantee, which is exactly as bad as the over-enforcement this fix removes.
1343
+ //
1344
+ // Best-effort like every other side-file helper here: a missing module, a missing
1345
+ // export, or any fs fault degrades to a silent 0. A consumption fault must NEVER
1346
+ // block or throw the Stop hook (T-209-24). Part 8: LOCAL-only, deletes local scalars.
1347
+ // ---------------------------------------------------------------------------
1348
+ function consumeReachedGatesForVerdict(turn, verdict) {
1349
+ try {
1350
+ const t = turn && typeof turn === 'object' ? turn : {};
1351
+ const v = verdict && typeof verdict === 'object' ? verdict : {};
1352
+ // ACTIVE force-loop: keep the record alive so the re-prompted turn re-checks it.
1353
+ if (v.intercept === true) return 0;
1354
+ const sidechannel = require(path.join(PLUGIN_ROOT, 'lib', 'core', 'card-fire-sidechannel.cjs'));
1355
+ if (typeof sidechannel.consumeReachedGates !== 'function') return 0;
1356
+ return sidechannel.consumeReachedGates(
1357
+ typeof t.session_id === 'string' ? t.session_id : ''
1358
+ );
1359
+ } catch (_e) {
1360
+ return 0;
1361
+ }
1362
+ }
1363
+
1364
+ // ----- stdin / envelope helpers (the on-stop idiom from operator-update.cjs) -----
1365
+
1366
+ function readStdinJson() {
1367
+ try {
1368
+ const raw = fs.readFileSync(0, 'utf8');
1369
+ if (!raw || !raw.trim()) return {};
1370
+ return JSON.parse(raw);
1371
+ } catch (_e) {
1372
+ return {};
1373
+ }
1374
+ }
1375
+
1376
+ function emitEnvelope(obj) {
1377
+ const filtered = {};
1378
+ for (const k of Object.keys(obj || {})) {
1379
+ if (ALLOWED_ENVELOPE_KEYS.has(k)) filtered[k] = obj[k];
1380
+ }
1381
+ if (filtered.continue === undefined && filtered.decision === undefined) {
1382
+ filtered.continue = true;
1383
+ }
1384
+ process.stdout.write(JSON.stringify(filtered));
1385
+ process.exit(0);
1386
+ }
1387
+
1388
+ function silentSuccess() {
1389
+ emitEnvelope({ continue: true, suppressOutput: true });
1390
+ }
1391
+
1392
+ // ---------------------------------------------------------------------------
1393
+ // readTranscriptTurn(transcriptPath) -- parse the Stop-hook transcript JSONL and extract
1394
+ // the signals a transcript can yield. Mirrors the scripts/on-stop:33 idiom: the Stop hook
1395
+ // delivers a `transcript_path` (a LOCAL .jsonl file, one JSON object per line).
1396
+ //
1397
+ // Phase 298-03: the parse walk itself (WR-08 tail-capped read, per-line JSON parse,
1398
+ // role:user window reset, assistant-content collection) moved to
1399
+ // lib/hmi/turn-text.cjs::readTurnText, the single transcript reader shared with a
1400
+ // later Stop-hook consumer (298-07). This function is now a thin wrapper: it calls
1401
+ // turnText.readTurnText for the shared parse, then computes the two fields that stay
1402
+ // card-fire DOMAIN logic (they need gateRelevance / ASCII_BOX_GLYPH_RE, which
1403
+ // turn-text.cjs deliberately does not depend on):
1404
+ // - askuserquestion_fired: true ONLY if the LAST assistant message fired the AskUserQuestion
1405
+ // card. Scoped to the SAME message that produced output_text (WR-06):
1406
+ // a STALE earlier card must NOT suppress interception of the CURRENT
1407
+ // (last) box turn -- the two signals MUST share the same turn scope.
1408
+ // - gate_signature : the CR-03 / WR-07 transcript-growth-INVARIANT gate identity -- a
1409
+ // sha256 over the GATE-IDENTIFYING content of the LAST assistant
1410
+ // message (the matched glyph span + normalized option-label SET).
1411
+ // Anchored on the GATE, never the user message and never an assistant
1412
+ // counter, so the no-role:user path has no livelock hole (CR-03) and
1413
+ // two distinct gates get distinct counters (WR-07).
1414
+ // Defensive (Part 8 / on-stop discipline): a missing / unreadable / malformed transcript
1415
+ // returns empty signals; NEVER throws (turnText.readTurnText already degrades this way; this
1416
+ // wrapper's own additions -- scanContentForAskUserQuestion and gateSignature -- are themselves
1417
+ // never-throw). The transcript content stays LOCAL -- read, scanned, discarded; never egressed
1418
+ // (gate_signature is a sha256 hash, not the message text itself).
1419
+ // ---------------------------------------------------------------------------
1420
+ function readTranscriptTurn(transcriptPath) {
1421
+ const turn = turnText.readTurnText(transcriptPath);
1422
+ // H2: askFired is an OR across every assistant message since the last user
1423
+ // boundary (the CURRENT turn), not the last message alone.
1424
+ const askFired = turn.assistant_contents.some(turnText.scanContentForAskUserQuestion);
1425
+ // CR-03 / WR-07 ROOT ANCHOR: the gate signature over the LAST assistant message's
1426
+ // gate-identifying content (Part 8: a sha256 hash, the raw message text never leaves this
1427
+ // function). Growth-invariant, per-gate, present whenever a gate is detected.
1428
+ const gateSig = gateSignature(turn.output_text);
1429
+ return {
1430
+ output_text: turn.output_text,
1431
+ askuserquestion_fired: askFired,
1432
+ gate_signature: gateSig,
1433
+ preceding_user_text: turn.preceding_user_text,
1434
+ preceding_user_text_source: turn.preceding_user_text_source,
1435
+ };
1436
+ }
1437
+
1438
+ // readTranscriptTail(transcriptPath) -- re-exported from lib/hmi/turn-text.cjs (298-03 lift);
1439
+ // this file's own export name is unchanged so lib/mcp/stop-gate-handler.cjs and any other
1440
+ // consumer of check-card-fire.cjs's exports.readTranscriptTail keep working unmodified.
1441
+ const readTranscriptTail = turnText.readTranscriptTail;
1442
+
1443
+ // ---------------------------------------------------------------------------
1444
+ // sidechannelReachIsFresh(sidechannelModule, sessionId) -- Phase 238-08 (GATE-04,
1445
+ // D-15): true when the most recent side-channel reach record for sessionId falls
1446
+ // within TURN_FRESH_MS of now. This is the SAME mostRecentReachedTs-vs-TURN_FRESH_MS
1447
+ // formula deriveTurnSignals already needed for gateIsFresh (the PRIMARY-path
1448
+ // staleness signal, card-fire-over-enforcement fix B); factored out here so it is
1449
+ // written ONCE and reused for BOTH gateIsFresh and the new reach_corroborated signal
1450
+ // below, rather than duplicated. Never throws: mostRecentReachedTs itself already
1451
+ // degrades to 0 on any fault (never-throw contract, T-209-24), and this wrapper
1452
+ // degrades to false on top of that for defensive symmetry with the rest of this file.
1453
+ // ---------------------------------------------------------------------------
1454
+ function sidechannelReachIsFresh(sidechannelModule, sessionId) {
1455
+ try {
1456
+ const ts = sidechannelModule.mostRecentReachedTs(sessionId);
1457
+ const freshWindow = typeof sidechannelModule.TURN_FRESH_MS === 'number'
1458
+ ? sidechannelModule.TURN_FRESH_MS
1459
+ : (2 * 60 * 1000);
1460
+ return Number.isFinite(ts) && ts > 0 && (Date.now() - ts) <= freshWindow;
1461
+ } catch (_e) {
1462
+ return false;
1463
+ }
1464
+ }
1465
+
1466
+ // ---------------------------------------------------------------------------
1467
+ // deriveTurnSignals(env) -- normalize the turn signals from the Stop-hook stdin envelope.
1468
+ //
1469
+ // BL-01 (the live cure): the REAL Stop-hook stdin delivers a `transcript_path`, NOT the
1470
+ // normalized fields. So when the envelope carries `transcript_path`, we PARSE the transcript
1471
+ // (readTranscriptTurn, mirroring scripts/on-stop:33): the last assistant text drives the
1472
+ // BACKSTOP and an AskUserQuestion tool-use drives askuserquestion_fired.
1473
+ //
1474
+ // BACKWARD-COMPAT: if the envelope already carries the normalized signals directly
1475
+ // (output_text / last_assistant_text / ran_entries / askuserquestion_fired -- the unit-test
1476
+ // shape), those are used as-is, so the 22 existing predicate assertions stay green.
1477
+ //
1478
+ // session_id + gate_signature (CR-03 / WR-07 root anchor) thread through for the
1479
+ // WR-01/CR-02/CR-03 stable retry key. PRIMARY's ran_entries stays read from the envelope (it
1480
+ // has no transcript source -- the WR-04 deferred note). Tolerant of missing fields; never throws.
1481
+ // ---------------------------------------------------------------------------
1482
+ function deriveTurnSignals(env) {
1483
+ const e = env && typeof env === 'object' ? env : {};
1484
+
1485
+ // PRIMARY ran-entries: side-channel only (no transcript source -- WR-04 deferred).
1486
+ // Phase 209-06 (H3): WR-04's doctrine note is UPDATED here, not just above --
1487
+ // the producer now exists (lib/core/card-fire-sidechannel.cjs, wired at the
1488
+ // pickShape trailer door + the two intent-classifier.cjs sites: the engine
1489
+ // arm and emitBindingGate). Direct-field envelopes (the unit-test shape)
1490
+ // keep PRECEDENCE: the side file is consulted ONLY when the envelope did
1491
+ // NOT already carry ran_entries/reached_gate_entries, so the 22 existing
1492
+ // predicate assertions stay green byte-for-byte. Regex BACKSTOP stays
1493
+ // SECONDARY permanently -- it is the only detector when the side-channel
1494
+ // writer itself fails (a missing/corrupt/oversized file all degrade to []
1495
+ // inside readReachedGates, never throwing here).
1496
+ let ranEntries = Array.isArray(e.ran_entries)
1497
+ ? e.ran_entries
1498
+ : (Array.isArray(e.reached_gate_entries) ? e.reached_gate_entries : []);
1499
+
1500
+ // 2026-07-05 relevance-gate fix: the reach's OWN recorded subject text
1501
+ // (side-channel only, populated ONLY when the side-channel itself supplied
1502
+ // ranEntries -- i.e. the true PRIMARY path). '' on the BACKSTOP path (no
1503
+ // side-channel producer runs there), so classifyCardFire falls back to its
1504
+ // prior output_text comparison unchanged for that path.
1505
+ let sideChannelSubjectText = '';
1506
+
1507
+ // card-fire-over-enforcement (2026-07-20) fix (B): whether the reached gate is
1508
+ // FRESH (reached this turn) or STALE (a prior turn's reach bled forward by the
1509
+ // file TTL). Direct-field / BACKSTOP gates are always this-turn, so freshness
1510
+ // defaults to true; only a side-channel-sourced gate can be stale, decided by
1511
+ // comparing its most-recent mint ts against TURN_FRESH_MS below.
1512
+ let gateIsFresh = true;
1513
+
1514
+ if (ranEntries.length === 0) {
1515
+ try {
1516
+ const sidechannel = require(path.join(PLUGIN_ROOT, 'lib', 'core', 'card-fire-sidechannel.cjs'));
1517
+ const sessionId = typeof e.session_id === 'string' ? e.session_id : '';
1518
+ const fromSideChannel = sidechannel.readReachedGates(sessionId);
1519
+ if (Array.isArray(fromSideChannel) && fromSideChannel.length > 0) {
1520
+ ranEntries = fromSideChannel;
1521
+ try {
1522
+ const subjects = sidechannel.readReachedGateSubjects(sessionId);
1523
+ sideChannelSubjectText = Array.isArray(subjects) ? subjects.join(' ') : '';
1524
+ } catch (_e2) {
1525
+ sideChannelSubjectText = '';
1526
+ }
1527
+ // Freshness verdict: a side-channel gate counts as reached THIS turn only
1528
+ // if its most recent mint is within the turn window. An older mint is a
1529
+ // prior turn's (or prior session's) reach still inside the file TTL.
1530
+ // Phase 238-08: reuses sidechannelReachIsFresh (the IDENTICAL
1531
+ // mostRecentReachedTs-vs-TURN_FRESH_MS formula, also used below for
1532
+ // reach_corroborated) rather than computing it a second time inline.
1533
+ gateIsFresh = sidechannelReachIsFresh(sidechannel, sessionId);
1534
+ }
1535
+ } catch (_e) {
1536
+ /* degrade to empty ran_entries; BACKSTOP alone still applies */
1537
+ }
1538
+ }
1539
+
1540
+ // Phase 238-08 (GATE-04, D-15): reach_corroborated -- true when a fresh reach
1541
+ // record exists for THIS session. Computed UNCONDITIONALLY (not only inside the
1542
+ // ran_entries-empty branch above), because a turn can carry non-empty direct-field
1543
+ // ran_entries (the PRIMARY path already supplying its own entries) and still need
1544
+ // this corroboration signal for the BACKSTOP arm's decision in classifyCardFire.
1545
+ // Direct-field envelopes keep PRECEDENCE, mirroring ran_entries / gate_subject_text
1546
+ // above, so the unit-test seam still works. Uses the SAME sidechannelReachIsFresh
1547
+ // helper the ran_entries-empty branch above reuses for gateIsFresh, via a SEPARATE
1548
+ // guarded require (this module intentionally requires the side-channel module more
1549
+ // than once across this function rather than threading a shared handle through
1550
+ // unrelated branches; every guarded require degrades identically on a require
1551
+ // fault). A require fault or read fault degrades to false (uncorroborated) --
1552
+ // there is no evidence of a fresh reach when the side channel cannot be consulted.
1553
+ let reachCorroborated = false;
1554
+ if (typeof e.reach_corroborated === 'boolean') {
1555
+ reachCorroborated = e.reach_corroborated;
1556
+ } else {
1557
+ try {
1558
+ const sidechannelForReach = require(path.join(PLUGIN_ROOT, 'lib', 'core', 'card-fire-sidechannel.cjs'));
1559
+ const sessionIdForReach = typeof e.session_id === 'string' ? e.session_id : '';
1560
+ reachCorroborated = sidechannelReachIsFresh(sidechannelForReach, sessionIdForReach);
1561
+ } catch (_eReach) {
1562
+ reachCorroborated = false;
1563
+ }
1564
+ }
1565
+
1566
+ // Phase 238-08 (GATE-04, D-15): sidechannel_health -- resolved via a SEPARATE
1567
+ // guarded require of the SAME module the ran_entries-empty branch above uses for
1568
+ // the reach-record read (the same "require it fresh at each use site" style as
1569
+ // reach_corroborated above). A require fault degrades to the unavailable value,
1570
+ // matching the existing degrade direction elsewhere in this function: a missing or
1571
+ // broken module means the side channel cannot be consulted at all, which is the
1572
+ // blind state the backstop's last-resort arm must stay armed for (D-15 state 3).
1573
+ // Direct-field envelopes keep PRECEDENCE, mirroring ran_entries / gate_subject_text
1574
+ // above, so the unit-test seam still works.
1575
+ let sidechannelHealth = SIDECHANNEL_HEALTH_UNAVAILABLE;
1576
+ if (typeof e.sidechannel_health === 'string' && e.sidechannel_health) {
1577
+ sidechannelHealth = e.sidechannel_health;
1578
+ } else {
1579
+ try {
1580
+ const sidechannelForHealth = require(path.join(PLUGIN_ROOT, 'lib', 'core', 'card-fire-sidechannel.cjs'));
1581
+ sidechannelHealth = sidechannelForHealth.sideChannelHealth();
1582
+ } catch (_eHealth) {
1583
+ sidechannelHealth = SIDECHANNEL_HEALTH_UNAVAILABLE;
1584
+ }
1585
+ }
1586
+
1587
+ // Direct-field signals (the unit-test / side-channel shape).
1588
+ const directText =
1589
+ typeof e.output_text === 'string' ? e.output_text
1590
+ : (typeof e.last_assistant_text === 'string' ? e.last_assistant_text : null);
1591
+ const directAsk =
1592
+ e.askuserquestion_fired === true || e.ask_user_question_fired === true;
1593
+
1594
+ // If no direct text was supplied but a transcript_path is present, parse the transcript
1595
+ // (the REAL Stop contract). Direct fields take precedence (backward-compat).
1596
+ let txn = null;
1597
+ if (directText === null && typeof e.transcript_path === 'string') {
1598
+ txn = readTranscriptTurn(e.transcript_path);
1599
+ }
1600
+
1601
+ const outputText = directText !== null ? directText : (txn ? txn.output_text : '');
1602
+ const askFired = directAsk || (txn ? txn.askuserquestion_fired : false);
1603
+ // CR-03 / WR-07: the transcript-growth-invariant, per-gate retry anchor. Precedence:
1604
+ // 1. an explicit gate_signature on the envelope (test / side-channel shape);
1605
+ // 2. the parsed transcript's gate signature (the LIVE BACKSTOP path);
1606
+ // 3. DERIVED from the output text (the direct-field unit-test shape that supplies
1607
+ // output_text but no transcript) so the key is stable without re-walking a transcript.
1608
+ // It is NEVER a transcript-length counter -- the gate_turn_index fallback is DELETED.
1609
+ let gateSig = '';
1610
+ if (typeof e.gate_signature === 'string' && e.gate_signature) {
1611
+ gateSig = e.gate_signature;
1612
+ } else if (txn && typeof txn.gate_signature === 'string' && txn.gate_signature) {
1613
+ gateSig = txn.gate_signature;
1614
+ } else {
1615
+ gateSig = gateSignature(outputText);
1616
+ }
1617
+
1618
+ // Phase 210-05 (item 210-E-1): thread the preceding user text through for the
1619
+ // relevance verdict. Direct-field envelopes may supply it; the transcript path
1620
+ // derives it. Absent on both -> '' (the conservative verdict: intercept). Per
1621
+ // CR-03 it never feeds gate_signature or turnContextHash.
1622
+ const precedingUserText = typeof e.preceding_user_text === 'string'
1623
+ ? e.preceding_user_text
1624
+ : (txn ? txn.preceding_user_text : '');
1625
+
1626
+ // room-bind-gate-fires-on-notification-only-turns (2026-07-23): thread the preceding-turn
1627
+ // source classification through the same precedence rule as precedingUserText itself
1628
+ // (direct-field envelopes -- the unit-test seam -- keep precedence; the transcript path
1629
+ // derives it; absent on both defaults to 'none', the UNEXPLAINED-absence case, which stays
1630
+ // on the pre-fix conservative floor -- only a CONFIRMED 'tool_result' classification bypasses
1631
+ // it). Feeds ONLY the PRIMARY-path relevance check in classifyCardFire, per the same CR-03
1632
+ // scoping as precedingUserText.
1633
+ const precedingUserTextSource = typeof e.preceding_user_text_source === 'string'
1634
+ ? e.preceding_user_text_source
1635
+ : (txn ? txn.preceding_user_text_source : 'none');
1636
+
1637
+ return {
1638
+ ran_entries: ranEntries,
1639
+ askuserquestion_fired: askFired,
1640
+ output_text: outputText,
1641
+ session_id: typeof e.session_id === 'string' ? e.session_id : '',
1642
+ gate_signature: gateSig,
1643
+ preceding_user_text: precedingUserText,
1644
+ preceding_user_text_source: precedingUserTextSource,
1645
+ // 2026-07-05 relevance-gate fix: direct-field envelopes (the unit-test
1646
+ // seam) keep precedence over the side-channel-derived subject text,
1647
+ // mirroring the existing ran_entries precedence rule exactly.
1648
+ gate_subject_text: (typeof e.gate_subject_text === 'string' && e.gate_subject_text)
1649
+ ? e.gate_subject_text
1650
+ : sideChannelSubjectText,
1651
+ // card-fire-over-enforcement (2026-07-20) fix (B): true when the reached
1652
+ // gate is this-turn (direct-field / BACKSTOP / a fresh side-channel mint),
1653
+ // false when a side-channel mint is stale (a prior turn's reach bled forward
1654
+ // by the file TTL). classifyCardFire feeds this to the low-signal relevance
1655
+ // branch so a terse turn no longer force-fires a stale gate.
1656
+ gate_is_fresh: gateIsFresh,
1657
+ // Phase 238-08 (GATE-04, D-15): the two new backstop-corroboration signals.
1658
+ // sidechannel_health distinguishes a healthy-but-empty side channel from a
1659
+ // blind one; reach_corroborated is true only when a FRESH reach record exists
1660
+ // for this session. classifyCardFire's new branch reads both to decide whether
1661
+ // an uncorroborated backstop hit on a healthy side channel should intercept.
1662
+ sidechannel_health: sidechannelHealth,
1663
+ reach_corroborated: reachCorroborated,
1664
+ };
1665
+ }
1666
+
1667
+ // ----- main (Stop-hook entry) -----
1668
+
1669
+ function main() {
1670
+ // Phase 198-09 (D-05): once the Stop-gate enforcement has moved server-side
1671
+ // (scripts/on-stop's own thin adapter, querying lib/mcp/tools/stop-gate.cjs
1672
+ // -> lib/mcp/stop-gate-handler.cjs, which WRAPS this exact predicate --
1673
+ // Part 7, no fork), this hook-side copy must no-op rather than run a SECOND,
1674
+ // independent enforcement pass in parallel (hooks/hooks.json dispatches
1675
+ // on-stop and this script as two SEPARATE Stop hook entries; running both
1676
+ // enforcement paths at once would double-block or race on the same retry
1677
+ // side-file). Flag OFF (unset/empty, the default) keeps this entire file's
1678
+ // call path byte-identical -- the check below is the ONLY change to the
1679
+ // OFF behavior (a no-op it can never reach), everything past this point is
1680
+ // untouched. The daemon-side path decides for itself via the SAME
1681
+ // MINDRIAN_MCP_FIRST contract (lib/mcp/mcp-first-flag.cjs's isMcpFirst),
1682
+ // required here rather than re-checked via a bash mirror since this file is
1683
+ // already Node.
1684
+ try {
1685
+ const { isMcpFirst } = require(path.join(PLUGIN_ROOT, 'lib', 'mcp', 'mcp-first-flag.cjs'));
1686
+ if (isMcpFirst('cli')) return silentSuccess();
1687
+ } catch (_e) {
1688
+ // A flag-reader failure must never suppress enforcement -- fall through
1689
+ // to the full legacy predicate below (the conservative direction).
1690
+ }
1691
+
1692
+ const env = readStdinJson();
1693
+ const evt = env.hook_event_name || env.hookEventName || process.env.HOOK_EVENT_NAME || null;
1694
+
1695
+ // Only act on the Stop event; any other event is a no-op (defensive: do not block).
1696
+ if (evt && evt !== 'Stop') return silentSuccess();
1697
+
1698
+ const registry = loadRegistry();
1699
+ const turn = deriveTurnSignals(env);
1700
+ const sessionId = turn.session_id;
1701
+ const ctxHash = turnContextHash(turn);
1702
+ // Feed BOTH counters into the predicate: the per-gate counter (per-gate UX granularity) and
1703
+ // the SESSION-wide counter (the CR-04 content-independent convergence floor). The predicate
1704
+ // degrades if EITHER ceiling is reached.
1705
+ turn.retry_count = readRetryCount(ctxHash);
1706
+ turn.session_count = readSessionCount(sessionId);
1707
+
1708
+ const verdict = classifyCardFire(turn, registry);
1709
+
1710
+ if (verdict.degrade === true) {
1711
+ // Bounded escape released (per-gate ceiling OR the CR-04 session ceiling): log + allow.
1712
+ // Clear BOTH the per-gate counter AND the session counter -- the navigator is being let
1713
+ // through, so the session is "unstuck" and the next continuous run starts fresh. Clearing
1714
+ // the session counter here is the sane reset: a continuous run of intercepts is bounded by
1715
+ // MAX_SESSION_INTERCEPTS, and a degrade ENDS that run.
1716
+ process.stderr.write(
1717
+ '[check-card-fire] bounded escape released; allowing turn (' + verdict.reason + ')\n'
1718
+ );
1719
+ // CR-07: record the degrade with its ORIGINAL slug before the envelope calms `reason`.
1720
+ appendInterceptLog(turn, verdict);
1721
+ clearRetryCount(ctxHash);
1722
+ clearSessionCount(sessionId);
1723
+ // TERMINAL verdict: the bounded escape released this gate, so its side-channel
1724
+ // record is spent and must not force again on a later turn.
1725
+ consumeReachedGatesForVerdict(turn, verdict);
1726
+ return emitEnvelope(buildEnforcementEnvelope(verdict));
1727
+ }
1728
+
1729
+ if (verdict.intercept === true) {
1730
+ // Force the card: bump BOTH the per-gate counter AND the session-wide counter, then emit
1731
+ // the Stop-block (decision:block-on-exit-0). Bumping the session counter on EVERY intercept
1732
+ // is what makes a flapping per-gate key (CR-04) still converge: the session counter climbs
1733
+ // regardless of which per-gate key the intercept landed on.
1734
+ bumpRetryCount(ctxHash);
1735
+ bumpSessionCount(sessionId);
1736
+ // CR-07: record the intercept with its ORIGINAL slug before the envelope calms `reason`.
1737
+ appendInterceptLog(turn, verdict);
1738
+ return emitEnvelope(buildEnforcementEnvelope(verdict));
1739
+ }
1740
+
1741
+ // The card fired (or no gate signal): the navigator got unstuck this turn, so clear the per-
1742
+ // gate counter AND reset the session counter (a no-intercept Stop turn ends any intercept run).
1743
+ clearRetryCount(ctxHash);
1744
+ clearSessionCount(sessionId);
1745
+ // TERMINAL verdict (card-fired / no-gate-signal / a relevance pass): this Stop
1746
+ // evaluation adjudicated the reached-gate records, so they are spent. Without this
1747
+ // the SAME mint kept forcing on every later turn inside its TURN_FRESH_MS window --
1748
+ // the answered-gate-refire defect (2026-07-28). See consumeReachedGatesForVerdict.
1749
+ consumeReachedGatesForVerdict(turn, verdict);
1750
+ return silentSuccess();
1751
+ }
1752
+
1753
+ module.exports = {
1754
+ MAX_FORCE_RETRIES,
1755
+ MAX_SESSION_INTERCEPTS,
1756
+ SESSION_KEY_PREFIX,
1757
+ RETRY_TTL_MS,
1758
+ TRANSCRIPT_TAIL_BYTES: turnText.TRANSCRIPT_TAIL_BYTES,
1759
+ ASCII_BOX_GLYPH_RE,
1760
+ computeBackstopHit,
1761
+ matchedGlyphSpan,
1762
+ classifyCardFire,
1763
+ buildEnforcementEnvelope,
1764
+ gateReachingEntries,
1765
+ gateSignature,
1766
+ turnContextHash,
1767
+ deriveTurnSignals,
1768
+ consumeReachedGatesForVerdict,
1769
+ readTranscriptTurn,
1770
+ readTranscriptTail,
1771
+ classifyPrecedingUserContentSource: turnText.classifyPrecedingUserContentSource,
1772
+ pruneRetryStore,
1773
+ normalizeRetryEntry,
1774
+ sessionKey,
1775
+ loadRegistry,
1776
+ // mcp-first-path-retry-ceiling-hardcoded-zero (2026-07-28): the bounded-escape
1777
+ // accessors, exported so the SECOND enforcement path (lib/mcp/stop-gate-handler.cjs)
1778
+ // can drive the SAME counters main() drives instead of minting a parallel one.
1779
+ //
1780
+ // WHY THIS EXPORT AND NOT A NEW COUNTER MODULE: these six functions ARE the store.
1781
+ // They read and write ONE local side-file (retryFilePath(), ~/.mindrian/card-fire-
1782
+ // retries.json) whose per-gate entries and `__session__:` entries share a TTL prune
1783
+ // and a single write path. Re-deriving them anywhere else would create a second,
1784
+ // divergent counting mechanism against the same file -- the exact drift the sibling
1785
+ // RCA (card-fire-answered-gate-refires-within-ttl-window) closed for the record
1786
+ // lifecycle and asked not to re-open for the counters. Exporting the existing
1787
+ // functions is purely additive: no call site, signature, or behavior in this file
1788
+ // changes, so the CLI path stays byte-identical.
1789
+ //
1790
+ // The frozen constitutional floor itself (MAX_FORCE_RETRIES / MAX_SESSION_INTERCEPTS)
1791
+ // is still declared in exactly one place -- above, in this file. Consumers read the
1792
+ // COUNTS through these accessors and the CEILINGS through classifyCardFire's verdict;
1793
+ // neither ever re-declares a scalar.
1794
+ readRetryCount,
1795
+ bumpRetryCount,
1796
+ clearRetryCount,
1797
+ readSessionCount,
1798
+ bumpSessionCount,
1799
+ clearSessionCount,
1800
+ };
1801
+
1802
+ if (require.main === module) {
1803
+ try {
1804
+ main();
1805
+ } catch (e) {
1806
+ process.stderr.write('[check-card-fire] uncaught: ' + e.message + '\n');
1807
+ silentSuccess();
1808
+ }
1809
+ }