@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,442 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
4
+ *
5
+ * Phase 88-07 Task 1 -- triple-context-formatter tests
6
+ * =====================================================
7
+ * Pure unit tests for the TRIPLE_CONTEXT formatter.
8
+ *
9
+ * Test map (12 cases, aligned with PLAN <behavior>):
10
+ *
11
+ * Test 1: 3-section input, all healthy -> formatter emits one block per
12
+ * section with Identity, References, State, Reasoning, Decision
13
+ * log lines.
14
+ * Test 2: Section with empty decision_log -> "Decision log:" header
15
+ * omitted (don't show empty list).
16
+ * Test 3: Section with 21 decision_log entries -> render only the latest
17
+ * 3, footer "[+18 older]".
18
+ * Test 4: Section with null governing_thought -> Reasoning line reads
19
+ * `governing thought: (not yet generated)`.
20
+ * Test 5: References rendering: 5 items -> 5 wikilinks space-separated;
21
+ * > 5 -> first 5 then `[+N more]`.
22
+ * Test 6: Budget cap (weakest-first): 30 sections @ 1k tokens -> truncate
23
+ * at MAX_BUDGET_TOKENS; append "N strongest sections elided"
24
+ * footer. Sort ascending by reasoning_health_score.
25
+ * Test 6b: reasoning_health_score === null is sorted FIRST (treated as
26
+ * weakest / highest-priority-to-surface). A section with null
27
+ * score appears BEFORE a section with score=0.1.
28
+ * Test 7: Token estimation uses Math.ceil((body || '').length / 4)
29
+ * consistently; total emitted length / 4 <= MAX_BUDGET_TOKENS.
30
+ * Test 8: Stale sections: is_stale:true -> annotate in the State line
31
+ * `MINTO health (warn) (stale: <stale_reason>)`.
32
+ * Test 9: pending-tier1-regen.json with 4 sections -> footer includes
33
+ * that count and the /mos:reason hint.
34
+ * Test 10: Zero sections -> formatter returns empty string (no block
35
+ * emitted; session-start falls through to existing behavior).
36
+ * Test 11: SESSION_START_BUDGET_TOKENS env override: env=3000 -> cap=3000;
37
+ * env="abc" -> default; env unset -> default.
38
+ * Test 12: Baseline measurement recorded in SUMMARY.md. Automated check:
39
+ * grep -c "baseline.*tokens\|measured.*session-start" SUMMARY >=1.
40
+ *
41
+ * Registered in lib/memory/run-feynman-tests.cjs.
42
+ * Pure unit tests. Zero fs mutation. No child processes.
43
+ */
44
+
45
+ 'use strict';
46
+
47
+ const assert = require('node:assert/strict');
48
+ const fs = require('node:fs');
49
+ const path = require('node:path');
50
+
51
+ const REPO = path.resolve(__dirname, '..', '..');
52
+ const FORMATTER_PATH = path.join(REPO, 'lib/memory/triple-context-formatter.cjs');
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Runner
56
+ // ---------------------------------------------------------------------------
57
+ const tests = [];
58
+ function test(name, fn) { tests.push({ name, fn }); }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Fixture helpers
62
+ // ---------------------------------------------------------------------------
63
+ function healthySection(overrides) {
64
+ const o = overrides || {};
65
+ return {
66
+ room: {
67
+ exists: true,
68
+ identity_text: o.identity_text || 'Bottom-up TAM analysis for the enterprise SaaS wedge',
69
+ references: o.references || [
70
+ { target: 'financial-model/tam-bottom-up', type: 'artifact', label: 'financial-model/tam-bottom-up' },
71
+ { target: 'competitive-analysis/first-mover', type: 'artifact', label: 'competitive-analysis/first-mover' }
72
+ ],
73
+ last_updated_at: o.last_updated_at || '2026-04-18T00:00:00Z',
74
+ },
75
+ state: {
76
+ exists: true,
77
+ artifact_count: o.artifact_count !== undefined ? o.artifact_count : 7,
78
+ gap_status: o.gap_status || 'active',
79
+ completeness_score: o.completeness_score !== undefined ? o.completeness_score : 0.85,
80
+ minto_health: '--',
81
+ last_activity_at: o.last_activity_at || '2026-04-18T00:00:00Z',
82
+ },
83
+ reasoning: {
84
+ exists: true,
85
+ governing_thought: o.governing_thought !== undefined
86
+ ? o.governing_thought
87
+ : 'TAM of $12B is bottom-up defensible',
88
+ arguments_count: o.arguments_count !== undefined ? o.arguments_count : 3,
89
+ evidence_density: o.evidence_density !== undefined ? o.evidence_density : 0.9,
90
+ mece_status: o.mece_status || 'pass',
91
+ reasoning_health_score: o.reasoning_health_score !== undefined ? o.reasoning_health_score : 0.8,
92
+ flagged_weaknesses: o.flagged_weaknesses || [],
93
+ decision_log: o.decision_log || [],
94
+ last_generated_at: o.last_generated_at || '2026-04-18T00:00:00Z',
95
+ last_artifact_write_seen_at: o.last_artifact_write_seen_at || '2026-04-18T00:00:00Z',
96
+ is_stale: o.is_stale !== undefined ? o.is_stale : false,
97
+ stale_reason: o.stale_reason !== undefined ? o.stale_reason : null,
98
+ },
99
+ };
100
+ }
101
+
102
+ function mkDecision(i) {
103
+ return {
104
+ session_id: 'sess-' + String(i),
105
+ timestamp: '2026-04-' + String((i % 28) + 1).padStart(2, '0') + 'T12:00:00Z',
106
+ action: 'flag_tam_staleness',
107
+ user_response: i % 2 === 0 ? 'approve' : 'defer',
108
+ reason: 'reason ' + String(i),
109
+ outcome: 'outcome ' + String(i),
110
+ };
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // Test 1: 3-section healthy input -> block has all lines per section
115
+ // ---------------------------------------------------------------------------
116
+ test('Test 1: 3-section input emits one block per section with required lines', () => {
117
+ const fmt = require(FORMATTER_PATH);
118
+ const sections = {
119
+ 'market-analysis': healthySection({
120
+ identity_text: 'bottom-up TAM analysis for enterprise SaaS wedge',
121
+ governing_thought: 'TAM of $12B is bottom-up defensible',
122
+ }),
123
+ 'problem-definition': healthySection({
124
+ identity_text: 'Mid-market IT buyers face integration fatigue',
125
+ governing_thought: 'IT integration is the wedge',
126
+ }),
127
+ 'solution-design': healthySection({
128
+ identity_text: 'API-first middleware layer',
129
+ governing_thought: 'API middleware unblocks integration',
130
+ }),
131
+ };
132
+ const out = fmt.formatTripleContext({ sections });
133
+ assert.ok(out.length > 0, 'output non-empty');
134
+ assert.ok(out.indexOf('## ACTIVE ROOM MEMORY') !== -1, 'header present');
135
+ assert.ok(out.indexOf('### market-analysis/') !== -1, 'market-analysis section header');
136
+ assert.ok(out.indexOf('### problem-definition/') !== -1, 'problem-definition section header');
137
+ assert.ok(out.indexOf('### solution-design/') !== -1, 'solution-design section header');
138
+ // Each section has Identity / References / State / Reasoning lines
139
+ assert.ok(out.indexOf('Identity:') !== -1, 'Identity line');
140
+ assert.ok(out.indexOf('References:') !== -1, 'References line');
141
+ assert.ok(out.indexOf('State:') !== -1, 'State line');
142
+ assert.ok(out.indexOf('Reasoning:') !== -1, 'Reasoning line');
143
+ });
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Test 2: Empty decision_log -> "Decision log:" header omitted
147
+ // ---------------------------------------------------------------------------
148
+ test('Test 2: empty decision_log -> "Decision log:" header omitted', () => {
149
+ const fmt = require(FORMATTER_PATH);
150
+ const sections = {
151
+ 'market-analysis': healthySection({ decision_log: [] }),
152
+ };
153
+ const out = fmt.formatTripleContext({ sections });
154
+ assert.ok(out.indexOf('Decision log:') === -1,
155
+ 'Decision log header must NOT appear when empty');
156
+ });
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // Test 3: 21 entries -> render only latest 3 with "[+18 older]" footer
160
+ // ---------------------------------------------------------------------------
161
+ test('Test 3: 21 decision_log entries -> render only latest 3 with +18 older footer', () => {
162
+ const fmt = require(FORMATTER_PATH);
163
+ const decisions = [];
164
+ for (let i = 0; i < 21; i++) decisions.push(mkDecision(i));
165
+ const sections = {
166
+ 'market-analysis': healthySection({ decision_log: decisions }),
167
+ };
168
+ const out = fmt.formatTripleContext({ sections });
169
+ assert.ok(out.indexOf('Decision log:') !== -1, 'Decision log header present');
170
+ // latest 3 = indices 18, 19, 20 (end of array is latest by write order)
171
+ assert.ok(out.indexOf('reason 18') !== -1, 'latest-3 entry 18 rendered');
172
+ assert.ok(out.indexOf('reason 19') !== -1, 'latest-3 entry 19 rendered');
173
+ assert.ok(out.indexOf('reason 20') !== -1, 'latest-3 entry 20 rendered');
174
+ // earlier entries NOT rendered
175
+ assert.ok(out.indexOf('reason 0\n') === -1 && out.indexOf('reason 0 ') === -1 && out.indexOf('reason 0,') === -1,
176
+ 'earliest entry NOT rendered');
177
+ // overflow footer present
178
+ assert.ok(out.indexOf('[+18 older]') !== -1, '+18 older footer present');
179
+ });
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // Test 4: null governing_thought -> "(not yet generated)"
183
+ // ---------------------------------------------------------------------------
184
+ test('Test 4: null governing_thought -> Reasoning line reads (not yet generated)', () => {
185
+ const fmt = require(FORMATTER_PATH);
186
+ const sections = {
187
+ 'market-analysis': healthySection({ governing_thought: null }),
188
+ };
189
+ const out = fmt.formatTripleContext({ sections });
190
+ assert.ok(out.indexOf('(not yet generated)') !== -1,
191
+ '(not yet generated) placeholder present');
192
+ });
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // Test 5: References rendering -- 5 items = all; > 5 = first 5 + [+N more]
196
+ // ---------------------------------------------------------------------------
197
+ test('Test 5: 5 references render fully; > 5 show first 5 + [+N more]', () => {
198
+ const fmt = require(FORMATTER_PATH);
199
+ // Case A: exactly 5 references render fully (no overflow marker)
200
+ const sections5 = {
201
+ 'market-analysis': healthySection({
202
+ references: [
203
+ { target: 'a', type: 'section', label: 'a' },
204
+ { target: 'b', type: 'section', label: 'b' },
205
+ { target: 'c', type: 'section', label: 'c' },
206
+ { target: 'd', type: 'section', label: 'd' },
207
+ { target: 'e', type: 'section', label: 'e' },
208
+ ],
209
+ }),
210
+ };
211
+ const out5 = fmt.formatTripleContext({ sections: sections5 });
212
+ assert.ok(out5.indexOf('[[a]]') !== -1, 'ref a rendered');
213
+ assert.ok(out5.indexOf('[[e]]') !== -1, 'ref e rendered');
214
+ assert.ok(out5.indexOf('[+') === -1 || out5.indexOf('[+0 more]') !== -1,
215
+ 'no overflow marker for exactly 5 refs');
216
+
217
+ // Case B: 8 references -> first 5 + [+3 more]
218
+ const sections8 = {
219
+ 'market-analysis': healthySection({
220
+ references: [
221
+ { target: 'r1', type: 'section', label: 'r1' },
222
+ { target: 'r2', type: 'section', label: 'r2' },
223
+ { target: 'r3', type: 'section', label: 'r3' },
224
+ { target: 'r4', type: 'section', label: 'r4' },
225
+ { target: 'r5', type: 'section', label: 'r5' },
226
+ { target: 'r6', type: 'section', label: 'r6' },
227
+ { target: 'r7', type: 'section', label: 'r7' },
228
+ { target: 'r8', type: 'section', label: 'r8' },
229
+ ],
230
+ }),
231
+ };
232
+ const out8 = fmt.formatTripleContext({ sections: sections8 });
233
+ assert.ok(out8.indexOf('[[r1]]') !== -1, 'r1 rendered');
234
+ assert.ok(out8.indexOf('[[r5]]') !== -1, 'r5 rendered');
235
+ assert.ok(out8.indexOf('[[r6]]') === -1, 'r6 NOT rendered');
236
+ assert.ok(out8.indexOf('[+3 more]') !== -1, '+3 more footer present');
237
+ });
238
+
239
+ // ---------------------------------------------------------------------------
240
+ // Test 6: Budget cap + weakest-first elision
241
+ // ---------------------------------------------------------------------------
242
+ test('Test 6: budget cap truncates weakest-first with strongest-elided footer', () => {
243
+ const fmt = require(FORMATTER_PATH);
244
+ // 30 sections, varying health scores 0.01..0.30 (1/100ths apart)
245
+ // Each has a fat payload so any 5-6 of them blow the default 5000-token cap.
246
+ const sections = {};
247
+ const fatIdentity = 'identity text '.repeat(200); // ~2800 chars per section
248
+ const fatThought = 'governing thought '.repeat(50);
249
+ for (let i = 0; i < 30; i++) {
250
+ const score = (i + 1) / 100; // 0.01, 0.02, ... 0.30
251
+ sections['section-' + String(i).padStart(2, '0')] = healthySection({
252
+ identity_text: fatIdentity,
253
+ governing_thought: fatThought,
254
+ reasoning_health_score: score,
255
+ references: [{ target: 't' + i, type: 'section', label: 't' + i }],
256
+ });
257
+ }
258
+ // Ensure default cap
259
+ delete process.env.SESSION_START_BUDGET_TOKENS;
260
+ const cap = fmt.getBudgetTokens();
261
+
262
+ const out = fmt.formatTripleContext({ sections });
263
+ // Total emitted tokens must be <= budget cap
264
+ const tokens = fmt.estimateTokens(out);
265
+ assert.ok(tokens <= cap,
266
+ 'emitted ' + tokens + ' tokens <= cap ' + cap);
267
+
268
+ // Weakest-first: section-00 (score 0.01) must appear BEFORE section-29 (0.30)
269
+ // If both were emitted, 00 appears earlier in the string; if not both,
270
+ // weakest (00) must be present and strongest (29) must be elided.
271
+ const idx00 = out.indexOf('### section-00/');
272
+ const idx29 = out.indexOf('### section-29/');
273
+ assert.ok(idx00 !== -1, 'weakest (section-00) present');
274
+ if (idx29 !== -1) {
275
+ assert.ok(idx00 < idx29, 'weakest appears before strongest');
276
+ }
277
+
278
+ // Elision footer present
279
+ assert.ok(/\[\+\d+ strongest sections elided/.test(out) ||
280
+ out.indexOf('strongest sections elided for budget') !== -1,
281
+ 'elision footer present (format: "N strongest sections elided for budget")');
282
+ });
283
+
284
+ // ---------------------------------------------------------------------------
285
+ // Test 6b: null reasoning_health_score sorts FIRST (weakest)
286
+ // ---------------------------------------------------------------------------
287
+ test('Test 6b: null reasoning_health_score sorted FIRST (before score=0.1)', () => {
288
+ const fmt = require(FORMATTER_PATH);
289
+ const sections = {
290
+ 'score-01': healthySection({ reasoning_health_score: 0.1 }),
291
+ 'score-null': healthySection({ reasoning_health_score: null }),
292
+ 'score-09': healthySection({ reasoning_health_score: 0.9 }),
293
+ };
294
+ const out = fmt.formatTripleContext({ sections });
295
+ const idxNull = out.indexOf('### score-null/');
296
+ const idx01 = out.indexOf('### score-01/');
297
+ const idx09 = out.indexOf('### score-09/');
298
+ assert.ok(idxNull !== -1 && idx01 !== -1 && idx09 !== -1, 'all sections present');
299
+ assert.ok(idxNull < idx01, 'null score appears BEFORE score=0.1');
300
+ assert.ok(idx01 < idx09, 'score=0.1 appears BEFORE score=0.9');
301
+ });
302
+
303
+ // ---------------------------------------------------------------------------
304
+ // Test 7: Token estimation consistency
305
+ // ---------------------------------------------------------------------------
306
+ test('Test 7: estimateTokens uses Math.ceil(length/4) and total <= cap', () => {
307
+ const fmt = require(FORMATTER_PATH);
308
+ // Known inputs
309
+ assert.equal(fmt.estimateTokens(''), 0, 'empty -> 0 tokens');
310
+ assert.equal(fmt.estimateTokens('abcd'), 1, '4 chars -> 1 token');
311
+ assert.equal(fmt.estimateTokens('abcde'), 2, '5 chars -> 2 tokens (ceil)');
312
+ assert.equal(fmt.estimateTokens(null), 0, 'null -> 0 tokens');
313
+ assert.equal(fmt.estimateTokens(undefined), 0, 'undefined -> 0 tokens');
314
+
315
+ // Formatted output always within cap
316
+ delete process.env.SESSION_START_BUDGET_TOKENS;
317
+ const cap = fmt.getBudgetTokens();
318
+ const sections = {};
319
+ for (let i = 0; i < 10; i++) {
320
+ sections['s' + i] = healthySection({ reasoning_health_score: i / 10 });
321
+ }
322
+ const out = fmt.formatTripleContext({ sections });
323
+ assert.ok(fmt.estimateTokens(out) <= cap,
324
+ 'total tokens <= cap (' + fmt.estimateTokens(out) + ' <= ' + cap + ')');
325
+ });
326
+
327
+ // ---------------------------------------------------------------------------
328
+ // Test 8: Stale annotation on State line
329
+ // ---------------------------------------------------------------------------
330
+ test('Test 8: is_stale:true -> State line annotated with stale_reason', () => {
331
+ const fmt = require(FORMATTER_PATH);
332
+ const sections = {
333
+ 'market-analysis': healthySection({
334
+ is_stale: true,
335
+ stale_reason: 'artifacts_newer_than_minto',
336
+ }),
337
+ };
338
+ const out = fmt.formatTripleContext({ sections });
339
+ assert.ok(out.indexOf('stale: artifacts_newer_than_minto') !== -1,
340
+ 'stale reason annotated on State line');
341
+ });
342
+
343
+ // ---------------------------------------------------------------------------
344
+ // Test 9: pending-tier1-regen footer
345
+ // ---------------------------------------------------------------------------
346
+ test('Test 9: pendingTier1 with 4 sections -> footer with count and /mos:reason hint', () => {
347
+ const fmt = require(FORMATTER_PATH);
348
+ const sections = {
349
+ 'market-analysis': healthySection(),
350
+ };
351
+ const out = fmt.formatTripleContext({
352
+ sections,
353
+ pendingTier1: [
354
+ { section: 'a' }, { section: 'b' }, { section: 'c' }, { section: 'd' },
355
+ ],
356
+ });
357
+ assert.ok(out.indexOf('4 sections') !== -1, 'count of 4 in footer');
358
+ assert.ok(out.indexOf('tier-0') !== -1 || out.indexOf('tier 0') !== -1 || out.indexOf('tier-1') !== -1,
359
+ 'tier-0 / tier-1 language in footer');
360
+ assert.ok(out.indexOf('/mos:reason') !== -1, '/mos:reason hint present');
361
+ });
362
+
363
+ // ---------------------------------------------------------------------------
364
+ // Test 10: Zero sections -> empty string
365
+ // ---------------------------------------------------------------------------
366
+ test('Test 10: zero sections -> empty string', () => {
367
+ const fmt = require(FORMATTER_PATH);
368
+ assert.equal(fmt.formatTripleContext({ sections: {} }), '',
369
+ 'empty sections returns empty string');
370
+ assert.equal(fmt.formatTripleContext({ sections: null }), '',
371
+ 'null sections returns empty string');
372
+ assert.equal(fmt.formatTripleContext({}), '',
373
+ 'missing sections returns empty string');
374
+ });
375
+
376
+ // ---------------------------------------------------------------------------
377
+ // Test 11: SESSION_START_BUDGET_TOKENS env override
378
+ // ---------------------------------------------------------------------------
379
+ test('Test 11: SESSION_START_BUDGET_TOKENS env override behavior', () => {
380
+ const fmt = require(FORMATTER_PATH);
381
+ const DEFAULT = fmt.DEFAULT_BUDGET_TOKENS;
382
+
383
+ // Set to a valid number -> cap = that number
384
+ process.env.SESSION_START_BUDGET_TOKENS = '3000';
385
+ assert.equal(fmt.getBudgetTokens(), 3000, 'env=3000 -> cap=3000');
386
+
387
+ // Set to garbage -> fallback to default
388
+ process.env.SESSION_START_BUDGET_TOKENS = 'abc';
389
+ assert.equal(fmt.getBudgetTokens(), DEFAULT, 'env=abc -> fallback to DEFAULT');
390
+
391
+ // Set to 0 -> fallback to default (invalid, must be > 0)
392
+ process.env.SESSION_START_BUDGET_TOKENS = '0';
393
+ assert.equal(fmt.getBudgetTokens(), DEFAULT, 'env=0 -> fallback to DEFAULT');
394
+
395
+ // Set to negative -> fallback
396
+ process.env.SESSION_START_BUDGET_TOKENS = '-100';
397
+ assert.equal(fmt.getBudgetTokens(), DEFAULT, 'env=-100 -> fallback to DEFAULT');
398
+
399
+ // Unset -> default
400
+ delete process.env.SESSION_START_BUDGET_TOKENS;
401
+ assert.equal(fmt.getBudgetTokens(), DEFAULT, 'env unset -> DEFAULT');
402
+ });
403
+
404
+ // ---------------------------------------------------------------------------
405
+ // Test 12: Baseline measurement recorded in SUMMARY.md
406
+ // ---------------------------------------------------------------------------
407
+ test('Test 12: baseline session-start emission recorded in 88-07-SUMMARY.md', () => {
408
+ const summaryPath = path.join(
409
+ REPO,
410
+ '.planning',
411
+ 'phases',
412
+ '88-feynman-minto-memory-layer',
413
+ '88-07-SUMMARY.md'
414
+ );
415
+ assert.ok(fs.existsSync(summaryPath),
416
+ 'SUMMARY.md must exist at ' + summaryPath);
417
+ const body = fs.readFileSync(summaryPath, 'utf8');
418
+ const hit = /baseline.*tokens|measured.*session-start/i.test(body);
419
+ assert.ok(hit,
420
+ 'SUMMARY.md must contain baseline-tokens or measured-session-start phrasing');
421
+ });
422
+
423
+ // ---------------------------------------------------------------------------
424
+ // Run all
425
+ // ---------------------------------------------------------------------------
426
+ (async () => {
427
+ let failed = 0;
428
+ for (const t of tests) {
429
+ try {
430
+ await t.fn();
431
+ process.stdout.write(' pass: ' + t.name + '\n');
432
+ } catch (e) {
433
+ failed += 1;
434
+ process.stderr.write(' FAIL: ' + t.name + '\n');
435
+ process.stderr.write(' ' + (e && e.stack ? e.stack : String(e)) + '\n');
436
+ }
437
+ }
438
+ process.stdout.write(
439
+ '\ntriple-context-formatter: ' + (tests.length - failed) + '/' + tests.length + ' passed\n'
440
+ );
441
+ process.exit(failed === 0 ? 0 : 1);
442
+ })();