@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,570 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ * Phase 89.1a Plan 01 + Plan 02 -- Brain methodology substrate loader core.
4
+ *
5
+ * Single chokepoint for pulling the Brain Pinecone methodology
6
+ * substrate into a local cache. Wraps lib/core/brain-client.cjs
7
+ * (Canon Part 7 Reuse Before Build; do NOT fork). Enforces Canon
8
+ * Part 8 at three layers:
9
+ * (1) validateCtx allow-list from rs-brain-substrate-prompts.cjs
10
+ * (2) buildBrainSubstrateQuery extracts ONLY slug-safe scalars
11
+ * (3) preSendAudit JSON.stringify scan against FORBIDDEN_PATTERNS
12
+ * before any network call
13
+ *
14
+ * loadSubstrate NEVER throws. Every external boundary returns a
15
+ * structured {success, substrate, mode, reason?, warning?} result.
16
+ *
17
+ * Plan 02 adds the cache persistence layer:
18
+ * readCache + atomicWriteSubstrateCache + isCacheFresh +
19
+ * getCacheAgeDays + sha256OfString + full 6-mode loadSubstrate
20
+ * matrix (A1/A2/A3/B1/B2/B3) against real .mindrian/brain-substrate-
21
+ * cache.json files on disk. Atomic write mirrors Phase 88-04-B
22
+ * openSync 'wx' + fsync + rename 7-step protocol.
23
+ *
24
+ * Pure CJS, zero npm deps, node built-ins only (fs, path, crypto).
25
+ */
26
+ 'use strict';
27
+
28
+ const fs = require('node:fs');
29
+ const path = require('node:path');
30
+ const crypto = require('node:crypto');
31
+ const brainClient = require('./brain-client.cjs');
32
+ const prompts = require('./rs-brain-substrate-prompts.cjs');
33
+ const {
34
+ ALLOWED_CTX_KEYS,
35
+ FORBIDDEN_PATTERNS,
36
+ SLUG_REGEX,
37
+ validateCtx,
38
+ PROMPT_VERSION,
39
+ } = prompts;
40
+
41
+ // ---------- BrainBoundaryViolation custom error ----------
42
+
43
+ class BrainBoundaryViolation extends Error {
44
+ constructor(message, meta) {
45
+ super(message);
46
+ this.name = 'BrainBoundaryViolation';
47
+ this.meta = meta || {};
48
+ }
49
+ }
50
+
51
+ // ---------- RESULT_MODES frozen enum ----------
52
+ //
53
+ // A1 = Brain reachable + cache fresh (serve cache, no network).
54
+ // A2 = Brain reachable + cache stale (re-pull, write cache, serve fresh).
55
+ // A3 = Brain reachable + cache missing (pull, write cache, serve fresh).
56
+ // B1 = Brain offline + cache fresh (serve cache with offline warning).
57
+ // B2 = Brain offline + cache stale (serve stale with warning + cache age).
58
+ // B3 = Brain offline + cache missing (tier-0 empty substrate, RS on user corpus only).
59
+
60
+ const RESULT_MODES = Object.freeze({
61
+ A1: 'A1', A2: 'A2', A3: 'A3',
62
+ B1: 'B1', B2: 'B2', B3: 'B3',
63
+ });
64
+ const RESULT_MODE_SET = Object.freeze(new Set(Object.values(RESULT_MODES)));
65
+
66
+ // ---------- Cache schema + TTL constants (Plan 02) ----------
67
+ //
68
+ // schema_version is locked at 1.0 per CONTEXT.md §Cache Design. Any
69
+ // future schema break must bump this string; the reader refuses to
70
+ // consume a cache whose schema_version is not '1.0'. The atomic-write
71
+ // tmpfile suffix 'substrate' distinguishes this producer's tmpfiles
72
+ // from any other .mindrian/*.tmp.* sibling (Phase 90-01 uses '.brain').
73
+
74
+ const CACHE_SCHEMA_VERSION = '1.0';
75
+ const DEFAULT_TTL_DAYS = 30;
76
+ const EXPECTED_EMBEDDING_DIM = 1024;
77
+ const TMP_SUFFIX = 'substrate';
78
+ // Tmpfile naming: brain-substrate-cache.json.tmp.<rand>.substrate.
79
+ // The 88-13 guardian can sweep orphans by walking .mindrian/ and matching
80
+ // this regex. The rand component is base36 slice + Date.now().toString(36)
81
+ // concatenation to guarantee uniqueness under concurrency.
82
+ const TMP_FILENAME_REGEX = /^brain-substrate-cache\.json\.tmp\.[a-z0-9]+\.substrate$/;
83
+
84
+ function getTtlDays() {
85
+ const env = process.env.MINDRIAN_BRAIN_SUBSTRATE_TTL_DAYS;
86
+ const n = env ? parseInt(env, 10) : DEFAULT_TTL_DAYS;
87
+ // Bound-check: [1, 3650] days is a sensible range. Anything outside
88
+ // falls back to the 30d default rather than crashing. Out-of-range
89
+ // values are silently clamped because the env var is user-tunable
90
+ // and a bad value should degrade gracefully, not break session-start.
91
+ if (!Number.isFinite(n) || n < 1 || n > 3650) return DEFAULT_TTL_DAYS;
92
+ return n;
93
+ }
94
+
95
+ function cachePath(roomDir) {
96
+ return path.join(roomDir, '.mindrian', 'brain-substrate-cache.json');
97
+ }
98
+
99
+ function cacheExists(roomDir) {
100
+ try { return fs.existsSync(cachePath(roomDir)); } catch (_e) { return false; }
101
+ }
102
+
103
+ function sha256OfString(s) {
104
+ return 'sha256:' + crypto.createHash('sha256').update(String(s)).digest('hex');
105
+ }
106
+
107
+ // ---------- Audit log writer (append-only JSONL, Canon Part 8 tripwire #3) ----------
108
+ //
109
+ // Local-only. Generic handles only. JSON-Lines format so grep -c outcome:reject
110
+ // answers "how many adversarial queries blocked" at a glance (per CONTEXT.md).
111
+
112
+ function getAuditPath(roomDir) {
113
+ return path.join(roomDir, '.mindrian', 'brain-substrate-audit.jsonl');
114
+ }
115
+
116
+ function appendAudit(roomDir, entry) {
117
+ try {
118
+ const auditDir = path.join(roomDir, '.mindrian');
119
+ fs.mkdirSync(auditDir, { recursive: true });
120
+ const line = JSON.stringify({
121
+ timestamp: new Date().toISOString(),
122
+ ...entry,
123
+ }) + '\n';
124
+ fs.appendFileSync(getAuditPath(roomDir), line);
125
+ } catch (_e) {
126
+ // Audit log failure must not crash loadSubstrate; log to stderr only.
127
+ process.stderr.write(
128
+ 'rs-brain-substrate: audit append failed: ' +
129
+ String(_e && _e.message) + '\n'
130
+ );
131
+ }
132
+ }
133
+
134
+ // ---------- preSendAudit (THE third tripwire; runs before every brainClient call) ----------
135
+ //
136
+ // JSON.stringify(payload) + FORBIDDEN_PATTERNS scan. Any match -> throw
137
+ // BrainBoundaryViolation BEFORE the payload leaves the process. This is the
138
+ // last line of defense if validateCtx and buildBrainSubstrateQuery both fail
139
+ // to catch a user-specific byte.
140
+
141
+ function preSendAudit(roomDir, payload, caller) {
142
+ const s = JSON.stringify(payload);
143
+ for (const re of FORBIDDEN_PATTERNS) {
144
+ if (re.test(s)) {
145
+ appendAudit(roomDir, {
146
+ caller: caller || 'unknown',
147
+ outcome: 'reject',
148
+ reason: 'forbidden_regex',
149
+ pattern: re.source,
150
+ });
151
+ throw new BrainBoundaryViolation(
152
+ 'forbidden regex match in outbound payload: ' + re.source,
153
+ { caller, pattern: re.source }
154
+ );
155
+ }
156
+ }
157
+ appendAudit(roomDir, {
158
+ caller: caller || 'unknown',
159
+ outcome: 'pass',
160
+ handles: Object.keys(payload || {}),
161
+ });
162
+ }
163
+
164
+ // ---------- buildBrainSubstrateQuery (THE Canon Part 8 chokepoint) ----------
165
+ //
166
+ // Every outbound Brain methodology query MUST pass through this function.
167
+ // validateCtx is called as the FIRST statement so no non-allow-list key
168
+ // can produce a searchParams descriptor.
169
+
170
+ function buildBrainSubstrateQuery(ctx) {
171
+ validateCtx(ctx || {});
172
+ const handles = Object.keys(ctx || {}).sort();
173
+ // Return a descriptor that pullFromBrain consumes. We do NOT build a
174
+ // Cypher string here; brain-client.search takes (queryText, {namespace, topK}).
175
+ // We return the SEARCH param shape derived from allow-list scalars only.
176
+ const searchParams = {
177
+ namespace: ctx.namespace || 'tools',
178
+ topK: ctx.limit || 100,
179
+ };
180
+ const audit_meta = {
181
+ handles,
182
+ prompt_version: PROMPT_VERSION,
183
+ built_at: new Date().toISOString(),
184
+ };
185
+ return { searchParams, audit_meta };
186
+ }
187
+
188
+ // ---------- categorizeError (mirror Phase 90-01 shape) ----------
189
+
190
+ function categorizeError(err) {
191
+ if (!err) return 'unknown';
192
+ const msg = String(err.message || err);
193
+ if (/timeout|ETIMEDOUT/i.test(msg)) return 'timeout';
194
+ if (/rate.?limit|quota/i.test(msg)) return 'rate_limited';
195
+ if (/401|auth|unauthorized/i.test(msg)) return 'auth_failed';
196
+ if (/ECONNREFUSED|ENETUNREACH|network/i.test(msg)) return 'network_error';
197
+ return 'unknown';
198
+ }
199
+
200
+ // ---------- adaptBrainSearchResponse (Phase 89.1 Plan 01; live MCP shape adapter) ----------
201
+ //
202
+ // brain-client.search returns one of TWO shapes depending on Pinecone path:
203
+ // LIVE (post-89.1a smoke): { result: { hits: [{_id, _score, fields}] }, usage }
204
+ // LEGACY (mocked 89.1a-03): { matches: [{id, values, metadata}] }
205
+ //
206
+ // This adapter normalizes both into the {matches:[{id, score?, embedding?, metadata}]}
207
+ // shape pullFromBrain returns to loadSubstrate. The adapter NEVER throws; on any
208
+ // unexpected shape it returns null which pullFromBrain converts to malformed_response.
209
+ //
210
+ // Field renames (live -> normalized):
211
+ // _id -> id
212
+ // _score -> score
213
+ // fields -> metadata
214
+ // fields.framework -> metadata.framework_name (per 89.1a smoke direct-probe finding)
215
+ //
216
+ // Score is preserved because the live brain_search MCP path (Pinecone searchRecords
217
+ // integrated inference) does NOT return embedding vectors. Downstream uses score
218
+ // directly until a separate raw-Pinecone fetch path is added (deferred to 89.2/89.5).
219
+ // Validator Check E is relaxed to "embedding-or-score required" in lockstep.
220
+
221
+ function adaptBrainSearchResponse(result) {
222
+ if (!result || typeof result !== 'object') return null;
223
+ // Legacy / mocked shape: already normalized.
224
+ if (Array.isArray(result.matches)) {
225
+ return { matches: result.matches };
226
+ }
227
+ // Live shape: { result: { hits: [...] } }
228
+ if (result.result && typeof result.result === 'object' &&
229
+ Array.isArray(result.result.hits)) {
230
+ const matches = result.result.hits.map(function (hit) {
231
+ const fields = (hit && hit.fields && typeof hit.fields === 'object') ? hit.fields : {};
232
+ const metadata = {};
233
+ // Rename framework -> framework_name; copy every other field as-is.
234
+ for (const k of Object.keys(fields)) {
235
+ if (k === 'framework') metadata.framework_name = fields[k];
236
+ else metadata[k] = fields[k];
237
+ }
238
+ const out = {
239
+ id: (hit && typeof hit._id === 'string') ? hit._id : '',
240
+ metadata: metadata,
241
+ };
242
+ if (typeof hit._score === 'number' && Number.isFinite(hit._score)) {
243
+ out.score = hit._score;
244
+ }
245
+ return out;
246
+ });
247
+ return { matches: matches };
248
+ }
249
+ return null;
250
+ }
251
+
252
+ // ---------- pullFromBrain (thin wrapper; preSendAudit before every network call) ----------
253
+ //
254
+ // Pitfall 1: detect pinecone_quota_exhausted AND _source === 'neo4j_fallback';
255
+ // do NOT treat Neo4j keyword-match fallback as substrate-quality embeddings.
256
+ //
257
+ // Phase 89.1 Plan 01: adaptBrainSearchResponse called immediately after
258
+ // await brainClient.search to translate the live MCP {result:{hits:[]}}
259
+ // shape into the legacy {matches:[]} shape. Adapter is fully localized
260
+ // here; brain-client.cjs surface unchanged (Canon Part 7 Reuse Before Build).
261
+
262
+ async function pullFromBrain(roomDir, ctx) {
263
+ const built = buildBrainSubstrateQuery(ctx);
264
+ const outboundPayload = { query: '*', ...built.searchParams };
265
+ preSendAudit(roomDir, outboundPayload, 'pullFromBrain');
266
+ try {
267
+ const raw = await brainClient.search('*', built.searchParams);
268
+ // Pitfall 1: Pinecone quota fallback must NOT be cached as substrate.
269
+ if (raw && (raw.error === 'pinecone_quota_exhausted' || raw._source === 'neo4j_fallback')) {
270
+ return { ok: false, reason: 'brain_quota_exhausted', err_category: 'rate_limited' };
271
+ }
272
+ let adapted;
273
+ try {
274
+ adapted = adaptBrainSearchResponse(raw);
275
+ } catch (_adapterErr) {
276
+ return { ok: false, reason: 'adapter_error', err_category: 'unknown' };
277
+ }
278
+ if (!adapted || !Array.isArray(adapted.matches)) {
279
+ return { ok: false, reason: 'malformed_response', err_category: 'unknown' };
280
+ }
281
+ return { ok: true, matches: adapted.matches };
282
+ } catch (err) {
283
+ return { ok: false, reason: 'brain_error', err_category: categorizeError(err) };
284
+ }
285
+ }
286
+
287
+ // ---------- Cache reader (Plan 02; never throws, always structured result) ----------
288
+ //
289
+ // readCache returns {ok, payload} on success, or {ok:false, reason, ...} on
290
+ // any failure. Reasons: 'missing', 'read_error', 'malformed_root',
291
+ // 'schema_version_mismatch', 'malformed_substrate_array', 'partial_cache'.
292
+ //
293
+ // Pitfall 5 completeness guard (partial_cache): if the payload declares
294
+ // embedding_count and the substrate array length disagrees, the cache is
295
+ // treated as invalid at the reader. The validator at lib/memory/validators/
296
+ // brain-substrate-invariants.cjs ALSO catches this case at session-start
297
+ // and pre-commit. Defense-in-depth: either layer alone blocks a partial
298
+ // cache from polluting downstream RS runs.
299
+
300
+ function readCache(roomDir) {
301
+ const p = cachePath(roomDir);
302
+ try {
303
+ if (!fs.existsSync(p)) return { ok: false, reason: 'missing' };
304
+ const raw = fs.readFileSync(p, 'utf8');
305
+ const payload = JSON.parse(raw);
306
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
307
+ return { ok: false, reason: 'malformed_root' };
308
+ }
309
+ if (payload.schema_version !== CACHE_SCHEMA_VERSION) {
310
+ return {
311
+ ok: false,
312
+ reason: 'schema_version_mismatch',
313
+ got: payload.schema_version,
314
+ };
315
+ }
316
+ if (!Array.isArray(payload.substrate)) {
317
+ return { ok: false, reason: 'malformed_substrate_array' };
318
+ }
319
+ // Pitfall 5 completeness guard.
320
+ if (typeof payload.embedding_count === 'number' &&
321
+ payload.substrate.length !== payload.embedding_count) {
322
+ return {
323
+ ok: false,
324
+ reason: 'partial_cache',
325
+ declared: payload.embedding_count,
326
+ actual: payload.substrate.length,
327
+ };
328
+ }
329
+ return { ok: true, payload };
330
+ } catch (err) {
331
+ return {
332
+ ok: false,
333
+ reason: 'read_error',
334
+ err_message: String(err && err.message),
335
+ };
336
+ }
337
+ }
338
+
339
+ // ---------- TTL math (Plan 02; Invariant I6) ----------
340
+ //
341
+ // getCacheAgeDays: (now - pulled_at) in days. Returns Infinity if
342
+ // pulled_at is missing or unparseable so a degenerate cache always
343
+ // sorts as stale. isCacheFresh: strictly less-than comparison against
344
+ // the payload-local ttl_days (falls back to env-driven default).
345
+
346
+ function getCacheAgeDays(payload) {
347
+ if (!payload || !payload.pulled_at) return Infinity;
348
+ const pulledMs = Date.parse(payload.pulled_at);
349
+ if (!Number.isFinite(pulledMs)) return Infinity;
350
+ return (Date.now() - pulledMs) / 86400000;
351
+ }
352
+
353
+ function isCacheFresh(payload) {
354
+ const ttl = (payload && typeof payload.ttl_days === 'number')
355
+ ? payload.ttl_days
356
+ : getTtlDays();
357
+ return getCacheAgeDays(payload) < ttl;
358
+ }
359
+
360
+ // ---------- Atomic write (Plan 02; Phase 88-04-B 7-step protocol) ----------
361
+ //
362
+ // Pattern mirrors lib/core/brain-derivation.cjs atomicWriteBrainMd
363
+ // byte-for-byte. Seven steps:
364
+ // 1. mkdirSync parent (recursive)
365
+ // 2. openSync(tmpPath, 'wx') -- exclusive create, EEXIST on collision
366
+ // 3. writeFileSync(fd, body)
367
+ // 4. fsyncSync(fd) -- durability: flush OS + disk buffers
368
+ // 5. closeSync(fd)
369
+ // 6. renameSync(tmpPath, finalPath) -- atomic publish
370
+ // 7. return {success, path}
371
+ // On ANY failure: closeSync (if fd open) + unlinkSync (best-effort) +
372
+ // return structured {success:false, fs_error}. loadSubstrate wraps this
373
+ // so a cache write failure never throws to the caller; it emits a
374
+ // warning on the result object instead.
375
+
376
+ function atomicWriteSubstrateCache(roomDir, payload) {
377
+ const finalPath = cachePath(roomDir);
378
+ const rand = Math.random().toString(36).slice(2) + Date.now().toString(36);
379
+ const tmpPath = finalPath + '.tmp.' + rand + '.' + TMP_SUFFIX;
380
+ let fd = null;
381
+ try {
382
+ fs.mkdirSync(path.dirname(finalPath), { recursive: true });
383
+ fd = fs.openSync(tmpPath, 'wx'); // exclusive create
384
+ fs.writeFileSync(fd, JSON.stringify(payload, null, 2));
385
+ fs.fsyncSync(fd); // durability fence
386
+ fs.closeSync(fd);
387
+ fd = null;
388
+ fs.renameSync(tmpPath, finalPath); // atomic publish
389
+ return { success: true, path: finalPath };
390
+ } catch (err) {
391
+ try { if (fd !== null) fs.closeSync(fd); } catch (_e) { /* ignore */ }
392
+ try { fs.unlinkSync(tmpPath); } catch (_e) { /* ignore */ }
393
+ return { success: false, fs_error: String(err && err.message) };
394
+ }
395
+ }
396
+
397
+ // ---------- loadSubstrate (top-level entry; NEVER throws; full 6-mode matrix) ----------
398
+ //
399
+ // Plan 02 behavior: implements all six graceful-degradation modes
400
+ // against real cache files on disk per CONTEXT.md §Graceful Degradation
401
+ // Contract. The mode matrix below names each RESULT_MODES value so a
402
+ // future reader can grep for RESULT_MODES.<mode> and find both its
403
+ // return site AND its documented contract in one place.
404
+ //
405
+ // RESULT_MODES.A1 : Brain reachable + cache fresh -> cached substrate, no network
406
+ // RESULT_MODES.A2 : Brain reachable + cache stale -> re-pull, write cache, return fresh
407
+ // RESULT_MODES.A3 : Brain reachable + cache missing -> pull, write cache, return fresh
408
+ // RESULT_MODES.B1 : Brain offline + cache fresh -> cached + offline warning
409
+ // RESULT_MODES.B2 : Brain offline + cache stale -> cached + stale warning (stale_days)
410
+ // RESULT_MODES.B3 : Brain offline + cache missing -> tier-0 empty substrate + warning
411
+ //
412
+ // Additional options:
413
+ // opts.forceRefresh = true -> skip Mode A1, always attempt pull when Brain up
414
+ // opts.roomDir -> override MINDRIAN_ROOM / process.cwd()
415
+ // opts.limit -> topK for pullFromBrain (default 100)
416
+
417
+ async function loadSubstrate(options) {
418
+ const opts = options || {};
419
+ const roomDir = opts.roomDir || process.env.MINDRIAN_ROOM || process.cwd();
420
+ try {
421
+ const cacheRead = readCache(roomDir);
422
+ const cacheOk = cacheRead.ok;
423
+ const fresh = cacheOk && isCacheFresh(cacheRead.payload);
424
+ const ageDays = cacheOk ? getCacheAgeDays(cacheRead.payload) : null;
425
+ const brainUp = brainClient.isAvailable();
426
+
427
+ const forceRefresh = opts.forceRefresh === true;
428
+
429
+ // Mode A1: Brain reachable + fresh cache + not forced -> serve cache,
430
+ // no network. Also covers Mode B1 when Brain is offline but cache is
431
+ // fresh (offline warning attached).
432
+ if (!forceRefresh && cacheOk && fresh) {
433
+ const mode = brainUp ? RESULT_MODES.A1 : RESULT_MODES.B1;
434
+ return {
435
+ success: true,
436
+ substrate: cacheRead.payload.substrate,
437
+ mode,
438
+ cache_age_days: ageDays,
439
+ warning: brainUp ? undefined : 'Brain offline; using cached methodology',
440
+ };
441
+ }
442
+
443
+ // Paths that need a pull (A2, A3, or forced refresh). If Brain up,
444
+ // attempt pull; on success, overwrite cache atomically and return.
445
+ if (brainUp) {
446
+ const pull = await pullFromBrain(roomDir, {
447
+ namespace: 'tools',
448
+ limit: opts.limit || 100,
449
+ });
450
+ if (pull.ok) {
451
+ const substrate = pull.matches.slice();
452
+ // Phase 89.1 Plan 01: cache _completeness reflects whether entries
453
+ // carry 1024-dim embedding vectors (legacy/mocked path) or only
454
+ // a Pinecone score (live brain_search path; no values returned by
455
+ // searchRecords today). Backward-compatible: pre-89.1 caches without
456
+ // this field are treated as 'full-vectors' by downstream readers.
457
+ let completeness = 'partial';
458
+ if (substrate.length === 0) {
459
+ completeness = 'partial';
460
+ } else {
461
+ const hasAnyEmbedding = substrate.some(function (e) {
462
+ return e && Array.isArray(e.embedding);
463
+ });
464
+ const hasAnyScore = substrate.some(function (e) {
465
+ return e && typeof e.score === 'number';
466
+ });
467
+ const allEmbedding = substrate.every(function (e) {
468
+ return e && Array.isArray(e.embedding);
469
+ });
470
+ const allScore = substrate.every(function (e) {
471
+ return e && typeof e.score === 'number';
472
+ });
473
+ if (allEmbedding) completeness = 'full-vectors';
474
+ else if (allScore && !hasAnyEmbedding) completeness = 'score-only';
475
+ else if (hasAnyEmbedding || hasAnyScore) completeness = 'partial';
476
+ }
477
+ const newPayload = {
478
+ schema_version: CACHE_SCHEMA_VERSION,
479
+ pulled_at: new Date().toISOString(),
480
+ ttl_days: getTtlDays(),
481
+ source_index: 'pws-brain',
482
+ source_namespaces: ['tools'],
483
+ embedding_count: substrate.length,
484
+ content_hash: sha256OfString(JSON.stringify(substrate)),
485
+ _completeness: completeness,
486
+ substrate,
487
+ };
488
+ const write = atomicWriteSubstrateCache(roomDir, newPayload);
489
+ const mode = cacheOk ? RESULT_MODES.A2 : RESULT_MODES.A3;
490
+ return {
491
+ success: true,
492
+ substrate,
493
+ mode,
494
+ cache_age_days: 0,
495
+ warning: write.success
496
+ ? undefined
497
+ : 'Cache write failed: ' + write.fs_error,
498
+ };
499
+ }
500
+ // Brain up but pull failed (including Pitfall 1 quota fallback)
501
+ // -> fall through to cache-present (B1/B2) or B3.
502
+ }
503
+
504
+ // Mode B1/B2: Brain unreachable (or pull failed) with cache present.
505
+ // Serve existing cache with appropriate warning. Fresh -> B1, stale -> B2.
506
+ if (cacheOk) {
507
+ const mode = fresh ? RESULT_MODES.B1 : RESULT_MODES.B2;
508
+ const warning = fresh
509
+ ? 'Brain offline; using cached methodology'
510
+ : 'Brain offline; using stale methodology (cache age ' +
511
+ Math.floor(ageDays) + ' days)';
512
+ return {
513
+ success: true,
514
+ substrate: cacheRead.payload.substrate,
515
+ mode,
516
+ cache_age_days: ageDays,
517
+ stale_days: fresh ? 0 : Math.floor(ageDays),
518
+ warning,
519
+ };
520
+ }
521
+
522
+ // Mode B3: tier-0 empty substrate, graceful degradation.
523
+ return {
524
+ success: true,
525
+ substrate: [],
526
+ mode: RESULT_MODES.B3,
527
+ warning: 'Brain offline and no cache; RS will run on user corpus only',
528
+ };
529
+ } catch (err) {
530
+ // Catch-all: loadSubstrate NEVER throws.
531
+ return {
532
+ success: true,
533
+ substrate: [],
534
+ mode: RESULT_MODES.B3,
535
+ warning: 'loadSubstrate caught: ' + String(err && err.message),
536
+ reason: categorizeError(err),
537
+ };
538
+ }
539
+ }
540
+
541
+ // ---------- Exports ----------
542
+
543
+ module.exports = {
544
+ loadSubstrate,
545
+ buildBrainSubstrateQuery,
546
+ preSendAudit,
547
+ categorizeError,
548
+ BrainBoundaryViolation,
549
+ RESULT_MODES,
550
+ _test: {
551
+ pullFromBrain,
552
+ adaptBrainSearchResponse,
553
+ appendAudit,
554
+ getAuditPath,
555
+ RESULT_MODE_SET,
556
+ // Plan 02 cache I/O surface (test-only; production callers use loadSubstrate).
557
+ readCache,
558
+ atomicWriteSubstrateCache,
559
+ isCacheFresh,
560
+ getCacheAgeDays,
561
+ cachePath,
562
+ cacheExists,
563
+ sha256OfString,
564
+ getTtlDays,
565
+ CACHE_SCHEMA_VERSION,
566
+ DEFAULT_TTL_DAYS,
567
+ EXPECTED_EMBEDDING_DIM,
568
+ TMP_FILENAME_REGEX,
569
+ },
570
+ };