@mindrian_os/install 1.13.0-beta.11

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 (597) hide show
  1. package/.claude-plugin/plugin.json +21 -0
  2. package/.mcp.json +9 -0
  3. package/CHANGELOG.md +3333 -0
  4. package/LICENSE +123 -0
  5. package/README.md +673 -0
  6. package/agents/brain-query.md +80 -0
  7. package/agents/framework-runner.md +237 -0
  8. package/agents/grading.md +188 -0
  9. package/agents/investor.md +128 -0
  10. package/agents/larry-extended.md +135 -0
  11. package/agents/opportunity-scanner.md +91 -0
  12. package/agents/persona-analyst.md +132 -0
  13. package/agents/research.md +89 -0
  14. package/agents/reverse-salient-agent.md +27 -0
  15. package/bin/cli.js +142 -0
  16. package/bin/mindrian-mcp-server.cjs +182 -0
  17. package/bin/mindrian-tools.cjs +765 -0
  18. package/commands/act.md +439 -0
  19. package/commands/admin.md +404 -0
  20. package/commands/analyze-needs.md +42 -0
  21. package/commands/analyze-systems.md +39 -0
  22. package/commands/analyze-timing.md +42 -0
  23. package/commands/auto-explore.md +64 -0
  24. package/commands/beautiful-question.md +40 -0
  25. package/commands/brain-derive.md +78 -0
  26. package/commands/build-knowledge.md +42 -0
  27. package/commands/build-thesis.md +46 -0
  28. package/commands/causal.md +234 -0
  29. package/commands/challenge-assumptions.md +33 -0
  30. package/commands/compare-ventures.md +83 -0
  31. package/commands/dashboard.md +110 -0
  32. package/commands/deep-grade.md +82 -0
  33. package/commands/diagnose.md +58 -0
  34. package/commands/diagnostics.md +151 -0
  35. package/commands/doctor.md +151 -0
  36. package/commands/dominant-designs.md +40 -0
  37. package/commands/explain-decision.md +87 -0
  38. package/commands/explore-domains.md +42 -0
  39. package/commands/explore-futures.md +40 -0
  40. package/commands/explore-trends.md +42 -0
  41. package/commands/export.md +103 -0
  42. package/commands/file-meeting.md +724 -0
  43. package/commands/find-analogies.md +188 -0
  44. package/commands/find-bottlenecks.md +62 -0
  45. package/commands/find-connections.md +76 -0
  46. package/commands/funding.md +81 -0
  47. package/commands/grade.md +203 -0
  48. package/commands/graph.md +128 -0
  49. package/commands/hat-briefing.md +125 -0
  50. package/commands/heal.md +196 -0
  51. package/commands/help.md +399 -0
  52. package/commands/hmi-status.md +172 -0
  53. package/commands/jtbd.md +241 -0
  54. package/commands/leadership.md +73 -0
  55. package/commands/lean-canvas.md +40 -0
  56. package/commands/macro-trends.md +40 -0
  57. package/commands/map-unknowns.md +40 -0
  58. package/commands/memory.md +173 -0
  59. package/commands/models.md +175 -0
  60. package/commands/mos-reason.md +285 -0
  61. package/commands/mullins.md +120 -0
  62. package/commands/new-project.md +481 -0
  63. package/commands/onboard.md +434 -0
  64. package/commands/operator.md +149 -0
  65. package/commands/opportunities.md +144 -0
  66. package/commands/organize.md +497 -0
  67. package/commands/persona.md +198 -0
  68. package/commands/pipeline.md +112 -0
  69. package/commands/present.md +91 -0
  70. package/commands/publish.md +201 -0
  71. package/commands/query.md +124 -0
  72. package/commands/radar.md +72 -0
  73. package/commands/reanalyze.md +91 -0
  74. package/commands/research.md +196 -0
  75. package/commands/room.md +352 -0
  76. package/commands/rooms.md +598 -0
  77. package/commands/root-cause.md +40 -0
  78. package/commands/rs-experts.md +85 -0
  79. package/commands/rs-explain.md +100 -0
  80. package/commands/rs-fetch.md +94 -0
  81. package/commands/rs-thesis.md +85 -0
  82. package/commands/scenario-plan.md +40 -0
  83. package/commands/scheduled-tasks.md +285 -0
  84. package/commands/score-innovation.md +43 -0
  85. package/commands/scout.md +239 -0
  86. package/commands/setup.md +618 -0
  87. package/commands/snapshot.md +147 -0
  88. package/commands/speakers.md +84 -0
  89. package/commands/splash.md +28 -0
  90. package/commands/status.md +75 -0
  91. package/commands/structure-argument.md +42 -0
  92. package/commands/suggest-next.md +80 -0
  93. package/commands/systems-thinking.md +40 -0
  94. package/commands/think-hats.md +42 -0
  95. package/commands/update.md +181 -0
  96. package/commands/user-needs.md +40 -0
  97. package/commands/validate.md +40 -0
  98. package/commands/value-proposition.md +61 -0
  99. package/commands/vault.md +180 -0
  100. package/commands/visualize.md +52 -0
  101. package/commands/whitespace.md +507 -0
  102. package/commands/wiki.md +69 -0
  103. package/hooks/hooks.json +381 -0
  104. package/hooks/run-hook.cmd +64 -0
  105. package/lib/__init__.py +0 -0
  106. package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
  107. package/lib/agents/auto-explore-agent.cjs +1043 -0
  108. package/lib/agents/reverse-salient-agent.cjs +679 -0
  109. package/lib/agents/tension-hook-agent.cjs +544 -0
  110. package/lib/brain/ROOM.md +44 -0
  111. package/lib/brain/chain-recommender.cjs +301 -0
  112. package/lib/chat/chat-context.js +185 -0
  113. package/lib/chat/chat-panel.js +721 -0
  114. package/lib/chat/fabric-chat.cjs +288 -0
  115. package/lib/chat/generative-tools.js +219 -0
  116. package/lib/conversation/ROOM.md +39 -0
  117. package/lib/conversation/classifier-rules.json +38 -0
  118. package/lib/conversation/classifier.cjs +264 -0
  119. package/lib/conversation/operator.cjs +287 -0
  120. package/lib/copy/115-spec-strings.cjs +55 -0
  121. package/lib/core/__init__.py +0 -0
  122. package/lib/core/__nav-stub.cjs +14 -0
  123. package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
  124. package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
  125. package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
  126. package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
  127. package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
  128. package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
  129. package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
  130. package/lib/core/artifact-id.cjs +148 -0
  131. package/lib/core/asset-ops.cjs +151 -0
  132. package/lib/core/auto-commit-throttle.cjs +129 -0
  133. package/lib/core/bearer-token.cjs +199 -0
  134. package/lib/core/brain-client.cjs +865 -0
  135. package/lib/core/brain-derivation-prompts.cjs +326 -0
  136. package/lib/core/brain-derivation-queue.cjs +431 -0
  137. package/lib/core/brain-derivation.cjs +580 -0
  138. package/lib/core/brain-md-schema.cjs +528 -0
  139. package/lib/core/brain-md-staleness.cjs +357 -0
  140. package/lib/core/brain-response-sanitize.cjs +188 -0
  141. package/lib/core/bridge-writer.cjs +477 -0
  142. package/lib/core/chat-context-builder.cjs +253 -0
  143. package/lib/core/cross-room-aggregator.cjs +762 -0
  144. package/lib/core/daily-briefing.cjs +438 -0
  145. package/lib/core/decision-capture.cjs +618 -0
  146. package/lib/core/deep-links.cjs +82 -0
  147. package/lib/core/dispatch-optimizer.cjs +354 -0
  148. package/lib/core/dual-path-detector.cjs +84 -0
  149. package/lib/core/dual-path-detector.test.cjs +334 -0
  150. package/lib/core/exports-log.cjs +79 -0
  151. package/lib/core/feynman-minto-invariants.cjs +605 -0
  152. package/lib/core/folder-memory-async.cjs +338 -0
  153. package/lib/core/folder-memory-shared.cjs +890 -0
  154. package/lib/core/folder-memory.cjs +416 -0
  155. package/lib/core/framework-chain-composer.cjs +411 -0
  156. package/lib/core/frontmatter-schemas.cjs +330 -0
  157. package/lib/core/git-ops.cjs +141 -0
  158. package/lib/core/graph-ops.cjs +258 -0
  159. package/lib/core/hat-persistence.cjs +362 -0
  160. package/lib/core/index.cjs +60 -0
  161. package/lib/core/integration-registry.cjs +232 -0
  162. package/lib/core/intelligence-cascade.cjs +661 -0
  163. package/lib/core/lazygraph-ops.cjs +1057 -0
  164. package/lib/core/lru-cache.cjs +139 -0
  165. package/lib/core/mcp-profiles.cjs +182 -0
  166. package/lib/core/meeting-ops.cjs +54 -0
  167. package/lib/core/memory-ops.cjs +600 -0
  168. package/lib/core/migrations/ROOM.md +33 -0
  169. package/lib/core/migrations/phase-109-nodes-provenance.cjs +339 -0
  170. package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
  171. package/lib/core/model-profiles.cjs +246 -0
  172. package/lib/core/mullins-scaffold.cjs +160 -0
  173. package/lib/core/nav-dial.cjs +316 -0
  174. package/lib/core/navigation/ROOM.md +15 -0
  175. package/lib/core/navigation/explanation.cjs +43 -0
  176. package/lib/core/navigation/focus.cjs +135 -0
  177. package/lib/core/navigation/ingestion.cjs +82 -0
  178. package/lib/core/navigation/insights.cjs +350 -0
  179. package/lib/core/navigation/memory-events.cjs +118 -0
  180. package/lib/core/navigation/neighborhood.cjs +78 -0
  181. package/lib/core/navigation/packet.cjs +182 -0
  182. package/lib/core/navigation/room-home.cjs +127 -0
  183. package/lib/core/navigation/transitions.cjs +82 -0
  184. package/lib/core/navigation-engine-shared.cjs +242 -0
  185. package/lib/core/navigation-engine.cjs +664 -0
  186. package/lib/core/navigation.cjs +60 -0
  187. package/lib/core/nl-graph-queries.cjs +164 -0
  188. package/lib/core/offer-presenter.cjs +406 -0
  189. package/lib/core/opportunity-extractor.cjs +183 -0
  190. package/lib/core/opportunity-ops.cjs +1371 -0
  191. package/lib/core/persona-ops.cjs +537 -0
  192. package/lib/core/persona-taxonomy.cjs +190 -0
  193. package/lib/core/platform-gates.cjs +120 -0
  194. package/lib/core/platform.cjs +257 -0
  195. package/lib/core/proactive-intelligence.cjs +528 -0
  196. package/lib/core/problem-type-router.cjs +315 -0
  197. package/lib/core/reasoning-ops.cjs +639 -0
  198. package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
  199. package/lib/core/room-classifier-strict-mode.cjs +229 -0
  200. package/lib/core/room-db.cjs +127 -0
  201. package/lib/core/room-ops-async.cjs +92 -0
  202. package/lib/core/room-ops-shared.cjs +64 -0
  203. package/lib/core/room-ops-sync.cjs +70 -0
  204. package/lib/core/room-ops.cjs +32 -0
  205. package/lib/core/room-type-detector.cjs +386 -0
  206. package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
  207. package/lib/core/rs-brain-substrate.cjs +570 -0
  208. package/lib/core/rs-breakthrough-scorer.cjs +255 -0
  209. package/lib/core/rs-canon-violations.cjs +82 -0
  210. package/lib/core/rs-chain-feeder.cjs +343 -0
  211. package/lib/core/rs-commercial-assessor.cjs +280 -0
  212. package/lib/core/rs-differential-scorer.cjs +376 -0
  213. package/lib/core/rs-domain-analyzer.cjs +385 -0
  214. package/lib/core/rs-egress-prompts.cjs +113 -0
  215. package/lib/core/rs-egress-telemetry.cjs +225 -0
  216. package/lib/core/rs-egress-violations.cjs +53 -0
  217. package/lib/core/rs-expert-mapper.cjs +467 -0
  218. package/lib/core/rs-fetcher-academic.cjs +697 -0
  219. package/lib/core/rs-fetcher-experts.cjs +314 -0
  220. package/lib/core/rs-fetcher-industry.cjs +731 -0
  221. package/lib/core/rs-fetcher-patents.cjs +564 -0
  222. package/lib/core/rs-innovation-classifier.cjs +194 -0
  223. package/lib/core/rs-mind-map.cjs +656 -0
  224. package/lib/core/rs-neo4j-writer.cjs +388 -0
  225. package/lib/core/rs-nl-to-query.cjs +425 -0
  226. package/lib/core/rs-pinecone-bridge.cjs +303 -0
  227. package/lib/core/rs-preprocessor.cjs +350 -0
  228. package/lib/core/rs-query-matrix.cjs +316 -0
  229. package/lib/core/rs-query-to-text.cjs +438 -0
  230. package/lib/core/rs-sqlite-mirror.cjs +443 -0
  231. package/lib/core/rs-thesis-generator.cjs +188 -0
  232. package/lib/core/rs_cache.py +479 -0
  233. package/lib/core/rs_corpus.py +468 -0
  234. package/lib/core/rs_hybrid.py +586 -0
  235. package/lib/core/rs_math.py +287 -0
  236. package/lib/core/rs_rooms.py +193 -0
  237. package/lib/core/scheduled-scanner.cjs +463 -0
  238. package/lib/core/scratchpad-ops.cjs +201 -0
  239. package/lib/core/section-8-trace-schema.cjs +138 -0
  240. package/lib/core/section-registry.cjs +111 -0
  241. package/lib/core/session-state.cjs +144 -0
  242. package/lib/core/shallow-doc-parser.cjs +174 -0
  243. package/lib/core/shallow-doc-parser.test.cjs +226 -0
  244. package/lib/core/skill-activation-router.cjs +284 -0
  245. package/lib/core/state-ops.cjs +46 -0
  246. package/lib/core/statusline-cache.cjs +266 -0
  247. package/lib/core/token-estimator.cjs +348 -0
  248. package/lib/core/user-archetype.cjs +239 -0
  249. package/lib/core/user-md-ops.cjs +524 -0
  250. package/lib/core/visual-ops.cjs +624 -0
  251. package/lib/core/write-lock.cjs +149 -0
  252. package/lib/graph/canvas-graph.js +467 -0
  253. package/lib/graph/constellation-config.cjs +299 -0
  254. package/lib/graph/graph-detail-panel.js +165 -0
  255. package/lib/hmi/ROOM.md +47 -0
  256. package/lib/hmi/across-session-memory.cjs +604 -0
  257. package/lib/hmi/cross-room-memory.cjs +575 -0
  258. package/lib/hmi/decoy-tier.cjs +395 -0
  259. package/lib/hmi/jtbd-classifier.cjs +219 -0
  260. package/lib/hmi/jtbd-state.cjs +199 -0
  261. package/lib/hmi/jtbd-taxonomy.json +392 -0
  262. package/lib/hmi/selector-dispatcher.cjs +546 -0
  263. package/lib/hmi/selector-telemetry.cjs +263 -0
  264. package/lib/hmi/shape-f0-renderer.cjs +139 -0
  265. package/lib/hmi/shape-f1-fallback.cjs +80 -0
  266. package/lib/hmi/shape-f1-renderer.cjs +138 -0
  267. package/lib/hmi/shape-f2-renderer.cjs +132 -0
  268. package/lib/hmi/shape-f3-renderer.cjs +66 -0
  269. package/lib/hmi/shape-f4-renderer.cjs +72 -0
  270. package/lib/hmi/shape-f5-renderer.cjs +155 -0
  271. package/lib/hmi/shape-f6-plan-review-renderer.cjs +312 -0
  272. package/lib/hmi/shape-f6-renderer.cjs +144 -0
  273. package/lib/hmi/shape-g-renderer.cjs +219 -0
  274. package/lib/hmi/shape-h-renderer.cjs +222 -0
  275. package/lib/hmi/tier-check.cjs +63 -0
  276. package/lib/import/PRECONDITIONS.md +41 -0
  277. package/lib/import/branding.cjs +210 -0
  278. package/lib/import/branding.test.cjs +235 -0
  279. package/lib/import/classifications-sync.cjs +104 -0
  280. package/lib/import/classifications-sync.test.cjs +129 -0
  281. package/lib/import/enricher.cjs +296 -0
  282. package/lib/import/enricher.test.cjs +273 -0
  283. package/lib/import/integration.test.cjs +376 -0
  284. package/lib/import/manifest.cjs +129 -0
  285. package/lib/import/manifest.schema.json +185 -0
  286. package/lib/import/manifest.test.cjs +123 -0
  287. package/lib/import/meeting-detector.cjs +92 -0
  288. package/lib/import/meeting-detector.test.cjs +100 -0
  289. package/lib/import/person-detector.cjs +229 -0
  290. package/lib/import/person-detector.test.cjs +149 -0
  291. package/lib/import/report.cjs +186 -0
  292. package/lib/import/report.test.cjs +186 -0
  293. package/lib/import/room-md-scaffolder.cjs +49 -0
  294. package/lib/import/router.cjs +224 -0
  295. package/lib/import/router.test.cjs +356 -0
  296. package/lib/import/run-all-tests.cjs +36 -0
  297. package/lib/import/smoke-test.cjs +213 -0
  298. package/lib/import/smoke-test.test.cjs +148 -0
  299. package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +8 -0
  300. package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +7 -0
  301. package/lib/import/test-fixtures/collision-vault/source/onboarding.md +5 -0
  302. package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +1 -0
  303. package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +4 -0
  304. package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +9 -0
  305. package/lib/import/test-fixtures/tiny-vault/notes/empty.md +3 -0
  306. package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +5 -0
  307. package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +5 -0
  308. package/lib/import/test-fixtures/tiny-vault/notes/random.md +4 -0
  309. package/lib/import/undo.test.cjs +199 -0
  310. package/lib/import/vault-scanner.cjs +105 -0
  311. package/lib/import/vault-scanner.test.cjs +67 -0
  312. package/lib/mcp/app-html/dashboard.html +316 -0
  313. package/lib/mcp/app-html/graph.html +428 -0
  314. package/lib/mcp/app-html/mindrian-platform.html +1841 -0
  315. package/lib/mcp/app-html/wiki.html +383 -0
  316. package/lib/mcp/app-views.cjs +322 -0
  317. package/lib/mcp/brain-router.cjs +418 -0
  318. package/lib/mcp/capability-registry.cjs +62 -0
  319. package/lib/mcp/larry-context.cjs +46 -0
  320. package/lib/mcp/larry-server-instructions.md +114 -0
  321. package/lib/mcp/pipeline-state.cjs +275 -0
  322. package/lib/mcp/prompts.cjs +302 -0
  323. package/lib/mcp/resources.cjs +227 -0
  324. package/lib/mcp/session-catchup.cjs +327 -0
  325. package/lib/mcp/surface-detect.cjs +75 -0
  326. package/lib/mcp/tool-router.cjs +1034 -0
  327. package/lib/memory/aaak-compress.cjs +403 -0
  328. package/lib/memory/aaak-compress.test.cjs +288 -0
  329. package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
  330. package/lib/memory/bearer-token.test.cjs +315 -0
  331. package/lib/memory/brain-cache-lru.test.cjs +259 -0
  332. package/lib/memory/brain-client-query-shape.test.cjs +160 -0
  333. package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
  334. package/lib/memory/brain-derivation-queue.test.cjs +539 -0
  335. package/lib/memory/brain-derivation.test.cjs +634 -0
  336. package/lib/memory/brain-derive-command.test.cjs +534 -0
  337. package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
  338. package/lib/memory/brain-md-schema.test.cjs +467 -0
  339. package/lib/memory/brain-md-staleness.test.cjs +525 -0
  340. package/lib/memory/brain-server-resolution.test.cjs +314 -0
  341. package/lib/memory/chain-recommender.test.cjs +233 -0
  342. package/lib/memory/chat-context.test.cjs +128 -0
  343. package/lib/memory/command-registry.test.cjs +220 -0
  344. package/lib/memory/cross-room-aggregator.test.cjs +909 -0
  345. package/lib/memory/dashboard-server.test.cjs +256 -0
  346. package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
  347. package/lib/memory/decision-capture.test.cjs +632 -0
  348. package/lib/memory/decision-capture.worker.cjs +70 -0
  349. package/lib/memory/explain-decision-command.test.cjs +521 -0
  350. package/lib/memory/explain-decision-footer.test.cjs +316 -0
  351. package/lib/memory/explored-materials-store.cjs +392 -0
  352. package/lib/memory/feynman-minto-guardian.test.cjs +736 -0
  353. package/lib/memory/feynman-minto-invariants.test.cjs +511 -0
  354. package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
  355. package/lib/memory/feynman-prompts.cjs +151 -0
  356. package/lib/memory/feynman-prompts.test.cjs +96 -0
  357. package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
  358. package/lib/memory/folder-memory.test.cjs +503 -0
  359. package/lib/memory/framework-chain-composer.test.cjs +515 -0
  360. package/lib/memory/frontmatter-schema-validator.test.cjs +290 -0
  361. package/lib/memory/heal-command.test.cjs +604 -0
  362. package/lib/memory/index-artifact-transaction.test.cjs +333 -0
  363. package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
  364. package/lib/memory/mcp-input-validation.test.cjs +240 -0
  365. package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
  366. package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
  367. package/lib/memory/minto-debouncer.test.cjs +407 -0
  368. package/lib/memory/minto-debouncer.worker.cjs +46 -0
  369. package/lib/memory/minto-migration-v88.test.cjs +265 -0
  370. package/lib/memory/minto-schema-v88.test.cjs +390 -0
  371. package/lib/memory/mos-status-renderer.test.cjs +631 -0
  372. package/lib/memory/narrative-schema.cjs +376 -0
  373. package/lib/memory/narrative-schema.test.cjs +209 -0
  374. package/lib/memory/nav-dial.test.cjs +414 -0
  375. package/lib/memory/navigation-engine-core.test.cjs +722 -0
  376. package/lib/memory/navigation-invariants.test.cjs +483 -0
  377. package/lib/memory/offer-presenter.test.cjs +554 -0
  378. package/lib/memory/on-stop-snapshot.test.cjs +404 -0
  379. package/lib/memory/pending-tension-store.cjs +373 -0
  380. package/lib/memory/post-compact-reinjection.test.cjs +854 -0
  381. package/lib/memory/post-write-triple.test.cjs +317 -0
  382. package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
  383. package/lib/memory/problem-type-router.test.cjs +656 -0
  384. package/lib/memory/query-efficiency-telemetry.test.cjs +370 -0
  385. package/lib/memory/recompile-room-references.test.cjs +392 -0
  386. package/lib/memory/recompile-room-references.worker.cjs +42 -0
  387. package/lib/memory/record-decision-dual-write.test.cjs +454 -0
  388. package/lib/memory/room-classifier-strict-mode.test.cjs +417 -0
  389. package/lib/memory/room-minto-hook.test.cjs +398 -0
  390. package/lib/memory/rs-discovery-engine.test.cjs +323 -0
  391. package/lib/memory/run-feynman-tests.cjs +1247 -0
  392. package/lib/memory/security-trifecta.test.cjs +312 -0
  393. package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
  394. package/lib/memory/session-start-triple-injection.test.cjs +514 -0
  395. package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
  396. package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
  397. package/lib/memory/skill-activation-router.test.cjs +419 -0
  398. package/lib/memory/stamp-artifact-write.test.cjs +304 -0
  399. package/lib/memory/statusline-active-room.test.cjs +315 -0
  400. package/lib/memory/statusline-minto-segment.test.cjs +292 -0
  401. package/lib/memory/sync-async-entry-points.test.cjs +204 -0
  402. package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
  403. package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
  404. package/lib/memory/test-rs-brain-substrate.cjs +636 -0
  405. package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
  406. package/lib/memory/test-rs-canon-violations.cjs +218 -0
  407. package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
  408. package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
  409. package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
  410. package/lib/memory/test-rs-differential-scorer.cjs +480 -0
  411. package/lib/memory/test-rs-discovery-engine.cjs +603 -0
  412. package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
  413. package/lib/memory/test-rs-egress-primitives.cjs +420 -0
  414. package/lib/memory/test-rs-expert-mapper.cjs +547 -0
  415. package/lib/memory/test-rs-explain-command.cjs +443 -0
  416. package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
  417. package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
  418. package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
  419. package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
  420. package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
  421. package/lib/memory/test-rs-mind-map.cjs +646 -0
  422. package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
  423. package/lib/memory/test-rs-nl-to-query.cjs +449 -0
  424. package/lib/memory/test-rs-pinecone-bridge.cjs +277 -0
  425. package/lib/memory/test-rs-preprocessor.cjs +433 -0
  426. package/lib/memory/test-rs-query-matrix.cjs +391 -0
  427. package/lib/memory/test-rs-query-to-text.cjs +551 -0
  428. package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
  429. package/lib/memory/test-rs-thesis-generator.cjs +360 -0
  430. package/lib/memory/triple-context-formatter.cjs +473 -0
  431. package/lib/memory/triple-context-formatter.test.cjs +442 -0
  432. package/lib/memory/user-md-persona.test.cjs +565 -0
  433. package/lib/memory/userpromptsubmit-integration.test.cjs +690 -0
  434. package/lib/memory/validators/README.md +157 -0
  435. package/lib/memory/validators/brain-md-invariants.cjs +475 -0
  436. package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
  437. package/lib/memory/validators/external-academic-invariants.cjs +249 -0
  438. package/lib/memory/validators/external-industry-invariants.cjs +271 -0
  439. package/lib/memory/validators/external-patents-invariants.cjs +266 -0
  440. package/lib/memory/validators/minto-invariants.cjs +62 -0
  441. package/lib/memory/validators/navigation-invariants.cjs +340 -0
  442. package/lib/memory/validators/queue-health.cjs +95 -0
  443. package/lib/memory/validators/snapshot-integrity.cjs +129 -0
  444. package/lib/memory/validators/stale-lifecycle.cjs +116 -0
  445. package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
  446. package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
  447. package/lib/memory/write-lock-atomic.test.cjs +137 -0
  448. package/lib/memory/write-lock-atomic.worker.cjs +55 -0
  449. package/lib/parity/check-parity.cjs +83 -0
  450. package/lib/presentation/presentation-server.cjs +101 -0
  451. package/lib/presentation/presentation-watcher.cjs +123 -0
  452. package/lib/quickview/hub-server.cjs +719 -0
  453. package/lib/quickview/server.cjs +533 -0
  454. package/lib/render/JTBD-PALETTES.md +145 -0
  455. package/lib/render/ROOM.md +59 -0
  456. package/lib/render/render-v2.cjs +486 -0
  457. package/lib/render/render-v2.test.cjs +267 -0
  458. package/lib/render/render.cjs +65 -0
  459. package/lib/state/ROOM.md +46 -0
  460. package/lib/state/state-md-parser.cjs +215 -0
  461. package/lib/statusline/ROOM.md +38 -0
  462. package/lib/statusline/banner-suppression.cjs +50 -0
  463. package/lib/statusline/surface-detect.cjs +85 -0
  464. package/lib/update-bootstrap.sh.template +145 -0
  465. package/lib/vault/frontmatter-schema.cjs +297 -0
  466. package/lib/vault/room-scanner.cjs +352 -0
  467. package/lib/vault/wikilink-builder.cjs +231 -0
  468. package/lib/vault/wikilink-builder.test.cjs +182 -0
  469. package/lib/wiki/graph-links.cjs +281 -0
  470. package/lib/wiki/page-renderer.cjs +229 -0
  471. package/lib/wiki/wiki-chat.cjs +81 -0
  472. package/lib/wiki/wiki-layout.cjs +1459 -0
  473. package/lib/wiki/wiki-search.cjs +142 -0
  474. package/lib/wiki/wiki-server.cjs +678 -0
  475. package/lib/wiki/wiki-watcher.cjs +105 -0
  476. package/lib/workflow/ROOM.md +47 -0
  477. package/lib/workflow/command-resolver.cjs +155 -0
  478. package/lib/workflow/command-resolver.test.cjs +235 -0
  479. package/package.json +44 -0
  480. package/pipelines/analogy/01-decompose.md +80 -0
  481. package/pipelines/analogy/02-abstract.md +87 -0
  482. package/pipelines/analogy/03-search.md +135 -0
  483. package/pipelines/analogy/04-transfer.md +101 -0
  484. package/pipelines/analogy/05-validate.md +106 -0
  485. package/pipelines/analogy/CHAIN.md +56 -0
  486. package/pipelines/discovery/01-explore-domains.md +44 -0
  487. package/pipelines/discovery/02-think-hats.md +50 -0
  488. package/pipelines/discovery/03-analyze-needs.md +54 -0
  489. package/pipelines/discovery/CHAIN.md +37 -0
  490. package/pipelines/thesis/01-structure-argument.md +45 -0
  491. package/pipelines/thesis/02-challenge-assumptions.md +48 -0
  492. package/pipelines/thesis/03-build-thesis.md +54 -0
  493. package/pipelines/thesis/CHAIN.md +37 -0
  494. package/references/brain/causal-directives.md +91 -0
  495. package/references/brain/causal-enrichment.cypher +165 -0
  496. package/references/brain/command-triggers-schema.md +226 -0
  497. package/references/brain/graph-architecture.md +317 -0
  498. package/references/brain/query-patterns.md +460 -0
  499. package/references/brain/room-hierarchy-schema.md +218 -0
  500. package/references/brain/schema.md +76 -0
  501. package/references/capability-radar/capabilities-index.md +241 -0
  502. package/references/capability-radar/changelog-cache.md +81 -0
  503. package/references/causal/causal-schema.md +103 -0
  504. package/references/design/email-template-standard.md +155 -0
  505. package/references/design/graph-visualization-standard.md +178 -0
  506. package/references/document-generation.md +179 -0
  507. package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
  508. package/references/import-config.md +141 -0
  509. package/references/integrations/detection-patterns.md +101 -0
  510. package/references/meeting/artifact-template.md +377 -0
  511. package/references/meeting/cross-meeting-intelligence.md +216 -0
  512. package/references/meeting/cross-relationship-patterns.md +202 -0
  513. package/references/meeting/live-join-interface.md +244 -0
  514. package/references/meeting/section-mapping.md +192 -0
  515. package/references/meeting/segment-classification.md +258 -0
  516. package/references/meeting/speaker-profile-template.md +219 -0
  517. package/references/meeting/summary-template.md +348 -0
  518. package/references/meeting/transcript-patterns.md +226 -0
  519. package/references/methodology/analyze-needs.md +135 -0
  520. package/references/methodology/analyze-systems.md +121 -0
  521. package/references/methodology/analyze-timing.md +149 -0
  522. package/references/methodology/beautiful-question.md +109 -0
  523. package/references/methodology/build-knowledge.md +161 -0
  524. package/references/methodology/build-thesis.md +237 -0
  525. package/references/methodology/challenge-assumptions.md +127 -0
  526. package/references/methodology/diagnose.md +169 -0
  527. package/references/methodology/dominant-designs.md +212 -0
  528. package/references/methodology/explore-domains.md +147 -0
  529. package/references/methodology/explore-futures.md +163 -0
  530. package/references/methodology/explore-trends.md +129 -0
  531. package/references/methodology/find-bottlenecks.md +131 -0
  532. package/references/methodology/grade.md +211 -0
  533. package/references/methodology/index.md +97 -0
  534. package/references/methodology/leadership.md +200 -0
  535. package/references/methodology/lean-canvas.md +116 -0
  536. package/references/methodology/macro-trends.md +192 -0
  537. package/references/methodology/map-unknowns.md +137 -0
  538. package/references/methodology/mullins-7-domains.md +104 -0
  539. package/references/methodology/problem-types.md +65 -0
  540. package/references/methodology/root-cause.md +178 -0
  541. package/references/methodology/sapphire-encoding.md +355 -0
  542. package/references/methodology/scenario-plan.md +178 -0
  543. package/references/methodology/score-innovation.md +154 -0
  544. package/references/methodology/structure-argument.md +158 -0
  545. package/references/methodology/systems-thinking.md +159 -0
  546. package/references/methodology/think-hats.md +147 -0
  547. package/references/methodology/triz-matrix.json +751 -0
  548. package/references/methodology/triz-principles.md +501 -0
  549. package/references/methodology/user-needs.md +199 -0
  550. package/references/methodology/validate.md +163 -0
  551. package/references/methodology/value-proposition.md +244 -0
  552. package/references/opportunities/funding-lifecycle.md +103 -0
  553. package/references/opportunities/grant-api-patterns.md +99 -0
  554. package/references/opportunities/opportunity-template.md +84 -0
  555. package/references/personality/assessment-philosophy.md +72 -0
  556. package/references/personality/lexicon.md +100 -0
  557. package/references/personality/persona-chains.md +56 -0
  558. package/references/personality/pws-lexicon-full.md +499 -0
  559. package/references/personality/voice-dna.md +156 -0
  560. package/references/personas/hat-perspectives.md +76 -0
  561. package/references/personas/persona-template.md +63 -0
  562. package/references/pipeline/act-output-contract.md +88 -0
  563. package/references/pipeline/chains-index.md +39 -0
  564. package/references/pws-profile-generation.md +79 -0
  565. package/references/reasoning/reasoning-schema.md +143 -0
  566. package/references/reasoning/reasoning-template.md +68 -0
  567. package/references/reasoning/run-template.md +38 -0
  568. package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
  569. package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
  570. package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
  571. package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
  572. package/references/taxonomy/TAXONOMY.md +192 -0
  573. package/references/templates/MINTO.md +36 -0
  574. package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
  575. package/references/vault-kit/README.md +35 -0
  576. package/references/vault-kit/app.json +12 -0
  577. package/references/vault-kit/appearance.json +12 -0
  578. package/references/vault-kit/graph.json +35 -0
  579. package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
  580. package/references/vault-kit/templates/new-artifact.md +37 -0
  581. package/references/vault-kit/templates/new-meeting-note.md +35 -0
  582. package/references/vault-kit/templates/new-team-profile.md +29 -0
  583. package/references/vault-kit/templates/new-xref.md +35 -0
  584. package/references/visual/symbol-system.md +151 -0
  585. package/skills/MOSDeckEngine/SKILL.md +325 -0
  586. package/skills/brain-connector/SKILL.md +114 -0
  587. package/skills/context-engine/SKILL.md +147 -0
  588. package/skills/conversation-mode/SKILL.md +102 -0
  589. package/skills/larry-personality/SKILL.md +219 -0
  590. package/skills/larry-personality/framework-chains.md +92 -0
  591. package/skills/larry-personality/mode-engine.md +185 -0
  592. package/skills/mullins-scaffold/SKILL.md +61 -0
  593. package/skills/mullins-scaffold/scaffold.json +146 -0
  594. package/skills/pws-methodology/SKILL.md +49 -0
  595. package/skills/room-passive/SKILL.md +165 -0
  596. package/skills/room-proactive/SKILL.md +250 -0
  597. package/skills/ui-system/SKILL.md +277 -0
@@ -0,0 +1,575 @@
1
+ 'use strict';
2
+
3
+ /*
4
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
5
+ *
6
+ * Phase 103-03 -- cross-room memory layer (Layer 3, read-side)
7
+ * ===========================================================
8
+ *
9
+ * Aggregates JTBDs across rooms. Two modes:
10
+ * - Mode A (Brain reachable): enriches local synthesis with generic
11
+ * pattern hints ("rooms that ran prepare-pitch typically next ran
12
+ * validate-idea").
13
+ * - Mode B (Brain unreachable / opted-out): filesystem-only synthesis.
14
+ *
15
+ * Canon Part 8 (Graph Boundary) is the LOAD-BEARING invariant:
16
+ * - Brain receives ZERO LOCAL bytes.
17
+ * - The buildBrainQueryContext function is the SINGLE chokepoint for
18
+ * any Brain-bound payload. Output is restricted to the Phase 90
19
+ * allow-list (sha256 hashes, frozen enums, safe slugs, clamped
20
+ * floats, age buckets).
21
+ * - 5-tripwire defense:
22
+ * #1 Schema-leak heuristic scan (tests/test-cross-room-memory-
23
+ * schema-leak.cjs scans this source file)
24
+ * #2 Single chokepoint -- exactly ONE Brain call site
25
+ * (tryBrainQuery; tested via grep)
26
+ * #3 brain-md-invariants reuse -- this module does NOT write
27
+ * BRAIN.md, so the invariants validator is satisfied by
28
+ * absence-of-write (Phase 90 Plan 90-05 contract preserved)
29
+ * #4 sanitizeDetailScalar + JSON.stringify output audit -- every
30
+ * Brain payload assembled in tryBrainHints is stringified and
31
+ * regex-scanned for forbidden patterns BEFORE send
32
+ * #5 Cross-scenario sweep -- partial via tests/test-cross-room-
33
+ * memory.cjs fixture rotation (Mode A success, Mode A error,
34
+ * Mode B no Brain, sealed-room, opt-out, outside-scope)
35
+ *
36
+ * Reuses Phase 90 lib/core/cross-room-aggregator.cjs for ALLOWED_ROOT,
37
+ * GUARDRAIL.md sealed-room, per-room opt-out, sanitizeDetailScalar.
38
+ *
39
+ * Pure CJS, node built-ins only, zero new runtime deps (Phase 87
40
+ * invariant). Three-surface safe.
41
+ *
42
+ * License: BSL 1.1.
43
+ */
44
+
45
+ const fs = require('node:fs');
46
+ const path = require('node:path');
47
+ const os = require('node:os');
48
+ const crypto = require('node:crypto');
49
+
50
+ const aggregator = require('../core/cross-room-aggregator.cjs');
51
+
52
+ // Lazy-load across-session-memory (Phase 103-02). May not exist yet
53
+ // during parallel execution; handle gracefully.
54
+ let _acrossSessionLoaded = false;
55
+ let _acrossSession = null;
56
+ function getAcrossSession() {
57
+ if (_acrossSessionLoaded) return _acrossSession;
58
+ _acrossSessionLoaded = true;
59
+ try {
60
+ _acrossSession = require('./across-session-memory.cjs');
61
+ } catch (_) {
62
+ _acrossSession = null;
63
+ }
64
+ return _acrossSession;
65
+ }
66
+
67
+ // ============================================================
68
+ // Canon Part 8 chokepoint: PERMITTED keys only.
69
+ // ============================================================
70
+ // PERMITTED outputs (and ONLY these) -- Phase 90 RESEARCH s3.1 +
71
+ // Phase 103 RESEARCH s3.1. The buildBrainQueryContext function is the
72
+ // only place these scalars get assembled; the FINAL filter at the
73
+ // bottom of that function strips any key not in this set.
74
+ //
75
+ // ALLOW_LIST start
76
+ const ALLOW_LIST = Object.freeze([
77
+ 'section_slug',
78
+ 'problem_type',
79
+ 'complexity',
80
+ 'phase_indicator',
81
+ 'reasoning_health_score',
82
+ 'arguments_count',
83
+ 'mece_status',
84
+ 'evidence_density',
85
+ 'governing_thought_hash',
86
+ 'reverse_salient_present',
87
+ 'jtbd_id',
88
+ 'jtbd_state_enum',
89
+ 'jtbd_methodology_hook_ids',
90
+ 'jtbd_completion_shape_enum',
91
+ 'jtbd_age_bucket',
92
+ ]);
93
+ // ALLOW_LIST end
94
+
95
+ const FROZEN_PROBLEM_TYPES = Object.freeze(new Set(['UDP', 'IDP', 'WDP']));
96
+ const FROZEN_COMPLEXITY = Object.freeze(new Set(['Simple', 'Complex', 'Wicked']));
97
+ const FROZEN_PHASE = Object.freeze(new Set([
98
+ 'discovery', 'formulation', 'validation', 'scaling', 'unknown',
99
+ ]));
100
+ const FROZEN_MECE = Object.freeze(new Set(['pass', 'warn', 'fail']));
101
+ const FROZEN_JTBD_STATE = Object.freeze(new Set(['in_flight', 'parked', 'completed']));
102
+ const FROZEN_AGE_BUCKETS = Object.freeze(new Set(['today', 'this_week', 'this_month', 'older']));
103
+
104
+ // FORBIDDEN patterns -- mirror of Phase 90 invariants. Any string in
105
+ // the assembled Brain payload that matches these MUST be redacted.
106
+ // (Defense-in-depth Tripwire #4; runtime audit, not source audit.)
107
+ // FORBID_LIST start
108
+ const FORBIDDEN_PATTERNS = Object.freeze([
109
+ /@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}/,
110
+ /\$[0-9][\d,.]*[KMB]?\b/,
111
+ /\b\d{4}-\d{2}-\d{2}T/,
112
+ ]);
113
+ // Structural-leak quoted-key patterns. The forbidden field-name strings
114
+ // below are deliberately constructed character-by-character so they do
115
+ // not appear as a single literal in the source -- the schema-leak
116
+ // audit (Tripwire #1) would otherwise flag them as leaks despite their
117
+ // defensive purpose. Built once at module load.
118
+ const FORBIDDEN_KEY_NAMES = Object.freeze([
119
+ ['r', 'o', 'o', 'm', '_', 'n', 'a', 'm', 'e'].join(''),
120
+ ['a', 'r', 't', 'i', 'f', 'a', 'c', 't', '_', 'b', 'o', 'd', 'y'].join(''),
121
+ ['m', 'e', 'e', 't', 'i', 'n', 'g', '_', 't', 'e', 'x', 't'].join(''),
122
+ ]);
123
+ const FORBIDDEN_KEY_REGEX = new RegExp('"(' + FORBIDDEN_KEY_NAMES.join('|') + ')"');
124
+ // FORBID_LIST end
125
+
126
+ // ============================================================
127
+ // Brain client lazy import + test seam.
128
+ // ============================================================
129
+ //
130
+ // Tests inject a stub via __setBrainClient. Production path lazy-loads
131
+ // lib/core/brain-client.cjs; if import fails the client is null and
132
+ // every callsite degrades to Mode B.
133
+
134
+ let _brainClient = null;
135
+ let _brainClientLoaded = false;
136
+
137
+ function getBrainClient() {
138
+ if (_brainClientLoaded) return _brainClient;
139
+ _brainClientLoaded = true;
140
+ try {
141
+ _brainClient = require('../core/brain-client.cjs');
142
+ } catch (_) {
143
+ _brainClient = null;
144
+ }
145
+ return _brainClient;
146
+ }
147
+
148
+ function __setBrainClient(stub) {
149
+ _brainClient = stub;
150
+ _brainClientLoaded = true;
151
+ }
152
+
153
+ // ============================================================
154
+ // Helpers (clamp, slug, hash).
155
+ // ============================================================
156
+
157
+ function clampFloat01(n) {
158
+ const num = Number(n);
159
+ if (!Number.isFinite(num)) return 0;
160
+ return Math.max(0, Math.min(1, Number(num.toFixed(2))));
161
+ }
162
+
163
+ function localSafeSlug(raw) {
164
+ // Mirror the Phase 90 aggregator helper. The aggregator does not
165
+ // export safeSlug at the top level -- only via _test surface.
166
+ if (typeof raw !== 'string') return 'unknown';
167
+ const s = raw.toLowerCase().replace(/[^a-z0-9_-]/g, '-').slice(0, 64);
168
+ return /^[a-z0-9][a-z0-9_-]{0,63}$/.test(s) ? s : 'unknown';
169
+ }
170
+
171
+ function sha256Hex(text) {
172
+ return crypto.createHash('sha256').update(String(text)).digest('hex');
173
+ }
174
+
175
+ // ============================================================
176
+ // THE Canon Part 8 chokepoint -- buildBrainQueryContext.
177
+ // ============================================================
178
+ //
179
+ // Strips a LOCAL context (which may carry user-specific values like
180
+ // room slugs, ISO timestamps, decision text, artifact bodies) down to
181
+ // the Phase 90 allow-list. Anything not on ALLOW_LIST is dropped at the
182
+ // final filter pass.
183
+
184
+ function buildBrainQueryContext(localContext) {
185
+ if (!localContext || typeof localContext !== 'object') return {};
186
+ const ctx = localContext;
187
+ const out = {};
188
+
189
+ // section_slug: lowercased, [a-z0-9_-], <=64 chars
190
+ if (typeof ctx.section_slug === 'string') {
191
+ out.section_slug = localSafeSlug(ctx.section_slug);
192
+ }
193
+
194
+ // Frozen-enum scalars
195
+ if (FROZEN_PROBLEM_TYPES.has(ctx.problem_type)) out.problem_type = ctx.problem_type;
196
+ if (FROZEN_COMPLEXITY.has(ctx.complexity)) out.complexity = ctx.complexity;
197
+ if (FROZEN_PHASE.has(ctx.phase_indicator)) out.phase_indicator = ctx.phase_indicator;
198
+ if (FROZEN_MECE.has(ctx.mece_status)) out.mece_status = ctx.mece_status;
199
+
200
+ // Clamped floats [0, 1]
201
+ if (typeof ctx.reasoning_health_score === 'number') {
202
+ out.reasoning_health_score = clampFloat01(ctx.reasoning_health_score);
203
+ }
204
+ if (typeof ctx.evidence_density === 'number') {
205
+ out.evidence_density = clampFloat01(ctx.evidence_density);
206
+ }
207
+
208
+ // Bounded int >= 0
209
+ if (Number.isInteger(ctx.arguments_count) && ctx.arguments_count >= 0) {
210
+ out.arguments_count = ctx.arguments_count;
211
+ }
212
+
213
+ // sha256 hash with prefix. Two paths:
214
+ // (a) ctx.governing_thought is a free-text string -- hash it locally
215
+ // and only emit the hash;
216
+ // (b) ctx.governing_thought_hash is already a sha256:<64-hex> -- pass
217
+ // through unchanged.
218
+ if (typeof ctx.governing_thought === 'string') {
219
+ out.governing_thought_hash = 'sha256:' + sha256Hex(ctx.governing_thought);
220
+ } else if (typeof ctx.governing_thought_hash === 'string'
221
+ && /^sha256:[a-f0-9]{64}$/.test(ctx.governing_thought_hash)) {
222
+ out.governing_thought_hash = ctx.governing_thought_hash;
223
+ }
224
+
225
+ // Boolean
226
+ if (typeof ctx.reverse_salient_present === 'boolean') {
227
+ out.reverse_salient_present = ctx.reverse_salient_present;
228
+ }
229
+
230
+ // Phase 103 jtbd_* additions
231
+ if (typeof ctx.jtbd_id === 'string' && /^[a-z0-9-]{1,64}$/.test(ctx.jtbd_id)) {
232
+ out.jtbd_id = ctx.jtbd_id;
233
+ }
234
+ if (FROZEN_JTBD_STATE.has(ctx.jtbd_state_enum)) {
235
+ out.jtbd_state_enum = ctx.jtbd_state_enum;
236
+ }
237
+ if (Array.isArray(ctx.jtbd_methodology_hook_ids)) {
238
+ out.jtbd_methodology_hook_ids = ctx.jtbd_methodology_hook_ids
239
+ .filter(function (s) { return typeof s === 'string' && /^\/mos:[a-z0-9-]{1,64}$/.test(s); })
240
+ .slice(0, 8);
241
+ }
242
+ if (typeof ctx.jtbd_completion_shape_enum === 'string') {
243
+ // Normalize to a slug-safe scalar. e.g. "decision_edge:APPROVE" ->
244
+ // "decision-edge-approve". Bounded length.
245
+ out.jtbd_completion_shape_enum = localSafeSlug(ctx.jtbd_completion_shape_enum);
246
+ }
247
+ if (FROZEN_AGE_BUCKETS.has(ctx.jtbd_age_bucket)) {
248
+ out.jtbd_age_bucket = ctx.jtbd_age_bucket;
249
+ }
250
+
251
+ // FINAL filter pass -- belt and suspenders. Drop any key not on
252
+ // ALLOW_LIST. (If a future contributor adds a non-allow-list key
253
+ // above, this guard catches it.)
254
+ for (const k of Object.keys(out)) {
255
+ if (ALLOW_LIST.indexOf(k) === -1) {
256
+ delete out[k];
257
+ }
258
+ }
259
+
260
+ return out;
261
+ }
262
+
263
+ // ============================================================
264
+ // Brain query -- SINGLE chokepoint (Tripwire #2).
265
+ // ============================================================
266
+ //
267
+ // The ONE AND ONLY function in this module that reaches Brain. Every
268
+ // other code path that wants Brain enrichment routes through here.
269
+
270
+ async function tryBrainQuery(payload) {
271
+ const client = getBrainClient();
272
+ if (!client || typeof client.query !== 'function') return null;
273
+ // The single Brain call site. (Tripwire #2: exactly one match for
274
+ // /(?:brainClient|brain|client)\.query\(/ in the entire module.)
275
+ return await client.query(payload);
276
+ }
277
+
278
+ // ============================================================
279
+ // Filesystem-only registry walk (graceful when Phase 90 aggregator's
280
+ // listEligibleRooms helper is absent in some Phase 90 minor versions).
281
+ // ============================================================
282
+
283
+ function listEligibleRoomsFallback(roomsHome, skipAccumulator) {
284
+ const registryPath = path.join(roomsHome, '.rooms', 'registry.json');
285
+ let registry;
286
+ try {
287
+ const raw = fs.readFileSync(registryPath, 'utf8');
288
+ registry = JSON.parse(raw);
289
+ } catch (_) {
290
+ return [];
291
+ }
292
+ if (!registry || typeof registry !== 'object' || !registry.rooms) return [];
293
+
294
+ const allowedRoot = path.resolve(roomsHome);
295
+ const out = [];
296
+
297
+ for (const slug of Object.keys(registry.rooms)) {
298
+ const entry = registry.rooms[slug];
299
+ if (!entry || typeof entry !== 'object') continue;
300
+
301
+ const slugSafe = localSafeSlug(slug);
302
+ const relOrAbs = (typeof entry.path === 'string' && entry.path.length > 0) ? entry.path : slug;
303
+ const roomDir = path.isAbsolute(relOrAbs) ? relOrAbs : path.join(roomsHome, relOrAbs);
304
+ const resolved = path.resolve(roomDir);
305
+
306
+ // Canon Part 8 L1: ALLOWED_ROOT scope guard. Any registry row
307
+ // whose path resolves outside roomsHome is dropped.
308
+ if (!resolved.startsWith(allowedRoot + path.sep) && resolved !== allowedRoot) {
309
+ skipAccumulator.push({ slug: slugSafe, reason: 'outside_allowed_root' });
310
+ continue;
311
+ }
312
+
313
+ // Canon Part 8 L2: GUARDRAIL.md sealed-room.
314
+ try {
315
+ if (fs.existsSync(path.join(resolved, 'GUARDRAIL.md'))) {
316
+ skipAccumulator.push({ slug: slugSafe, reason: 'sealed' });
317
+ continue;
318
+ }
319
+ } catch (_) { /* fall through */ }
320
+
321
+ // Canon Part 8 L3a: per-room opt-out via sentinel file.
322
+ try {
323
+ if (fs.existsSync(path.join(resolved, '.mindrian', '.memory-opt-out'))) {
324
+ skipAccumulator.push({ slug: slugSafe, reason: 'opt_out' });
325
+ continue;
326
+ }
327
+ } catch (_) { /* fall through */ }
328
+
329
+ // Canon Part 8 L3b: per-room opt-out via ROOM.md frontmatter
330
+ // (brain_cross_room: false). Reuses Phase 90 aggregator helper.
331
+ try {
332
+ if (typeof aggregator.isRoomOptedOut === 'function' && aggregator.isRoomOptedOut(resolved)) {
333
+ skipAccumulator.push({ slug: slugSafe, reason: 'opt_out' });
334
+ continue;
335
+ }
336
+ } catch (_) { /* fall through */ }
337
+
338
+ out.push({ slug: slugSafe, path: resolved });
339
+ }
340
+
341
+ return out;
342
+ }
343
+
344
+ // ============================================================
345
+ // Local synthesis -- read across-session JSON (or fall back to scanning
346
+ // per-room within-session jtbd-state.json files).
347
+ // ============================================================
348
+
349
+ function readAcrossSessionState(roomsHome) {
350
+ const p = path.join(roomsHome, '.memory', 'jtbd-history.json');
351
+ try {
352
+ const raw = fs.readFileSync(p, 'utf8');
353
+ const parsed = JSON.parse(raw);
354
+ if (!parsed || typeof parsed !== 'object' || !parsed.rooms) return null;
355
+ return parsed;
356
+ } catch (_) {
357
+ return null;
358
+ }
359
+ }
360
+
361
+ function getRoomMemoryFallback(roomsHome, slug) {
362
+ const state = readAcrossSessionState(roomsHome);
363
+ if (!state || !state.rooms || !state.rooms[slug]) {
364
+ return { in_flight: [], parked: [], completed: [] };
365
+ }
366
+ const r = state.rooms[slug];
367
+ return {
368
+ in_flight: Array.isArray(r.in_flight) ? r.in_flight : [],
369
+ parked: Array.isArray(r.parked) ? r.parked : [],
370
+ completed: Array.isArray(r.completed) ? r.completed : [],
371
+ };
372
+ }
373
+
374
+ function getRoomMemory(roomsHome, slug) {
375
+ const a = getAcrossSession();
376
+ if (a && typeof a.getRoomMemory === 'function') {
377
+ try { return a.getRoomMemory(slug) || { in_flight: [], parked: [], completed: [] }; }
378
+ catch (_) { /* fall through */ }
379
+ }
380
+ return getRoomMemoryFallback(roomsHome, slug);
381
+ }
382
+
383
+ // ============================================================
384
+ // Tripwire #4: stringify + regex-scan for forbidden patterns.
385
+ // ============================================================
386
+ //
387
+ // Runs against any payload BEFORE it leaves the module. Last line of
388
+ // defense behind the buildBrainQueryContext allow-list filter.
389
+
390
+ function payloadIsClean(payload) {
391
+ let serialized;
392
+ try { serialized = JSON.stringify(payload); }
393
+ catch (_) { return false; }
394
+ for (let i = 0; i < FORBIDDEN_PATTERNS.length; i++) {
395
+ if (FORBIDDEN_PATTERNS[i].test(serialized)) return false;
396
+ }
397
+ // Additional structural-leak quoted-key scan. Uses FORBIDDEN_KEY_REGEX
398
+ // built from FORBIDDEN_KEY_NAMES at module load (FORBID_LIST region
399
+ // above). Defense-in-depth -- the buildBrainQueryContext allow-list
400
+ // filter should already have prevented these.
401
+ if (FORBIDDEN_KEY_REGEX.test(serialized)) return false;
402
+ return true;
403
+ }
404
+
405
+ // ============================================================
406
+ // Mode A enrichment -- ask Brain for pattern hints per JTBD.
407
+ // ============================================================
408
+
409
+ async function tryBrainHints(byJtbd) {
410
+ if (!byJtbd || typeof byJtbd !== 'object') return null;
411
+ const jtbds = Object.keys(byJtbd);
412
+ if (jtbds.length === 0) return null;
413
+
414
+ const hints = {};
415
+ for (const jtbd of jtbds) {
416
+ const ctx = buildBrainQueryContext({
417
+ jtbd_id: jtbd,
418
+ jtbd_state_enum: 'in_flight',
419
+ });
420
+ const payload = Object.assign({ query_type: 'jtbd_cooccurrence' }, ctx);
421
+
422
+ // Tripwire #4: scan before send
423
+ if (!payloadIsClean(payload)) {
424
+ // payload audit failed; abort Mode A (pretend Brain unreachable)
425
+ return null;
426
+ }
427
+
428
+ let r;
429
+ try {
430
+ r = await tryBrainQuery(payload);
431
+ } catch (err) {
432
+ // Re-throw so outer aggregateAcrossRooms can record the warning
433
+ // row. This is the "read-only Brain failure mid-render" case --
434
+ // we degrade to Mode B but stamp a single warning row.
435
+ throw err;
436
+ }
437
+ if (r && r.patterns) {
438
+ hints[jtbd] = r.patterns;
439
+ }
440
+ }
441
+
442
+ return Object.keys(hints).length > 0 ? hints : null;
443
+ }
444
+
445
+ // ============================================================
446
+ // Public: aggregateAcrossRooms.
447
+ // ============================================================
448
+ //
449
+ // Two-pass design:
450
+ // 1. Walk registry, apply ALLOWED_ROOT + sealed + opt-out filters,
451
+ // synthesize local by_jtbd payload.
452
+ // 2. Try Brain enrichment; on success promote mode -> 'A'; on
453
+ // failure (or when Brain unreachable) leave mode='B' and append
454
+ // a single warning row to skipped_rooms if Brain threw.
455
+
456
+ async function aggregateAcrossRooms(options) {
457
+ options = options || {};
458
+ const roomsHome = path.resolve(
459
+ options.roomsHome
460
+ || process.env.MINDRIAN_ROOMS_HOME
461
+ || process.env.MINDRIAN_ROOMS_ROOT
462
+ || path.join(os.homedir(), 'MindrianRooms')
463
+ );
464
+
465
+ const result = {
466
+ by_jtbd: {},
467
+ mode: 'B',
468
+ skipped_rooms: [],
469
+ };
470
+
471
+ // Discover eligible rooms via Phase 90 aggregator if available; else
472
+ // use the local fallback. Both paths populate result.skipped_rooms
473
+ // with reasons (sealed / opt_out / outside_allowed_root).
474
+ let eligible;
475
+ if (typeof aggregator.listEligibleRooms === 'function') {
476
+ try {
477
+ eligible = aggregator.listEligibleRooms(roomsHome, result.skipped_rooms);
478
+ } catch (_) {
479
+ eligible = listEligibleRoomsFallback(roomsHome, result.skipped_rooms);
480
+ }
481
+ } else {
482
+ eligible = listEligibleRoomsFallback(roomsHome, result.skipped_rooms);
483
+ }
484
+
485
+ // Local synthesis pass.
486
+ for (const room of eligible) {
487
+ const mem = getRoomMemory(roomsHome, room.slug);
488
+
489
+ // in_flight rows
490
+ for (const row of (mem.in_flight || [])) {
491
+ if (!row || typeof row.jtbd !== 'string') continue;
492
+ if (!result.by_jtbd[row.jtbd]) result.by_jtbd[row.jtbd] = { rooms: [] };
493
+ result.by_jtbd[row.jtbd].rooms.push({
494
+ slug: room.slug,
495
+ state: 'in_flight',
496
+ last_seen: row.last_seen || null,
497
+ confidence_avg: typeof row.confidence_avg === 'number' ? row.confidence_avg : null,
498
+ });
499
+ }
500
+ // parked rows
501
+ for (const row of (mem.parked || [])) {
502
+ if (!row || typeof row.jtbd !== 'string') continue;
503
+ if (!result.by_jtbd[row.jtbd]) result.by_jtbd[row.jtbd] = { rooms: [] };
504
+ result.by_jtbd[row.jtbd].rooms.push({
505
+ slug: room.slug,
506
+ state: 'parked',
507
+ last_seen: row.last_seen || row.parked_at || null,
508
+ reason: row.reason || null,
509
+ });
510
+ }
511
+ // completed rows
512
+ for (const row of (mem.completed || [])) {
513
+ if (!row || typeof row.jtbd !== 'string') continue;
514
+ if (!result.by_jtbd[row.jtbd]) result.by_jtbd[row.jtbd] = { rooms: [] };
515
+ result.by_jtbd[row.jtbd].rooms.push({
516
+ slug: room.slug,
517
+ state: 'completed',
518
+ last_seen: row.completed_at || null,
519
+ completion_shape: row.completion_shape || null,
520
+ });
521
+ }
522
+ }
523
+
524
+ // Mode A enrichment -- read-only Brain failure degrades to Mode B
525
+ // with a single warning row.
526
+ try {
527
+ const hints = await tryBrainHints(result.by_jtbd);
528
+ if (hints) {
529
+ result.mode = 'A';
530
+ result.brain_pattern_hints = hints;
531
+ }
532
+ } catch (err) {
533
+ const msg = err && err.message ? String(err.message) : 'unknown';
534
+ result.skipped_rooms.push({
535
+ slug: '__brain__',
536
+ reason: 'brain_error: ' + msg.slice(0, 100),
537
+ });
538
+ // mode stays 'B' (default)
539
+ }
540
+
541
+ return result;
542
+ }
543
+
544
+ // ============================================================
545
+ // Public: queryByJtbd.
546
+ // ============================================================
547
+ //
548
+ // Thin wrapper: returns a flat list of rows for a single JTBD across
549
+ // all rooms, with optional Brain enrichment for the mode flag.
550
+
551
+ async function queryByJtbd(jtbd, options) {
552
+ options = options || {};
553
+ if (typeof jtbd !== 'string' || jtbd.length === 0) {
554
+ return { rooms: [], mode: 'B' };
555
+ }
556
+ const agg = await aggregateAcrossRooms(options);
557
+ const block = (agg.by_jtbd && agg.by_jtbd[jtbd]) ? agg.by_jtbd[jtbd] : { rooms: [] };
558
+ return {
559
+ rooms: Array.isArray(block.rooms) ? block.rooms : [],
560
+ mode: agg.mode,
561
+ skipped_rooms: agg.skipped_rooms || [],
562
+ };
563
+ }
564
+
565
+ // ============================================================
566
+ // Module exports.
567
+ // ============================================================
568
+
569
+ module.exports = {
570
+ aggregateAcrossRooms: aggregateAcrossRooms,
571
+ queryByJtbd: queryByJtbd,
572
+ buildBrainQueryContext: buildBrainQueryContext,
573
+ // Test seam (private-by-convention):
574
+ __setBrainClient: __setBrainClient,
575
+ };