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

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 +467 -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 +2365 -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 +217 -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 +545 -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 +536 -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 +530 -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 +2113 -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 +218 -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/compute-bayesian-surprise.py +175 -0
  1402. package/scripts/compute-blindspot-mass.py +209 -0
  1403. package/scripts/compute-disruption-index.py +211 -0
  1404. package/scripts/compute-element-novelty.py +254 -0
  1405. package/scripts/compute-external-whitespace.py +563 -0
  1406. package/scripts/compute-hsi.py +947 -0
  1407. package/scripts/compute-meetings-intelligence +716 -0
  1408. package/scripts/compute-opportunity-state +17 -0
  1409. package/scripts/compute-state +393 -0
  1410. package/scripts/compute-team +1112 -0
  1411. package/scripts/compute-whitespace-embeddings.py +464 -0
  1412. package/scripts/compute-whitespace-gaps.py +562 -0
  1413. package/scripts/compute_topic_forest.py +684 -0
  1414. package/scripts/consolidate-pinecone.py +265 -0
  1415. package/scripts/context-monitor +943 -0
  1416. package/scripts/create-speaker-profile +311 -0
  1417. package/scripts/cross-room-detect.cjs +195 -0
  1418. package/scripts/csv-to-idea-graph.cjs +755 -0
  1419. package/scripts/ctxl-eval.cjs +846 -0
  1420. package/scripts/curation-132-03-dedup-held-rename.cjs +395 -0
  1421. package/scripts/curation-132-05-pseudonymize.cjs +189 -0
  1422. package/scripts/derive-verb-reach-affinity.cjs +507 -0
  1423. package/scripts/detect-reverse-salients.py +242 -0
  1424. package/scripts/diagnostics-command.cjs +345 -0
  1425. package/scripts/dial-memory-refresh-command.cjs +147 -0
  1426. package/scripts/discover-analogy-whitespace.py +433 -0
  1427. package/scripts/discover-hsi-whitespace.py +352 -0
  1428. package/scripts/discover-rs-whitespace.py +327 -0
  1429. package/scripts/discovery-cycle.cjs +625 -0
  1430. package/scripts/disposition-render-v2.cjs +229 -0
  1431. package/scripts/doctor-preflight-format.cjs +101 -0
  1432. package/scripts/doctor.cjs +4327 -0
  1433. package/scripts/dogfood-bridge/append-to-queue.sh +59 -0
  1434. package/scripts/dogfood-bridge/path-filter.cjs +86 -0
  1435. package/scripts/dogfood-derive.cjs +158 -0
  1436. package/scripts/dogfood-emit.cjs +126 -0
  1437. package/scripts/empathy-observation-emit.cjs +108 -0
  1438. package/scripts/enrichment-queue-append.cjs +157 -0
  1439. package/scripts/ensure-brain-baseline.cjs +117 -0
  1440. package/scripts/entity-extract.cjs +1135 -0
  1441. package/scripts/eureka-command.cjs +687 -0
  1442. package/scripts/eureka-critic-run.cjs +662 -0
  1443. package/scripts/eureka-portfolio-report.cjs +2038 -0
  1444. package/scripts/eureka-room-report.cjs +419 -0
  1445. package/scripts/explain-decision-command.cjs +499 -0
  1446. package/scripts/export-pinecone-embeddings.cjs +516 -0
  1447. package/scripts/extract-room-intelligence.cjs +714 -0
  1448. package/scripts/fetch-brain-baseline.cjs +190 -0
  1449. package/scripts/fetch-brain-baseline.py +360 -0
  1450. package/scripts/feynman-minto-guardian.cjs +672 -0
  1451. package/scripts/feynman-timeline-refresh-command.cjs +270 -0
  1452. package/scripts/file-asset +253 -0
  1453. package/scripts/fire-sensor-event.cjs +83 -0
  1454. package/scripts/first-install-router.cjs +968 -0
  1455. package/scripts/frontmatter-schema-validator.cjs +339 -0
  1456. package/scripts/fts-index-drain.cjs +221 -0
  1457. package/scripts/generate-chat-embed.cjs +179 -0
  1458. package/scripts/generate-deck.cjs +322 -0
  1459. package/scripts/generate-export.cjs +474 -0
  1460. package/scripts/generate-hub.cjs +2553 -0
  1461. package/scripts/generate-lobby.cjs +718 -0
  1462. package/scripts/generate-presentation.cjs +988 -0
  1463. package/scripts/generate-presentation.test.cjs +405 -0
  1464. package/scripts/generate-section-intelligence.cjs +330 -0
  1465. package/scripts/generate-snapshot.cjs +1410 -0
  1466. package/scripts/generate-standalone +159 -0
  1467. package/scripts/git-ops +211 -0
  1468. package/scripts/graph-heal-pipeline.cjs +321 -0
  1469. package/scripts/gsd-artifact-graph-hook.cjs +219 -0
  1470. package/scripts/gsd-graph-derive-drain.cjs +571 -0
  1471. package/scripts/gsd-graph-derive-sweep.cjs +195 -0
  1472. package/scripts/heal-command.cjs +1365 -0
  1473. package/scripts/hedge-refit-pipeline.cjs +207 -0
  1474. package/scripts/help-renderer.cjs +303 -0
  1475. package/scripts/hmi-compliance-poll.cjs +451 -0
  1476. package/scripts/hmi-status-command.cjs +510 -0
  1477. package/scripts/hooked-rescore-117.cjs +224 -0
  1478. package/scripts/hooks/pre-commit +533 -0
  1479. package/scripts/hooks/pre-commit-room-minto-guard.cmd +43 -0
  1480. package/scripts/hooks/pre-commit-room-minto-guard.sh +533 -0
  1481. package/scripts/hsi-to-graph.cjs +194 -0
  1482. package/scripts/huji-batch.cjs +821 -0
  1483. package/scripts/huji-eval.cjs +1158 -0
  1484. package/scripts/huji-intake.cjs +563 -0
  1485. package/scripts/huji-pin-smoketest.cjs +454 -0
  1486. package/scripts/huji-run-one-async.cjs +305 -0
  1487. package/scripts/huji-run-one.cjs +671 -0
  1488. package/scripts/install-pre-commit.sh +113 -0
  1489. package/scripts/intent-classifier +106 -0
  1490. package/scripts/intent-classifier.cjs +3620 -0
  1491. package/scripts/interpret-whitespace.cjs +691 -0
  1492. package/scripts/jtbd-command.cjs +810 -0
  1493. package/scripts/jtbd-update.cjs +299 -0
  1494. package/scripts/label-topic-forest.cjs +667 -0
  1495. package/scripts/learn-from-usage +168 -0
  1496. package/scripts/lib/__pycache__/ensure_ml_deps.cpython-312.pyc +0 -0
  1497. package/scripts/lib/ensure_ml_deps.py +97 -0
  1498. package/scripts/load-embeddings-into-neo4j.cjs +569 -0
  1499. package/scripts/memory-artifact-graph-hook.cjs +191 -0
  1500. package/scripts/memory-command.cjs +687 -0
  1501. package/scripts/memory-completion-detector.cjs +217 -0
  1502. package/scripts/memory-lifecycle.cjs +620 -0
  1503. package/scripts/memory-resume-nudge.cjs +233 -0
  1504. package/scripts/methodology-ingest-local.sh +36 -0
  1505. package/scripts/migrate-brain-mcp-from-http-to-stdio.cjs +190 -0
  1506. package/scripts/migrate-brain-mcp-from-http-to-stdio.test.cjs +242 -0
  1507. package/scripts/migrate-hats-to-roomdb.cjs +217 -0
  1508. package/scripts/migrate-lazygraph.cjs +250 -0
  1509. package/scripts/migrate-minto-schema-v88.cjs +296 -0
  1510. package/scripts/migrate-plugin-root-refs.cjs +168 -0
  1511. package/scripts/migrate-room-sections-v275.cjs +556 -0
  1512. package/scripts/migrate-rooms +417 -0
  1513. package/scripts/migrate-skill-frontmatter.cjs +472 -0
  1514. package/scripts/migrate-stale-user-settings.cjs +296 -0
  1515. package/scripts/migrate-telemetry-v1.cjs +384 -0
  1516. package/scripts/migrate-telemetry-v1.test.cjs +356 -0
  1517. package/scripts/minto-debouncer.cjs +428 -0
  1518. package/scripts/mos-status.cjs +622 -0
  1519. package/scripts/mva-detect.cjs +229 -0
  1520. package/scripts/mva-run.cjs +36 -0
  1521. package/scripts/on-agent-complete +163 -0
  1522. package/scripts/on-cwd-changed +149 -0
  1523. package/scripts/on-file-changed +68 -0
  1524. package/scripts/on-stop +617 -0
  1525. package/scripts/on-task-complete +194 -0
  1526. package/scripts/operator-command.cjs +858 -0
  1527. package/scripts/operator-update.cjs +308 -0
  1528. package/scripts/part8-egress-guard-hook.cjs +229 -0
  1529. package/scripts/pipeline-command.cjs +271 -0
  1530. package/scripts/post-compact +383 -0
  1531. package/scripts/post-update-activation.cjs +339 -0
  1532. package/scripts/post-write +283 -0
  1533. package/scripts/power-demo-prompt.md +621 -0
  1534. package/scripts/pre-compact +273 -0
  1535. package/scripts/preflight-auto-explore.cjs +314 -0
  1536. package/scripts/preflight-doctor.cjs +225 -0
  1537. package/scripts/preflight-release-drift.cjs +168 -0
  1538. package/scripts/preflight-tension-surface.cjs +414 -0
  1539. package/scripts/probe-brain-contract.cjs +502 -0
  1540. package/scripts/publish-ops +346 -0
  1541. package/scripts/query-efficiency-telemetry.cjs +364 -0
  1542. package/scripts/query-semantic-scholar.cjs +545 -0
  1543. package/scripts/reapply-modifications +49 -0
  1544. package/scripts/reassign-primary.cjs +125 -0
  1545. package/scripts/recompile-room-references.cjs +601 -0
  1546. package/scripts/release-beta-preflight.sh +69 -0
  1547. package/scripts/render-pdf +588 -0
  1548. package/scripts/render-viz +190 -0
  1549. package/scripts/research-speaker +239 -0
  1550. package/scripts/resolve-room +204 -0
  1551. package/scripts/restore-post-compact-context.cjs +320 -0
  1552. package/scripts/room-auto-create-nudge.cjs +136 -0
  1553. package/scripts/room-naming-selector.cjs +201 -0
  1554. package/scripts/room-registry +767 -0
  1555. package/scripts/rs-discovery-engine.cjs +725 -0
  1556. package/scripts/rs-engine.py +2073 -0
  1557. package/scripts/rs-experts-command.cjs +300 -0
  1558. package/scripts/rs-explain-command.cjs +323 -0
  1559. package/scripts/rs-fetch-command.cjs +170 -0
  1560. package/scripts/rs-thesis-command.cjs +203 -0
  1561. package/scripts/rs-vector-bridge.cjs +410 -0
  1562. package/scripts/run-harness.cjs +890 -0
  1563. package/scripts/scout-cadence-guard.cjs +323 -0
  1564. package/scripts/scout-cadence-runner.cjs +509 -0
  1565. package/scripts/scout-telemetry-aggregator.cjs +268 -0
  1566. package/scripts/sealed-walker.py +96 -0
  1567. package/scripts/seed-brain-commands.cjs +324 -0
  1568. package/scripts/self-update +105 -0
  1569. package/scripts/sentinel-deadline-monitor +241 -0
  1570. package/scripts/sentinel-health-check +198 -0
  1571. package/scripts/sentinel-snapshot +42 -0
  1572. package/scripts/serve-dashboard +103 -0
  1573. package/scripts/serve-dashboard-live +932 -0
  1574. package/scripts/serve-presentation +97 -0
  1575. package/scripts/serve-wiki +90 -0
  1576. package/scripts/session-end-presence.cjs +79 -0
  1577. package/scripts/session-start +1942 -0
  1578. package/scripts/sessionstart-coordinator.cjs +249 -0
  1579. package/scripts/sessionstart-npm-reconcile.cjs +111 -0
  1580. package/scripts/sessionstart-post-update-preflight.cjs +303 -0
  1581. package/scripts/sessionstart-reference-now-seed.cjs +137 -0
  1582. package/scripts/setup-hooks.sh +112 -0
  1583. package/scripts/skillopt-codereview.cjs +830 -0
  1584. package/scripts/skillopt-eval.cjs +519 -0
  1585. package/scripts/skillopt-funnel.cjs +1076 -0
  1586. package/scripts/skillopt-genqueries.cjs +571 -0
  1587. package/scripts/skillopt-inventory.cjs +319 -0
  1588. package/scripts/skillopt-merge.cjs +656 -0
  1589. package/scripts/skillopt-triggerloop.cjs +1126 -0
  1590. package/scripts/soft-alias-runner.cjs +116 -0
  1591. package/scripts/stamp-artifact-write.cjs +276 -0
  1592. package/scripts/stamp-firing-block.cjs +325 -0
  1593. package/scripts/state-write.cjs +97 -0
  1594. package/scripts/statusline-fallback-echo.cjs +297 -0
  1595. package/scripts/statusline-mos +116 -0
  1596. package/scripts/statusline-mos-dispatch +127 -0
  1597. package/scripts/suggest-next-command.cjs +416 -0
  1598. package/scripts/sweep-skill-descriptions.cjs +263 -0
  1599. package/scripts/sync-rooms-brain +438 -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 +383 -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 +570 -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,2365 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Brain HTTP Client -- calls the Brain HTTP server. Default is
5
+ * `https://theo-mcp.onrender.com`, a BARE origin (no path, no trailing
6
+ * slash): this client appends `/mcp` for tool calls and `/register` for the
7
+ * key ladder, so a `/mcp` suffix here would yield `/mcp/mcp` and a trailing
8
+ * slash a double slash, both 404 and both rendered as "Brain unreachable"
9
+ * rather than a configuration error. Override via the MINDRIAN_BRAIN_URL env
10
+ * var, the per-install rollback lever; that lever (and the fleet-wide
11
+ * patch-release revert of this line) is valid only while the previous
12
+ * origin is still running, because pointing it at a suspended service is a
13
+ * second outage stacked on the first, arriving exactly when the operator is
14
+ * under pressure.
15
+ *
16
+ * Replaces direct MCP tool calls (mcp__neo4j-brain__*, mcp__pinecone-brain__*)
17
+ * with a single HTTP API that handles the graph backend behind one key.
18
+ *
19
+ * Falls back gracefully:
20
+ * 1. If MINDRIAN_BRAIN_KEY is set → calls Brain API
21
+ * 2. If Brain API returns a quota/capacity error → retries once
22
+ * 3. If no key → returns null (Tier 0, no Brain)
23
+ *
24
+ * Usage in commands/skills:
25
+ * const brain = require('./brain-client.cjs');
26
+ * const result = await brain.query('MATCH (f:Framework) RETURN f.name LIMIT 5');
27
+ * const result = await brain.search('innovation framework');
28
+ * const schema = await brain.schema();
29
+ */
30
+
31
+ // Phase 339, 2026-09-03 (FLIP-10, D-13 locked): the flip. BARE origin only --
32
+ // no path, no trailing slash -- because `${BRAIN_URL}/mcp` and
33
+ // `${BRAIN_URL}/register` are both formed by appending below. This does NOT
34
+ // change: input arg keys (byte-for-byte unchanged, tests/test-247-contract-
35
+ // client.cjs stays green untouched), the shim server key `mindrian-brain`,
36
+ // BRAIN_TOOL_MATCHER / hooks/hooks.json for the CLI surface, or the
37
+ // brain_query {rows, diagnostics} shape adaptation (already shipped at
38
+ // :927-945, commit 21fdd7bc). MINDRIAN_BRAIN_URL remains the per-install
39
+ // override and the one-line rollback lever.
40
+ const BRAIN_URL = process.env.MINDRIAN_BRAIN_URL || 'https://theo-mcp.onrender.com';
41
+
42
+ // Per-request hard timeout for every Brain HTTP call (init handshake + tool
43
+ // calls). Node's global fetch() has NO default timeout, so without this a
44
+ // slow/wedged Brain hangs the calling /mos: command indefinitely. The Render
45
+ // service answers in ~1-2s normally; 20s is a generous-but-bounded ceiling.
46
+ // Override via MINDRIAN_BRAIN_TIMEOUT_MS (brain-router wants ~2000 for Tier 3).
47
+ const BRAIN_REQUEST_TIMEOUT_MS = Number(process.env.MINDRIAN_BRAIN_TIMEOUT_MS) || 20000;
48
+
49
+ // Phase 250-01 (AVAIL-02, navigator ruling 2026-08-10): bounded transport
50
+ // retry budget around the single HTTP dispatch seam every Brain tool flows
51
+ // through (callTool()'s tools/call POST below). Retries ONLY transport-class
52
+ // outcomes -- network errors and 5xx responses -- BEFORE a blip ever becomes
53
+ // an unreachable refusal. NEVER retries 401/403 (validation-class, mapped to
54
+ // their own sentinels) or any other status; those are zero-retry by design
55
+ // (retrying an auth failure hammers auth, taxonomy-wrong per the data4sci
56
+ // four-class error taxonomy). Defensive numeric-env convention (repo-wide,
57
+ // e.g. BRAIN_REQUEST_TIMEOUT_MS above): an invalid override falls back to
58
+ // the default rather than throwing or disabling the feature silently.
59
+ const RETRY_MAX_DEFAULT = 2; // 2 retries = 3 attempts total.
60
+ const RETRY_BASE_MS_DEFAULT = 300; // 300ms, then 900ms (base * 3^attempt).
61
+
62
+ function _envNonNegativeInt(name, def) {
63
+ const raw = process.env[name];
64
+ if (raw === undefined || raw === '') return def;
65
+ const n = Number(raw);
66
+ return (Number.isFinite(n) && n >= 0) ? Math.floor(n) : def;
67
+ }
68
+
69
+ function _retryMax() {
70
+ return _envNonNegativeInt('MINDRIAN_BRAIN_RETRY_MAX', RETRY_MAX_DEFAULT);
71
+ }
72
+
73
+ function _retryBaseMs() {
74
+ return _envNonNegativeInt('MINDRIAN_BRAIN_RETRY_BASE_MS', RETRY_BASE_MS_DEFAULT);
75
+ }
76
+
77
+ function _sleep(ms) {
78
+ return new Promise((resolve) => setTimeout(resolve, ms));
79
+ }
80
+
81
+ // Phase 259 (TRUST-01, D-01/D-02/D-03): a dedicated retry budget for HTTP
82
+ // 429 (rate limited), separate from AVAIL-02's RETRY_MAX_DEFAULT /
83
+ // RETRY_BASE_MS_DEFAULT above. Deliberately NOT reusing
84
+ // MINDRIAN_BRAIN_RETRY_MAX / MINDRIAN_BRAIN_RETRY_BASE_MS: those are the
85
+ // operator knob for transport blips (network errors, 5xx), and sharing
86
+ // them would let an operator who sets MINDRIAN_BRAIN_RETRY_MAX=0 for
87
+ // fast-fail silently also disable Retry-After honoring, regressing into
88
+ // the exact bug this phase closes. D-01/D-02's schedule (3 retries,
89
+ // 500/1000/2000ms) is also arithmetically distinct from AVAIL-02's (2
90
+ // retries, base * 3^attempt).
91
+ const RATE_LIMIT_RETRY_MAX_DEFAULT = 3; // 3 retries = 4 attempts total (D-01).
92
+ const RATE_LIMIT_BASE_MS_DEFAULT = 500; // 500ms, then 1000ms, then 2000ms (base * 2^attempt) (D-02).
93
+
94
+ function _rateLimitRetryMax() {
95
+ return _envNonNegativeInt('MINDRIAN_BRAIN_RATELIMIT_RETRY_MAX', RATE_LIMIT_RETRY_MAX_DEFAULT);
96
+ }
97
+
98
+ function _rateLimitBaseMs() {
99
+ return _envNonNegativeInt('MINDRIAN_BRAIN_RATELIMIT_BASE_MS', RATE_LIMIT_BASE_MS_DEFAULT);
100
+ }
101
+
102
+ // OQ-4: an explicit, operator-set, self-declaring ceiling on the wait --
103
+ // UNSET by default, which is what ships D-01 ("honor Retry-After exactly")
104
+ // literally, never a silent Math.min. The Brain's own limiter bounds
105
+ // Retry-After to its window (60s at defaults, verified against
106
+ // ProblemsWorthSolving-Brain src/http/rate-limit.mjs), so an operator
107
+ // only needs this when self-hosting a differently-configured limiter.
108
+ function _rateLimitMaxWaitMs() {
109
+ const raw = process.env.MINDRIAN_BRAIN_RATELIMIT_MAX_WAIT_MS;
110
+ if (raw === undefined || raw === '') return null;
111
+ const n = Number(raw);
112
+ return (Number.isFinite(n) && n >= 0) ? Math.floor(n) : null;
113
+ }
114
+
115
+ // Phase 259 (TRUST-01): parse a Retry-After header value into milliseconds.
116
+ // Returns null when the header is absent or unusable, meaning "fall back
117
+ // to the D-02 exponential schedule". Handles both RFC 9110 forms: the
118
+ // delay-seconds integer form (the Brain's own live wire shape, verified
119
+ // this session against its deployed limiter) and the HTTP-date form
120
+ // (defensive only -- no known live caller sends it). Never lets NaN, a
121
+ // negative, or Infinity reach _sleep: _sleep(NaN) resolves on the very
122
+ // next tick, which is a silent zero-wait that would hammer the limiter.
123
+ // RFC 7231 IMF-fixdate, the exact shape Date.prototype.toUTCString() emits
124
+ // (e.g. "Wed, 21 Oct 2015 07:28:00 GMT") -- the only HTTP-date form worth
125
+ // trusting. Gating on this BEFORE calling Date.parse matters: V8's Date.parse
126
+ // falls back to a lenient legacy-format heuristic for anything that isn't a
127
+ // recognized standard form, and mis-parses garbage like "-5" or "1.5" into
128
+ // real (wrong) timestamps instead of NaN (verified this session).
129
+ const HTTP_DATE_RE = /^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/;
130
+
131
+ function _parseRetryAfterMs(raw) {
132
+ if (typeof raw !== 'string') return null;
133
+ const trimmed = raw.trim();
134
+ if (trimmed === '') return null;
135
+ if (/^\d+$/.test(trimmed)) {
136
+ const seconds = Number(trimmed);
137
+ if (!Number.isFinite(seconds) || seconds < 0) return null;
138
+ return seconds * 1000;
139
+ }
140
+ if (!HTTP_DATE_RE.test(trimmed)) return null;
141
+ const parsedDate = Date.parse(trimmed);
142
+ if (!Number.isFinite(parsedDate)) return null;
143
+ const deltaMs = parsedDate - Date.now();
144
+ return deltaMs > 0 ? deltaMs : 0;
145
+ }
146
+
147
+ // Phase 259 (TRUST-01): pure wait-schedule function -- no I/O, no clock
148
+ // beyond the Date.now() inside _parseRetryAfterMs. attemptIndex is 0-based
149
+ // over the RETRIES (0 -> first retry, 1 -> second, 2 -> third), matching
150
+ // Pattern 1 in 259-RESEARCH.md.
151
+ function _rateLimitWaitMs(attemptIndex, retryAfterHeader, baseMs) {
152
+ const parsed = _parseRetryAfterMs(retryAfterHeader);
153
+ const computed = parsed !== null ? parsed : baseMs * Math.pow(2, attemptIndex);
154
+ const ceiling = _rateLimitMaxWaitMs();
155
+ if (ceiling !== null && computed > ceiling) return ceiling;
156
+ return computed;
157
+ }
158
+
159
+ // Phase 87-07 (CASCADE-06): Brain session cache with 5-minute TTL.
160
+ // Every callTool() previously re-ran the `initialize` handshake (~1 network
161
+ // round-trip). With a long-lived MCP server this is wasted work -- sessions
162
+ // live longer than the ~60s transport timeout. Cache the initialized
163
+ // sessionId (keyed by api-key-hash) for 5 minutes.
164
+ //
165
+ // R-87-07-RACE (audit): two concurrent callTool() invocations with the same
166
+ // api_key previously both saw a cache miss, both initialized, and the second
167
+ // overwrote the first -- one of the two initialize handshakes was wasted.
168
+ // Fix: cache the init *Promise*, not the resolved session. The first caller
169
+ // stores { promise: initSession(apiKey), expiresAt }; concurrent callers
170
+ // within the TTL `await entry.promise`. On rejection we remove the entry so
171
+ // the next caller re-initializes fresh.
172
+ //
173
+ // Hash: sha256 truncated to 16 hex chars (64 bits of key space, zero realistic
174
+ // collision). A cheaper non-crypto hash was considered but its narrower int
175
+ // space has non-zero collision probability once the design extends across
176
+ // users; sha256 is effectively free at these volumes and eliminates the
177
+ // concern entirely (R-87-07-RACE).
178
+ const crypto = require('node:crypto');
179
+ const fs = require('node:fs');
180
+ const path = require('node:path');
181
+ // Phase 123 Plan-07: getApiKey() delegates to the single Brain-key resolver.
182
+ // The legacy inline 3-path lookup (env -> CWD .env -> ~/.mindrian.env) is gone;
183
+ // the resolver does env -> ~/.mindrian.env -> CWD .env (D-31 order) + SEC-02
184
+ // POSIX permission check + explicit reason strings. See HARNESS-123-15.
185
+ const { resolveBrainKey } = require('./resolve-brain-key.cjs');
186
+ const SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
187
+ /** @type {Map<string, {promise: Promise<string>, expiresAt: number}>} */
188
+ const sessionCache = new Map();
189
+
190
+ function _hashKey(key) {
191
+ return crypto.createHash('sha256').update(String(key)).digest('hex').slice(0, 16);
192
+ }
193
+
194
+ /**
195
+ * SEC-01: Sanitize any user-origin string before interpolation into a
196
+ * Cypher query. Whitelist from 87-CONTEXT.md lines 121-127:
197
+ * [a-zA-Z0-9 ._-]
198
+ * Every other char (including `"`, `'`, backtick, newline, `{`, `}`, `$`,
199
+ * `\`, `;`, `/`, `*`) is stripped. Null/undefined return ''. Non-strings
200
+ * are coerced via String() defensively so the caller never crashes.
201
+ *
202
+ * This replaces the legacy single-quote-escape pattern that only
203
+ * escaped one metacharacter (double-quote) and was trivially bypassable
204
+ * via backticks, newlines, `${...}` expansions, or Cypher comments.
205
+ *
206
+ * @param {*} value
207
+ * @returns {string}
208
+ */
209
+ function sanitizeCypherInput(value) {
210
+ if (value === null || value === undefined) return '';
211
+ if (typeof value !== 'string') {
212
+ try { value = String(value); } catch (_e) { return ''; }
213
+ }
214
+ return value.replace(/[^a-zA-Z0-9 ._-]/g, '');
215
+ }
216
+
217
+ /**
218
+ * SEC-02: Refuse to load a Brain API key from a .env file whose permissions
219
+ * expose it to group or world readers. Unix semantics only -- on Windows
220
+ * POSIX mode bits are not meaningful for NTFS ACLs, so we return true and
221
+ * warn once per process.
222
+ *
223
+ * mode & 0o077 !== 0 => any group/world bit is set => reject
224
+ * mode 0o600 (-rw-------) and 0o400 (-r--------) pass; 0o644, 0o664 fail.
225
+ *
226
+ * On stat failure we return false (no key beats a key we cannot verify).
227
+ *
228
+ * @param {string} envPath
229
+ * @returns {boolean}
230
+ */
231
+ function checkFilePermissions(envPath) {
232
+ try {
233
+ const fs = require('fs');
234
+ if (process.platform === 'win32') {
235
+ if (!checkFilePermissions._warned) {
236
+ process.stderr.write(
237
+ '[mindrian-os] Note: API key file permission check is Linux/macOS only; '
238
+ + 'on Windows rely on NTFS ACLs.\n'
239
+ );
240
+ checkFilePermissions._warned = true;
241
+ }
242
+ return true;
243
+ }
244
+ const stat = fs.statSync(envPath);
245
+ if ((stat.mode & 0o077) !== 0) {
246
+ process.stderr.write(
247
+ `[mindrian-os] Refusing to load API key from ${envPath}: `
248
+ + `permissions too open (must be 0600). chmod 600 ${envPath}\n`
249
+ );
250
+ return false;
251
+ }
252
+ return true;
253
+ } catch (_e) {
254
+ return false;
255
+ }
256
+ }
257
+ checkFilePermissions._warned = false;
258
+
259
+ // Phase 123 Plan-07: getApiKey() delegates to lib/core/resolve-brain-key.cjs.
260
+ //
261
+ // Order: MINDRIAN_BRAIN_KEY env -> ~/.mindrian.env -> CWD .env -> not-found.
262
+ // NOTE: this REVERSES the previous CWD-first-then-~/.mindrian.env order.
263
+ // Rationale: the global backup (~/.mindrian.env, mode 0600 per SEC-02) is more
264
+ // trustworthy than a project's potentially-stale .env file. Cited: Phase 123
265
+ // D-31. The resolver returns { key, source, available, reason }; we surface
266
+ // the key (or null) here and log a non-null reason ONCE per process via
267
+ // console.error -- SEC-02 group/world-bit rejection routes through this
268
+ // channel, never as a silent null.
269
+ //
270
+ // The legacy inline 3-path lookup and the per-file checkFilePermissions gate
271
+ // previously inlined here are gone -- the resolver owns both responsibilities
272
+ // now. checkFilePermissions remains exported on _test for backward-compat
273
+ // with security-trifecta.test.cjs (the helper itself still works locally;
274
+ // it's just not called by getApiKey anymore).
275
+ let _memoizedKey = null;
276
+ let _memoizedAt = 0;
277
+ let _reasonLoggedThisProcess = false;
278
+ const _GETKEY_MEMO_MS = 60 * 1000;
279
+ function getApiKey() {
280
+ if (_memoizedAt && (Date.now() - _memoizedAt) < _GETKEY_MEMO_MS) {
281
+ return _memoizedKey;
282
+ }
283
+ const r = resolveBrainKey();
284
+ if (r && r.available) {
285
+ _memoizedKey = r.key;
286
+ _memoizedAt = Date.now();
287
+ return _memoizedKey;
288
+ }
289
+ if (r && r.reason && !_reasonLoggedThisProcess) {
290
+ // SEC-02 reject + not-found-with-reason both route through stderr ONCE
291
+ // per process -- never a silent null. The session-start status line is
292
+ // the user-visible surface; this is the in-process diagnostic.
293
+ process.stderr.write('[mindrian-os] Brain key not loaded: ' + r.reason + '\n');
294
+ _reasonLoggedThisProcess = true;
295
+ }
296
+ _memoizedKey = null;
297
+ _memoizedAt = Date.now();
298
+ return null;
299
+ }
300
+
301
+ /**
302
+ * Check if Brain is available (key exists).
303
+ */
304
+ function isAvailable() {
305
+ return !!getApiKey();
306
+ }
307
+
308
+ // ---------------------------------------------------------------------------
309
+ // Phase 250-04 (HONEST-03, SEED-011 Option A) -- per-install silent
310
+ // registration. Design doc: docs/BRAIN-IDENTITY-DESIGN.md.
311
+ //
312
+ // The ladder's fourth leg (resolve-brain-key.cjs, read-only) resolves an
313
+ // existing cached install token; THIS module owns the minting side. When the
314
+ // ladder resolves nothing at the first Brain consult, mint a fresh UUID,
315
+ // POST it to the Brain's /register endpoint, cache the returned token at
316
+ // mode 0600, and let the SAME process's next getApiKey() call pick it up.
317
+ //
318
+ // Once-per-process cap: exactly ONE registration attempt per process,
319
+ // success or failure. A failed attempt is the failure edge (registration
320
+ // failed / Brain offline) -- it is NEVER retried within the process (the
321
+ // AVAIL-02 bounded-retry budget explicitly does not apply here; a fresh
322
+ // process retries fresh on its own next launch). NEVER thrown into the
323
+ // caller; NEVER blocks a non-methodology path (this only runs from the
324
+ // Brain-consult chokepoint below, never from session-start or a hot path).
325
+ let _autoRegisterAttemptedThisProcess = false;
326
+ let _autoRegisterFailureReason = null;
327
+
328
+ function _installTokenPath(home) {
329
+ const h = home || process.env.HOME || process.env.USERPROFILE || require('node:os').homedir();
330
+ return path.join(h, '.mindrian-install.json');
331
+ }
332
+
333
+ /**
334
+ * Attempt the one-shot silent registration. Returns the minted key string on
335
+ * success, or null (opt-out, already-attempted, or any failure). On success,
336
+ * updates the module's own memoized key so the CALLER's next getApiKey()
337
+ * returns it immediately (no redundant resolver re-read needed, though a
338
+ * fresh resolveBrainKey() call would ALSO see the cache file now).
339
+ *
340
+ * @returns {Promise<string|null>}
341
+ */
342
+ async function _tryAutoRegister() {
343
+ if (_autoRegisterAttemptedThisProcess) return null;
344
+ _autoRegisterAttemptedThisProcess = true;
345
+
346
+ if (process.env.MINDRIAN_DISABLE_AUTO_REGISTER) {
347
+ _autoRegisterFailureReason = 'auto-registration disabled (MINDRIAN_DISABLE_AUTO_REGISTER set)';
348
+ return null;
349
+ }
350
+
351
+ try {
352
+ const installId = crypto.randomUUID();
353
+ const res = await fetch(`${BRAIN_URL}/register`, {
354
+ method: 'POST',
355
+ signal: AbortSignal.timeout(BRAIN_REQUEST_TIMEOUT_MS),
356
+ headers: { 'Content-Type': 'application/json' },
357
+ // Part 8 posture (T-250-13): install_id ONLY ever crosses in this body.
358
+ body: JSON.stringify({ install_id: installId }),
359
+ });
360
+ if (!res.ok) {
361
+ try { await res.arrayBuffer(); } catch (_e) { /* drain, see _ensureSession's precedent */ }
362
+ _autoRegisterFailureReason = 'registration failed (HTTP ' + res.status + ', offline or unreachable)';
363
+ return null;
364
+ }
365
+ const body = await res.json();
366
+ if (!body || typeof body.token !== 'string' || body.token.length === 0) {
367
+ _autoRegisterFailureReason = 'registration returned a malformed response (offline or unreachable)';
368
+ return null;
369
+ }
370
+
371
+ const cachePath = _installTokenPath();
372
+ const payload = { install_id: installId, token: body.token, minted_at: new Date().toISOString() };
373
+ fs.writeFileSync(cachePath, JSON.stringify(payload, null, 2) + '\n', { mode: 0o600 });
374
+ // writeFileSync's mode option only applies on file CREATION; force it
375
+ // explicitly so a pre-existing looser-permission file is corrected too
376
+ // (SEC-02 posture, mirrors resolve-brain-key.cjs's own gate on this file).
377
+ try { fs.chmodSync(cachePath, 0o600); } catch (_e) { /* best-effort on platforms without chmod semantics */ }
378
+
379
+ _memoizedKey = body.token;
380
+ _memoizedAt = Date.now();
381
+ return body.token;
382
+ } catch (e) {
383
+ _autoRegisterFailureReason = 'registration failed: ' + (e && e.message || String(e)) + ' (offline or unreachable)';
384
+ return null;
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Async-aware availability gate: the "first Brain consult" seam every
390
+ * MCP-surface entry point passes through before dispatching a tool
391
+ * (bin/mindrian-brain-mcp-client.cjs's per-tool gates use this INSTEAD of
392
+ * the synchronous isAvailable(), so silent registration actually fires on
393
+ * that path -- isAvailable() alone cannot attempt an async network mint).
394
+ * Direct brain-client consumers (query/ask/schema/... via callTool) do not
395
+ * need to call this explicitly -- callTool() below performs the identical
396
+ * fallback internally, so BOTH surfaces share the SAME once-per-process cap.
397
+ *
398
+ * @returns {Promise<boolean>}
399
+ */
400
+ async function ensureAvailable() {
401
+ if (isAvailable()) return true;
402
+ await _tryAutoRegister();
403
+ return isAvailable();
404
+ }
405
+
406
+ /**
407
+ * The honest reason the last auto-registration attempt failed (or the
408
+ * opt-out reason), or null if no attempt has failed this process (either
409
+ * none was attempted yet, or the last attempt succeeded). Consumed by the
410
+ * no_key failure-edge refusal copy (refusal-messaging.cjs) so the reason names
411
+ * "registration" / "offline" rather than a generic "no key" framing.
412
+ *
413
+ * @returns {string|null}
414
+ */
415
+ function getAutoRegisterFailureReason() {
416
+ return _autoRegisterFailureReason;
417
+ }
418
+
419
+ /**
420
+ * Phase 87-07: ensure we have a valid initialized Brain session for the given
421
+ * api key, reusing the cached one if non-expired. Uses the pending-promise
422
+ * pattern so concurrent callers share a single in-flight init (R-87-07-RACE).
423
+ *
424
+ * Returns the resolved session marker (an opaque string -- the Brain Streamable
425
+ * HTTP transport does not require us to echo a sessionId on subsequent requests
426
+ * inside the same cache window, but awaiting this promise proves the key is
427
+ * valid against the Brain endpoint exactly once per TTL window).
428
+ *
429
+ * On any init rejection (network error, 401, etc.) the cache entry is removed
430
+ * in the .catch() tail so the next caller retries fresh rather than inheriting
431
+ * a poisoned promise.
432
+ *
433
+ * Sentinel `{ error: 'invalid_key' }` is returned *through* the promise (not
434
+ * thrown) so callers treat 401 identically to the pre-cache flow.
435
+ *
436
+ * @param {string} apiKey
437
+ * @returns {Promise<string|{error:string,message:string}|null>}
438
+ */
439
+ async function _ensureSession(apiKey) {
440
+ const keyHash = _hashKey(apiKey);
441
+ const cached = sessionCache.get(keyHash);
442
+ if (cached && cached.expiresAt > Date.now()) {
443
+ // Cache hit. Works whether the promise is still pending (concurrent init
444
+ // in flight) or already resolved (TTL reuse). Awaiting a resolved promise
445
+ // is a microtask no-op, so the fast path stays fast.
446
+ return cached.promise;
447
+ }
448
+ // Cache miss. Build the promise FIRST, install it in the cache BEFORE the
449
+ // first real await, so concurrent callers within the same event-loop tick
450
+ // see the same in-flight promise (R-87-07-RACE pending-promise pattern).
451
+ const promise = (async () => {
452
+ const initRes = await fetch(`${BRAIN_URL}/mcp`, {
453
+ method: 'POST',
454
+ signal: AbortSignal.timeout(BRAIN_REQUEST_TIMEOUT_MS),
455
+ headers: {
456
+ 'Content-Type': 'application/json',
457
+ 'Accept': 'application/json, text/event-stream',
458
+ 'Authorization': `Bearer ${apiKey}`,
459
+ },
460
+ body: JSON.stringify({
461
+ jsonrpc: '2.0',
462
+ id: 1,
463
+ method: 'initialize',
464
+ params: {
465
+ protocolVersion: '2024-11-05',
466
+ capabilities: {},
467
+ clientInfo: { name: 'mindrian-cli', version: '1.0.0' },
468
+ },
469
+ }),
470
+ });
471
+ if (!initRes.ok) {
472
+ // Debug session doctor-brain-smoke-win-crash (2026-05-30): drain the
473
+ // response body on the non-OK path. Node global fetch (undici) keeps the
474
+ // underlying TLS socket in a keep-alive, not-yet-released state until its
475
+ // body is consumed. An un-drained socket is a live libuv handle at exit;
476
+ // a synchronous process.exit() in a caller tears it down mid-close and
477
+ // asserts on Windows (src/win/async.c UV_HANDLE_CLOSING). Consuming the
478
+ // body lets undici release/recycle the socket cleanly. Cross-platform.
479
+ try { await initRes.arrayBuffer(); } catch (_) { /* body already gone */ }
480
+ if (initRes.status === 401) {
481
+ return { error: 'invalid_key', message: 'Brain API key is invalid.' };
482
+ }
483
+ // Any other non-OK status becomes a throw so the cache entry is purged
484
+ // by the .catch() below and the next caller retries.
485
+ throw new Error(`Brain init HTTP ${initRes.status}`);
486
+ }
487
+ // Opaque session marker. Subsequent tools/call requests don't need to
488
+ // echo this back -- the transport is stateless at the HTTP level. What
489
+ // matters is that we validated the key is live within this TTL window.
490
+ return 'validated-' + Date.now();
491
+ })();
492
+ sessionCache.set(keyHash, { promise, expiresAt: Date.now() + SESSION_TTL_MS });
493
+ // On reject, purge the entry so the next caller initializes fresh. Swallow
494
+ // here (we re-throw in the awaiter below) so Node doesn't see an
495
+ // unhandledRejection on the cache handle itself.
496
+ promise.catch(() => { sessionCache.delete(keyHash); });
497
+ return promise;
498
+ }
499
+
500
+ /**
501
+ * Phase 254 / COMP-02 (D-02 Option A): attach an additive `egress_disclosure`
502
+ * field to a callTool() success return when the Part 8 belt captured an
503
+ * `ambiguous` verdict for this call. Module-private -- used only at
504
+ * callTool()'s three success-return sites below.
505
+ *
506
+ * Returns `result` UNCHANGED when `disclosure` is falsy, when `result` is
507
+ * not a non-null plain object, or when `result` already carries an own
508
+ * `error` property (so `tier_denied` / `invalid_key` / `rate_limited` /
509
+ * `egress_blocked` sentinels are never decorated -- those are refusals, not
510
+ * success returns). Never throws: the assignment is wrapped so a frozen or
511
+ * exotic result object degrades to the undecorated value rather than
512
+ * crashing a Brain call.
513
+ *
514
+ * COPY-ON-ATTACH FOR PLAIN OBJECTS, MUTATE FOR ARRAYS (WR-02, 254-REVIEW.md):
515
+ * for a plain object, this returns a NEW shallow-copied object rather than
516
+ * mutating `result` in place -- every call site hands in a value freshly
517
+ * parsed via `JSON.parse` two lines above, so no other reference exists to
518
+ * preserve, and copy-on-attach closes the "same reference silently gains a
519
+ * field" hazard at zero real cost. For an ARRAY, mutation is structurally
520
+ * required: `callTool`'s contract for `brain_query` must stay a bare array
521
+ * per the 2026-05-11 hotfix note, so wrapping it in a new object here would
522
+ * break the `Array.isArray(result)` shape every `brain_query` consumer keys
523
+ * on. The disclosure is therefore attached as a non-index own property of
524
+ * the SAME array reference -- this is load-bearing for `query()`'s own
525
+ * `Array.isArray(result)` normalization branch below, which reads this
526
+ * property off the array and copies + deletes it onto the new top-level
527
+ * object it constructs (CR-01, 254-REVIEW.md). Any OTHER caller reading a
528
+ * bare array off `callTool('brain_query', ...)` directly (bypassing
529
+ * `query()`) must do the same: check `result.egress_disclosure` before
530
+ * treating `result` as a plain row array, since `JSON.stringify` silently
531
+ * drops non-index array properties.
532
+ *
533
+ * @param {*} result
534
+ * @param {object|null} disclosure
535
+ * @returns {*}
536
+ */
537
+ function _attachEgressDisclosure(result, disclosure) {
538
+ if (!disclosure) return result;
539
+ if (result === null || typeof result !== 'object') return result;
540
+ if (Object.prototype.hasOwnProperty.call(result, 'error')) return result;
541
+ try {
542
+ if (Array.isArray(result)) {
543
+ result.egress_disclosure = disclosure;
544
+ return result;
545
+ }
546
+ return Object.assign({}, result, { egress_disclosure: disclosure });
547
+ } catch (_e) {
548
+ // Frozen or exotic result object -- degrade to the undecorated value. A
549
+ // belt that can crash a Brain call is worse than the gap it closes.
550
+ return result;
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Call a Brain MCP tool via HTTP.
556
+ * @param {string} toolName - e.g., 'brain_query', 'brain_search', 'brain_schema'
557
+ * @param {object} args - tool arguments
558
+ * @returns {object|null} - result or null if unavailable
559
+ */
560
+ async function callTool(toolName, args) {
561
+ let key = getApiKey();
562
+ if (!key) {
563
+ // Phase 250-04: the ladder resolved nothing -- this IS the first Brain
564
+ // consult. Attempt the one-shot silent registration before giving up;
565
+ // shares the same _autoRegisterAttemptedThisProcess cap as
566
+ // ensureAvailable() (the shim's gate), so whichever surface consults
567
+ // first performs the real network attempt and the other reuses it.
568
+ key = await _tryAutoRegister();
569
+ }
570
+ if (!key) return null;
571
+
572
+ // Quick 260819-c8j (WS-D2): the Part 8 in-process classify() belt at the
573
+ // single dispatch seam every callTool() caller flows through. Placement is
574
+ // load-bearing: AFTER the key gate above (so the no-key `null` contract
575
+ // stays byte-unchanged) and BEFORE _ensureSession below (so a blocked
576
+ // payload opens no socket at all -- not even a session init).
577
+ //
578
+ // MECHANISM CHOICE: one guard in one function covers all 16 wrappers,
579
+ // versus ~12 near-identical per-wrapper edits that drift the moment a 17th
580
+ // wrapper lands. Double-classification is NOT double-prompting --
581
+ // classify() returns a verdict, it does not elicit. The 4 existing
582
+ // raw-field guards (query() :601, hatAwareRecommend() :942,
583
+ // suggestValidationSteps() :1056, sendPacket() :1643) are NOT removed and
584
+ // NOT weakened by this belt: their own docblocks prove why the belt cannot
585
+ // replace them (classifying the ASSEMBLED template string instead of the
586
+ // raw field lets the template's own word "Framework" launder an embedded
587
+ // canary from ambiguous to allow, and sanitizeCypherInput strips the '@'
588
+ // the PII pattern keys on) -- this is a belt UNDERNEATH them, never a
589
+ // substitute. An 'ambiguous' verdict never blocks and never prompts, the
590
+ // same posture sendPacket()'s belt already takes at :1643 in spirit.
591
+ //
592
+ // `egress_blocked` is a sentinel OBJECT, not `null`: `null` is the
593
+ // test-pinned transport-failure signal across ~82 degradation tests, and
594
+ // conflating a constitutional refusal with an outage would make the
595
+ // refusal invisible. The sentinel-object idiom is already established by
596
+ // `tier_denied` (:497 area) and `invalid_key` above.
597
+ //
598
+ // Phase 254 / COMP-02 (D-02 Option A, navigator-ruled 2026-09-02):
599
+ // `ambiguous` now DISCLOSES and still PROCEEDS. `ambiguousDisclosure`
600
+ // (declared below, function-scoped so it survives into the retry loop and
601
+ // the SSE parse) captures the typed disclosure ADDITIVELY -- borrowing the
602
+ // idiom `brain-router.cjs:414-422` already uses for `brain_refusal`
603
+ // (an additive field, best-effort, never blocking), not the function
604
+ // itself. Option B (fail-closed on `ambiguous` too) was considered and
605
+ // explicitly rejected for this phase: it would change the behaviour of all
606
+ // 16 `callTool` wrappers at once and needs its own canary suite, out of
607
+ // this phase's scope. A Shape F.1 gate belongs at the MCP handler
608
+ // (`lib/mcp/gate-render.cjs::renderGate`) and never at this transport
609
+ // chokepoint -- inventing an elicitation path inside a stateless server
610
+ // handler is exactly what Option A avoids. The disclosure names the
611
+ // verdict class and the tool; it never carries payload bytes (every
612
+ // `ambiguous`-branch `reason` string in `part8-egress-guard.cjs` is a
613
+ // constant literal, unlike the `block` branch's reason which embeds the
614
+ // matched pattern -- this path never reaches that branch).
615
+ //
616
+ // The host PreToolUse hook (`scripts/part8-egress-guard-hook.cjs`) still
617
+ // gates `ambiguous` with a real Shape F.1 render on the model-issued path.
618
+ // The two enforcement points now DIVERGE BY A STATED DECISION rather than
619
+ // by omission -- COMP-02's literal wording.
620
+ let ambiguousDisclosure = null;
621
+ try {
622
+ const callToolEgressGuard = require('./part8-egress-guard.cjs');
623
+ const callToolEgressVerdict = callToolEgressGuard.classify(args, { toolName: toolName });
624
+ if (callToolEgressVerdict && callToolEgressVerdict.verdict === 'block') {
625
+ return {
626
+ error: 'egress_blocked',
627
+ tool: toolName,
628
+ egress_class: callToolEgressVerdict.class || 'content_set',
629
+ };
630
+ } else if (callToolEgressVerdict && callToolEgressVerdict.verdict === 'ambiguous') {
631
+ ambiguousDisclosure = {
632
+ verdict: 'ambiguous',
633
+ egress_class: callToolEgressVerdict.class || 'unknown',
634
+ reason: callToolEgressVerdict.reason || null,
635
+ tool: toolName,
636
+ disposition: 'proceeded',
637
+ };
638
+ }
639
+ } catch (_e) {
640
+ // Belt-internal error (guard module missing/throws): degrade to existing
641
+ // behavior. This belt is a belt, not the primary control.
642
+ }
643
+
644
+ try {
645
+ // Phase 87-07: reuse cached Brain session (5-min TTL) instead of
646
+ // re-running initialize on every callTool. Concurrent callers share
647
+ // the in-flight promise via the pending-promise pattern.
648
+ const session = await _ensureSession(key);
649
+ if (session && typeof session === 'object' && session.error === 'invalid_key') {
650
+ return session;
651
+ }
652
+ if (!session) return null;
653
+
654
+ // Phase 250-01 (AVAIL-02): bounded retry loop around the tools/call
655
+ // dispatch -- the single HTTP seam every Brain tool flows through after
656
+ // session establishment. NULL CONTRACT PRESERVED: the retry changes WHEN
657
+ // null returns (after the budget instead of after one attempt), never
658
+ // WHAT returns null, and never which statuses map to which sentinels
659
+ // (247-02 do-not-widen note; 82 degradation tests key on this).
660
+ const retryMax = _retryMax();
661
+ const baseMs = _retryBaseMs();
662
+ // Phase 259 (TRUST-01): a SEPARATE counter from the loop's `attempt`,
663
+ // so a 5xx blip earlier in this same callTool invocation cannot eat
664
+ // into the 429 budget, and vice versa. Declared outside the `for` so
665
+ // it survives iterations.
666
+ let rlAttempt = 0;
667
+ let rlTruncated = false; // OQ-4: set when MINDRIAN_BRAIN_RATELIMIT_MAX_WAIT_MS truncated a wait this call.
668
+ for (let attempt = 0; ; attempt += 1) {
669
+ let toolRes;
670
+ try {
671
+ toolRes = await fetch(`${BRAIN_URL}/mcp`, {
672
+ method: 'POST',
673
+ signal: AbortSignal.timeout(BRAIN_REQUEST_TIMEOUT_MS),
674
+ headers: {
675
+ 'Content-Type': 'application/json',
676
+ 'Accept': 'application/json, text/event-stream',
677
+ 'Authorization': `Bearer ${key}`,
678
+ },
679
+ body: JSON.stringify({
680
+ jsonrpc: '2.0',
681
+ id: 2,
682
+ method: 'tools/call',
683
+ params: { name: toolName, arguments: args },
684
+ }),
685
+ });
686
+ } catch (fetchErr) {
687
+ // Network error / timeout at the tools/call seam -- transport-class,
688
+ // retryable. Every other thrown error (outside this inner try) still
689
+ // falls through to the outer catch below, unchanged.
690
+ if (attempt < retryMax) {
691
+ await _sleep(baseMs * Math.pow(3, attempt));
692
+ continue;
693
+ }
694
+ return null;
695
+ }
696
+
697
+ if (!toolRes.ok) {
698
+ // Phase 247-02 (CONTRACT-01 error semantics): HTTP 403 means the Brain's
699
+ // tier gate refused this tool on this key (a MoatViolation), NOT that the
700
+ // Brain is unreachable. Mirrors the invalid_key sentinel precedent in
701
+ // _ensureSession above -- a plain object returned through the promise,
702
+ // never thrown, so callers that already understand sentinel passthrough
703
+ // (query()'s {error:...} passthrough is the existing example) keep
704
+ // working unchanged. 401/403 are validation-class -- ZERO retry, ever
705
+ // (AVAIL-02: retrying an auth failure hammers auth, taxonomy-wrong).
706
+ if (toolRes.status === 403) {
707
+ let rawText = '';
708
+ try { rawText = await toolRes.text(); } catch (_e) { rawText = ''; }
709
+ let message = null;
710
+ try {
711
+ const parsedBody = JSON.parse(rawText);
712
+ if (parsedBody && parsedBody.error && typeof parsedBody.error.message === 'string') {
713
+ message = parsedBody.error.message;
714
+ }
715
+ } catch (_e) {
716
+ // Unparseable body -- fall through to the raw-text fallback below.
717
+ }
718
+ if (!message) {
719
+ message = rawText
720
+ ? rawText.slice(0, 300)
721
+ : 'Brain denied tier access (403, no body).';
722
+ }
723
+ return { error: 'tier_denied', tool: toolName, message: message };
724
+ }
725
+ // Phase 259 (TRUST-01): 429 previously fell through the generic
726
+ // non-OK ladder into the bare `return null` at the bottom of this
727
+ // block, which the MCP shim renders as BRAIN_UNREACHABLE with copy
728
+ // claiming a retry budget was spent -- factually false, since zero
729
+ // retries ran on that leg. Verified wire contract (this session,
730
+ // ProblemsWorthSolving-Brain src/http/rate-limit.mjs::
731
+ // perKeyRateLimit): 120 requests per 60s per key at defaults,
732
+ // Retry-After ALWAYS set as an integer delay-seconds string,
733
+ // floored at 1 and bounded above by the window. D-01: honor it
734
+ // exactly. D-02: fall back to 500/1000/2000ms when absent. D-03:
735
+ // after the budget exhausts, return a distinct rate_limited
736
+ // sentinel, never null.
737
+ if (toolRes.status === 429) {
738
+ const retryAfterRaw = toolRes.headers.get('retry-after');
739
+ // Drain this branch's own body before bailing/continuing, exactly
740
+ // as the 403 block above consumes its own body (an un-drained
741
+ // undici socket is a live libuv handle that asserts on Windows).
742
+ try { await toolRes.arrayBuffer(); } catch (_e) { /* body already gone */ }
743
+ if (rlAttempt < _rateLimitRetryMax()) {
744
+ const ceilingMsForWait = _rateLimitMaxWaitMs();
745
+ const computedWaitMs = _rateLimitWaitMs(rlAttempt, retryAfterRaw, _rateLimitBaseMs());
746
+ if (ceilingMsForWait !== null && computedWaitMs >= ceilingMsForWait) rlTruncated = true;
747
+ await _sleep(computedWaitMs);
748
+ rlAttempt += 1;
749
+ continue;
750
+ }
751
+ const parsedRetryAfterMs = _parseRetryAfterMs(retryAfterRaw);
752
+ const retryAfterS = parsedRetryAfterMs !== null ? Math.ceil(parsedRetryAfterMs / 1000) : null;
753
+ const ceilingMs = _rateLimitMaxWaitMs();
754
+ let message = `Brain rate-limited ${toolName} after ${rlAttempt + 1} attempts (429).`;
755
+ if (rlTruncated && ceilingMs !== null) {
756
+ message += ` At least one Retry-After wait was truncated to the operator-set ceiling of ${ceilingMs}ms.`;
757
+ }
758
+ return {
759
+ error: 'rate_limited',
760
+ tool: toolName,
761
+ retry_after_s: retryAfterS,
762
+ attempts: rlAttempt + 1,
763
+ message: message.slice(0, 300),
764
+ };
765
+ }
766
+ // Drain the body before bailing so undici releases the keep-alive socket
767
+ // (see _ensureSession non-OK note: an un-drained socket is a live libuv
768
+ // handle that asserts on Windows when a caller force-exits).
769
+ try { await toolRes.arrayBuffer(); } catch (_) { /* body already gone */ }
770
+ // 5xx is transport-class (transient) -- retryable within budget.
771
+ // Every OTHER non-OK, non-retried status still returns null -- that
772
+ // remains the sole transport-failure signal (research Pitfall 4: 82
773
+ // degradation tests key on it; do not widen this branch).
774
+ if (toolRes.status >= 500 && toolRes.status < 600 && attempt < retryMax) {
775
+ await _sleep(baseMs * Math.pow(3, attempt));
776
+ continue;
777
+ }
778
+ return null;
779
+ }
780
+
781
+ const text = await toolRes.text();
782
+ // Parse SSE response
783
+ const dataLine = text.split('\n').find(l => l.startsWith('data: '));
784
+ if (!dataLine) return null;
785
+
786
+ const parsed = JSON.parse(dataLine.slice(6));
787
+ if (parsed.result && parsed.result.content) {
788
+ const textContent = parsed.result.content.find(c => c.type === 'text');
789
+ if (textContent) {
790
+ try {
791
+ return _attachEgressDisclosure(JSON.parse(textContent.text), ambiguousDisclosure);
792
+ } catch (e) {
793
+ return _attachEgressDisclosure({ text: textContent.text }, ambiguousDisclosure);
794
+ }
795
+ }
796
+ }
797
+ // The helper's own non-object guard already handles the null case
798
+ // here (parsed.result || null); wrapped anyway so the intent is
799
+ // legible at the call site rather than relying on the guard alone.
800
+ return _attachEgressDisclosure(parsed.result || null, ambiguousDisclosure);
801
+ }
802
+ } catch (err) {
803
+ // Network error, timeout, etc. (outside the retry loop -- e.g. during
804
+ // _ensureSession).
805
+ return null;
806
+ }
807
+ }
808
+
809
+ /**
810
+ * Query Neo4j via Brain (Cypher query).
811
+ * This does NOT use Pinecone, no embedding quota consumed.
812
+ *
813
+ * NOTE (Finding I, v1.10.9 hotfix 2026-04-15): the Brain MCP brain_query
814
+ * tool expects the parameter name `cypher`, not `query`. Previously this
815
+ * function sent { query: cypher } which tripped an MCP input validation
816
+ * error (code -32602, path ["cypher"], "Required"). Downstream scripts
817
+ * like fetch-brain-baseline.cjs and compute-whitespace-gaps.py then
818
+ * silently fell through to empty-baseline mode even though Brain was
819
+ * fully reachable and the key was valid. Witnessed against the live
820
+ * iia-deeptech-centers room on 2026-04-15. brain_search uses `query`
821
+ * which is why Pinecone semantic search kept working and masked this.
822
+ *
823
+ * NOTE (2026-05-11, graph-on-graph P0): `query` now accepts an optional
824
+ * second argument `params` and forwards it to the `brain_query` MCP tool
825
+ * as { cypher, params }. The Brain tool declares `params:
826
+ * z.record(z.any()).optional()`, so a parameterized Cypher gets its
827
+ * bindings through cleanly. `params` MUST be a generic-handles-only object
828
+ * -- framework names, phase identifiers, problem types per Canon Part 8 --
829
+ * NEVER user content (artifact bodies, meeting text, personal identifiers,
830
+ * proprietary numbers). Previously the second arg was silently dropped, so
831
+ * callers (rs-explain-command.cjs, rs-thesis-command.cjs, rs-nl-to-query)
832
+ * that generated parameterized Cypher had their bindings disappear or were
833
+ * pushed toward unsafe string interpolation. A param-less call still sends
834
+ * only { cypher } and behaves exactly as before.
835
+ *
836
+ * NOTE (2026-05-11, graph-on-graph P0 cont.): RESULT-SHAPE NORMALIZATION.
837
+ * The Brain MCP `brain_query` tool serializes its result as
838
+ * `JSON.stringify(records)` where `records` is a BARE ARRAY of row objects.
839
+ * `callTool` returns that array directly (or `{ text: 'Error: ...' }` on a
840
+ * Cypher error, or `null` when the Brain is unreachable / no API key).
841
+ * Consumers across the codebase -- brain-router.cjs, brain-derivation.cjs's
842
+ * `renderRecords`, rs-chain-feeder.cjs, rs-experts-command.cjs,
843
+ * rs-explain-command.cjs, rs-thesis-command.cjs -- all read `result.records`,
844
+ * so the bare-array shape silently dropped every row. `query` therefore now
845
+ * ALWAYS returns `{ records: [...] }` on a successful brain_query; an
846
+ * unreachable Brain / missing key still returns `null`; a Cypher-error
847
+ * response (`{ text: 'Error: ...' }` or `{ error: ... }`) passes through
848
+ * unchanged so callers that inspect the failure can still see it; any other
849
+ * unexpected shape collapses to `{ records: [] }` so callers never crash.
850
+ * `search`, `smartSearch`, `schema`, `stats`, `write`, `callTool` are
851
+ * deliberately untouched -- only `query` is normalized.
852
+ *
853
+ * NOTE (2026-09-01, quick/260901-ipp): a THIRD recognized shape. Theo's
854
+ * `brain_query` contract cutover returns `{ rows: [...], diagnostics: {...} }`
855
+ * instead of the bare array above, and that shape matched none of the
856
+ * branches here -- it fell through to the unexpected-shape safety net, so
857
+ * every post-flip `brain_query` call returned an empty result set that was
858
+ * indistinguishable from a legitimate no-match, with no error and no crash.
859
+ * `query` now recognizes `result.rows` (guarded with `Array.isArray`, never
860
+ * mere key presence, so a malformed `rows` value still lands on the safety
861
+ * net) and normalizes it into `records` while preserving every other field
862
+ * the Brain sent (`diagnostics`, and any future `coverage` block). Preserving
863
+ * `diagnostics` is load-bearing: it is what lets a caller tell a genuine
864
+ * `{ rows: [], diagnostics: {...} }` "nothing matched" apart from an
865
+ * unrecognized-shape response (see the 2026-09-03 note below for what the
866
+ * fallback returns now). Sources: this repo's
867
+ * `docs/2026-09-01-HANDOFF-phases-272-274-275-plus-theo-flip-coordination.md`
868
+ * finding #1, and Theo's own
869
+ * `.planning/phases/09-brain-contract-cutover/09-MOS-LEARNING.md`.
870
+ *
871
+ * NOTE (2026-09-03, quick/260903-eit): the safety net stopped being blind.
872
+ * An unrecognized shape still returns an object carrying `records: []` so
873
+ * callers never crash, but it now ALSO carries
874
+ * `error: 'brain_query_unrecognized_shape'` plus `shape_type` and
875
+ * `shape_keys`, and emits one warn-once `[mindrian-os]` line naming the
876
+ * offending top-level key names. Reason: the bare `{ records: [] }` was
877
+ * byte-identical to a legitimate no-match, which is precisely how the Theo
878
+ * `{ rows, diagnostics }` drift went unnoticed above until a human read this
879
+ * code. This change recognizes ZERO new response shapes -- it only makes the
880
+ * next mismatch audible. Sources: this task directory
881
+ * (`.planning/quick/260903-eit-.../260903-eit-PLAN.md`) alongside the
882
+ * 2026-09-01 sources above.
883
+ */
884
+ async function query(cypher, params) {
885
+ // Part 8 BACKSTOP (Phase 239 / BRAIN-02). This is a BACKSTOP ONLY and is
886
+ // PROVABLY INSUFFICIENT ALONE: MEASURED, the template's own vocabulary word
887
+ // "Framework" satisfies the classifier's positive methodology recognizer
888
+ // and launders an embedded canary from ambiguous to allow -- classifying
889
+ // the payload {cypher:"CANARY7F3A2B"} on its own yields verdict ambiguous,
890
+ // but classifying {cypher:'MATCH (f:Framework) WHERE x="CANARY7F3A2B"'}
891
+ // yields verdict allow. The REAL coverage is the raw-field guard added in
892
+ // hatAwareRecommend and suggestValidationSteps (classify-before-sanitize,
893
+ // classify-before-interpolate). Anyone tempted to delete those raw-field
894
+ // guards because "query() already checks" must read this comment first:
895
+ // it does not.
896
+ // An 'ambiguous' verdict on an assembled template is EXPECTED policy here
897
+ // (every legitimate methodology query looks ambiguous at this tier) and is
898
+ // deliberately NOT blocked; only a proven 'block' (a CONTENT-SET hit) stops
899
+ // the call.
900
+ try {
901
+ const queryEgressGuard = require('./part8-egress-guard.cjs');
902
+ const queryEgressVerdict = queryEgressGuard.classify(
903
+ { cypher: String(cypher || '') },
904
+ { toolName: 'brain_query' }
905
+ );
906
+ if (queryEgressVerdict && queryEgressVerdict.verdict === 'block') {
907
+ _logEventBestEffort(undefined, 'brain_egress_blocked', {
908
+ egress_class: queryEgressVerdict.class || 'content_set',
909
+ verdict: 'block',
910
+ count: 1,
911
+ created_by: 'system',
912
+ source_path: 'system:brain-query',
913
+ });
914
+ return null;
915
+ }
916
+ } catch (_e) {
917
+ // Belt-internal error (guard module missing/throws): degrade to existing
918
+ // behavior. This backstop is a belt, not the primary control.
919
+ }
920
+
921
+ const args = { cypher: cypher };
922
+ if (params && typeof params === 'object' && Object.keys(params).length > 0) {
923
+ args.params = params;
924
+ }
925
+ const result = await callTool('brain_query', args);
926
+ if (result == null) return null; // unreachable / no API key
927
+ if (Array.isArray(result)) {
928
+ // the normal brain_query shape. `_attachEgressDisclosure` (Phase 254 /
929
+ // COMP-02) attaches `egress_disclosure` as a non-index own property of
930
+ // this SAME array when the Part 8 belt captured an `ambiguous` verdict.
931
+ // The `{ records: result }` wrapper below is a BRAND-NEW object, so that
932
+ // property is not carried over automatically -- it must be copied onto
933
+ // the new top-level object explicitly, or it silently relocates to
934
+ // `.records.egress_disclosure` (invisible to every documented/tested
935
+ // caller and to JSON.stringify). See CR-01, 254-REVIEW.md.
936
+ const normalized = { records: result };
937
+ if (Object.prototype.hasOwnProperty.call(result, 'egress_disclosure')) {
938
+ normalized.egress_disclosure = result.egress_disclosure;
939
+ // `normalized.records` is the SAME array reference as `result` (not a
940
+ // copy), so without this the stray non-index property would still sit
941
+ // on it after normalization -- accessible via result.records.egress_disclosure
942
+ // even though the documented, tested contract is the top-level field
943
+ // above. Deleting closes the "silently relocates" failure mode WR-02
944
+ // flagged, not just CR-01's missing top-level copy.
945
+ delete result.egress_disclosure;
946
+ }
947
+ return normalized;
948
+ }
949
+ if (result && Array.isArray(result.records)) return result; // already normalized (defensive)
950
+ // Theo's brain_query contract shape: { rows, diagnostics }. Guard on
951
+ // Array.isArray(result.rows), never mere key presence, so a malformed
952
+ // `rows` value still falls through to the safety net below. Placed
953
+ // adjacent to the other shape checks so all shape recognition stays in
954
+ // one block, ahead of the fallback. Theo's error envelope is
955
+ // { text: 'CODE: detail' } and carries no `rows`, so this branch can
956
+ // never swallow an error.
957
+ if (result && Array.isArray(result.rows)) {
958
+ return Object.assign({}, result, { records: result.rows });
959
+ }
960
+ if (result && (result.error || result.text)) return result; // error / message passthrough
961
+ return _unrecognizedQueryShape(result);
962
+ }
963
+
964
+ // ----------------------------------------------------------------------------
965
+ // _unrecognizedQueryShape -- the query() safety net, made loud (2026-09-03,
966
+ // quick/260903-eit). Mirrors the _legacyPathWarned / _warnLegacyOnce idiom
967
+ // this file already documents as "the existing once-per-process warning
968
+ // pattern in this file".
969
+ //
970
+ // CANON PART 8: key NAMES only, never VALUES. A Brain response envelope's
971
+ // top-level key names are generic schema handles; its values may carry graph
972
+ // payload. Neither the returned `shape_keys` nor the warning line may ever
973
+ // contain a value from the response body.
974
+ // ----------------------------------------------------------------------------
975
+
976
+ let _queryShapeWarned = false;
977
+
978
+ function _unrecognizedQueryShape(result) {
979
+ const shapeType = typeof result;
980
+ // Arrays never reach here in practice (Array.isArray(result) is caught by
981
+ // the branch above), but keep the check anyway so this helper stays
982
+ // correct even if it is ever called from elsewhere.
983
+ const isPlainObject =
984
+ result !== null && shapeType === 'object' && !Array.isArray(result);
985
+ const shapeKeys = isPlainObject
986
+ ? Object.keys(result)
987
+ .slice(0, 12) // cap key count so a hostile/malformed envelope can't flood the log
988
+ .map((k) => String(k).slice(0, 64)) // cap key length for the same reason
989
+ : []; // never Object.keys() a string -- that yields character indices, not key names
990
+
991
+ if (!_queryShapeWarned) {
992
+ _queryShapeWarned = true;
993
+ // eslint-disable-next-line no-console
994
+ console.warn(
995
+ '[mindrian-os] brain_query_unrecognized_shape: the Brain returned a '
996
+ + 'response shape (' + shapeType + ', keys: [' + shapeKeys.join(', ') + ']) '
997
+ + 'that query() does not recognize. This is a CONTRACT MISMATCH, NOT an '
998
+ + 'empty answer -- the caller still receives records: [] so it does not '
999
+ + 'crash, but every downstream reader should treat this as unresolved '
1000
+ + 'until the response contract is reconciled.'
1001
+ );
1002
+ }
1003
+
1004
+ return {
1005
+ records: [],
1006
+ error: 'brain_query_unrecognized_shape',
1007
+ shape_type: shapeType,
1008
+ shape_keys: shapeKeys,
1009
+ };
1010
+ }
1011
+
1012
+ /**
1013
+ * Search Pinecone via Brain (semantic search).
1014
+ * If quota exhausted, returns error with fallback suggestion.
1015
+ */
1016
+ async function search(queryText, options = {}) {
1017
+ const result = await callTool('brain_search', {
1018
+ query: queryText,
1019
+ namespace: options.namespace || undefined,
1020
+ topK: options.topK || 5,
1021
+ });
1022
+
1023
+ // Check for Pinecone quota exhaustion
1024
+ if (result && result.text && result.text.includes('RESOURCE_EXHAUSTED')) {
1025
+ return {
1026
+ error: 'pinecone_quota_exhausted',
1027
+ message: 'Pinecone embedding quota exhausted for this month. Using Neo4j Cypher fallback.',
1028
+ fallback: 'neo4j',
1029
+ };
1030
+ }
1031
+
1032
+ return result;
1033
+ }
1034
+
1035
+ /**
1036
+ * Search with automatic fallback: Pinecone first, Neo4j Cypher if quota exhausted.
1037
+ */
1038
+ async function smartSearch(queryText, options = {}) {
1039
+ // Try Pinecone first
1040
+ const pineconeResult = await search(queryText, options);
1041
+
1042
+ if (pineconeResult && pineconeResult.error === 'pinecone_quota_exhausted') {
1043
+ // Fallback to Neo4j full-text search
1044
+ const cypher = `
1045
+ CALL db.index.fulltext.queryNodes("framework_search", $query)
1046
+ YIELD node, score
1047
+ RETURN node.name AS name, node.description AS description, score
1048
+ LIMIT ${options.topK || 5}
1049
+ `;
1050
+ const neo4jResult = await query(cypher.replace('$query', `"${sanitizeCypherInput(queryText)}"`));
1051
+ if (neo4jResult) {
1052
+ neo4jResult._source = 'neo4j_fallback';
1053
+ neo4jResult._note = 'Pinecone quota exhausted. Results from Neo4j Cypher fulltext search.';
1054
+ }
1055
+ return neo4jResult;
1056
+ }
1057
+
1058
+ return pineconeResult;
1059
+ }
1060
+
1061
+ // brain_schema is near-static (the teaching graph's label/relationship/property
1062
+ // taxonomy changes ~never) and is hit by several modules. Memoize it
1063
+ // process-wide for 30 minutes.
1064
+ //
1065
+ // Phase 339 (2026-09-03, FLIP-05, D-13 as corrected): _schemaCacheOrigin
1066
+ // (declared beside _schemaCacheAt below) keys the memo on the resolved
1067
+ // origin (getBrainUrl()'s own value, compared by identity), so a cached
1068
+ // schema can never be served across an origin change. The correction this
1069
+ // comment states plainly so the next reader does not re-derive it:
1070
+ // BRAIN_URL is a module-scope const resolved once at require time, so no
1071
+ // running process can ever OBSERVE an origin change -- this guard is
1072
+ // therefore provably inert against the incumbent today (the comparison
1073
+ // below is always true within one process). It ships anyway as defense in
1074
+ // depth: it becomes load-bearing the day anything makes the origin mutable
1075
+ // per process, which is exactly the class of future change that would
1076
+ // otherwise reintroduce this bug silently. By the same reasoning, no
1077
+ // exported flush-the-memo function exists here BY DECISION: it would have
1078
+ // zero callers (nothing can observe the origin change it would be flushing
1079
+ // for), which Canon Part 7 and this repo's dead-surface discipline both
1080
+ // argue against; tests/test-339-schema-memo-origin-keyed.cjs Arm 7 asserts
1081
+ // its absence. Flip-day answer for 09-MOS-LEARNING's addendum, verbatim:
1082
+ // "no flush needed: memo is process-local, keyed by origin since beta.17".
1083
+ let _schemaCache = null;
1084
+ let _schemaCacheAt = 0;
1085
+ let _schemaCacheOrigin = null;
1086
+ const SCHEMA_CACHE_TTL_MS = 30 * 60 * 1000;
1087
+
1088
+ /**
1089
+ * Get the Brain Neo4j schema (node labels, relationship types, property keys).
1090
+ * Memoized for 30 minutes (process-wide), keyed on the resolved origin.
1091
+ */
1092
+ async function schema() {
1093
+ if (
1094
+ _schemaCache &&
1095
+ _schemaCacheOrigin === getBrainUrl() &&
1096
+ (Date.now() - _schemaCacheAt) < SCHEMA_CACHE_TTL_MS
1097
+ ) {
1098
+ return _schemaCache;
1099
+ }
1100
+ const result = await callTool('brain_schema', {});
1101
+ // Phase 247-02 audit fix (Rule 1): a sentinel object (tier_denied /
1102
+ // invalid_key -- anything carrying .error) is NOT valid schema data. Caching
1103
+ // it would serve a stale denial for up to 30 minutes even after the Brain
1104
+ // recovers or the key is fixed. Only cache a genuine, error-free result.
1105
+ if (result != null && !(typeof result === 'object' && result.error)) {
1106
+ _schemaCache = result;
1107
+ _schemaCacheAt = Date.now();
1108
+ _schemaCacheOrigin = getBrainUrl();
1109
+ }
1110
+ return result;
1111
+ }
1112
+
1113
+ /**
1114
+ * Natural-language methodology question against the Brain (wraps brain_ask).
1115
+ *
1116
+ * brain_ask auto-routes Pinecone/Neo4j server-side and handles its own
1117
+ * fallback -- it is the highest-level Brain entry point. Prefer it over a
1118
+ * hand-rolled Cypher query when the caller has a natural-language methodology
1119
+ * question. Canon Part 8: the question string carries only generic methodology
1120
+ * language -- never user artifacts, meeting text, or personal identifiers.
1121
+ *
1122
+ * Returns the parsed brain_ask payload ({ question, keyword, source, count,
1123
+ * results: [...] }) on success; a { text: 'Error: ...' } / { error: ... }
1124
+ * passthrough on a server-side error; null when the Brain is unreachable or no
1125
+ * API key is configured (graceful degradation -- mirrors query()).
1126
+ *
1127
+ * @param {string} question
1128
+ * @returns {Promise<object|null>}
1129
+ */
1130
+ async function ask(question) {
1131
+ if (typeof question !== 'string' || !question.trim()) return null;
1132
+ return callTool('brain_ask', { question: question });
1133
+ }
1134
+
1135
+ /**
1136
+ * Curated-op call against the Brain (the `op` MODE of brain_ask).
1137
+ *
1138
+ * brain_ask gained an optional curated-op surface (BUG 2 fix). Where ask()
1139
+ * runs the natural-language directive path, askOp() runs one of a closed set
1140
+ * of named, parameterized operations the Brain resolves to a FROZEN
1141
+ * server-side Cypher string. The three ops:
1142
+ *
1143
+ * - 'list_frameworks' params { limit? } -> rows { name, description, category }
1144
+ * - 'framework_edges' params { edge_type, limit? } -> rows { from, to, confidence, transform }
1145
+ * or { framework, problem_type }
1146
+ * - 'framework_chain_slice' params { seeds, max_hops?, limit? } -> rows { from, to, hop_distance }
1147
+ *
1148
+ * Canon Part 8: every param is a generic methodology handle (framework name,
1149
+ * closed enum, integer) -- never user content. No caller Cypher is ever sent;
1150
+ * the Brain owns the query text. This path is ungated -- any valid key may
1151
+ * call it (only query()/write() touch the admin-gated tools).
1152
+ *
1153
+ * Consumers that only need a framework chain for ONE anchor keep using
1154
+ * ask(question) and read next_gate.options[].framework (the directive path).
1155
+ *
1156
+ * Returns the parsed curated-op payload { op, source, count, rows, degraded? }
1157
+ * on success. On any transport / parse failure (Brain unreachable, no API key,
1158
+ * bad payload) returns a graceful { op, count: 0, rows: [], degraded: true } so
1159
+ * the caller never crashes -- mirrors query()'s graceful-degradation contract.
1160
+ *
1161
+ * @param {string} operation - one of the three curated op names
1162
+ * @param {object} [params] - generic-handles-only params object
1163
+ * @returns {Promise<{op: string, source?: string, count: number, rows: Array, degraded?: boolean}>}
1164
+ */
1165
+ async function askOp(operation, params = {}) {
1166
+ try {
1167
+ const result = await callTool('brain_ask', { op: operation, params: params || {} });
1168
+ // callTool already parses the JSON text payload of the MCP content item,
1169
+ // so a well-formed curated-op response arrives as the payload object.
1170
+ if (result && typeof result === 'object'
1171
+ && typeof result.count === 'number' && Array.isArray(result.rows)) {
1172
+ return {
1173
+ op: result.op || operation,
1174
+ source: result.source,
1175
+ count: result.count,
1176
+ rows: result.rows,
1177
+ ...(result.degraded ? { degraded: true } : {}),
1178
+ };
1179
+ }
1180
+ // Unreachable Brain (null), an error/text passthrough, or any unexpected
1181
+ // shape -> graceful degraded sentinel.
1182
+ return { op: operation, count: 0, rows: [], degraded: true };
1183
+ } catch (_err) {
1184
+ return { op: operation, count: 0, rows: [], degraded: true };
1185
+ }
1186
+ }
1187
+
1188
+ /**
1189
+ * Get Pinecone stats.
1190
+ */
1191
+ async function stats() {
1192
+ return callTool('brain_stats', {});
1193
+ }
1194
+
1195
+ /**
1196
+ * Return the resolved Brain endpoint (BRAIN_URL above, the module-level
1197
+ * single source of truth). The doctor store-identity sense (class-m-brain-
1198
+ * smoke.cjs layer 6) needs to report which endpoint the wire actually
1199
+ * resolved to, so it must read that value from the one place that decides
1200
+ * it rather than duplicating the canon literal as a second source of truth.
1201
+ *
1202
+ * @returns {string}
1203
+ */
1204
+ function getBrainUrl() {
1205
+ return BRAIN_URL;
1206
+ }
1207
+
1208
+ /**
1209
+ * Enrich local graph with causal edges from Brain's teaching graph.
1210
+ *
1211
+ * Queries the Brain Neo4j for causal framework chains relevant to the
1212
+ * given problem type or section keywords. Returns structured causal data
1213
+ * suitable for writing to local SQLite graph as CAUSES/ROOT_CAUSE_OF edges.
1214
+ *
1215
+ * @param {string} problemType - Room problem type (e.g., 'market-validation')
1216
+ * @param {string[]} sectionKeywords - Keywords from room sections for context
1217
+ * @param {object} [options] - Optional config
1218
+ * @param {number} [options.maxChainDepth=3] - Maximum causal chain depth
1219
+ * @param {number} [options.minConfidence=0.5] - Minimum confidence threshold
1220
+ * @returns {Promise<{ causes: Array, rootCauses: Array } | null>}
1221
+ * causes: [{ from, to, mechanism, confidence, framework }]
1222
+ * rootCauses: [{ from, to, chainLength, intermediateCauses, confidence }]
1223
+ */
1224
+ async function enrichCausalEdges(problemType, sectionKeywords, options = {}) {
1225
+ if (!isAvailable()) return null;
1226
+
1227
+ // SEC-01 defence-in-depth: coerce + bound numeric interpolants so a hostile
1228
+ // non-number (e.g. an object with .toString() side-effects) cannot reach
1229
+ // the Cypher string.
1230
+ const maxDepth = Math.max(1, Math.min(10, Number(options.maxChainDepth) || 3));
1231
+ const minConf = Math.max(0, Math.min(1, Number(options.minConfidence) || 0.5));
1232
+ const keywordFilter = sectionKeywords && sectionKeywords.length > 0
1233
+ ? sectionKeywords.map(k => `"${sanitizeCypherInput(k)}"`).join(', ')
1234
+ : '';
1235
+
1236
+ // Query 1: Direct causal relationships from framework chains
1237
+ const causesCypher = `
1238
+ MATCH (f1:Framework)-[r:ADDRESSES_PROBLEM_TYPE]->(pt:ProblemType)
1239
+ WHERE pt.name CONTAINS "${sanitizeCypherInput(problemType || '')}"
1240
+ WITH f1
1241
+ MATCH (f1)-[co:CO_OCCURS]->(f2:Framework)
1242
+ WHERE co.weight >= ${minConf}
1243
+ RETURN f1.name AS cause_framework,
1244
+ f2.name AS effect_framework,
1245
+ co.weight AS confidence,
1246
+ f1.description AS mechanism
1247
+ LIMIT 20
1248
+ `;
1249
+
1250
+ // Query 2: Root cause chains (multi-hop framework dependencies)
1251
+ const rootCauseCypher = `
1252
+ MATCH path = (root:Framework)-[:CO_OCCURS*1..${maxDepth}]->(leaf:Framework)
1253
+ WHERE root <> leaf
1254
+ ${keywordFilter ? `AND ANY(k IN [${keywordFilter}] WHERE root.name CONTAINS k OR root.description CONTAINS k)` : ''}
1255
+ WITH root, leaf, path, length(path) AS depth
1256
+ WHERE depth >= 2
1257
+ RETURN root.name AS root_cause,
1258
+ leaf.name AS symptom,
1259
+ depth AS chain_length,
1260
+ [n IN nodes(path) | n.name] AS chain_nodes
1261
+ LIMIT 10
1262
+ `;
1263
+
1264
+ try {
1265
+ const [causesResult, rootCausesResult] = await Promise.all([
1266
+ query(causesCypher),
1267
+ query(rootCauseCypher),
1268
+ ]);
1269
+
1270
+ const causes = [];
1271
+ const rootCauses = [];
1272
+
1273
+ // Parse causes
1274
+ if (causesResult && Array.isArray(causesResult.records)) {
1275
+ for (const rec of causesResult.records) {
1276
+ causes.push({
1277
+ from: rec.cause_framework || rec[0],
1278
+ to: rec.effect_framework || rec[1],
1279
+ mechanism: rec.mechanism || rec[3] || '',
1280
+ confidence: parseFloat(rec.confidence || rec[2] || 0),
1281
+ framework: rec.cause_framework || rec[0] || '',
1282
+ });
1283
+ }
1284
+ }
1285
+
1286
+ // Parse root causes
1287
+ if (rootCausesResult && Array.isArray(rootCausesResult.records)) {
1288
+ for (const rec of rootCausesResult.records) {
1289
+ rootCauses.push({
1290
+ from: rec.root_cause || rec[0],
1291
+ to: rec.symptom || rec[1],
1292
+ chainLength: parseInt(rec.chain_length || rec[2] || 1, 10),
1293
+ intermediateCauses: rec.chain_nodes || rec[3] || [],
1294
+ confidence: 1.0 / (parseInt(rec.chain_length || rec[2] || 1, 10) + 1),
1295
+ });
1296
+ }
1297
+ }
1298
+
1299
+ return { causes, rootCauses };
1300
+ } catch (err) {
1301
+ // Brain query failed -- return null for graceful degradation
1302
+ return null;
1303
+ }
1304
+ }
1305
+
1306
+ /**
1307
+ * Hat-aware framework recommendation.
1308
+ *
1309
+ * Reads persistent hat states and adjusts Brain framework queries:
1310
+ * - Black Hat concerns boost risk-related frameworks (Risk Matrix, SWOT threats)
1311
+ * - Yellow Hat opportunities boost HSI scoring and opportunity frameworks
1312
+ * - Blue Hat methodology notes avoid repeating ineffective frameworks
1313
+ *
1314
+ * @param {string} roomDir - Absolute path to room directory
1315
+ * @param {string} problemType - Room problem type
1316
+ * @param {object} [options] - Optional config
1317
+ * @param {number} [options.topK=5] - Number of frameworks to return
1318
+ * @returns {Promise<{ frameworks: Array, hat_influence: object } | null>}
1319
+ */
1320
+ async function hatAwareRecommend(roomDir, problemType, options = {}) {
1321
+ if (!isAvailable()) return null;
1322
+
1323
+ // Lazy-require to avoid circular dependency at module load time
1324
+ const { loadAllHatStates } = require('./hat-persistence.cjs');
1325
+ const hatStates = loadAllHatStates(roomDir);
1326
+ // SEC-01 defence-in-depth: bound topK numeric interpolation.
1327
+ const topK = Math.max(1, Math.min(100, Number(options.topK) || 5));
1328
+
1329
+ const hatInfluence = {
1330
+ risk_boost: false,
1331
+ opportunity_boost: false,
1332
+ avoid_frameworks: [],
1333
+ };
1334
+
1335
+ // Black Hat: if concerns exist, boost risk-related frameworks
1336
+ const blackConcerns = hatStates.black.top_concerns || [];
1337
+ const riskBoost = blackConcerns.length > 0;
1338
+ hatInfluence.risk_boost = riskBoost;
1339
+
1340
+ // Yellow Hat: if opportunities exist, boost HSI/opportunity frameworks
1341
+ const yellowOpps = hatStates.yellow.top_opportunities || [];
1342
+ const oppBoost = yellowOpps.length > 0;
1343
+ hatInfluence.opportunity_boost = oppBoost;
1344
+
1345
+ // Blue Hat: methodology notes may flag ineffective frameworks to avoid
1346
+ const blueNotes = hatStates.blue.methodology_notes || [];
1347
+
1348
+ // Part 8 raw-field egress guard (Phase 239 / BRAIN-02, threats T2, T4, T5).
1349
+ // Classifies the RAW problemType and each RAW blueNotes entry BEFORE
1350
+ // sanitizeCypherInput and BEFORE any Cypher interpolation below -- the raw
1351
+ // field is the only place the content signal is still intact. MEASURED:
1352
+ // classifying the ASSEMBLED cypher string instead would let the template's
1353
+ // own vocabulary word "Framework" launder an embedded canary from ambiguous
1354
+ // to allow, and sanitizeCypherInput strips the char the Part-8 PII pattern
1355
+ // keys on. Fail-closed: any missing or non-allow verdict skips the Brain leg.
1356
+ for (const rawField of [problemType].concat(blueNotes)) {
1357
+ let hatEgressVerdict = null;
1358
+ try {
1359
+ const hatEgressGuard = require('./part8-egress-guard.cjs');
1360
+ hatEgressVerdict = hatEgressGuard.classify(
1361
+ { question: String(rawField || '') },
1362
+ { toolName: 'brain_ask' }
1363
+ );
1364
+ } catch (_e) {
1365
+ hatEgressVerdict = null;
1366
+ }
1367
+ if (!hatEgressVerdict || hatEgressVerdict.verdict !== 'allow') {
1368
+ _logEventBestEffort(options.db, 'brain_egress_blocked', {
1369
+ egress_class: (hatEgressVerdict && hatEgressVerdict.class) || 'unknown',
1370
+ verdict: (hatEgressVerdict && hatEgressVerdict.verdict) || 'unverified',
1371
+ count: 1,
1372
+ created_by: 'system',
1373
+ source_path: 'system:brain-hat-recommend',
1374
+ });
1375
+ return null;
1376
+ }
1377
+ }
1378
+
1379
+ const avoidPatterns = blueNotes
1380
+ .filter(n => /ineffective|didn't work|not useful|skip|avoid/i.test(n))
1381
+ .map(n => {
1382
+ // Extract framework name from notes like "SWOT was ineffective for this stage"
1383
+ const match = n.match(/^(\w[\w\s]+?)\s+(?:was|is|were|proved)\s/i);
1384
+ return match ? match[1].trim() : null;
1385
+ })
1386
+ .filter(Boolean);
1387
+ hatInfluence.avoid_frameworks = avoidPatterns;
1388
+
1389
+ // Build Cypher query with hat-influenced scoring
1390
+ const safeProblemType = sanitizeCypherInput(problemType || '');
1391
+ const avoidClause = avoidPatterns.length > 0
1392
+ ? `AND NOT ANY(avoid IN [${avoidPatterns.map(a => `"${sanitizeCypherInput(a)}"`).join(', ')}] WHERE f.name CONTAINS avoid)`
1393
+ : '';
1394
+
1395
+ // Query: frameworks for problem type, with hat-influenced ordering
1396
+ const cypher = `
1397
+ MATCH (f:Framework)-[:ADDRESSES_PROBLEM_TYPE]->(pt:ProblemType)
1398
+ WHERE pt.name CONTAINS "${safeProblemType}"
1399
+ ${avoidClause}
1400
+ WITH f
1401
+ OPTIONAL MATCH (f)-[co:CO_OCCURS]->(f2:Framework)
1402
+ WITH f, count(co) AS connections
1403
+ RETURN f.name AS name,
1404
+ f.description AS description,
1405
+ connections,
1406
+ CASE
1407
+ WHEN ${riskBoost ? 'true' : 'false'} AND (f.name CONTAINS 'Risk' OR f.name CONTAINS 'SWOT' OR f.name CONTAINS 'Failure') THEN connections + 10
1408
+ WHEN ${oppBoost ? 'true' : 'false'} AND (f.name CONTAINS 'HSI' OR f.name CONTAINS 'Opportunity' OR f.name CONTAINS 'Innovation') THEN connections + 10
1409
+ ELSE connections
1410
+ END AS hat_score
1411
+ ORDER BY hat_score DESC
1412
+ LIMIT ${topK}
1413
+ `;
1414
+
1415
+ try {
1416
+ const result = await query(cypher);
1417
+ const frameworks = [];
1418
+
1419
+ if (result && Array.isArray(result.records)) {
1420
+ for (const rec of result.records) {
1421
+ frameworks.push({
1422
+ name: rec.name || rec[0],
1423
+ description: rec.description || rec[1],
1424
+ connections: parseInt(rec.connections || rec[2] || 0, 10),
1425
+ hat_score: parseInt(rec.hat_score || rec[3] || 0, 10),
1426
+ });
1427
+ }
1428
+ }
1429
+
1430
+ return {
1431
+ frameworks,
1432
+ hat_influence: hatInfluence,
1433
+ black_concerns: blackConcerns.slice(0, 3),
1434
+ yellow_opportunities: yellowOpps.slice(0, 3),
1435
+ blue_avoid: avoidPatterns,
1436
+ };
1437
+ } catch (err) {
1438
+ return null;
1439
+ }
1440
+ }
1441
+
1442
+ /**
1443
+ * Suggest validation steps for a banked opportunity using Brain framework chains.
1444
+ *
1445
+ * Queries Brain Neo4j for frameworks that ADDRESSES_PROBLEM_TYPE matching the
1446
+ * opportunity's domain/problem, then follows FEEDS_INTO chains to build a
1447
+ * suggested validation sequence.
1448
+ *
1449
+ * @param {Object} opportunity - Opportunity object with at minimum: problem, domain, knight_position
1450
+ * @param {Object} [options] - Optional config
1451
+ * @param {number} [options.maxSteps=5] - Maximum validation steps to return
1452
+ * @param {number} [options.chainDepth=3] - Maximum FEEDS_INTO chain depth
1453
+ * @returns {Promise<{ steps: Array<{framework: string, reason: string, order: number}>, chain_source: string } | null>}
1454
+ * Returns null if Brain unavailable (Tier 0 graceful degradation)
1455
+ */
1456
+ async function suggestValidationSteps(opportunity, options = {}) {
1457
+ if (!isAvailable()) return null;
1458
+ if (!opportunity || !opportunity.problem) return null;
1459
+
1460
+ // Part 8 raw-field egress guard (Phase 239 / BRAIN-02, threats T2, T4, T5).
1461
+ // Classifies the RAW opportunity.domain and the RAW opportunity.problem
1462
+ // BEFORE sanitizeCypherInput and BEFORE any Cypher interpolation below --
1463
+ // strictly upstream of sanitizeCypherInput, which is the entire point.
1464
+ // MEASURED: sanitizeCypherInput strips the '@' the Part-8 email pattern
1465
+ // keys on (jane@startup.com -> janestartup.com), flipping a block verdict
1466
+ // into an allow. Classifying the ASSEMBLED cypher string instead would also
1467
+ // let the template's own vocabulary word "Framework" launder an embedded
1468
+ // canary from ambiguous to allow. Fail-closed: any missing or non-allow
1469
+ // verdict skips the Brain leg entirely.
1470
+ for (const rawField of [opportunity.domain, opportunity.problem]) {
1471
+ let validationEgressVerdict = null;
1472
+ try {
1473
+ const validationEgressGuard = require('./part8-egress-guard.cjs');
1474
+ validationEgressVerdict = validationEgressGuard.classify(
1475
+ { question: String(rawField || '') },
1476
+ { toolName: 'brain_ask' }
1477
+ );
1478
+ } catch (_e) {
1479
+ validationEgressVerdict = null;
1480
+ }
1481
+ if (!validationEgressVerdict || validationEgressVerdict.verdict !== 'allow') {
1482
+ _logEventBestEffort(options.db, 'brain_egress_blocked', {
1483
+ egress_class: (validationEgressVerdict && validationEgressVerdict.class) || 'unknown',
1484
+ verdict: (validationEgressVerdict && validationEgressVerdict.verdict) || 'unverified',
1485
+ count: 1,
1486
+ created_by: 'system',
1487
+ source_path: 'system:brain-validation-steps',
1488
+ });
1489
+ return null;
1490
+ }
1491
+ }
1492
+
1493
+ const maxSteps = options.maxSteps || 5;
1494
+ const chainDepth = options.chainDepth || 3;
1495
+ const safeProblem = sanitizeCypherInput(opportunity.problem || '').substring(0, 200);
1496
+ const safeDomain = sanitizeCypherInput(opportunity.domain || '').substring(0, 100);
1497
+ const safeKnight = opportunity.knight_position || 'uncertainty';
1498
+
1499
+ // Query 1: Find frameworks that address this problem type / domain
1500
+ const matchCypher = `
1501
+ MATCH (f:Framework)-[:ADDRESSES_PROBLEM_TYPE]->(pt:ProblemType)
1502
+ WHERE pt.name CONTAINS "${safeDomain}"
1503
+ OR pt.description CONTAINS "${safeDomain}"
1504
+ RETURN f.name AS name, f.description AS description
1505
+ LIMIT 10
1506
+ `;
1507
+
1508
+ // Query 2: Follow FEEDS_INTO chains from matched frameworks
1509
+ const chainCypher = `
1510
+ MATCH (f:Framework)-[:ADDRESSES_PROBLEM_TYPE]->(pt:ProblemType)
1511
+ WHERE pt.name CONTAINS "${safeDomain}"
1512
+ OR pt.description CONTAINS "${safeDomain}"
1513
+ WITH f LIMIT 3
1514
+ MATCH path = (f)-[:FEEDS_INTO*1..${chainDepth}]->(next:Framework)
1515
+ RETURN f.name AS start_framework,
1516
+ next.name AS next_framework,
1517
+ next.description AS next_description,
1518
+ length(path) AS depth
1519
+ ORDER BY depth ASC
1520
+ LIMIT ${maxSteps * 2}
1521
+ `;
1522
+
1523
+ try {
1524
+ const [matchResult, chainResult] = await Promise.all([
1525
+ query(matchCypher),
1526
+ query(chainCypher),
1527
+ ]);
1528
+
1529
+ const steps = [];
1530
+ const seen = new Set();
1531
+
1532
+ // First: add the entry-point frameworks
1533
+ if (matchResult && Array.isArray(matchResult.records)) {
1534
+ for (const rec of matchResult.records) {
1535
+ const name = rec.name || rec[0];
1536
+ if (name && !seen.has(name) && steps.length < maxSteps) {
1537
+ seen.add(name);
1538
+ steps.push({
1539
+ framework: name,
1540
+ reason: safeKnight === 'uncertainty'
1541
+ ? `Explore this ${safeDomain} uncertainty with ${name}`
1542
+ : `Validate this ${safeDomain} risk using ${name}`,
1543
+ order: steps.length + 1,
1544
+ });
1545
+ }
1546
+ }
1547
+ }
1548
+
1549
+ // Then: add FEEDS_INTO chain steps
1550
+ if (chainResult && Array.isArray(chainResult.records)) {
1551
+ for (const rec of chainResult.records) {
1552
+ const name = rec.next_framework || rec[1];
1553
+ const desc = rec.next_description || rec[2] || '';
1554
+ if (name && !seen.has(name) && steps.length < maxSteps) {
1555
+ seen.add(name);
1556
+ steps.push({
1557
+ framework: name,
1558
+ reason: desc ? `Then apply ${name}: ${desc.substring(0, 120)}` : `Then apply ${name} (follows from chain)`,
1559
+ order: steps.length + 1,
1560
+ });
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+ if (steps.length === 0) return null;
1566
+
1567
+ return {
1568
+ steps,
1569
+ chain_source: 'brain_feeds_into',
1570
+ };
1571
+ } catch (err) {
1572
+ // Brain query failed -- graceful degradation
1573
+ return null;
1574
+ }
1575
+ }
1576
+
1577
+ /**
1578
+ * Write Cypher to Neo4j via Brain (write operations).
1579
+ * Used by sync-rooms-brain for creating Room/RoomGroup nodes and edges.
1580
+ * Returns null if Brain is unavailable -- never throws.
1581
+ *
1582
+ * NOTE (Finding I sibling, v1.10.9 hotfix 2026-04-15): same param-name
1583
+ * mismatch as brain_query had. Brain MCP brain_write expects `cypher`,
1584
+ * not `query`. This function had the mirror bug since inception but
1585
+ * never fired in production because sync-rooms-brain is rarely invoked
1586
+ * against the live Brain. Caught by the plan-checker audit for Phase 85.
1587
+ *
1588
+ * @param {string} cypher - Cypher write query
1589
+ * @returns {Promise<object|null>}
1590
+ */
1591
+ async function write(cypher) {
1592
+ return callTool('brain_write', { cypher: cypher });
1593
+ }
1594
+
1595
+ // ============================================================================
1596
+ // Loop-contract read wrappers (Phase 247-02, CONTRACT-01).
1597
+ // ============================================================================
1598
+ //
1599
+ // Thin pass-through wrappers over callTool for the five loop-contract tools
1600
+ // that had NO client wrapper before this phase (data/brain-surface-contract.json
1601
+ // is the source of truth for the tool name + arg-key shape each wrapper below
1602
+ // must emit; tests/test-247-contract-client.cjs derives its expectations from
1603
+ // that file, not from this comment). brain_stats is the sixth loop-contract
1604
+ // tool and already has a wrapper: stats() above.
1605
+ //
1606
+ // Every wrapper is a straight callTool(name, args) call with NO result
1607
+ // reshaping -- the tier_denied / invalid_key sentinels and the transport-null
1608
+ // pass through unchanged, exactly like write() and stats() already do.
1609
+ // Part 7 (extend, never a fourth brain skill): these live in this file.
1610
+ //
1611
+ // loopSearch() is named to avoid colliding with the existing search() export
1612
+ // above, which wraps the DIFFERENT brain_search tool (Pinecone semantic
1613
+ // search with quota-fallback handling). The loop-contract `search` tool is a
1614
+ // distinct, simpler read tool -- same English word, different Brain tool,
1615
+ // different client function, deliberately renamed so callers cannot conflate
1616
+ // them.
1617
+
1618
+ /**
1619
+ * Loop-contract `normalize_framework_name` tool.
1620
+ * @param {string} raw
1621
+ * @returns {Promise<object|null>}
1622
+ */
1623
+ async function normalizeFrameworkName(raw) {
1624
+ return callTool('normalize_framework_name', { raw: raw });
1625
+ }
1626
+
1627
+ /**
1628
+ * Loop-contract `search` tool (NOT brain_search -- see module-level note above).
1629
+ * @param {string} queryText
1630
+ * @param {number} [topK]
1631
+ * @returns {Promise<object|null>}
1632
+ */
1633
+ async function loopSearch(queryText, topK) {
1634
+ return callTool('search', { query: queryText, topK: topK });
1635
+ }
1636
+
1637
+ // ----------------------------------------------------------------------------
1638
+ // Phase 249-01 (ENRICH-01) -- capture-on-miss for the two readiness-shaped
1639
+ // loop wrappers below. NEITHER wrapper reshapes its return value (247-02's
1640
+ // "zero result reshaping so sentinels propagate unchanged" is preserved
1641
+ // here); capture happens in a try/catch side branch AFTER resolution, and
1642
+ // the raw callTool result is returned unchanged in every case, including
1643
+ // when the capture branch itself fails. opts is OPTIONAL and backward
1644
+ // compatible: no opts / no opts.roomDir means zero capture, zero throw,
1645
+ // identical behavior to the pre-249 wrapper.
1646
+ //
1647
+ // Sentinel discipline: a result carrying .error (tier_denied, invalid_key)
1648
+ // or a null (transport failure) is NEVER a capture trigger -- failure
1649
+ // visibility is Phase 250's refusal territory, not an enrichment miss
1650
+ // (research "Where the readiness probe should run").
1651
+ //
1652
+ // Each successful capture logs a scalar enrichment_queue_captured
1653
+ // memory_event (framework handle + score only), mirroring the existing
1654
+ // brain_packet_rejected precedent's _logEventBestEffort mechanism above --
1655
+ // best-effort, silently skipped when opts.db is absent.
1656
+ // ----------------------------------------------------------------------------
1657
+
1658
+ function _isCapturableResult(result) {
1659
+ return result !== null && typeof result === 'object' && !result.error;
1660
+ }
1661
+
1662
+ function _maybeCaptureEnrichmentMiss(frameworkName, result, opts) {
1663
+ try {
1664
+ if (!opts || typeof opts !== 'object') return;
1665
+ if (typeof opts.roomDir !== 'string' || opts.roomDir.length === 0) return;
1666
+ if (!_isCapturableResult(result)) return;
1667
+ // eslint-disable-next-line global-require
1668
+ const enrichmentQueue = require('./enrichment-queue.cjs');
1669
+ const captureResult = enrichmentQueue.captureReadinessMiss(
1670
+ opts.roomDir, frameworkName, result, opts.contextClass || {}
1671
+ );
1672
+ if (captureResult && captureResult.queued) {
1673
+ _logEventBestEffort(opts.db, 'enrichment_queue_captured', {
1674
+ framework: frameworkName,
1675
+ // Phase 339 (2026-09-03, FLIP-03): recognizes Theo's orchestration_readiness
1676
+ // payload shape (result.score, an integer 0-4 whose practical ceiling is 3,
1677
+ // /home/jsagi/Theo/src/mcp/content/orchestration-readiness.ts:494) alongside
1678
+ // the incumbent's result.readiness_score, in the SAME expression, each
1679
+ // guarded by typeof === 'number' (D-04) and never on key presence. The
1680
+ // incumbent's field is checked first so today's log bytes stay identical
1681
+ // when both are somehow present. Deliberately does NOT rescale, does NOT
1682
+ // default a missing score to 0, and does NOT read coverage -- coverage
1683
+ // semantics live in the capture path in lib/core/enrichment-queue.cjs
1684
+ // (plan 339-05's territory). null is still the final fallback so an
1685
+ // unrecognized shape is honestly null rather than a coerced zero.
1686
+ readiness_score: (typeof result.readiness_score === 'number')
1687
+ ? result.readiness_score
1688
+ : ((typeof result.score === 'number') ? result.score : null),
1689
+ source_path: 'system:enrichment-queue',
1690
+ });
1691
+ }
1692
+ } catch (_e) {
1693
+ // Best-effort capture side branch: NEVER surfaces to the wrapper caller.
1694
+ }
1695
+ }
1696
+
1697
+ /**
1698
+ * Loop-contract `discover_structure` tool.
1699
+ *
1700
+ * @param {string} frameworkName
1701
+ * @param {object} [opts] - { roomDir?, contextClass?, db? }. Phase 249-01:
1702
+ * when opts.roomDir is set and the resolved payload carries
1703
+ * grounded === false, best-effort captures an enrichment-queue entry.
1704
+ * Absent opts / opts.roomDir: zero capture, zero throw, unchanged
1705
+ * backward-compatible behavior.
1706
+ * @returns {Promise<object|null>}
1707
+ */
1708
+ async function discoverStructure(frameworkName, opts) {
1709
+ const result = await callTool('discover_structure', { framework_name: frameworkName });
1710
+ _maybeCaptureEnrichmentMiss(frameworkName, result, opts);
1711
+ return result;
1712
+ }
1713
+
1714
+ /**
1715
+ * Loop-contract `orchestration_readiness` tool.
1716
+ *
1717
+ * @param {string} frameworkName
1718
+ * @param {object} [opts] - { roomDir?, contextClass?, db? }. Phase 249-01:
1719
+ * when opts.roomDir is set and the resolved payload carries
1720
+ * readiness_score <= 2, best-effort captures an enrichment-queue entry.
1721
+ * Absent opts / opts.roomDir: zero capture, zero throw, unchanged
1722
+ * backward-compatible behavior.
1723
+ * @returns {Promise<object|null>}
1724
+ */
1725
+ async function orchestrationReadiness(frameworkName, opts) {
1726
+ const result = await callTool('orchestration_readiness', { framework_name: frameworkName });
1727
+ _maybeCaptureEnrichmentMiss(frameworkName, result, opts);
1728
+ return result;
1729
+ }
1730
+
1731
+ /**
1732
+ * Loop-contract `feeds_into_chains` tool.
1733
+ * @param {string[]} seeds
1734
+ * @param {number} [maxHops]
1735
+ * @returns {Promise<object|null>}
1736
+ */
1737
+ async function feedsIntoChains(seeds, maxHops) {
1738
+ return callTool('feeds_into_chains', { seeds: seeds, max_hops: maxHops });
1739
+ }
1740
+
1741
+ // Quick 260819-c8j (WS-C1): the enum-only Part 8 shape gate for
1742
+ // recommendChain(), below. `problemTypeOf(tuple)` (lib/core/insight-
1743
+ // sensors.cjs) returns `tuple.problem_type` VERBATIM off the /mos:diagnose
1744
+ // tuple, so the `brain_framework_chain:<pt>` companion string is NOT
1745
+ // structurally guaranteed to be a Brain ProblemType enum -- it could carry
1746
+ // anything the classifier wrote. A handle-shaped token (letter-initial,
1747
+ // letters/digits/space/hyphen only, 1..49 chars) cannot carry prose, a
1748
+ // sentence, a URL, an email, or a payload, so this regex is the enum-only
1749
+ // enforcement at the wire: a non-handle input is refused locally with ZERO
1750
+ // network rather than forwarded and hoped-safe.
1751
+ const PROBLEM_TYPE_HANDLE_RE = /^[A-Za-z][A-Za-z0-9 -]{0,48}$/;
1752
+
1753
+ // Projects the LOCAL sensor slugs (`problemTypeOf`'s output shape) onto the
1754
+ // Brain's canonical ProblemType node names. This is a PROJECTION, not an
1755
+ // allow-list: an unmapped token still passes THROUGH _normalizeBrainProblemType
1756
+ // unchanged, because data/brain-census.generated.json records 26 live
1757
+ // ProblemType nodes on the Brain and this map names only the 3 the local
1758
+ // sensors are known to emit today -- a local allow-list would silently block
1759
+ // the other 23 valid types the Brain already knows how to answer.
1760
+ //
1761
+ // Deliberately NOT the same map as this file's sibling,
1762
+ // lib/brain/chain-recommender.cjs's PROBLEM_TYPE_ALIASES (:71 there): that
1763
+ // map projects onto the LOCAL router codes UDP/IDP/WDP (a different target,
1764
+ // consumed by problem-type-router.cjs), not onto Brain ProblemType node
1765
+ // names. The two are not shared on purpose, so a reader cannot conflate a
1766
+ // local router code with a Brain node name. This stays true of BOTH tables
1767
+ // below.
1768
+ //
1769
+ // Phase 339 (2026-09-03): TWO tables, not one, plus an origin-keyed
1770
+ // selector. Theo matches WHERE toLower(m.id) = toLower($problemType) AND
1771
+ // NOTHING MORE (/home/jsagi/Theo/src/mcp/content/recommend-chain.ts:320-321,
1772
+ // the matching rule stated at :65-69): no trimming, no hyphen folding, no
1773
+ // suffix stripping, no fuzzy fallback. The incumbent's target value
1774
+ // 'Undefined Problem' matches nothing on Theo's :DomainConcept nodes, whose
1775
+ // ids are the exact strings 'UnDefined' / 'IllDefined' / 'WellDefined' /
1776
+ // 'Wicked' / 'Trinity' / 'Compass' (recommend-chain.ts:27-47). A single
1777
+ // shared table can never be correct for both origins at once -- the map
1778
+ // ITSELF is what breaks the post-flip match, so the map itself is what this
1779
+ // phase fixes, before the flip ships, not with it.
1780
+ //
1781
+ // This mechanism deliberately does NOT key on a response, does not retry on
1782
+ // PROBLEM_TYPE_NOT_FOUND using available_problem_types, and does not sniff
1783
+ // the server. A runtime retry would cost a round trip on every miss, would
1784
+ // paper over a vocabulary bug at runtime instead of fixing it, and would
1785
+ // break the property this selector exists to preserve: a
1786
+ // MINDRIAN_BRAIN_URL revert moves vocabulary and URL together, with no
1787
+ // second edit anywhere.
1788
+ //
1789
+ // Canon Part 8: both tables carry problem-type handles only, closed
1790
+ // vocabulary, never room content.
1791
+ const BRAIN_PROBLEM_TYPE_ALIASES_INCUMBENT = Object.freeze({
1792
+ 'undefined': 'Undefined Problem',
1793
+ udp: 'Undefined Problem',
1794
+ 'ill-defined': 'Ill-Defined Problem',
1795
+ ill_defined: 'Ill-Defined Problem',
1796
+ idp: 'Ill-Defined Problem',
1797
+ 'well-defined': 'Well-Defined Problem',
1798
+ well_defined: 'Well-Defined Problem',
1799
+ wdp: 'Well-Defined Problem',
1800
+ });
1801
+
1802
+ const BRAIN_PROBLEM_TYPE_ALIASES_THEO = Object.freeze({
1803
+ 'undefined': 'UnDefined',
1804
+ udp: 'UnDefined',
1805
+ 'ill-defined': 'IllDefined',
1806
+ ill_defined: 'IllDefined',
1807
+ idp: 'IllDefined',
1808
+ 'well-defined': 'WellDefined',
1809
+ well_defined: 'WellDefined',
1810
+ wdp: 'WellDefined',
1811
+ });
1812
+
1813
+ // The set of Brain origins whose problem-type vocabulary is Theo's, not the
1814
+ // incumbent's. An ARRAY, not a bare string literal, so a Theo staging
1815
+ // origin is a one-line addition rather than a re-architecture. Exported so
1816
+ // lib/core/doctor/class-m-brain-smoke.cjs can key its per-origin node floor
1817
+ // on this SAME set (plan 339-12), rather than minting a second copy of the
1818
+ // origin list.
1819
+ const THEO_ORIGINS = Object.freeze(['https://theo-mcp.onrender.com']);
1820
+
1821
+ // Selects the alias table by the resolved origin (BRAIN_URL, the same
1822
+ // module-scope const getBrainUrl() reads). Anything not in THEO_ORIGINS
1823
+ // gets the incumbent vocabulary -- the correct default while line 24 names
1824
+ // the incumbent, and the conservative default afterwards for any origin
1825
+ // this set does not yet name.
1826
+ function _brainProblemTypeAliases() {
1827
+ return THEO_ORIGINS.indexOf(BRAIN_URL) !== -1
1828
+ ? BRAIN_PROBLEM_TYPE_ALIASES_THEO
1829
+ : BRAIN_PROBLEM_TYPE_ALIASES_INCUMBENT;
1830
+ }
1831
+
1832
+ /**
1833
+ * _normalizeBrainProblemType(raw) -> canonical string | null
1834
+ * null when raw is not a string, is empty after trim, or fails the
1835
+ * PROBLEM_TYPE_HANDLE_RE shape gate above. A known local slug (matched
1836
+ * case-insensitively on the trimmed token) projects to its Brain canonical
1837
+ * name; anything else well-shaped passes through unchanged for the Brain to
1838
+ * rule on honestly.
1839
+ * @param {*} raw
1840
+ * @returns {string|null}
1841
+ */
1842
+ function _normalizeBrainProblemType(raw) {
1843
+ if (typeof raw !== 'string') return null;
1844
+ const trimmed = raw.trim();
1845
+ if (trimmed.length === 0) return null;
1846
+ if (!PROBLEM_TYPE_HANDLE_RE.test(trimmed)) return null;
1847
+ const lc = trimmed.toLowerCase();
1848
+ const table = _brainProblemTypeAliases();
1849
+ if (Object.prototype.hasOwnProperty.call(table, lc)) {
1850
+ return table[lc];
1851
+ }
1852
+ return trimmed;
1853
+ }
1854
+
1855
+ /**
1856
+ * Loop-contract `recommend_chain` tool. A straight sibling of
1857
+ * feedsIntoChains() above: ZERO result reshaping, so sentinels
1858
+ * (tier_denied/invalid_key) and the transport-null pass through untouched
1859
+ * (247-02 convention) -- match its behavior byte-for-byte except for the
1860
+ * pre-wire shape gate this tool needs and the sibling above does not.
1861
+ *
1862
+ * Live output shape (verified live 2026-08-19 AND now contractually pinned):
1863
+ * { tool, backend, grounded, problem_type, seed_candidates,
1864
+ * chain: [{ step, framework, pagerank, edge_confidence, commands }],
1865
+ * note, execution_hint }
1866
+ * The Brain team froze recommend_chain as a v1 ADDITIVE-ONLY contract in
1867
+ * their own repo (ProblemsWorthSolving-Brain, docs/RECOMMEND-CHAIN-
1868
+ * CONTRACT.md, commit 721d8e1): under v1 these keys may gain siblings but
1869
+ * will not be renamed or removed, and an unknown problem type is GUARANTEED
1870
+ * to come back as { grounded: false, chain: [] } rather than an error or a
1871
+ * throw. This wrapper does not depend on any of that shape -- it is a pure
1872
+ * pass-through -- so a v2 or an out-of-contract change degrades at the
1873
+ * consumer (lib/brain/chain-recommender.cjs), never here.
1874
+ *
1875
+ * @param {string} problemType
1876
+ * @param {number} [maxSteps]
1877
+ * @returns {Promise<object|null>}
1878
+ */
1879
+ async function recommendChain(problemType, maxSteps) {
1880
+ const normalized = _normalizeBrainProblemType(problemType);
1881
+ if (normalized === null) {
1882
+ // Shape gate failed: refuse locally, zero network, zero key consumption,
1883
+ // zero auto-register attempt. T-c8j-01 mitigation.
1884
+ return { error: 'invalid_problem_type', tool: 'recommend_chain' };
1885
+ }
1886
+ const steps = Number.isInteger(maxSteps) && maxSteps >= 1 && maxSteps <= 6 ? maxSteps : 6;
1887
+ return callTool('recommend_chain', { problem_type: normalized, max_steps: steps });
1888
+ }
1889
+
1890
+ // Phase 252-01 (SWEEP-01, guard sweep) -- getTier0Chain() / getFrameworkChain()
1891
+ // DELETED here. They served hardcoded, non-graph-grounded persona chains
1892
+ // with `source: 'tier0'` -- the counterfeit core the 250-01 doctrine kill
1893
+ // list (site #11) marked but deferred flipping. Live grep at 252 execution
1894
+ // time confirmed zero CJS consumers outside this file; their only consumer
1895
+ // was the conversation-mode SKILL instruction (skills/conversation-mode/
1896
+ // SKILL.md), rewritten in this same task to follow the refusal rail instead
1897
+ // of calling either function. The 247-02 do-not-widen note on the null
1898
+ // branch (`callTool()`'s transport-failure contract) is untouched -- this
1899
+ // deletion removes a local fallback CHAIN, not the null contract.
1900
+
1901
+ // ============================================================================
1902
+ // Phase 110-03: Brain Context Packet wire enforcement (Canon Part 8 + Part 9).
1903
+ // ============================================================================
1904
+ //
1905
+ // sendPacket(packet, opts) is the SOLE typed-packet wire path. It runs:
1906
+ // (1) D-08 layer-3 origin allowlist (the belt to the schema's suspenders --
1907
+ // a caller who bypassed ajv still gets caught here).
1908
+ // (2) Unknown-job guard against the closed D-02 vocabulary (12 jobs).
1909
+ // (3) ajv in-validation (reject hard: throw + log brain_packet_rejected).
1910
+ // (4) POST tools/call name:'brain_packet' via the existing callTool transport
1911
+ // (degrade soft when the tool is absent: { advice:null, reason:
1912
+ // 'brain_packet_tool_absent' }; on transport error: { advice:null,
1913
+ // reason: 'brain_unreachable' }). Never throws on Brain-side problems.
1914
+ // (5) ajv out-validation (reject hard, degrade soft: log
1915
+ // brain_response_rejected + return { advice:null, reason:
1916
+ // 'response_schema_invalid' }). Never throws, never partial-ingests.
1917
+ // (6) Returns the validated out payload on success.
1918
+ //
1919
+ // ajv@8.18.0 is transitive via @modelcontextprotocol/sdk -- do NOT add it to
1920
+ // package.json (CLAUDE.md "What NOT to Use"). strict:false at runtime; the
1921
+ // strict:true build gate lives in scripts/build-brain-packet-schema.cjs. The
1922
+ // schema is draft 2020-12, so Ajv2020 is required (ajv/dist/2020).
1923
+ //
1924
+ // SHIPPED_JOBS is the D-02 closed vocabulary (locked in 110-CONTEXT D-02).
1925
+
1926
+ const Ajv2020 = require('ajv/dist/2020').default || require('ajv/dist/2020');
1927
+
1928
+ const _BRAIN_PACKET_SCHEMA_PATH = process.env.MINDRIAN_BRAIN_PACKET_SCHEMA
1929
+ || path.join(__dirname, '..', '..', 'data', 'brain-packet-schema.json');
1930
+
1931
+ const SHIPPED_JOBS = new Set([
1932
+ 'select_methodology',
1933
+ 'suggest_next_move',
1934
+ 'detect_contradiction',
1935
+ 'summarize_neighborhood',
1936
+ 'classify_room_budding',
1937
+ 'rank_assumptions',
1938
+ 'generate_feynman_explanation',
1939
+ 'strengthen_minto',
1940
+ 'prepare_investor_brief',
1941
+ 'opportunity_react',
1942
+ 'opportunity_reflect',
1943
+ 'opportunity_rank',
1944
+ ]);
1945
+
1946
+ let _ajv = null;
1947
+ let _schemaRaw = null;
1948
+ const _jobValidators = new Map(); // job -> { in: fn, out: fn }
1949
+
1950
+ /**
1951
+ * Lazily compile the brain-packet schema. Reads data/brain-packet-schema.json
1952
+ * (or process.env.MINDRIAN_BRAIN_PACKET_SCHEMA, the test seam set up by 110-01)
1953
+ * once at first use; subsequent calls reuse the in-memory Ajv instance.
1954
+ *
1955
+ * NOTE on the schema's pointer shape: the 110-01 schema's per-job $defs are
1956
+ * { in: {...}, out: {...} } -- NOT { properties: { in, out } }. So the JSON
1957
+ * pointer for a job half is #/$defs/<job>/<half>, not the planner's interfaces
1958
+ * sketch shape #/$defs/<job>/properties/<half>. Compiled wrappers carry the
1959
+ * root's $defs inline because ajv 8.x cannot resolve a deep JSON pointer into
1960
+ * a schema indexed only by its absolute $id (a known ajv@8 quirk -- the build
1961
+ * script in scripts/build-brain-packet-schema.cjs validates the root by
1962
+ * compiling it directly with the same Ajv2020 class).
1963
+ */
1964
+ function _ensureSchema() {
1965
+ if (_ajv) return;
1966
+ _schemaRaw = JSON.parse(fs.readFileSync(_BRAIN_PACKET_SCHEMA_PATH, 'utf8'));
1967
+ _ajv = new Ajv2020({ allErrors: true, strict: false });
1968
+ // Pre-add the root so cross-refs (FocusNode, Origin, BankedOpportunities,
1969
+ // BrainResponse, etc.) resolve when sub-schemas reference them. Wrapper
1970
+ // schemas below carry $defs inline as a defensive duplicate.
1971
+ _ajv.addSchema(_schemaRaw);
1972
+ }
1973
+
1974
+ /**
1975
+ * Return the memoized in/out validator for a given (job, half). Half is
1976
+ * 'in' or 'out'. Compiles on first use.
1977
+ *
1978
+ * @param {string} job - D-02 jobname (must be in SHIPPED_JOBS).
1979
+ * @param {'in'|'out'} half
1980
+ * @returns {Function} a compiled ajv validator function.
1981
+ */
1982
+ function _validatorFor(job, half) {
1983
+ _ensureSchema();
1984
+ let pair = _jobValidators.get(job);
1985
+ if (!pair) { pair = {}; _jobValidators.set(job, pair); }
1986
+ if (!pair[half]) {
1987
+ pair[half] = _ajv.compile({
1988
+ $id: 'urn:mindrian:brain-packet:' + job + ':' + half,
1989
+ $ref: '#/$defs/' + job + '/' + half,
1990
+ $defs: _schemaRaw.$defs,
1991
+ });
1992
+ }
1993
+ return pair[half];
1994
+ }
1995
+
1996
+ /**
1997
+ * Reset the lazy schema state. Test hook only -- NOT part of the public API.
1998
+ * Used by 110-05 (the per-job validation suite) and 110-04 (the pre-commit
1999
+ * tripwire) to swap the schema seam (MINDRIAN_BRAIN_PACKET_SCHEMA) and re-run.
2000
+ */
2001
+ function _resetSchema() {
2002
+ _ajv = null;
2003
+ _schemaRaw = null;
2004
+ _jobValidators.clear();
2005
+ }
2006
+
2007
+ /**
2008
+ * Best-effort memory_event log. Skips silently if opts.db is absent OR if the
2009
+ * navigation re-export throws (Brain telemetry should never break a Brain call).
2010
+ *
2011
+ * @param {object} db - SQLite db handle from openRoomDb (or undefined).
2012
+ * @param {string} eventType - one of 'brain_packet_rejected' /
2013
+ * 'brain_response_rejected' / 'brain_legacy_path_used'
2014
+ * (Phase 110-02 added these to EVENT_TYPES).
2015
+ * @param {object} payload - { job, errors, source_path, ... } scalars only.
2016
+ */
2017
+ function _logEventBestEffort(db, eventType, payload) {
2018
+ if (!db) return;
2019
+ try {
2020
+ // Lazy-require to avoid a circular load between brain-client.cjs and
2021
+ // navigation.cjs (navigation.cjs does NOT require brain-client.cjs today,
2022
+ // but this stays robust if a future closure of the loop ever happens).
2023
+ require('./navigation.cjs').logMemoryEvent(db, eventType, payload || {});
2024
+ } catch (_e) { /* best-effort */ }
2025
+ }
2026
+
2027
+ /**
2028
+ * Detect a "Brain doesn't recognize this tool" error in the callTool result.
2029
+ * Per the callTool JSDoc around line ~329, the result on a server-side error
2030
+ * is shaped { text: 'Error: ...' } (Cypher errors pass through the same way).
2031
+ * A missing brain_packet tool will show up as -32602 / 'unknown tool' / 'No
2032
+ * such tool' / a 404-ish marker. Be liberal: D-04 says "degrade gracefully
2033
+ * when the Brain doesn't recognize the contract."
2034
+ *
2035
+ * @param {*} result
2036
+ * @returns {boolean}
2037
+ */
2038
+ function _looksLikeUnknownToolError(result) {
2039
+ if (!result) return false;
2040
+ let t = '';
2041
+ if (typeof result === 'string') t = result;
2042
+ else if (typeof result === 'object') t = result.text || result.error || JSON.stringify(result);
2043
+ const s = String(t).toLowerCase();
2044
+ return s.includes('unknown tool')
2045
+ || s.includes('no such tool')
2046
+ || s.includes('method not found')
2047
+ || s.includes('-32602')
2048
+ || (s.includes('brain_packet') && (s.includes('not') || s.includes('unknown')))
2049
+ || s.includes('tool not found');
2050
+ }
2051
+
2052
+ /**
2053
+ * Unwrap the callTool result to the Brain response object the schema wants to
2054
+ * validate. callTool returns:
2055
+ * - an array (the tools/call content array on a successful brain_query-style
2056
+ * parsed result),
2057
+ * - or a parsed object (when content[0] is text and parses as JSON),
2058
+ * - or { text: '...' } (text content that did not parse as JSON, or an error
2059
+ * string),
2060
+ * - or null (unreachable / no API key -- handled before this is called).
2061
+ *
2062
+ * For brain_packet specifically, the Brain side (when implemented) will return
2063
+ * a BrainResponse-shaped JSON object: { job_id, suggestions: [...] }. Older
2064
+ * test transports inject [{ type:'text', text: JSON.stringify(...) }] (the raw
2065
+ * MCP content array shape). Both shapes are unwrapped to the response object.
2066
+ *
2067
+ * @param {*} result
2068
+ * @returns {object}
2069
+ */
2070
+ function _parseBrainResult(result) {
2071
+ if (Array.isArray(result)) {
2072
+ for (const item of result) {
2073
+ if (item && item.type === 'text' && typeof item.text === 'string') {
2074
+ try { return JSON.parse(item.text); } catch (_) { /* fall through */ }
2075
+ }
2076
+ }
2077
+ return { suggestions: [] };
2078
+ }
2079
+ if (result && typeof result === 'object') {
2080
+ // text-only error/string shape -- try to parse, else return { suggestions: [] }
2081
+ if (typeof result.text === 'string' && !result.job_id && !result.suggestions) {
2082
+ try { return JSON.parse(result.text); } catch (_) { return { suggestions: [] }; }
2083
+ }
2084
+ return result;
2085
+ }
2086
+ if (typeof result === 'string') {
2087
+ try { return JSON.parse(result); } catch (_) { return { suggestions: [] }; }
2088
+ }
2089
+ return { suggestions: [] };
2090
+ }
2091
+
2092
+ // ----------------------------------------------------------------------------
2093
+ // _warnLegacyOnce -- the D-10 dual-path deprecation guard.
2094
+ //
2095
+ // As of v1.13.0-beta.3 there is NO legacy free-form Brain *job* call site --
2096
+ // new job-style work goes through sendPacket(). The guard ships now as a
2097
+ // forward-looking contract: if a free-form job helper is ever added before
2098
+ // v1.14.0, it MUST call _warnLegacyOnce() first; in v1.14.0 both the helper
2099
+ // and this guard are deleted.
2100
+ //
2101
+ // query() / write() / search() / schema() / callTool() / ask() / stats() are
2102
+ // NOT "legacy" -- raw-Cypher methodology lookups carry only generic handles
2103
+ // (framework names, phase identifiers, problem-type enums) and are Part-8
2104
+ // clean by construction; they are PERMANENT.
2105
+ //
2106
+ // Module-level flag idiom mirrors checkFilePermissions._warned (the existing
2107
+ // once-per-process warning pattern in this file).
2108
+ // ----------------------------------------------------------------------------
2109
+
2110
+ let _legacyPathWarned = false;
2111
+
2112
+ function _warnLegacyOnce(db) {
2113
+ if (_legacyPathWarned) return;
2114
+ _legacyPathWarned = true;
2115
+ // eslint-disable-next-line no-console
2116
+ console.warn('[mindrian-os] legacy free-form Brain job call detected. '
2117
+ + 'Migrate to brain-client.sendPacket() -- the legacy job path is removed in v1.14.0.');
2118
+ _logEventBestEffort(db, 'brain_legacy_path_used', {
2119
+ source_path: 'system:brain-legacy',
2120
+ });
2121
+ }
2122
+
2123
+ /**
2124
+ * Validate-then-route a Brain Context Packet. The ONLY door for typed Brain
2125
+ * job calls.
2126
+ *
2127
+ * Per CONTEXT D-07 "reject hard, degrade soft":
2128
+ * - Bad in-packet (a programmer error in OUR code) -> throw.
2129
+ * - Bad origin (D-08 layer 3) -> throw.
2130
+ * - Unknown job -> throw.
2131
+ * - Brain unreachable -> { advice: null, reason: 'brain_unreachable' } (no throw).
2132
+ * - brain_packet tool absent on the Brain -> { advice: null, reason:
2133
+ * 'brain_packet_tool_absent' } (no throw, no log -- D-04 graceful degrade
2134
+ * is NOT a bad-response situation; a half-trusted response IS one).
2135
+ * - Bad out-response -> { advice: null, reason: 'response_schema_invalid' }
2136
+ * + log brain_response_rejected. NEVER throws, NEVER partial-ingests.
2137
+ *
2138
+ * @param {object} packet - MUST come from lib/core/navigation.cjs::buildBrainPacket
2139
+ * (D-01 chokepoint; D-08 layer 2 enforces lexically;
2140
+ * D-08 layer 3 is the origin check below).
2141
+ * @param {object} [opts] - { db?, roomDir?, __transport? }
2142
+ * db -> the SQLite handle for the memory_event log
2143
+ * roomDir -> reserved for future use; not read today
2144
+ * __transport -> optional test seam: a function
2145
+ * (toolName, args) => Promise<result> that
2146
+ * replaces callTool (lets tests inject a
2147
+ * fake without require.cache surgery)
2148
+ * @returns {Promise<object>} the validated Brain out on success; a no-advice
2149
+ * sentinel on a soft-degrade.
2150
+ * @throws on a bad in-packet, a bad origin (D-08 layer 3), or an unknown job.
2151
+ */
2152
+ // PARKED (2026-07-30, Phase 239, BRAIN-03): ZERO production sendPacket(
2153
+ // consumers. Census across lib/, scripts/, bin/, pipelines/: the only
2154
+ // definition is this one; non-definition references are this file's own
2155
+ // export/comments, tests/test-brain-packet-validation-per-job.cjs, and the
2156
+ // D-08 layer-2 guard (scripts/check-schema-aliases.cjs --check-sendpacket).
2157
+ // This reconciles two prior contradictory claims: navigation/packet.cjs:105
2158
+ // ("zero production consumers today") was TRUE; test-150-brain-egress.cjs:12
2159
+ // ("FIRST real sendPacket consumer") was FALSE and is corrected in this
2160
+ // change. RULING: PARKED, not wired -- wiring it to a real job is net-new
2161
+ // feature work, forbidden inside this remediation-only milestone (RESEARCH.md
2162
+ // A3, a navigator-equivalent ruling, cheap to overturn). CONSEQUENCE: the
2163
+ // PB8-10 belt below (step 3.5) is correct code on an unreached path -- do NOT
2164
+ // count it as live Part 8 coverage; the live in-process coverage is sibling
2165
+ // plan 239-05's raw-field guard in hatAwareRecommend()/suggestValidationSteps().
2166
+ // RE-OPEN CONDITION: the first real caller. Caught by the D-08 layer-2
2167
+ // pre-commit guard (requires a preceding buildBrainPacket() call) and by
2168
+ // tests/test-239-sendpacket-parked.cjs LEG 1's census. See also the matching
2169
+ // ADR amendment in docs/architecture/SUBSTRATE-CONTRACT.md (Phase 239-06).
2170
+ async function sendPacket(packet, opts) {
2171
+ const o = opts || {};
2172
+
2173
+ // (1) D-08 layer 3 -- the belt to the schema's suspenders. Runs FIRST so a
2174
+ // caller who bypassed ajv still gets caught.
2175
+ if (!packet || typeof packet.origin !== 'string') {
2176
+ throw new Error('brain packet missing origin (D-08): packets must come from buildBrainPacket');
2177
+ }
2178
+ if (packet.origin === 'test_fixture' && process.env.MINDRIAN_TEST_MODE !== '1') {
2179
+ throw new Error('brain packet origin "test_fixture" only valid when MINDRIAN_TEST_MODE=1');
2180
+ }
2181
+ if (packet.origin !== 'navigation_api' && packet.origin !== 'test_fixture') {
2182
+ throw new Error('brain packet origin "' + packet.origin
2183
+ + '" not in the closed allowlist (D-08): navigation_api | test_fixture');
2184
+ }
2185
+
2186
+ // (2) Unknown-job guard.
2187
+ if (!SHIPPED_JOBS.has(packet.job)) {
2188
+ throw new Error('brain packet: unknown job "' + packet.job
2189
+ + '" (not in the D-02 closed vocabulary)');
2190
+ }
2191
+
2192
+ // (3) in-validation -- reject hard.
2193
+ const inFn = _validatorFor(packet.job, 'in');
2194
+ if (!inFn(packet)) {
2195
+ // Pitfall 1: snapshot errors immediately -- validate.errors is overwritten
2196
+ // on every subsequent validate() call.
2197
+ const errsSnapshot = (inFn.errors || []).slice();
2198
+ const errStr = errsSnapshot
2199
+ .map(function (e) { return (e.instancePath || '(root)') + ' ' + (e.message || ''); })
2200
+ .join('; ');
2201
+ _logEventBestEffort(o.db, 'brain_packet_rejected', {
2202
+ job: packet.job,
2203
+ errors: errsSnapshot.length,
2204
+ source_path: 'system:brain-packet',
2205
+ });
2206
+ throw new Error('brain packet rejected for job "' + packet.job + '": ' + errStr);
2207
+ }
2208
+
2209
+ // (3.5) PB8-10 -- the in-sendPacket defense-in-depth belt. sendPacket is the
2210
+ // SOLE typed-packet wire path; this is the last LOCAL check before the
2211
+ // packet goes on the wire. It COMPLEMENTS the required PreToolUse hook
2212
+ // (D-02, the primary), never replaces it. Runs the pure LOCAL classifier
2213
+ // (zero network, zero judge wire, D-01):
2214
+ // - 'block' verdict -> refuse the send, returning the same soft-degrade
2215
+ // sentinel the unreachable path uses; best-effort log brain_egress_blocked.
2216
+ // - 'ambiguous' verdict -> belt posture: the hook is the gate, so do NOT
2217
+ // double-prompt; best-effort log brain_egress_ambiguous and allow through.
2218
+ // The whole belt is wrapped so a belt-INTERNAL error degrades to the
2219
+ // existing behavior (the hook remains the primary). It NEVER throws and
2220
+ // NEVER opens a Brain wire to judge.
2221
+ try {
2222
+ const _guard = require('./part8-egress-guard.cjs');
2223
+ const _verdict = _guard.classify(packet, { toolName: 'brain_packet' });
2224
+ if (_verdict && _verdict.verdict === 'block') {
2225
+ _logEventBestEffort(o.db, 'brain_egress_blocked', {
2226
+ egress_class: _verdict.class || 'content_set',
2227
+ verdict: 'block',
2228
+ count: 1,
2229
+ created_by: 'system',
2230
+ source_path: 'system:brain-packet',
2231
+ });
2232
+ return { advice: null, reason: 'egress_blocked' };
2233
+ }
2234
+ if (_verdict && _verdict.verdict === 'ambiguous') {
2235
+ _logEventBestEffort(o.db, 'brain_egress_ambiguous', {
2236
+ egress_class: _verdict.class || 'unknown',
2237
+ verdict: 'ambiguous',
2238
+ count: 1,
2239
+ created_by: 'system',
2240
+ source_path: 'system:brain-packet',
2241
+ });
2242
+ // belt posture: allow the hook to have been the gate; do not double-prompt.
2243
+ }
2244
+ } catch (_e) {
2245
+ // belt-internal error degrades to existing behavior (the hook is the primary, D-02).
2246
+ }
2247
+
2248
+ // (4) Build the wire envelope + POST. Reuse callTool's transport (it does
2249
+ // tools/call over Streamable HTTP + SSE-parse). Tests can inject a fake
2250
+ // via opts.__transport.
2251
+ const transport = (typeof o.__transport === 'function') ? o.__transport : callTool;
2252
+ let result;
2253
+ try {
2254
+ result = await transport('brain_packet', { packet: packet });
2255
+ } catch (_e) {
2256
+ // Network / transport error: treat like the Brain being unreachable.
2257
+ // No log -- it is not a leak, and not a contract violation either.
2258
+ return { advice: null, reason: 'brain_unreachable' };
2259
+ }
2260
+ if (result == null) {
2261
+ // callTool returns null when there is no API key or when the HTTP layer
2262
+ // returned a non-ok status -- functionally the same as "Brain unreachable".
2263
+ return { advice: null, reason: 'brain_unreachable' };
2264
+ }
2265
+ if (_looksLikeUnknownToolError(result)) {
2266
+ // The live Brain has no brain_packet tool yet (D-04 generalized).
2267
+ // Degrade soft, NO brain_response_rejected log -- this is NOT a bad
2268
+ // response; it is the absence of a contract handler.
2269
+ return { advice: null, reason: 'brain_packet_tool_absent' };
2270
+ }
2271
+
2272
+ // (5) out-validation -- reject hard but degrade soft.
2273
+ const parsed = _parseBrainResult(result);
2274
+ const outFn = _validatorFor(packet.job, 'out');
2275
+ if (!outFn(parsed)) {
2276
+ const errsSnapshot = (outFn.errors || []).slice();
2277
+ _logEventBestEffort(o.db, 'brain_response_rejected', {
2278
+ job: packet.job,
2279
+ errors: errsSnapshot.length,
2280
+ source_path: 'system:brain-packet',
2281
+ });
2282
+ // NEVER throw on a bad response; NEVER partial-ingest.
2283
+ return { advice: null, reason: 'response_schema_invalid' };
2284
+ }
2285
+
2286
+ // (6) Success -- the caller gets a known-good shape (typically then calls
2287
+ // navigation.storeBrainSuggestions).
2288
+ return parsed;
2289
+ }
2290
+
2291
+ module.exports = {
2292
+ isAvailable,
2293
+ ensureAvailable,
2294
+ getAutoRegisterFailureReason,
2295
+ getApiKey,
2296
+ callTool,
2297
+ query,
2298
+ write,
2299
+ search,
2300
+ smartSearch,
2301
+ ask,
2302
+ askOp,
2303
+ schema,
2304
+ stats,
2305
+ getBrainUrl,
2306
+ // Phase 339 (FLIP-02): the set of Brain origins whose problem-type
2307
+ // vocabulary is Theo's. Exported so class-m-brain-smoke.cjs's per-origin
2308
+ // node floor (plan 339-12) keys on this SAME set rather than minting a
2309
+ // second copy.
2310
+ THEO_ORIGINS,
2311
+ enrichCausalEdges,
2312
+ hatAwareRecommend,
2313
+ suggestValidationSteps,
2314
+ // getFrameworkChain: DELETED (Phase 252-01, SWEEP-01) -- the counterfeit
2315
+ // Tier-0 hardcoded-chain fallback. Zero CJS consumers at deletion time.
2316
+ // Phase 247-02 (CONTRACT-01): loop-contract read wrappers. brain_stats is
2317
+ // the sixth loop tool and is already exported above as stats().
2318
+ normalizeFrameworkName,
2319
+ loopSearch,
2320
+ discoverStructure,
2321
+ orchestrationReadiness,
2322
+ feedsIntoChains,
2323
+ // Quick 260819-c8j (WS-C1): recommend_chain is the seventh loop-contract
2324
+ // read wrapper, a sibling of feedsIntoChains above.
2325
+ recommendChain,
2326
+ // Phase 110-03 (Brain Context Packet Contract wire-level enforcement):
2327
+ // sendPacket is the SOLE typed-packet wire path; _warnLegacyOnce is the
2328
+ // forward-looking D-10 deprecation guard with no current call site.
2329
+ sendPacket,
2330
+ _warnLegacyOnce,
2331
+ // SEC-01/SEC-02 + CASCADE-06 test surface: not part of the public API.
2332
+ // See lib/memory/security-trifecta.test.cjs + brain-cache-lru.test.cjs.
2333
+ // Helpers are small and pure. sessionCache + _ensureSession + _hashKey +
2334
+ // SESSION_TTL_MS are exposed for Phase 87-07 cache-behavior tests.
2335
+ // Phase 110-03: ajv middleware test seam (_resetSchema clears the lazy
2336
+ // ajv state so a test can swap MINDRIAN_BRAIN_PACKET_SCHEMA and re-run;
2337
+ // _setLegacyWarned resets the once-per-session deprecation flag;
2338
+ // _validatorFor / _parseBrainResult / _looksLikeUnknownToolError are
2339
+ // the helpers Plan 110-05 covers in its per-job round-trip suite).
2340
+ _test: {
2341
+ sanitizeCypherInput,
2342
+ checkFilePermissions,
2343
+ sessionCache,
2344
+ SESSION_TTL_MS,
2345
+ _hashKey,
2346
+ _ensureSession,
2347
+ _resetSchema,
2348
+ _validatorFor,
2349
+ _parseBrainResult,
2350
+ _looksLikeUnknownToolError,
2351
+ _ensureSchema,
2352
+ SHIPPED_JOBS,
2353
+ _setLegacyWarned: function (v) { _legacyPathWarned = !!v; },
2354
+ // Quick 260903-eit: reset seam for query()'s unrecognized-shape
2355
+ // warn-once flag, mirroring _setLegacyWarned above.
2356
+ _setQueryShapeWarned: function (v) { _queryShapeWarned = !!v; },
2357
+ // Phase 250-04 test surface: silent registration internals.
2358
+ _tryAutoRegister,
2359
+ _installTokenPath,
2360
+ // Phase 259 (TRUST-01) test surface: the pure 429 wait-schedule helpers,
2361
+ // so the exact D-01/D-02 schedule is unit-tested with zero sleeps.
2362
+ _parseRetryAfterMs,
2363
+ _rateLimitWaitMs,
2364
+ },
2365
+ };