@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,636 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ * Phase 89.1a Plan 03 -- Brain substrate loader adversarial fixture suite.
7
+ *
8
+ * 14 scenarios covering:
9
+ * Adversarial (I1): scenarios 1-6
10
+ * Happy path (I1, I2, I5): scenarios 7-9
11
+ * Cache + persistence (I2,I3,I6,I8): scenarios 10-12
12
+ * Graceful degradation (I4,I5): scenarios 13-14
13
+ *
14
+ * Mocks brain-client via require.cache override (Phase 90-08 pattern).
15
+ * Between scenarios, resetRequireCache clears brain-client + module-
16
+ * under-test so the next require() sees fresh module state.
17
+ *
18
+ * End-of-suite sweeps:
19
+ * A1: re-scan every landed cache file against FORBIDDEN_PATTERNS +
20
+ * DANGEROUS_SUBSTRINGS (Canon Part 8 cross-scenario guarantee).
21
+ * A2: glob every scenario roomDir for orphan tmpfiles matching
22
+ * /^brain-substrate-cache\.json\.tmp\.[a-z0-9]+\.substrate$/.
23
+ *
24
+ * Pure CJS, zero npm deps, node built-ins only (assert, fs, os, path).
25
+ */
26
+
27
+ const assert = require('node:assert/strict');
28
+ const fs = require('node:fs');
29
+ const os = require('node:os');
30
+ const path = require('node:path');
31
+
32
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
33
+
34
+ // ---------- Frozen invariant enums ----------
35
+
36
+ const FROZEN_MODES = Object.freeze(['A1', 'A2', 'A3', 'B1', 'B2', 'B3']);
37
+
38
+ // Source of truth for the parity gate at suite start. Importing from the
39
+ // authoritative module (cross-room-aggregator) means any canon amendment
40
+ // there is felt here with zero code change. A drift at any FORBIDDEN_PATTERNS
41
+ // index vs. the prompts module breaks the suite loudly at the parity gate.
42
+ const crossRoomAggregator = require('../core/cross-room-aggregator.cjs');
43
+
44
+ // Hard substrings that must never appear in any landed cache file. Parity
45
+ // with Phase 90-08 DANGEROUS_SUBSTRINGS so the A1 sweep mirrors the
46
+ // reference suite byte-for-byte.
47
+ const DANGEROUS_SUBSTRINGS = Object.freeze([
48
+ 'Lawrence',
49
+ '5M',
50
+ 'revenue',
51
+ 'Q4 meeting',
52
+ 'jonathan@mindrian.com',
53
+ '123-45-6789',
54
+ ]);
55
+
56
+ // Every cache file written by any scenario (happy-path A3 + the planted
57
+ // fixtures). A1 sweep at suite end scans each against FORBIDDEN_PATTERNS.
58
+ const landedCachePaths = [];
59
+ // Every roomDir used by a scenario. A2 sweep at suite end scans the
60
+ // .mindrian/ subdir of each for orphan tmpfiles.
61
+ const scenarioRoomDirs = [];
62
+
63
+ // ---------- Tmpdir cleanup ----------
64
+
65
+ const ALL_TMP_ROOTS = [];
66
+ process.on('exit', function () {
67
+ for (const d of ALL_TMP_ROOTS) {
68
+ try { fs.rmSync(d, { recursive: true, force: true }); } catch (_e) { /* best effort */ }
69
+ }
70
+ });
71
+
72
+ // ---------- Brain-client mock helpers ----------
73
+ //
74
+ // Mirrors Phase 90-08 installMockBrainClient byte-for-byte. The fake
75
+ // exports are written to require.cache BEFORE rs-brain-substrate is
76
+ // loaded (resetRequireCache is called in runScenario's finally block)
77
+ // so the substrate module sees the mocked client on every re-require.
78
+
79
+ function installMockBrainClient(opts) {
80
+ opts = opts || {};
81
+ const audit = {
82
+ isAvailable_calls: 0,
83
+ query_calls: [],
84
+ search_calls: [],
85
+ smartSearch_calls: [],
86
+ };
87
+ const brainClientPath = require.resolve('../core/brain-client.cjs');
88
+ const realClient = require('../core/brain-client.cjs');
89
+ const fakeExports = {
90
+ isAvailable: function () {
91
+ audit.isAvailable_calls += 1;
92
+ if (typeof opts.isAvailable === 'function') return opts.isAvailable(audit.isAvailable_calls);
93
+ return opts.isAvailable === undefined ? true : !!opts.isAvailable;
94
+ },
95
+ query: async function (cypher) {
96
+ audit.query_calls.push({ cypher: cypher });
97
+ if (typeof opts.query === 'function') return opts.query(cypher);
98
+ return { records: [] };
99
+ },
100
+ search: async function (q, o) {
101
+ audit.search_calls.push({ query: q, options: o });
102
+ if (typeof opts.search === 'function') return opts.search(q, o);
103
+ return { matches: [] };
104
+ },
105
+ smartSearch: async function (q, o) {
106
+ audit.smartSearch_calls.push({ query: q, options: o });
107
+ return null;
108
+ },
109
+ _test: realClient._test,
110
+ };
111
+ require.cache[brainClientPath] = {
112
+ id: brainClientPath,
113
+ filename: brainClientPath,
114
+ loaded: true,
115
+ exports: fakeExports,
116
+ };
117
+ return audit;
118
+ }
119
+
120
+ function resetRequireCache() {
121
+ const targets = [
122
+ '../core/brain-client.cjs',
123
+ '../core/rs-brain-substrate.cjs',
124
+ '../core/rs-brain-substrate-prompts.cjs',
125
+ '../core/cross-room-aggregator.cjs',
126
+ ];
127
+ for (const t of targets) {
128
+ try {
129
+ const p = require.resolve(t);
130
+ delete require.cache[p];
131
+ } catch (_e) { /* best effort */ }
132
+ }
133
+ }
134
+
135
+ // ---------- Scenario bookkeeping ----------
136
+
137
+ let passed = 0;
138
+ let failed = 0;
139
+ const failures = [];
140
+
141
+ async function runScenario(name, fn) {
142
+ const start = Date.now();
143
+ try {
144
+ await fn();
145
+ passed += 1;
146
+ process.stdout.write(' ok ' + name + ' (' + (Date.now() - start) + 'ms)\n');
147
+ } catch (err) {
148
+ failed += 1;
149
+ failures.push({ name: name, err: err });
150
+ process.stderr.write(' FAIL ' + name + '\n');
151
+ process.stderr.write(' ' + (err && err.stack ? err.stack : err) + '\n');
152
+ } finally {
153
+ resetRequireCache();
154
+ }
155
+ }
156
+
157
+ // ---------- runLoad helper (universal I4 + I5 enforcement) ----------
158
+ //
159
+ // Wraps loadSubstrate with try/catch. Asserts:
160
+ // Invariant I4: loadSubstrate NEVER throws (any throw is a suite failure).
161
+ // Invariant I5: result.mode is always in the frozen enum.
162
+ // These apply to every loadSubstrate call across all scenarios, so the
163
+ // helper is the single universal contract enforcement point.
164
+
165
+ async function runLoad(options) {
166
+ let threw = null;
167
+ let result = null;
168
+ try {
169
+ const m = require('../core/rs-brain-substrate.cjs');
170
+ result = await m.loadSubstrate(options);
171
+ } catch (err) {
172
+ threw = err;
173
+ }
174
+ assert.equal(threw, null,
175
+ 'I4: loadSubstrate threw: ' + (threw && (threw.stack || threw.message)));
176
+ assert.ok(result && typeof result === 'object',
177
+ 'I4: loadSubstrate returned non-object');
178
+ assert.ok(FROZEN_MODES.includes(result.mode),
179
+ 'I5: result.mode not in enum: ' + String(result.mode));
180
+ return result;
181
+ }
182
+
183
+ // ---------- Fixture helpers ----------
184
+
185
+ function makeRoomDir(label) {
186
+ const d = fs.mkdtempSync(path.join(os.tmpdir(), 'rssub-s-' + label + '-'));
187
+ ALL_TMP_ROOTS.push(d);
188
+ scenarioRoomDirs.push(d);
189
+ return d;
190
+ }
191
+
192
+ function writePoisonedCache(roomDir, overrides) {
193
+ fs.mkdirSync(path.join(roomDir, '.mindrian'), { recursive: true });
194
+ const base = {
195
+ schema_version: '1.0',
196
+ pulled_at: new Date().toISOString(),
197
+ ttl_days: 30,
198
+ source_index: 'pws-brain',
199
+ source_namespaces: ['tools'],
200
+ embedding_count: 1,
201
+ content_hash: 'sha256:deadbeef',
202
+ _completeness: 'full',
203
+ substrate: [{
204
+ id: 'six_thinking_hats',
205
+ embedding: new Array(1024).fill(0.0),
206
+ metadata: {
207
+ framework_name: 'Six Thinking Hats',
208
+ phase_id: 'phase_2',
209
+ problem_type: 'idp',
210
+ domain: 'innovation',
211
+ },
212
+ }],
213
+ };
214
+ const payload = Object.assign({}, base, overrides || {});
215
+ const cachePath = path.join(roomDir, '.mindrian', 'brain-substrate-cache.json');
216
+ fs.writeFileSync(cachePath, JSON.stringify(payload));
217
+ landedCachePaths.push(cachePath);
218
+ return cachePath;
219
+ }
220
+
221
+ // ---------- Main ----------
222
+
223
+ async function main() {
224
+ process.stdout.write('\n=== Phase 89.1a Plan 03: Brain substrate fixture suite ===\n\n');
225
+
226
+ // ----- Parity gate (runs BEFORE scenario 1) -----
227
+ //
228
+ // The prompts module re-exports FORBIDDEN_PATTERNS from cross-room-
229
+ // aggregator by reference. If anyone ever redefines them instead of re-
230
+ // exporting, this gate catches the drift. Plan 01 already defends
231
+ // against this at require-time, but asserting byte-for-byte parity at
232
+ // every index is the contractual tripwire for Phase 89.1a + Plan 90-08
233
+ // FORBIDDEN_PATTERNS drift detection.
234
+ const prompts = require('../core/rs-brain-substrate-prompts.cjs');
235
+ assert.equal(
236
+ prompts.FORBIDDEN_PATTERNS.length,
237
+ crossRoomAggregator.FORBIDDEN_PATTERNS.length,
238
+ 'FORBIDDEN_PATTERNS parity: length mismatch with cross-room-aggregator'
239
+ );
240
+ for (let i = 0; i < prompts.FORBIDDEN_PATTERNS.length; i += 1) {
241
+ assert.equal(
242
+ prompts.FORBIDDEN_PATTERNS[i].source,
243
+ crossRoomAggregator.FORBIDDEN_PATTERNS[i].source,
244
+ 'FORBIDDEN_PATTERNS parity: regex[' + i + '].source mismatch (drift detected)'
245
+ );
246
+ }
247
+ process.stdout.write(' ok Parity gate: FORBIDDEN_PATTERNS[' +
248
+ prompts.FORBIDDEN_PATTERNS.length + '] byte-for-byte with cross-room-aggregator\n');
249
+ resetRequireCache();
250
+
251
+ // ========== Adversarial scenarios (Invariant I1) ==========
252
+ //
253
+ // Every adversarial scenario MUST assert audit.search_calls.length === 0
254
+ // AND audit.query_calls.length === 0 after the throwing call. That is
255
+ // the load-bearing Canon Part 8 contract: forbidden payloads must be
256
+ // rejected BEFORE any byte leaves the process.
257
+
258
+ await runScenario("Scenario 01: Leaked artifact body in query parameter", async () => {
259
+ const audit = installMockBrainClient({ isAvailable: true });
260
+ const roomDir = makeRoomDir('s01');
261
+ const m = require('../core/rs-brain-substrate.cjs');
262
+ let threw = null;
263
+ try {
264
+ m.buildBrainSubstrateQuery({
265
+ framework_ids: ['The user said at the meeting with Jonathan'],
266
+ });
267
+ } catch (err) { threw = err; }
268
+ assert.ok(threw !== null, 'Must throw on leaked artifact body');
269
+ assert.ok(threw instanceof TypeError || threw.name === 'BrainBoundaryViolation',
270
+ 'Expected TypeError or BrainBoundaryViolation, got: ' + (threw && threw.name));
271
+ assert.equal(audit.search_calls.length, 0,
272
+ 'NO bytes left process: search_calls=' + audit.search_calls.length);
273
+ assert.equal(audit.query_calls.length, 0,
274
+ 'NO bytes left process: query_calls=' + audit.query_calls.length);
275
+ // Unused but retained so future extensions can assert against it.
276
+ void roomDir;
277
+ });
278
+
279
+ await runScenario("Scenario 02: Leaked venture name in domains", async () => {
280
+ const audit = installMockBrainClient({ isAvailable: true });
281
+ const roomDir = makeRoomDir('s02');
282
+ const m = require('../core/rs-brain-substrate.cjs');
283
+ let threw = null;
284
+ try {
285
+ m.buildBrainSubstrateQuery({ domains: ['ACME Corp (Pat Pending)'] });
286
+ } catch (err) { threw = err; }
287
+ assert.ok(threw !== null, 'Must throw on leaked venture name');
288
+ assert.ok(threw instanceof TypeError, 'Expected TypeError, got: ' + (threw && threw.name));
289
+ assert.equal(audit.search_calls.length, 0, 'NO bytes left process: search_calls');
290
+ assert.equal(audit.query_calls.length, 0, 'NO bytes left process: query_calls');
291
+ void roomDir;
292
+ });
293
+
294
+ await runScenario("Scenario 03: Leaked meeting transcript via preSendAudit", async () => {
295
+ const audit = installMockBrainClient({ isAvailable: true });
296
+ const roomDir = makeRoomDir('s03');
297
+ const m = require('../core/rs-brain-substrate.cjs');
298
+ let threw = null;
299
+ try {
300
+ m.preSendAudit(roomDir, {
301
+ query: 'meeting with stakeholders discussed Q4',
302
+ namespace: 'tools',
303
+ }, 'test_s03');
304
+ } catch (err) { threw = err; }
305
+ assert.ok(threw !== null, 'Must throw BrainBoundaryViolation on meeting fragment');
306
+ assert.equal(threw.name, 'BrainBoundaryViolation',
307
+ 'Expected BrainBoundaryViolation, got: ' + (threw && threw.name));
308
+ assert.equal(audit.search_calls.length, 0, 'NO bytes left process: search_calls');
309
+ assert.equal(audit.query_calls.length, 0, 'NO bytes left process: query_calls');
310
+ });
311
+
312
+ await runScenario("Scenario 04: Leaked currency in preSendAudit payload", async () => {
313
+ const audit = installMockBrainClient({ isAvailable: true });
314
+ const roomDir = makeRoomDir('s04');
315
+ const m = require('../core/rs-brain-substrate.cjs');
316
+ let threw = null;
317
+ try {
318
+ m.preSendAudit(roomDir, {
319
+ query: 'valuation is $5.2M',
320
+ namespace: 'tools',
321
+ }, 'test_s04');
322
+ } catch (err) { threw = err; }
323
+ assert.ok(threw !== null, 'Must throw on leaked currency');
324
+ assert.equal(threw.name, 'BrainBoundaryViolation',
325
+ 'Expected BrainBoundaryViolation, got: ' + (threw && threw.name));
326
+ assert.equal(audit.search_calls.length, 0, 'NO bytes left process: search_calls');
327
+ assert.equal(audit.query_calls.length, 0, 'NO bytes left process: query_calls');
328
+ });
329
+
330
+ await runScenario("Scenario 05: Malformed payload JSON-structure injection", async () => {
331
+ const audit = installMockBrainClient({ isAvailable: true });
332
+ const roomDir = makeRoomDir('s05');
333
+ const m = require('../core/rs-brain-substrate.cjs');
334
+ // Object masquerading as framework_ids array -> validateCtx must reject
335
+ // at the array-type check before any nested string is even examined.
336
+ let threw = null;
337
+ try {
338
+ m.buildBrainSubstrateQuery({
339
+ framework_ids: { leaked: 'Lawrence said revenue' },
340
+ });
341
+ } catch (err) { threw = err; }
342
+ assert.ok(threw instanceof TypeError,
343
+ 'Expected TypeError on JSON-structure injection, got: ' + (threw && threw.name));
344
+ assert.equal(audit.search_calls.length, 0, 'NO bytes left process: search_calls');
345
+ assert.equal(audit.query_calls.length, 0, 'NO bytes left process: query_calls');
346
+ void roomDir;
347
+ });
348
+
349
+ await runScenario("Scenario 06: Oversized framework_ids (bypass via volume)", async () => {
350
+ const audit = installMockBrainClient({ isAvailable: true });
351
+ const roomDir = makeRoomDir('s06');
352
+ const m = require('../core/rs-brain-substrate.cjs');
353
+ // 70-char value exceeds SLUG_REGEX limit of 64 characters.
354
+ let threw = null;
355
+ try {
356
+ m.buildBrainSubstrateQuery({ framework_ids: ['a'.repeat(70)] });
357
+ } catch (err) { threw = err; }
358
+ assert.ok(threw instanceof TypeError,
359
+ 'Expected TypeError on oversized slug, got: ' + (threw && threw.name));
360
+ assert.equal(audit.search_calls.length, 0, 'NO bytes left process: search_calls');
361
+ assert.equal(audit.query_calls.length, 0, 'NO bytes left process: query_calls');
362
+ void roomDir;
363
+ });
364
+
365
+ // ========== Happy-path scenarios (Invariants I1, I2, I5) ==========
366
+
367
+ await runScenario("Scenario 07: Mode A1 fresh cache hit, zero network", async () => {
368
+ const audit = installMockBrainClient({ isAvailable: true });
369
+ const roomDir = makeRoomDir('s07');
370
+ writePoisonedCache(roomDir, {
371
+ embedding_count: 1,
372
+ substrate: [{
373
+ id: 'six_thinking_hats',
374
+ embedding: new Array(1024).fill(0.5),
375
+ metadata: {
376
+ framework_name: 'Six Thinking Hats',
377
+ phase_id: 'phase_2',
378
+ problem_type: 'idp',
379
+ domain: 'innovation',
380
+ },
381
+ }],
382
+ });
383
+ const result = await runLoad({ roomDir: roomDir });
384
+ assert.equal(result.mode, 'A1', 'Expected Mode A1, got: ' + result.mode);
385
+ assert.equal(audit.search_calls.length, 0,
386
+ 'A1 must be zero-network: search_calls=' + audit.search_calls.length);
387
+ assert.ok(Array.isArray(result.substrate) && result.substrate.length === 1,
388
+ 'A1 substrate array length 1');
389
+ });
390
+
391
+ await runScenario("Scenario 08: Mode A2 stale cache re-pull", async () => {
392
+ const audit = installMockBrainClient({
393
+ isAvailable: true,
394
+ search: async () => ({
395
+ matches: [{
396
+ id: 'minto',
397
+ embedding: new Array(1024).fill(0.1),
398
+ metadata: {
399
+ framework_name: 'Minto',
400
+ phase_id: 'phase_3',
401
+ problem_type: 'wdp',
402
+ domain: 'strategy',
403
+ },
404
+ }],
405
+ }),
406
+ });
407
+ const roomDir = makeRoomDir('s08');
408
+ // Plant a stale cache (pulled_at 40 days ago -> past 30d TTL default).
409
+ writePoisonedCache(roomDir, {
410
+ pulled_at: new Date(Date.now() - 40 * 86400000).toISOString(),
411
+ });
412
+ const result = await runLoad({ roomDir: roomDir });
413
+ assert.equal(result.mode, 'A2', 'Expected Mode A2, got: ' + result.mode);
414
+ assert.ok(audit.search_calls.length >= 1, 'A2 must re-pull at least once');
415
+ // After A2 writes the fresh cache, record its path for the A1 sweep.
416
+ const freshCachePath = path.join(roomDir, '.mindrian', 'brain-substrate-cache.json');
417
+ if (fs.existsSync(freshCachePath)) landedCachePaths.push(freshCachePath);
418
+ });
419
+
420
+ await runScenario("Scenario 09: Mode A3 missing cache fresh pull", async () => {
421
+ const audit = installMockBrainClient({
422
+ isAvailable: true,
423
+ search: async () => ({
424
+ matches: [{
425
+ id: 'jtbd',
426
+ embedding: new Array(1024).fill(0.2),
427
+ metadata: {
428
+ framework_name: 'JTBD',
429
+ phase_id: 'phase_1',
430
+ problem_type: 'udp',
431
+ domain: 'innovation',
432
+ },
433
+ }],
434
+ }),
435
+ });
436
+ const roomDir = makeRoomDir('s09');
437
+ const result = await runLoad({ roomDir: roomDir });
438
+ assert.equal(result.mode, 'A3', 'Expected Mode A3, got: ' + result.mode);
439
+ assert.ok(audit.search_calls.length >= 1, 'A3 must pull from Brain');
440
+ const m = require('../core/rs-brain-substrate.cjs');
441
+ const cp = m._test.cachePath(roomDir);
442
+ assert.ok(fs.existsSync(cp), 'A3 must write cache atomically at ' + cp);
443
+ landedCachePaths.push(cp);
444
+ });
445
+
446
+ // ========== Cache + persistence (I2, I3, I6, I8) ==========
447
+
448
+ await runScenario("Scenario 10: Malformed cache triggers validator", async () => {
449
+ const roomDir = makeRoomDir('s10');
450
+ fs.mkdirSync(path.join(roomDir, '.mindrian'), { recursive: true });
451
+ fs.writeFileSync(
452
+ path.join(roomDir, '.mindrian', 'brain-substrate-cache.json'),
453
+ '{ not: valid json }'
454
+ );
455
+ const v = require('./validators/brain-substrate-invariants.cjs');
456
+ const r = v.validate(roomDir, {});
457
+ assert.ok(Array.isArray(r.violations), 'validator returns violations array');
458
+ assert.ok(
459
+ r.violations.some(function (x) { return x.category === 'cache_unreadable'; }),
460
+ 'Expected category cache_unreadable in violations'
461
+ );
462
+ });
463
+
464
+ await runScenario("Scenario 11: 31-day-old cache returns B2 under Brain offline", async () => {
465
+ installMockBrainClient({ isAvailable: false });
466
+ const roomDir = makeRoomDir('s11');
467
+ writePoisonedCache(roomDir, {
468
+ pulled_at: new Date(Date.now() - 31 * 86400000).toISOString(),
469
+ });
470
+ const result = await runLoad({ roomDir: roomDir });
471
+ assert.equal(result.mode, 'B2',
472
+ 'Expected Mode B2 (not A1) on 31-day cache + Brain offline, got: ' + result.mode);
473
+ assert.ok(typeof result.stale_days === 'number' && result.stale_days >= 30,
474
+ 'stale_days must be >= 30 on 31-day-old cache, got: ' + result.stale_days);
475
+ });
476
+
477
+ await runScenario("Scenario 12: Validator registers {id, scope, validate}", async () => {
478
+ const v = require('./validators/brain-substrate-invariants.cjs');
479
+ // Registry-compatible shape (Phase 88-13 guardian contract).
480
+ assert.equal(v.id, 'brain-substrate-invariants',
481
+ 'Expected validator id "brain-substrate-invariants", got: ' + String(v.id));
482
+ assert.equal(v.scope, 'room',
483
+ 'Expected validator scope "room", got: ' + String(v.scope));
484
+ assert.equal(typeof v.validate, 'function',
485
+ 'Expected validator.validate to be a function');
486
+ // Exercise the validator against a forbidden-regex-laden metadata cache.
487
+ // Canon boundary check (Plan 02 Check D) must flag this critical.
488
+ const roomDir = makeRoomDir('s12');
489
+ writePoisonedCache(roomDir, {
490
+ substrate: [{
491
+ id: 'six_thinking_hats',
492
+ embedding: new Array(1024).fill(0.0),
493
+ metadata: {
494
+ // The framework_name deliberately embeds a FORBIDDEN_PATTERNS hit
495
+ // (quoted-person + 'meeting with'). The validator's Check D runs
496
+ // JSON.stringify(metadata) and scans against FORBIDDEN_PATTERNS.
497
+ // We keep this content INSIDE the test file (not in the landed
498
+ // cache as a parseable string) by overwriting the cache IMMEDIATELY
499
+ // before the validator runs and then DELETING the file in the
500
+ // A1 sweep's accept-list.
501
+ framework_name: 'PLACEHOLDER',
502
+ phase_id: 'phase_2',
503
+ problem_type: 'idp',
504
+ domain: 'innovation',
505
+ },
506
+ }],
507
+ });
508
+ // Overwrite with the dangerous-content fixture inline. After the
509
+ // validator runs, delete the file so A1 sweep does not see it. The
510
+ // A1 sweep's job is to prove that NO cache landed in the "healthy
511
+ // code path" carries forbidden content; intentionally-poisoned
512
+ // test fixtures are out of scope.
513
+ const cp = path.join(roomDir, '.mindrian', 'brain-substrate-cache.json');
514
+ const poisoned = {
515
+ schema_version: '1.0',
516
+ pulled_at: new Date().toISOString(),
517
+ ttl_days: 30,
518
+ source_index: 'pws-brain',
519
+ source_namespaces: ['tools'],
520
+ embedding_count: 1,
521
+ content_hash: 'sha256:deadbeef',
522
+ _completeness: 'full',
523
+ substrate: [{
524
+ id: 'six_thinking_hats',
525
+ embedding: new Array(1024).fill(0.0),
526
+ metadata: {
527
+ framework_name: 'Lawrence said revenue at Q4 meeting',
528
+ phase_id: 'phase_2',
529
+ problem_type: 'idp',
530
+ domain: 'innovation',
531
+ },
532
+ }],
533
+ };
534
+ fs.writeFileSync(cp, JSON.stringify(poisoned));
535
+ const r = v.validate(roomDir, {});
536
+ assert.ok(
537
+ r.violations.some(function (x) { return x.category === 'canon_boundary'; }),
538
+ 'Expected canon_boundary violation on forbidden-regex-laden metadata'
539
+ );
540
+ assert.equal(r.severity, 'critical',
541
+ 'Expected aggregate severity critical on canon_boundary hit, got: ' + r.severity);
542
+ // Delete the poisoned fixture BEFORE suite-end A1 sweep walks it.
543
+ // This cache is intentionally dangerous for a single validator test;
544
+ // it is not a production-landed cache, so exclude it from A1.
545
+ try { fs.unlinkSync(cp); } catch (_e) { /* best effort */ }
546
+ });
547
+
548
+ // ========== Graceful degradation (I4, I5) ==========
549
+
550
+ await runScenario("Scenario 13: Mode B1 Brain offline + fresh cache", async () => {
551
+ installMockBrainClient({ isAvailable: false });
552
+ const roomDir = makeRoomDir('s13');
553
+ writePoisonedCache(roomDir, {}); // default: fresh (pulled_at = now)
554
+ const result = await runLoad({ roomDir: roomDir });
555
+ assert.equal(result.mode, 'B1',
556
+ 'Expected Mode B1 on offline + fresh cache, got: ' + result.mode);
557
+ assert.ok(typeof result.warning === 'string' && /offline/i.test(result.warning),
558
+ 'B1 must carry "offline" warning string, got: ' + String(result.warning));
559
+ });
560
+
561
+ await runScenario("Scenario 14: Mode B3 offline + no cache = tier-0", async () => {
562
+ installMockBrainClient({ isAvailable: false });
563
+ const roomDir = makeRoomDir('s14');
564
+ const result = await runLoad({ roomDir: roomDir });
565
+ assert.equal(result.mode, 'B3',
566
+ 'Expected Mode B3 on offline + missing cache, got: ' + result.mode);
567
+ assert.deepEqual(result.substrate, [],
568
+ 'B3 substrate must be empty tier-0 array');
569
+ assert.equal(result.success, true,
570
+ 'success must be true even in B3 (tier-0 is a legitimate degradation mode)');
571
+ });
572
+
573
+ // ========== End-of-suite cross-cutting sweeps ==========
574
+ //
575
+ // These sweeps run AFTER all scenarios complete. They are the final
576
+ // Canon Part 8 guarantee: no cache landed during the suite carries a
577
+ // forbidden regex hit OR a dangerous substring, and no orphan tmpfile
578
+ // was left behind by any atomic-write invocation.
579
+
580
+ // A1: Canon Part 8 cross-scenario cache sweep.
581
+ let scanned = 0;
582
+ for (const p of landedCachePaths) {
583
+ if (!fs.existsSync(p)) continue;
584
+ scanned += 1;
585
+ const content = fs.readFileSync(p, 'utf8');
586
+ for (const re of crossRoomAggregator.FORBIDDEN_PATTERNS) {
587
+ assert.ok(!re.test(content),
588
+ 'A1 sweep: ' + p + ' matched forbidden regex ' + re.source);
589
+ }
590
+ for (const s of DANGEROUS_SUBSTRINGS) {
591
+ assert.ok(!content.includes(s),
592
+ 'A1 sweep: ' + p + ' contains dangerous substring ' + s);
593
+ }
594
+ }
595
+ process.stdout.write(' ok A1 sweep: 0 forbidden matches across ' +
596
+ scanned + ' landed cache files\n');
597
+
598
+ // A2: Orphan tmpfile sweep.
599
+ const tmpRegex = /^brain-substrate-cache\.json\.tmp\.[a-z0-9]+\.substrate$/;
600
+ let orphans = 0;
601
+ const orphanPaths = [];
602
+ for (const rd of scenarioRoomDirs) {
603
+ const mindrianDir = path.join(rd, '.mindrian');
604
+ if (!fs.existsSync(mindrianDir)) continue;
605
+ let entries;
606
+ try { entries = fs.readdirSync(mindrianDir); } catch (_e) { continue; }
607
+ for (const f of entries) {
608
+ if (tmpRegex.test(f)) {
609
+ orphans += 1;
610
+ orphanPaths.push(path.join(mindrianDir, f));
611
+ }
612
+ }
613
+ }
614
+ assert.equal(orphans, 0,
615
+ 'A2 sweep: ' + orphans + ' orphan tmpfiles found: ' + orphanPaths.join(','));
616
+ process.stdout.write(' ok A2 sweep: 0 orphan tmpfiles across ' +
617
+ scenarioRoomDirs.length + ' roomDirs\n');
618
+
619
+ // ----- Summary -----
620
+ const total = passed + failed;
621
+ process.stdout.write('\n=== 89.1a substrate fixture suite: ' +
622
+ passed + '/' + total + ' passed, ' + failed + ' failed ===\n');
623
+ if (failed > 0) {
624
+ for (const f of failures) {
625
+ process.stderr.write(' - ' + f.name + ': ' +
626
+ (f.err && f.err.message ? f.err.message : String(f.err)) + '\n');
627
+ }
628
+ process.exit(1);
629
+ }
630
+ process.exit(0);
631
+ }
632
+
633
+ main().catch(function (err) {
634
+ process.stderr.write('FATAL: ' + String(err && err.stack || err) + '\n');
635
+ process.exit(1);
636
+ });