@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,265 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
4
+ * Phase 88-00 Task 2 tests: idempotent migration of existing Feynman-MINTO
5
+ * files to the v88 schema.
6
+ *
7
+ * Covers:
8
+ * Test 1: migration backfills five v88 fields with sentinel defaults
9
+ * Test 2: second migration run produces byte-identical output (idempotent)
10
+ * Test 3: narrative body unchanged across migration
11
+ * Test 4: existing structural keys (schema_version, governing_thought) unchanged
12
+ * Test 5: pre-migrated file with all v88 fields is detected + skipped
13
+ * Test 6: --dry-run lists but writes nothing (mtime stable)
14
+ *
15
+ * Node built-in assert + child_process for subprocess invocation so the
16
+ * whole CLI surface is exercised end-to-end.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ const assert = require('node:assert');
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+ const path = require('node:path');
25
+ const { spawnSync } = require('node:child_process');
26
+ const crypto = require('node:crypto');
27
+
28
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
29
+ const MIGRATOR = path.join(REPO_ROOT, 'scripts', 'migrate-minto-schema-v88.cjs');
30
+
31
+ // Fixture workspace.
32
+ const WORK = fs.mkdtempSync(path.join(os.tmpdir(), 'minto-migrate-v88-'));
33
+ process.on('exit', function cleanup() {
34
+ try {
35
+ fs.rmSync(WORK, { recursive: true, force: true });
36
+ } catch (_) {
37
+ /* best effort */
38
+ }
39
+ });
40
+
41
+ function buildFixtureRoom(sectionFiles) {
42
+ const root = fs.mkdtempSync(path.join(WORK, 'room-'));
43
+ fs.writeFileSync(path.join(root, '.room-root'), '');
44
+ for (const sf of sectionFiles) {
45
+ const sdir = path.join(root, sf.section);
46
+ fs.mkdirSync(sdir, { recursive: true });
47
+ fs.writeFileSync(path.join(sdir, 'MINTO.md'), sf.content);
48
+ }
49
+ return root;
50
+ }
51
+
52
+ function sha256(filePath) {
53
+ const raw = fs.readFileSync(filePath);
54
+ return crypto.createHash('sha256').update(raw).digest('hex');
55
+ }
56
+
57
+ function runMigrate(args) {
58
+ const res = spawnSync(process.execPath, [MIGRATOR].concat(args), {
59
+ encoding: 'utf-8',
60
+ });
61
+ return {
62
+ status: res.status,
63
+ stdout: res.stdout || '',
64
+ stderr: res.stderr || '',
65
+ };
66
+ }
67
+
68
+ const PHASE81_MINTO = [
69
+ '---',
70
+ 'type: section-minto',
71
+ 'schema_version: "1"',
72
+ 'section: problem-definition',
73
+ 'created: 2026-04-14',
74
+ 'room: fx-room',
75
+ 'methodology: feynman-minto',
76
+ 'governing_thought: "Problem definition is the anchor for this venture."',
77
+ 'status: active',
78
+ '---',
79
+ '',
80
+ '# Problem Definition -- Feynman-MINTO Reasoning',
81
+ '',
82
+ 'Body content line one.',
83
+ 'Body content line two.',
84
+ '',
85
+ ].join('\n');
86
+
87
+ let pass = 0;
88
+ let fail = 0;
89
+
90
+ function t(name, fn) {
91
+ try {
92
+ fn();
93
+ pass += 1;
94
+ process.stdout.write(' OK ' + name + '\n');
95
+ } catch (e) {
96
+ fail += 1;
97
+ process.stderr.write(' FAIL ' + name + ': ' + e.message + '\n');
98
+ if (e.stack) {
99
+ process.stderr.write(e.stack.split('\n').slice(0, 5).join('\n') + '\n');
100
+ }
101
+ }
102
+ }
103
+
104
+ // Test 1: backfill defaults
105
+ t('Test 1: backfills five v88 fields with sentinel defaults', function () {
106
+ const room = buildFixtureRoom([
107
+ { section: 'problem-definition', content: PHASE81_MINTO },
108
+ ]);
109
+ const res = runMigrate([room]);
110
+ assert.strictEqual(res.status, 0, 'non-zero exit: ' + res.stderr);
111
+ const after = fs.readFileSync(
112
+ path.join(room, 'problem-definition', 'MINTO.md'),
113
+ 'utf-8'
114
+ );
115
+ assert.ok(
116
+ /last_generated_at:\s*"1970-01-01T00:00:00Z"/.test(after),
117
+ 'missing last_generated_at sentinel; output:\n' + after
118
+ );
119
+ assert.ok(
120
+ /last_artifact_write_seen_at:\s*null/.test(after),
121
+ 'missing last_artifact_write_seen_at null'
122
+ );
123
+ assert.ok(
124
+ /reasoning_health_score:\s*null/.test(after),
125
+ 'missing reasoning_health_score null'
126
+ );
127
+ assert.ok(
128
+ /flagged_weaknesses:\s*\[\]/.test(after),
129
+ 'missing flagged_weaknesses []'
130
+ );
131
+ assert.ok(
132
+ /decision_log:\s*\[\]/.test(after),
133
+ 'missing decision_log []'
134
+ );
135
+ });
136
+
137
+ // Test 2: idempotency
138
+ t('Test 2: second migration run produces byte-identical file', function () {
139
+ const room = buildFixtureRoom([
140
+ { section: 'market-analysis', content: PHASE81_MINTO.replace('problem-definition', 'market-analysis') },
141
+ ]);
142
+ const target = path.join(room, 'market-analysis', 'MINTO.md');
143
+ let r = runMigrate([room]);
144
+ assert.strictEqual(r.status, 0, 'first run failed: ' + r.stderr);
145
+ const hash1 = sha256(target);
146
+ r = runMigrate([room]);
147
+ assert.strictEqual(r.status, 0, 'second run failed: ' + r.stderr);
148
+ const hash2 = sha256(target);
149
+ assert.strictEqual(hash1, hash2, 'second run changed bytes');
150
+ });
151
+
152
+ // Test 3: body unchanged
153
+ t('Test 3: narrative body unchanged across migration', function () {
154
+ const room = buildFixtureRoom([
155
+ { section: 'solution-design', content: PHASE81_MINTO.replace('problem-definition', 'solution-design') },
156
+ ]);
157
+ const target = path.join(room, 'solution-design', 'MINTO.md');
158
+ const before = fs.readFileSync(target, 'utf-8');
159
+ runMigrate([room]);
160
+ const after = fs.readFileSync(target, 'utf-8');
161
+ // Extract body after second --- delimiter.
162
+ const extractBody = function (src) {
163
+ const m = src.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n([\s\S]*)$/);
164
+ return m ? m[1] : null;
165
+ };
166
+ const bodyBefore = extractBody(before);
167
+ const bodyAfter = extractBody(after);
168
+ assert.ok(bodyBefore !== null, 'cannot locate body in before');
169
+ assert.ok(bodyAfter !== null, 'cannot locate body in after');
170
+ assert.strictEqual(
171
+ bodyBefore,
172
+ bodyAfter,
173
+ 'narrative body changed:\n--- before ---\n' +
174
+ bodyBefore +
175
+ '\n--- after ---\n' +
176
+ bodyAfter
177
+ );
178
+ });
179
+
180
+ // Test 4: existing structural keys unchanged
181
+ t('Test 4: existing structural keys preserved', function () {
182
+ const room = buildFixtureRoom([
183
+ { section: 'team', content: PHASE81_MINTO.replace('problem-definition', 'team') },
184
+ ]);
185
+ runMigrate([room]);
186
+ const after = fs.readFileSync(
187
+ path.join(room, 'team', 'MINTO.md'),
188
+ 'utf-8'
189
+ );
190
+ assert.ok(/schema_version:\s*"1"/.test(after), 'schema_version lost');
191
+ assert.ok(
192
+ /governing_thought:\s*"Problem definition is the anchor for this venture."/.test(
193
+ after
194
+ ),
195
+ 'governing_thought lost'
196
+ );
197
+ assert.ok(/section:\s*team/.test(after), 'section lost');
198
+ });
199
+
200
+ // Test 5: already-v88 file skipped
201
+ t('Test 5: already-v88 file detected as already v88 and skipped', function () {
202
+ const alreadyV88 = [
203
+ '---',
204
+ 'type: section-minto',
205
+ 'schema_version: "1"',
206
+ 'section: legal-ip',
207
+ 'created: 2026-04-14',
208
+ 'room: fx-room',
209
+ 'governing_thought: "Legal IP clarifies ownership."',
210
+ 'status: active',
211
+ 'last_generated_at: "2026-04-19T10:00:00Z"',
212
+ 'last_artifact_write_seen_at: null',
213
+ 'reasoning_health_score: null',
214
+ 'flagged_weaknesses: []',
215
+ 'decision_log: []',
216
+ '---',
217
+ '',
218
+ '# body',
219
+ '',
220
+ ].join('\n');
221
+ const room = buildFixtureRoom([
222
+ { section: 'legal-ip', content: alreadyV88 },
223
+ ]);
224
+ const target = path.join(room, 'legal-ip', 'MINTO.md');
225
+ const hashBefore = sha256(target);
226
+ const res = runMigrate([room]);
227
+ assert.strictEqual(res.status, 0, 'non-zero exit: ' + res.stderr);
228
+ const combined = res.stdout + '\n' + res.stderr;
229
+ assert.ok(
230
+ /already v88/.test(combined),
231
+ 'no "already v88" message in output:\n' + combined
232
+ );
233
+ const hashAfter = sha256(target);
234
+ assert.strictEqual(hashBefore, hashAfter, 'already-v88 file was rewritten');
235
+ });
236
+
237
+ // Test 6: --dry-run writes nothing
238
+ t('Test 6: --dry-run lists affected files but writes nothing', function () {
239
+ const room = buildFixtureRoom([
240
+ { section: 'financial-model', content: PHASE81_MINTO.replace('problem-definition', 'financial-model') },
241
+ ]);
242
+ const target = path.join(room, 'financial-model', 'MINTO.md');
243
+ const hashBefore = sha256(target);
244
+ const statBefore = fs.statSync(target);
245
+ const res = runMigrate([room, '--dry-run']);
246
+ assert.strictEqual(res.status, 0, 'non-zero exit: ' + res.stderr);
247
+ const combined = res.stdout + '\n' + res.stderr;
248
+ assert.ok(
249
+ /financial-model/.test(combined),
250
+ 'dry-run did not report file in output:\n' + combined
251
+ );
252
+ const hashAfter = sha256(target);
253
+ const statAfter = fs.statSync(target);
254
+ assert.strictEqual(hashBefore, hashAfter, 'dry-run wrote bytes');
255
+ assert.strictEqual(
256
+ statBefore.mtimeMs,
257
+ statAfter.mtimeMs,
258
+ 'dry-run changed mtime'
259
+ );
260
+ });
261
+
262
+ process.stdout.write(
263
+ '\nminto-migration-v88.test.cjs: ' + pass + ' passed, ' + fail + ' failed\n'
264
+ );
265
+ process.exit(fail === 0 ? 0 : 1);
@@ -0,0 +1,390 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
4
+ * Phase 88-00: Feynman-MINTO frontmatter schema v88 tests.
5
+ *
6
+ * Covers:
7
+ * Test 1: generator --write emits last_generated_at matching ISO-8601
8
+ * Test 2: generator --write preserves last_artifact_write_seen_at on regen
9
+ * Test 3: generator --write preserves decision_log array byte-for-byte on regen
10
+ * Test 4: new narrative JSON advances last_generated_at while decision_log stays
11
+ * Test 5: narrative-schema accepts structural payload WITHOUT new fields
12
+ * Test 6: narrative-schema accepts structural payload WITH new fields, bounded
13
+ * Test 7: validator rejects decision_log entry missing session_id or wrong user_response
14
+ *
15
+ * Node built-in assert only. Uses fs.mkdtempSync fixtures with process.on('exit')
16
+ * cleanup so git status stays clean.
17
+ *
18
+ * Runs standalone or via lib/memory/run-feynman-tests.cjs.
19
+ */
20
+
21
+ 'use strict';
22
+
23
+ const assert = require('node:assert');
24
+ const fs = require('node:fs');
25
+ const os = require('node:os');
26
+ const path = require('node:path');
27
+ const { spawnSync } = require('node:child_process');
28
+
29
+ const {
30
+ validateStructural,
31
+ validateDecisionLogEntry,
32
+ } = require('./narrative-schema.cjs');
33
+
34
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
35
+ const GENERATOR = path.join(
36
+ REPO_ROOT,
37
+ 'scripts',
38
+ 'vault-section-minto-generator.cjs'
39
+ );
40
+
41
+ // ---------- Fixture workspace ----------
42
+
43
+ const WORK = fs.mkdtempSync(path.join(os.tmpdir(), 'minto-schema-v88-'));
44
+ process.on('exit', function cleanup() {
45
+ try {
46
+ fs.rmSync(WORK, { recursive: true, force: true });
47
+ } catch (_) {
48
+ /* best effort */
49
+ }
50
+ });
51
+
52
+ function buildRoom(roomName, sectionName, artifactCount) {
53
+ const roomDir = path.join(WORK, roomName);
54
+ const sectionDir = path.join(roomDir, sectionName);
55
+ fs.mkdirSync(sectionDir, { recursive: true });
56
+ fs.writeFileSync(path.join(roomDir, 'ROOM.md'), '# ' + roomName + '\n');
57
+ fs.writeFileSync(path.join(roomDir, 'STATE.md'), '# state\n');
58
+ fs.writeFileSync(path.join(sectionDir, 'ROOM.md'), '# section\n');
59
+ for (let i = 0; i < artifactCount; i++) {
60
+ const artDir = path.join(sectionDir, 'artifact-' + (i + 1));
61
+ fs.mkdirSync(artDir, { recursive: true });
62
+ fs.writeFileSync(
63
+ path.join(artDir, 'artifact-' + (i + 1) + '.md'),
64
+ '---\ntype: artifact\n---\n\nArtifact body ' + (i + 1) + ' content line.\n'
65
+ );
66
+ }
67
+ return { roomDir: roomDir, sectionDir: sectionDir, sectionName: sectionName };
68
+ }
69
+
70
+ function writeNarrativeFile(payload) {
71
+ const p = path.join(WORK, 'narrative-' + Date.now() + '-' + Math.random() + '.json');
72
+ fs.writeFileSync(p, JSON.stringify(payload));
73
+ return p;
74
+ }
75
+
76
+ function validNarrative(sectionName) {
77
+ return {
78
+ section: sectionName,
79
+ essence:
80
+ 'Irreducible truth about ' +
81
+ sectionName +
82
+ ' lives here as one compressed sentence.',
83
+ plain_language:
84
+ 'The elevator version: this section packages its artifacts into an argument that a reader can understand in one read.',
85
+ governing_thought:
86
+ 'The ' +
87
+ sectionName +
88
+ ' argument holds because the artifacts align on a single defensible claim.',
89
+ mental_model: {
90
+ analogy: 'It is like stacking boxes into a clean tower.',
91
+ mapping:
92
+ 'Each artifact is a box. Each claim is the shape at the top. The stack is the argument.',
93
+ limits: 'Unlike real boxes, claims can be re-ordered without losing mass.',
94
+ },
95
+ sweet_spot:
96
+ 'Readers should leave with the compressed idea that the artifacts agree, the top sits on the bottom, and nothing dangles outside the pyramid.',
97
+ key_claims: [
98
+ 'Every artifact in this section is a checkable claim.',
99
+ 'The claims support a single governing thought.',
100
+ 'The pyramid is tight enough to pass MECE inspection.',
101
+ ],
102
+ };
103
+ }
104
+
105
+ function runWrite(roomDir, sectionName, narrativePath) {
106
+ const env = Object.assign({}, process.env);
107
+ // We do NOT freeze timestamp here; tests want to see live advance.
108
+ delete env.MINTO_FROZEN_TIMESTAMP;
109
+ env.MINTO_FROZEN_DATE = '2026-04-14';
110
+ const res = spawnSync(
111
+ process.execPath,
112
+ [
113
+ GENERATOR,
114
+ roomDir,
115
+ '--write',
116
+ '--section',
117
+ sectionName,
118
+ '--narrative',
119
+ narrativePath,
120
+ ],
121
+ { encoding: 'utf-8', env: env }
122
+ );
123
+ assert.strictEqual(
124
+ res.status,
125
+ 0,
126
+ 'generator --write failed: ' + res.stderr
127
+ );
128
+ return res;
129
+ }
130
+
131
+ function readMinto(sectionDir) {
132
+ return fs.readFileSync(path.join(sectionDir, 'MINTO.md'), 'utf-8');
133
+ }
134
+
135
+ function extractFrontmatter(md) {
136
+ const m = md.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
137
+ if (!m) throw new Error('no frontmatter');
138
+ return m[1];
139
+ }
140
+
141
+ function getScalar(fm, key) {
142
+ const re = new RegExp('^' + key + ':\\s*(.*)$', 'm');
143
+ const m = fm.match(re);
144
+ if (!m) return undefined;
145
+ let v = m[1].trim();
146
+ if (v.startsWith('"') && v.endsWith('"')) v = v.slice(1, -1);
147
+ return v;
148
+ }
149
+
150
+ const ISO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;
151
+
152
+ // ---------- Tests ----------
153
+
154
+ let pass = 0;
155
+ let fail = 0;
156
+
157
+ function t(name, fn) {
158
+ try {
159
+ fn();
160
+ pass += 1;
161
+ process.stdout.write(' OK ' + name + '\n');
162
+ } catch (e) {
163
+ fail += 1;
164
+ process.stderr.write(' FAIL ' + name + ': ' + e.message + '\n');
165
+ if (e.stack) process.stderr.write(e.stack.split('\n').slice(0, 6).join('\n') + '\n');
166
+ }
167
+ }
168
+
169
+ // Test 1: last_generated_at ISO on --write
170
+ t('Test 1: --write emits last_generated_at matching ISO-8601', function () {
171
+ const fx = buildRoom('room-t1', 'problem-definition', 3);
172
+ const np = writeNarrativeFile(validNarrative('problem-definition'));
173
+ runWrite(fx.roomDir, fx.sectionName, np);
174
+ const md = readMinto(fx.sectionDir);
175
+ const fm = extractFrontmatter(md);
176
+ const lga = getScalar(fm, 'last_generated_at');
177
+ assert.ok(lga, 'last_generated_at missing from frontmatter');
178
+ assert.ok(
179
+ ISO_RE.test(lga),
180
+ 'last_generated_at does not match ISO-8601: ' + lga
181
+ );
182
+ });
183
+
184
+ // Test 2: --write preserves last_artifact_write_seen_at
185
+ t('Test 2: --write preserves last_artifact_write_seen_at across regens', function () {
186
+ const fx = buildRoom('room-t2', 'market-analysis', 3);
187
+ const np = writeNarrativeFile(validNarrative('market-analysis'));
188
+ runWrite(fx.roomDir, fx.sectionName, np);
189
+ // Simulate post-write hook: inject a known value into the file.
190
+ const mintoPath = path.join(fx.sectionDir, 'MINTO.md');
191
+ let md = fs.readFileSync(mintoPath, 'utf-8');
192
+ const knownValue = '2026-04-18T12:34:56Z';
193
+ md = md.replace(
194
+ /last_artifact_write_seen_at:.*\n/,
195
+ 'last_artifact_write_seen_at: "' + knownValue + '"\n'
196
+ );
197
+ fs.writeFileSync(mintoPath, md);
198
+
199
+ // Regen.
200
+ runWrite(fx.roomDir, fx.sectionName, np);
201
+ const after = readMinto(fx.sectionDir);
202
+ const fm = extractFrontmatter(after);
203
+ const preserved = getScalar(fm, 'last_artifact_write_seen_at');
204
+ assert.strictEqual(
205
+ preserved,
206
+ knownValue,
207
+ 'last_artifact_write_seen_at not preserved: got ' + preserved
208
+ );
209
+ });
210
+
211
+ // Test 3: --write preserves decision_log array byte-for-byte
212
+ t('Test 3: --write preserves decision_log across regen', function () {
213
+ const fx = buildRoom('room-t3', 'solution-design', 3);
214
+ const np = writeNarrativeFile(validNarrative('solution-design'));
215
+ runWrite(fx.roomDir, fx.sectionName, np);
216
+ const mintoPath = path.join(fx.sectionDir, 'MINTO.md');
217
+ let md = fs.readFileSync(mintoPath, 'utf-8');
218
+
219
+ // Inject a decision_log block in the frontmatter.
220
+ const inject = [
221
+ 'decision_log:',
222
+ ' - session_id: "sess-2026-04-17-abc"',
223
+ ' timestamp: "2026-04-17T14:23:00Z"',
224
+ ' action: "flag_tam_staleness"',
225
+ ' user_response: "defer"',
226
+ ' reason: "Jonathan deferred benchmark refresh Q3"',
227
+ ' outcome: "suppressed"',
228
+ '',
229
+ ].join('\n');
230
+ md = md.replace(/decision_log:\s*\[\]\n/, inject);
231
+ fs.writeFileSync(mintoPath, md);
232
+
233
+ // Regenerate.
234
+ runWrite(fx.roomDir, fx.sectionName, np);
235
+ const after = fs.readFileSync(mintoPath, 'utf-8');
236
+ const fm = extractFrontmatter(after);
237
+ // The preserved block must still contain every original line.
238
+ const requiredLines = [
239
+ 'session_id: "sess-2026-04-17-abc"',
240
+ 'timestamp: "2026-04-17T14:23:00Z"',
241
+ 'action: "flag_tam_staleness"',
242
+ 'user_response: "defer"',
243
+ 'reason: "Jonathan deferred benchmark refresh Q3"',
244
+ 'outcome: "suppressed"',
245
+ ];
246
+ for (const line of requiredLines) {
247
+ assert.ok(
248
+ fm.indexOf(line) !== -1,
249
+ 'decision_log lost line: ' + line + '\n---\n' + fm
250
+ );
251
+ }
252
+ });
253
+
254
+ // Test 4: New narrative advances last_generated_at while decision_log stable
255
+ t('Test 4: new narrative advances timestamp, keeps decision_log', function () {
256
+ const fx = buildRoom('room-t4', 'business-model', 3);
257
+ const np1 = writeNarrativeFile(validNarrative('business-model'));
258
+ runWrite(fx.roomDir, fx.sectionName, np1);
259
+ const mintoPath = path.join(fx.sectionDir, 'MINTO.md');
260
+ let md = fs.readFileSync(mintoPath, 'utf-8');
261
+
262
+ // Inject decision_log.
263
+ const inject = [
264
+ 'decision_log:',
265
+ ' - session_id: "sess-alpha"',
266
+ ' timestamp: "2026-04-10T10:00:00Z"',
267
+ ' action: "accept_metric"',
268
+ ' user_response: "approve"',
269
+ ' reason: "Passes acceptance"',
270
+ '',
271
+ ].join('\n');
272
+ md = md.replace(/decision_log:\s*\[\]\n/, inject);
273
+ fs.writeFileSync(mintoPath, md);
274
+
275
+ const before = readMinto(fx.sectionDir);
276
+ const lgaBefore = getScalar(extractFrontmatter(before), 'last_generated_at');
277
+
278
+ // Wait briefly so new timestamp is strictly greater (resolution = sec).
279
+ const start = Date.now();
280
+ while (Date.now() - start < 1100) {
281
+ /* spin */
282
+ }
283
+
284
+ // Second write with a new narrative (change essence).
285
+ const n2 = validNarrative('business-model');
286
+ n2.essence = 'Second pass refines the irreducible claim for this section.';
287
+ const np2 = writeNarrativeFile(n2);
288
+ runWrite(fx.roomDir, fx.sectionName, np2);
289
+ const after = readMinto(fx.sectionDir);
290
+ const lgaAfter = getScalar(extractFrontmatter(after), 'last_generated_at');
291
+
292
+ assert.ok(
293
+ Date.parse(lgaAfter) > Date.parse(lgaBefore),
294
+ 'last_generated_at did not advance: before=' +
295
+ lgaBefore +
296
+ ' after=' +
297
+ lgaAfter
298
+ );
299
+ // decision_log preserved.
300
+ const fmAfter = extractFrontmatter(after);
301
+ assert.ok(
302
+ fmAfter.indexOf('session_id: "sess-alpha"') !== -1,
303
+ 'decision_log lost after second write'
304
+ );
305
+ });
306
+
307
+ // Test 5: structural validator accepts payload WITHOUT new fields (backcompat)
308
+ t('Test 5: validateStructural accepts pre-v88 payload (no new fields)', function () {
309
+ const payload = {
310
+ schema_version: '1',
311
+ governing_thought: 'A non-empty governing thought for back-compat.',
312
+ };
313
+ const r = validateStructural(payload);
314
+ assert.strictEqual(
315
+ r.valid,
316
+ true,
317
+ 'back-compat payload rejected: ' + JSON.stringify(r.errors)
318
+ );
319
+ });
320
+
321
+ // Test 6: structural validator accepts payload WITH new fields, validates types
322
+ t('Test 6: validateStructural accepts v88 payload, range-checks fields', function () {
323
+ const payload = {
324
+ schema_version: '1',
325
+ governing_thought: 'A defensible sentence.',
326
+ last_generated_at: '2026-04-19T12:00:00Z',
327
+ last_artifact_write_seen_at: null,
328
+ reasoning_health_score: 0.75,
329
+ flagged_weaknesses: ['thin tam', 'weak moat'],
330
+ decision_log: [
331
+ {
332
+ session_id: 'sess-1',
333
+ timestamp: '2026-04-17T10:00:00Z',
334
+ action: 'flag',
335
+ user_response: 'defer',
336
+ reason: 'deferred for Q3 refresh',
337
+ outcome: 'suppressed',
338
+ },
339
+ ],
340
+ };
341
+ const r = validateStructural(payload);
342
+ assert.strictEqual(
343
+ r.valid,
344
+ true,
345
+ 'v88 payload rejected: ' + JSON.stringify(r.errors)
346
+ );
347
+
348
+ // Range check: reasoning_health_score > 1 rejected.
349
+ const bad = Object.assign({}, payload, { reasoning_health_score: 1.5 });
350
+ const rBad = validateStructural(bad);
351
+ assert.strictEqual(rBad.valid, false, 'rhs=1.5 should be rejected');
352
+
353
+ // flagged_weaknesses must be array of strings.
354
+ const bad2 = Object.assign({}, payload, { flagged_weaknesses: [42] });
355
+ const rBad2 = validateStructural(bad2);
356
+ assert.strictEqual(rBad2.valid, false, 'flagged_weaknesses with number should be rejected');
357
+ });
358
+
359
+ // Test 7: validateDecisionLogEntry
360
+ t('Test 7: validateDecisionLogEntry catches missing session_id + bad user_response', function () {
361
+ const good = {
362
+ session_id: 's1',
363
+ timestamp: '2026-04-19T00:00:00Z',
364
+ action: 'x',
365
+ user_response: 'defer',
366
+ reason: 'y',
367
+ };
368
+ const r = validateDecisionLogEntry(good);
369
+ assert.strictEqual(r.valid, true, 'good entry rejected: ' + JSON.stringify(r.errors));
370
+
371
+ const missingSession = Object.assign({}, good);
372
+ delete missingSession.session_id;
373
+ const r1 = validateDecisionLogEntry(missingSession);
374
+ assert.strictEqual(r1.valid, false, 'missing session_id should be rejected');
375
+
376
+ const badResponse = Object.assign({}, good, { user_response: 'maybe' });
377
+ const r2 = validateDecisionLogEntry(badResponse);
378
+ assert.strictEqual(r2.valid, false, 'user_response=maybe should be rejected');
379
+
380
+ for (const ok of ['approve', 'reject', 'defer']) {
381
+ const e = Object.assign({}, good, { user_response: ok });
382
+ const rr = validateDecisionLogEntry(e);
383
+ assert.strictEqual(rr.valid, true, 'user_response=' + ok + ' should be accepted');
384
+ }
385
+ });
386
+
387
+ process.stdout.write(
388
+ '\nminto-schema-v88.test.cjs: ' + pass + ' passed, ' + fail + ' failed\n'
389
+ );
390
+ process.exit(fail === 0 ? 0 : 1);