@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,515 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ *
7
+ * Phase 91-08 -- Framework Chain Composer fixture tests
8
+ * ======================================================
9
+ * Exercises lib/core/framework-chain-composer.cjs. The composer parses
10
+ * BRAIN.md framework_chain_predictions section bodies (FEEDS_INTO edges
11
+ * authored by Phase 90-01 deriveSection) and proposes the next framework
12
+ * to run when the user just completed framework A.
13
+ *
14
+ * Canon Part 2 Engine 1 + Appendix E: framework chains power Act 1 to
15
+ * BONO Orchestration handoffs; FEEDS_INTO is the graph infrastructure.
16
+ *
17
+ * Canon Part 3 Section 6 RECOMMENDED gate: chain proposals respect the
18
+ * gate (Mode A + confidence >= 0.7 -> recommended_eligible:true). The
19
+ * gate result is consumed by offer-presenter.cjs (Plan 91-04).
20
+ *
21
+ * Canon Part 7 Reuse Before Build: FEEDS_INTO edges are existing graph
22
+ * infrastructure. This module CONSUMES them; it does not invent a chain
23
+ * representation.
24
+ *
25
+ * Canon Part 8 Graph Boundary: composer reads only the LOCAL BRAIN.md
26
+ * body via readQuadruple.brain.sections. NEVER queries Brain at engine
27
+ * time. The pre-derivation ran in Phase 90-01 inside the Plan 90-01
28
+ * chokepoint, hours before this code runs.
29
+ *
30
+ * Test map:
31
+ * Task 1 (Tests 1-15): parser + completion detection + chain proposal
32
+ * 1. parseFrameworkChainSection 4 FEEDS_INTO lines -> 4 edges
33
+ * 2. parseFrameworkChainSection (no signal) -> []
34
+ * 3. parseFrameworkChainSection format-tolerant (FEEDS_INTO + ->)
35
+ * 4. parseFrameworkChainSection missing confidence -> null edge.confidence
36
+ * 5. detectCompletedFramework via governing_thought match
37
+ * 6. detectCompletedFramework mtime fallback
38
+ * 7. detectCompletedFramework no signal -> null
39
+ * 8. proposeNextFramework happy path -> {next, confidence, source}
40
+ * 9. proposeNextFramework no outgoing edge -> null
41
+ * 10. proposeNextFramework confidence gating (<0.5 -> null)
42
+ * 11. proposeNextFramework tie-breaking by confidence desc
43
+ * 12. proposeNextFramework /mos: command mapping
44
+ * 13. proposeNextFramework grounding rule (reason has FEEDS_INTO + Brain + conf)
45
+ * 14. proposeNextFramework RECOMMENDED eligibility flag
46
+ * 15. proposeNextFramework empty edges -> null
47
+ *
48
+ * Task 2 (Tests 16-18): navigation-engine.cjs decide() integration
49
+ * 16. decide() with chain section + governing_thought -> offer_next_step
50
+ * non-null + reason contains 'FEEDS_INTO'
51
+ * 17. decide() Mode A confidence 0.85 -> recommended_eligible flag set
52
+ * in trace; offer-presenter would render RECOMMENDED marker
53
+ * 18. decide() user override path: turn 1 offers /mos:porter-five-forces;
54
+ * turn 2 userText invokes /mos:lean-canvas -> trace records
55
+ * REJECTED chain suggestion + offer-history outcome=ignored
56
+ *
57
+ * Registered in lib/memory/run-feynman-tests.cjs.
58
+ */
59
+
60
+ const assert = require('node:assert/strict');
61
+ const fs = require('node:fs');
62
+ const path = require('node:path');
63
+ const os = require('node:os');
64
+
65
+ const REPO = path.resolve(__dirname, '..', '..');
66
+ const COMPOSER_PATH = path.join(REPO, 'lib/core/framework-chain-composer.cjs');
67
+ const ENGINE_PATH = path.join(REPO, 'lib/core/navigation-engine.cjs');
68
+
69
+ function requireComposer() {
70
+ return require(COMPOSER_PATH);
71
+ }
72
+
73
+ function requireEngine() {
74
+ return require(ENGINE_PATH);
75
+ }
76
+
77
+ // ---------- Test scaffolding ----------
78
+
79
+ let passed = 0;
80
+ let failed = 0;
81
+ function run(name, fn) {
82
+ try {
83
+ fn();
84
+ process.stdout.write('ok ' + name + '\n');
85
+ passed += 1;
86
+ } catch (err) {
87
+ process.stderr.write('FAIL ' + name + '\n');
88
+ process.stderr.write(String(err && err.stack ? err.stack : err) + '\n');
89
+ failed += 1;
90
+ }
91
+ }
92
+
93
+ // ---------- Section-body fixture helpers ----------
94
+
95
+ function makeChainSection(bodyText) {
96
+ if (bodyText === null) return null;
97
+ return { body: bodyText, tokens_estimate: Math.max(1, Math.ceil(bodyText.length / 4)) };
98
+ }
99
+
100
+ const SAMPLE_4_LINES = [
101
+ '- SWOT Analysis FEEDS_INTO Porter Five Forces (confidence: 0.85, phase: early-market)',
102
+ '- Porter Five Forces FEEDS_INTO Value Chain Analysis (confidence: 0.78, phase: early-market)',
103
+ '- Business Model Canvas FEEDS_INTO Lean Canvas (confidence: 0.82, phase: thesis-build)',
104
+ '- Jobs-to-be-Done FEEDS_INTO Value Proposition Canvas (confidence: 0.90, phase: pre-opportunity)',
105
+ ].join('\n');
106
+
107
+ // =========================================================
108
+ // Task 1 -- parser + completion detection + proposal (Tests 1..15)
109
+ // =========================================================
110
+
111
+ run('Test 1: parseFrameworkChainSection 4 FEEDS_INTO lines -> 4 edges', () => {
112
+ const { parseFrameworkChainSection } = requireComposer();
113
+ const section = makeChainSection(SAMPLE_4_LINES);
114
+ const edges = parseFrameworkChainSection(section);
115
+ assert.equal(Array.isArray(edges), true);
116
+ assert.equal(edges.length, 4, 'expected 4 edges; got ' + edges.length);
117
+ // Each edge has the four expected fields.
118
+ for (const e of edges) {
119
+ assert.equal(typeof e.from, 'string');
120
+ assert.equal(typeof e.to, 'string');
121
+ assert.equal(typeof e.confidence === 'number' || e.confidence === null, true);
122
+ // phase_indicator may be null when not present; in this fixture all
123
+ // four lines provide one.
124
+ assert.equal(typeof e.phase_indicator === 'string' || e.phase_indicator === null, true);
125
+ }
126
+ // Spot-check the first edge.
127
+ assert.equal(edges[0].from, 'SWOT Analysis');
128
+ assert.equal(edges[0].to, 'Porter Five Forces');
129
+ assert.equal(Math.abs(edges[0].confidence - 0.85) < 1e-9, true);
130
+ assert.equal(edges[0].phase_indicator, 'early-market');
131
+ });
132
+
133
+ run('Test 2: parseFrameworkChainSection (no signal) -> []', () => {
134
+ const { parseFrameworkChainSection } = requireComposer();
135
+ const section = makeChainSection('(no signal)');
136
+ const edges = parseFrameworkChainSection(section);
137
+ assert.equal(Array.isArray(edges), true);
138
+ assert.equal(edges.length, 0);
139
+ // Also null section.
140
+ assert.deepEqual(parseFrameworkChainSection(null), []);
141
+ // Also undefined.
142
+ assert.deepEqual(parseFrameworkChainSection(undefined), []);
143
+ // Also empty body.
144
+ assert.deepEqual(parseFrameworkChainSection({ body: '', tokens_estimate: 0 }), []);
145
+ });
146
+
147
+ run('Test 3: parseFrameworkChainSection tolerant format (FEEDS_INTO + arrow)', () => {
148
+ const { parseFrameworkChainSection } = requireComposer();
149
+ // Mix: FEEDS_INTO form + arrow form. Arrow form drops the phase indicator.
150
+ const body = [
151
+ '- SWOT FEEDS_INTO Porter (confidence: 0.8)',
152
+ '- Lean Canvas -> Value Proposition Canvas (confidence: 0.7)',
153
+ ].join('\n');
154
+ const edges = parseFrameworkChainSection(makeChainSection(body));
155
+ assert.equal(edges.length, 2, 'expected 2 edges; got ' + edges.length);
156
+ // Both should parse with valid confidence numbers.
157
+ assert.equal(typeof edges[0].confidence, 'number');
158
+ assert.equal(typeof edges[1].confidence, 'number');
159
+ // From/to extracted (whitespace-trimmed; case preserved).
160
+ assert.equal(edges[0].from, 'SWOT');
161
+ assert.equal(edges[0].to, 'Porter');
162
+ assert.equal(edges[1].from, 'Lean Canvas');
163
+ assert.equal(edges[1].to, 'Value Proposition Canvas');
164
+ });
165
+
166
+ run('Test 4: parseFrameworkChainSection missing confidence -> null edge.confidence (not filtered)', () => {
167
+ const { parseFrameworkChainSection } = requireComposer();
168
+ // Confidence absent. The edge MUST still parse so callers see the
169
+ // structural FEEDS_INTO relationship; downstream gating decides what
170
+ // to do with null confidence.
171
+ const body = '- SWOT Analysis FEEDS_INTO Porter Five Forces';
172
+ const edges = parseFrameworkChainSection(makeChainSection(body));
173
+ // Either the parser tolerantly emits an edge with null confidence,
174
+ // OR (acceptable) the parser drops it. The plan requires "not
175
+ // filtered", so we assert the edge survives.
176
+ assert.equal(edges.length >= 1, true,
177
+ 'parser should preserve edge with missing confidence; got 0 edges');
178
+ const e = edges[0];
179
+ assert.equal(e.from, 'SWOT Analysis');
180
+ assert.equal(e.to, 'Porter Five Forces');
181
+ assert.equal(e.confidence, null);
182
+ });
183
+
184
+ run('Test 5: detectCompletedFramework via governing_thought match', () => {
185
+ const { detectCompletedFramework } = requireComposer();
186
+ // Reasoning fixture contains "SWOT Analysis" in governing_thought.
187
+ const reasoning = {
188
+ exists: true,
189
+ governing_thought: 'After running our SWOT Analysis we identified two threats.',
190
+ reasoning_health_score: 0.8,
191
+ is_stale: false,
192
+ arguments: [],
193
+ };
194
+ const result = detectCompletedFramework('/tmp/nonexistent', '/tmp/nonexistent/section', reasoning);
195
+ assert.equal(result, 'SWOT Analysis',
196
+ 'should detect SWOT Analysis from governing_thought; got: ' + result);
197
+ });
198
+
199
+ run('Test 6: detectCompletedFramework mtime fallback', () => {
200
+ const { detectCompletedFramework } = requireComposer();
201
+ // Build a tmp section dir with a recently-touched file matching a
202
+ // framework slug. Reasoning is empty so the fallback path runs.
203
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'p91-08-mtime-'));
204
+ try {
205
+ const sectionDir = path.join(tmpRoot, 'market-analysis');
206
+ fs.mkdirSync(sectionDir, { recursive: true });
207
+ // File slug matching a known framework (lean-canvas).
208
+ fs.writeFileSync(path.join(sectionDir, 'lean-canvas.md'), '# Lean Canvas\n');
209
+ // Touch mtime so it's clearly within window.
210
+ const now = Date.now();
211
+ fs.utimesSync(path.join(sectionDir, 'lean-canvas.md'), now / 1000, now / 1000);
212
+
213
+ const reasoning = {
214
+ exists: true,
215
+ governing_thought: 'Some thought without any framework name in it.',
216
+ reasoning_health_score: 0.5,
217
+ is_stale: false,
218
+ arguments: [],
219
+ };
220
+ const result = detectCompletedFramework(tmpRoot, sectionDir, reasoning);
221
+ // Should match the lean-canvas slug -> 'Lean Canvas' (or any
222
+ // canonical name; here we accept any non-null match).
223
+ assert.equal(result !== null, true,
224
+ 'mtime fallback should detect framework slug; got: ' + result);
225
+ assert.equal(/lean.?canvas/i.test(result), true,
226
+ 'detected framework should reference Lean Canvas; got: ' + result);
227
+ } finally {
228
+ try { fs.rmSync(tmpRoot, { recursive: true, force: true }); } catch (_) {}
229
+ }
230
+ });
231
+
232
+ run('Test 7: detectCompletedFramework no signal -> null', () => {
233
+ const { detectCompletedFramework } = requireComposer();
234
+ // Empty reasoning + no section dir.
235
+ const reasoning = {
236
+ exists: true,
237
+ governing_thought: 'No framework names here, just prose about widgets.',
238
+ reasoning_health_score: 0.5,
239
+ is_stale: false,
240
+ arguments: [],
241
+ };
242
+ const result = detectCompletedFramework('/tmp/nonexistent-' + Date.now(), '/tmp/nonexistent-' + Date.now() + '/x', reasoning);
243
+ assert.equal(result, null);
244
+ // Also null reasoning.
245
+ assert.equal(detectCompletedFramework('/tmp/nope', '/tmp/nope/x', null), null);
246
+ });
247
+
248
+ run('Test 8: proposeNextFramework happy path', () => {
249
+ const { parseFrameworkChainSection, proposeNextFramework } = requireComposer();
250
+ const edges = parseFrameworkChainSection(makeChainSection(SAMPLE_4_LINES));
251
+ const out = proposeNextFramework('SWOT Analysis', edges);
252
+ assert.equal(out !== null, true);
253
+ assert.equal(out.next, 'Porter Five Forces');
254
+ assert.equal(Math.abs(out.confidence - 0.85) < 1e-9, true);
255
+ assert.equal(out.source, 'FEEDS_INTO');
256
+ assert.equal(out.phase_indicator, 'early-market');
257
+ });
258
+
259
+ run('Test 9: proposeNextFramework no outgoing edge -> null', () => {
260
+ const { parseFrameworkChainSection, proposeNextFramework } = requireComposer();
261
+ const edges = parseFrameworkChainSection(makeChainSection(SAMPLE_4_LINES));
262
+ // SAMPLE_4_LINES has no outgoing edge from "Random Framework".
263
+ const out = proposeNextFramework('Random Framework', edges);
264
+ assert.equal(out, null);
265
+ });
266
+
267
+ run('Test 10: proposeNextFramework confidence gating (< 0.5 noise floor)', () => {
268
+ const { proposeNextFramework } = requireComposer();
269
+ // Manually-built edges with sub-0.5 confidence.
270
+ const lowEdges = [
271
+ { from: 'SWOT', to: 'Porter', confidence: 0.4, phase_indicator: null },
272
+ ];
273
+ const out = proposeNextFramework('SWOT', lowEdges);
274
+ assert.equal(out, null, 'sub-0.5 confidence must be filtered as noise; got: ' + JSON.stringify(out));
275
+ // Boundary: 0.5 is acceptable (it's the floor, not strictly less than).
276
+ // Either the implementation accepts 0.5 OR rejects it; we accept both
277
+ // behaviors but document the floor as < 0.5 = null.
278
+ const boundaryEdges = [
279
+ { from: 'SWOT', to: 'Porter', confidence: 0.55, phase_indicator: null },
280
+ ];
281
+ const boundaryOut = proposeNextFramework('SWOT', boundaryEdges);
282
+ assert.equal(boundaryOut !== null, true,
283
+ '0.55 confidence must propose; got: ' + JSON.stringify(boundaryOut));
284
+ });
285
+
286
+ run('Test 11: proposeNextFramework tie-breaking by confidence desc', () => {
287
+ const { proposeNextFramework } = requireComposer();
288
+ // Multiple edges from SWOT; engine returns the highest-confidence one.
289
+ const edges = [
290
+ { from: 'SWOT', to: 'Lean Canvas', confidence: 0.7, phase_indicator: 'thesis' },
291
+ { from: 'SWOT', to: 'Porter', confidence: 0.85, phase_indicator: 'early' },
292
+ { from: 'SWOT', to: 'Value Chain', confidence: 0.6, phase_indicator: 'thesis' },
293
+ ];
294
+ const out = proposeNextFramework('SWOT', edges);
295
+ assert.equal(out !== null, true);
296
+ assert.equal(out.next, 'Porter', 'highest-confidence edge wins; got: ' + out.next);
297
+ assert.equal(Math.abs(out.confidence - 0.85) < 1e-9, true);
298
+ });
299
+
300
+ run('Test 12: proposeNextFramework /mos: command mapping', () => {
301
+ const { proposeNextFramework } = requireComposer();
302
+ // 'Lean Canvas' has an existing /mos:lean-canvas command.
303
+ const knownEdges = [
304
+ { from: 'Business Model Canvas', to: 'Lean Canvas', confidence: 0.82, phase_indicator: 'thesis' },
305
+ ];
306
+ const known = proposeNextFramework('Business Model Canvas', knownEdges);
307
+ assert.equal(known !== null, true);
308
+ assert.equal(typeof known.command, 'string');
309
+ assert.equal(known.command.indexOf('/mos:') === 0, true,
310
+ 'command must start with /mos:; got: ' + known.command);
311
+ // Unknown framework name falls back to /mos:beautiful-question or
312
+ // a slugified default. Either way the command MUST start with /mos:.
313
+ const unknownEdges = [
314
+ { from: 'X', to: 'A Wholly Imaginary Framework', confidence: 0.8, phase_indicator: null },
315
+ ];
316
+ const unknown = proposeNextFramework('X', unknownEdges);
317
+ assert.equal(unknown !== null, true);
318
+ assert.equal(unknown.command.indexOf('/mos:') === 0, true);
319
+ });
320
+
321
+ run('Test 13: proposeNextFramework grounding rule (FEEDS_INTO + Brain + confidence in reason)', () => {
322
+ const { proposeNextFramework } = requireComposer();
323
+ const edges = [
324
+ { from: 'SWOT', to: 'Porter', confidence: 0.85, phase_indicator: 'early-market' },
325
+ ];
326
+ const out = proposeNextFramework('SWOT', edges);
327
+ assert.equal(typeof out.reason, 'string');
328
+ assert.equal(/FEEDS_INTO/.test(out.reason), true,
329
+ 'reason must reference FEEDS_INTO; got: ' + out.reason);
330
+ assert.equal(/Brain/i.test(out.reason), true,
331
+ 'reason must reference Brain; got: ' + out.reason);
332
+ // Confidence number appears in the reason (either '0.85' or '0.8' fragment).
333
+ assert.equal(/0\.85|0\.8/.test(out.reason), true,
334
+ 'reason must include confidence number; got: ' + out.reason);
335
+ });
336
+
337
+ run('Test 14: proposeNextFramework RECOMMENDED eligibility flag', () => {
338
+ const { proposeNextFramework } = requireComposer();
339
+ // 0.85 -> eligible.
340
+ const high = proposeNextFramework('SWOT', [
341
+ { from: 'SWOT', to: 'Porter', confidence: 0.85, phase_indicator: null },
342
+ ]);
343
+ assert.equal(high.recommended_eligible, true,
344
+ '0.85 confidence must mark recommended_eligible:true');
345
+ // 0.65 -> not eligible (between 0.5 noise floor and 0.7 recommended floor).
346
+ const mid = proposeNextFramework('SWOT', [
347
+ { from: 'SWOT', to: 'Porter', confidence: 0.65, phase_indicator: null },
348
+ ]);
349
+ assert.equal(mid.recommended_eligible, false,
350
+ '0.65 confidence must NOT mark recommended_eligible:true');
351
+ });
352
+
353
+ run('Test 15: proposeNextFramework empty edges -> null', () => {
354
+ const { proposeNextFramework } = requireComposer();
355
+ assert.equal(proposeNextFramework('SWOT', []), null);
356
+ assert.equal(proposeNextFramework('SWOT', null), null);
357
+ // Null completedFramework -> null.
358
+ assert.equal(proposeNextFramework(null, [
359
+ { from: 'X', to: 'Y', confidence: 0.9, phase_indicator: null },
360
+ ]), null);
361
+ });
362
+
363
+ // =========================================================
364
+ // Task 2 -- decide() integration (Tests 16..18)
365
+ // =========================================================
366
+
367
+ function makeBrainWithChain(chainBody, governingThought) {
368
+ return {
369
+ exists: true,
370
+ section: 'market-analysis',
371
+ brain_generated_at: '2026-04-27T12:00:00Z',
372
+ brain_graph_version: 1,
373
+ governing_thought_hash: 'sha256:fixture',
374
+ staleness: 'fresh',
375
+ stale_reason: null,
376
+ author: 'brain',
377
+ confidence_baseline: 0.5,
378
+ parse_failed: false,
379
+ sections: {
380
+ pattern_matches: null,
381
+ framework_chain_predictions: chainBody !== null ? makeChainSection(chainBody) : null,
382
+ cross_domain_analogies: null,
383
+ wicked_indicators: null,
384
+ unfilled_opportunity_matches: null,
385
+ assessment_thinking_chain_position: null,
386
+ problemtype_classification: null,
387
+ flagged_contradictions_xroom: null,
388
+ hsi_signals: null,
389
+ },
390
+ flagged_weaknesses: [],
391
+ };
392
+ }
393
+
394
+ function makeQuadrupleWithChain(chainBody, governingThought) {
395
+ return {
396
+ room: { exists: true, identity_text: 'fixture', references: [] },
397
+ state: { exists: true, artifact_count: 1, completeness_score: 0.5 },
398
+ reasoning: {
399
+ exists: true,
400
+ governing_thought: governingThought,
401
+ reasoning_health_score: 0.7,
402
+ is_stale: false,
403
+ arguments: [],
404
+ },
405
+ brain: makeBrainWithChain(chainBody, governingThought),
406
+ };
407
+ }
408
+
409
+ run('Test 16: decide() with chain + governing_thought -> offer_next_step with FEEDS_INTO reason', () => {
410
+ const { decide } = requireEngine();
411
+ const quadruple = makeQuadrupleWithChain(
412
+ SAMPLE_4_LINES,
413
+ 'After our SWOT Analysis we found two key threats and one opportunity.'
414
+ );
415
+ const out = decide(
416
+ { sectionPath: '/tmp/fixture', sessionId: 's1' },
417
+ {
418
+ quadruple: quadruple,
419
+ brainAvailable: true,
420
+ userPersona: null,
421
+ intentSignal: null,
422
+ }
423
+ );
424
+ // Engine should compose a chain offer: SWOT -> Porter (the highest-conf
425
+ // outgoing edge from SWOT in SAMPLE_4_LINES).
426
+ assert.equal(out.offer_next_step !== null, true,
427
+ 'expected non-null offer_next_step; trace: ' + (out.decision_trace.chosen_rationale || ''));
428
+ assert.equal(typeof out.offer_next_step.command, 'string');
429
+ assert.equal(out.offer_next_step.command.indexOf('/mos:') === 0, true);
430
+ assert.equal(/FEEDS_INTO/.test(out.offer_next_step.reason), true,
431
+ 'offer reason must reference FEEDS_INTO; got: ' + out.offer_next_step.reason);
432
+ });
433
+
434
+ run('Test 17: decide() Mode A confidence 0.85 chain -> recommended_eligible flag in trace', () => {
435
+ const { decide } = requireEngine();
436
+ const quadruple = makeQuadrupleWithChain(
437
+ SAMPLE_4_LINES,
438
+ 'We just completed a SWOT Analysis review with the team.'
439
+ );
440
+ const out = decide(
441
+ { sectionPath: '/tmp/fixture', sessionId: 's1' },
442
+ {
443
+ quadruple: quadruple,
444
+ brainAvailable: true,
445
+ userPersona: null,
446
+ intentSignal: null,
447
+ }
448
+ );
449
+ // The chain proposal sets a recommended_eligible flag in decision_trace
450
+ // OR sets brain_md_recommended_marker_rendered when the chain confidence
451
+ // qualifies and Mode A holds. Either field signals offer-presenter to
452
+ // render the marker.
453
+ const trace = out.decision_trace;
454
+ const eligible =
455
+ trace.brain_md_recommended_marker_rendered === true ||
456
+ (trace.chain_recommended_eligible === true);
457
+ assert.equal(eligible, true,
458
+ 'Mode A + chain conf 0.85 must mark eligibility; trace: ' + JSON.stringify(trace));
459
+ });
460
+
461
+ run('Test 18: decide() user override path: turn 1 offer; turn 2 different command -> REJECTED chain trace', () => {
462
+ const { decide } = requireEngine();
463
+ // Turn 1: chain proposes /mos:porter-five-forces (or similar slug from
464
+ // Porter Five Forces). Engine writes trace.brain_patterns including
465
+ // category 'framework_chain_proposal' OR sets offer_next_step with
466
+ // chain context.
467
+ const turn1Quad = makeQuadrupleWithChain(
468
+ SAMPLE_4_LINES,
469
+ 'After our SWOT Analysis we identified threats.'
470
+ );
471
+ const turn1 = decide(
472
+ { sectionPath: '/tmp/fixture', sessionId: 's1', userText: '' },
473
+ {
474
+ quadruple: turn1Quad,
475
+ brainAvailable: true,
476
+ userPersona: null,
477
+ intentSignal: null,
478
+ }
479
+ );
480
+ assert.equal(turn1.offer_next_step !== null, true,
481
+ 'turn 1 must produce a chain offer; trace: ' + turn1.decision_trace.chosen_rationale);
482
+ const turn1Command = turn1.offer_next_step.command;
483
+
484
+ // Turn 2: user invokes a DIFFERENT /mos: command. Engine should record
485
+ // this as REJECTED chain suggestion in decision_trace.
486
+ const turn2 = decide(
487
+ {
488
+ sectionPath: '/tmp/fixture',
489
+ sessionId: 's1',
490
+ userText: '/mos:lean-canvas help me with my lean canvas instead',
491
+ },
492
+ {
493
+ quadruple: turn1Quad,
494
+ brainAvailable: true,
495
+ userPersona: null,
496
+ intentSignal: null,
497
+ lastTurnOffer: { command: turn1Command, reason: turn1.offer_next_step.reason },
498
+ }
499
+ );
500
+ // The override is captured either in chosen_rationale or in a dedicated
501
+ // trace field. Both are acceptable -- /mos:explain-decision can read
502
+ // either. We assert at least one path is present.
503
+ const rationale = turn2.decision_trace.chosen_rationale || '';
504
+ const hasOverride =
505
+ /REJECTED chain suggestion/i.test(rationale) ||
506
+ turn2.decision_trace.chain_override_recorded === true;
507
+ assert.equal(hasOverride, true,
508
+ 'turn 2 must record REJECTED chain suggestion; rationale: ' + rationale);
509
+ });
510
+
511
+ // ---------- Suite footer ----------
512
+
513
+ const total = passed + failed;
514
+ process.stdout.write('\nframework-chain-composer: ' + passed + '/' + total + ' passed\n');
515
+ process.exit(failed === 0 ? 0 : 1);