@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,438 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ * Phase 89.5 Plan 03 -- Query-to-Text Larry-voiced explainer.
4
+ *
5
+ * Translates raw graph query results (rs_discovery / expert_network /
6
+ * methodology_chain / discovery_history / fallback) into a Larry-voiced
7
+ * natural-language explanation string. The (b) half of the Bidirectional
8
+ * NL-Graph Surface; pairs with rs-nl-to-query.cjs (the (a) Text->Query
9
+ * half) shipped in Plan 89.5-02.
10
+ *
11
+ * Together: user types question -> rs-nl-to-query translates to
12
+ * {cypher, sql, brain_query} bundle -> orchestrator executes ->
13
+ * rs-query-to-text renders raw results back as Larry-voiced NL.
14
+ *
15
+ * NO RUNTIME LLM. Larry's voice is template-driven. Voice patterns are
16
+ * extracted from skills/larry-personality/SKILL.md at design time and
17
+ * frozen here as VOICE_TEMPLATES (5 result kinds x 3-4 templates each).
18
+ * Template selection is deterministic from the input (hash-based) so
19
+ * same input -> same render across runs.
20
+ *
21
+ * Reuses (Canon Part 7):
22
+ * folder-memory.cjs::readQuadruple (Phase 90)
23
+ * rs-egress-violations.cjs::ExternalEgressViolation (89.2-01)
24
+ * rs-egress-prompts.cjs::auditQueryString (89.2-01)
25
+ * rs-egress-prompts.cjs::auditQueryObject (89.2-01)
26
+ *
27
+ * NEVER imports (this module RENDERS, never queries Brain or executes):
28
+ * the Brain HTTP client module (orchestrator only)
29
+ * lazygraph-ops.cjs::queryGraph (orchestrator only)
30
+ *
31
+ * NEVER invokes any network primitive. Pure CJS, zero npm deps,
32
+ * no Node built-ins beyond core require.
33
+ *
34
+ * Canon Part 8 defense (2 audit seams):
35
+ * SEAM A (input audit on {query_results, opts}): catches forbidden
36
+ * patterns nested anywhere in the input row payload BEFORE rendering.
37
+ * SEAM B (post-render audit on the rendered string): catches
38
+ * template-substitution leaks AFTER rendering. This is the last line
39
+ * of defense -- if a forbidden byte slipped past the input audit
40
+ * (e.g. via a substring not flagged by the input regex but assembled
41
+ * into a forbidden phrase by the template), this seam catches it.
42
+ *
43
+ * Mode A (BRAIN.md present + fresh) -> render includes Brain enrichment.
44
+ * Mode B (BRAIN.md absent or stale) -> render omits Brain enrichment.
45
+ * Tier 0 (no room_dir / no quadruple) -> render uses safe defaults.
46
+ *
47
+ * License: BSL 1.1.
48
+ */
49
+ 'use strict';
50
+
51
+ const folderMemory = require('./folder-memory.cjs');
52
+ const { ExternalEgressViolation } = require('./rs-egress-violations.cjs');
53
+ const {
54
+ auditQueryString,
55
+ auditQueryObject,
56
+ FORBIDDEN_PATTERNS,
57
+ } = require('./rs-egress-prompts.cjs');
58
+
59
+ // ---------- Frozen VOICE_TEMPLATES (5 kinds, 3-4 templates each) ----------
60
+ //
61
+ // Voice patterns extracted from skills/larry-personality/SKILL.md at
62
+ // design time. Each template carries {placeholder} slots that fillTemplate
63
+ // substitutes from query_results + venture_context. The Evidence -> Insight
64
+ // -> Warning pedagogical structure is preserved across all templates.
65
+ //
66
+ // Adding a template (or a new kind) is a Plan-N revision (canon-amend
67
+ // discipline; new templates expand the surface area Canon Part 8 must
68
+ // defend, so we want explicit review).
69
+ //
70
+ // NB: the source bytes here MUST NOT contain em-dashes (BSL 1.1 + canon
71
+ // rule); plain ASCII hyphens only.
72
+
73
+ const VOICE_TEMPLATES = Object.freeze({
74
+ rs_discovery: Object.freeze([
75
+ 'Found {n} reverse salients across {domain_count} domains. The strongest is {top_thesis} (breakthrough score {top_score}). Filed to opportunity-bank/. {brain_line}{room_line}Worth Bank Opportunity or Devils Advocate.',
76
+ '{n} discoveries surfaced. Top: {top_thesis}. Pattern: {classification}. {brain_line}{room_line}Next: Bank Opportunity or Run Methodology /mos:lean-canvas.',
77
+ 'Reading the Room: {room_context}. {n} candidates ranked. Strongest: {top_thesis}. {brain_line}Worth filing.',
78
+ '{n} differential pairs cleared the dual floor. Top: {top_thesis} (score {top_score}). {brain_line}{room_line}Merits Run Methodology.',
79
+ ]),
80
+ expert_network: Object.freeze([
81
+ 'Mapped {n} experts across {institution_count} institutions. Top institutions: {institutions}. {brain_line}{room_line}/mos:persona may be warranted.',
82
+ '{n} authors resolved. Institutions: {institutions}. {brain_line}{room_line}Worth Run Methodology /mos:persona.',
83
+ 'Found {n} domain experts. Leading institutions: {institutions}. {brain_line}Cross-reference your room: {room_context}.',
84
+ ]),
85
+ methodology_chain: Object.freeze([
86
+ '{source} chains into {n} downstream methodologies: {chain_list}. {brain_line}{room_line}Given your room stage {state_stage}, the next hop is {recommended}.',
87
+ 'Methodology graph: {source} -> {chain_list} ({n} hops). {brain_line}Synthesize next? Or Run Methodology on {recommended}.',
88
+ '{n} downstream paths from {source}. Pick one: {chain_list}. {brain_line}{room_line}Worth Synthesize.',
89
+ ]),
90
+ discovery_history: Object.freeze([
91
+ 'You have {n} RS discoveries logged in this room. Most recent: {recent_thesis}. The pattern: {convergence}. {brain_line}{room_line}Worth Synthesize via /mos:reflect.',
92
+ '{n} discoveries logged. Newest: {recent_thesis}. Convergence: {convergence}. {brain_line}{room_line}Worth Reflect.',
93
+ 'Looking back: {n} discoveries. {recent_thesis} stands out. {brain_line}{room_line}Defer the rest? Synthesize?',
94
+ ]),
95
+ fallback: Object.freeze([
96
+ 'Searched 3 graphs and found {summary}. {brain_line}Relevant context: {room_context}. Next move: Run Methodology or Reformulate.',
97
+ 'Triangulated across room.db + Aura + Brain. {summary}. {brain_line}{room_line}Worth reframing? /mos:beautiful-question.',
98
+ '{summary}. {brain_line}Given {room_context}, consider Run Methodology or Defer.',
99
+ ]),
100
+ });
101
+
102
+ // ---------- Frozen kind enum ----------
103
+
104
+ const KNOWN_KINDS = Object.freeze([
105
+ 'rs_discovery',
106
+ 'expert_network',
107
+ 'methodology_chain',
108
+ 'discovery_history',
109
+ 'fallback',
110
+ ]);
111
+
112
+ // ---------- Internal helpers ----------
113
+
114
+ // detectKind: deterministic. Returns the kind from input if it matches a
115
+ // known kind; otherwise 'fallback'. NEVER throws.
116
+ function detectKind(query_results) {
117
+ if (!query_results || typeof query_results !== 'object') return 'fallback';
118
+ const k = query_results.kind;
119
+ if (typeof k !== 'string') return 'fallback';
120
+ for (let i = 0; i < KNOWN_KINDS.length; i++) {
121
+ if (KNOWN_KINDS[i] === k) return k;
122
+ }
123
+ return 'fallback';
124
+ }
125
+
126
+ // loadVentureContext: reads the per-folder memory quadruple if a room_dir
127
+ // is provided; respects _test_quadruple_override for test surfaces. Always
128
+ // returns a 4-field object {room, state, reasoning, brain}; missing fields
129
+ // fall back to null. Graceful: any throw inside readQuadruple yields the
130
+ // all-null shell (Mode B / Tier 0 contract).
131
+ function loadVentureContext(opts) {
132
+ const safe = opts && typeof opts === 'object' ? opts : {};
133
+ const empty = { room: null, state: null, reasoning: null, brain: null };
134
+
135
+ // Test surface: explicit override wins.
136
+ if (safe._test_quadruple_override && typeof safe._test_quadruple_override === 'object') {
137
+ const ov = safe._test_quadruple_override;
138
+ return {
139
+ room: ov.room === undefined ? null : ov.room,
140
+ state: ov.state === undefined ? null : ov.state,
141
+ reasoning: ov.reasoning === undefined ? null : ov.reasoning,
142
+ brain: ov.brain === undefined ? null : ov.brain,
143
+ };
144
+ }
145
+
146
+ // Production path: room_dir -> readQuadruple.
147
+ if (typeof safe.room_dir !== 'string' || safe.room_dir.length === 0) return empty;
148
+ let quad = null;
149
+ try {
150
+ quad = folderMemory.readQuadruple(safe.room_dir);
151
+ } catch (_e) {
152
+ return empty;
153
+ }
154
+ if (!quad || typeof quad !== 'object') return empty;
155
+ return {
156
+ room: quad.room === undefined ? null : quad.room,
157
+ state: quad.state === undefined ? null : quad.state,
158
+ reasoning: quad.reasoning === undefined ? null : quad.reasoning,
159
+ brain: quad.brain === undefined ? null : quad.brain,
160
+ };
161
+ }
162
+
163
+ // pickTemplate: deterministic hash-based selection so the same input
164
+ // always renders the same template (no random selection in production).
165
+ // Hash inputs: kind + first row id + first row thesis (or first key).
166
+ // NEVER throws.
167
+ function pickTemplate(kind, query_results) {
168
+ const bucket = VOICE_TEMPLATES[kind] || VOICE_TEMPLATES.fallback;
169
+ if (!Array.isArray(bucket) || bucket.length === 0) {
170
+ return VOICE_TEMPLATES.fallback[0];
171
+ }
172
+ // Build a tiny deterministic seed from query_results.
173
+ let seedStr = String(kind);
174
+ const rows = query_results && Array.isArray(query_results.rows) ? query_results.rows : [];
175
+ if (rows.length > 0 && rows[0] && typeof rows[0] === 'object') {
176
+ const r = rows[0];
177
+ if (typeof r.id === 'string') seedStr += '|' + r.id;
178
+ else if (typeof r.thesis === 'string') seedStr += '|' + r.thesis.slice(0, 40);
179
+ else if (typeof r.from === 'string') seedStr += '|' + r.from + '->' + (r.to || '');
180
+ else if (typeof r.name === 'string') seedStr += '|' + r.name;
181
+ }
182
+ // FNV-1a 32-bit hash (pure JS, deterministic).
183
+ let h = 0x811c9dc5;
184
+ for (let i = 0; i < seedStr.length; i++) {
185
+ h ^= seedStr.charCodeAt(i);
186
+ h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;
187
+ }
188
+ const idx = h % bucket.length;
189
+ return bucket[idx];
190
+ }
191
+
192
+ // safeScalar: coerce a value into a short, audit-safe string. Numbers and
193
+ // booleans pass through; strings are length-capped; null/undefined become
194
+ // the provided default. Objects and arrays render as a count or stringified
195
+ // short form (defense against runaway payload size).
196
+ function safeScalar(v, defaultStr) {
197
+ if (v === null || v === undefined) return defaultStr;
198
+ if (typeof v === 'string') {
199
+ return v.length > 200 ? v.slice(0, 200) : v;
200
+ }
201
+ if (typeof v === 'number' || typeof v === 'boolean') return String(v);
202
+ if (Array.isArray(v)) {
203
+ return v.length === 0 ? defaultStr : String(v.length);
204
+ }
205
+ if (typeof v === 'object') {
206
+ return defaultStr;
207
+ }
208
+ return defaultStr;
209
+ }
210
+
211
+ // buildPlaceholderMap: assemble the placeholder substitution map from
212
+ // query_results + venture_context. Missing fields fall back to safe
213
+ // defaults so the rendered string is always coherent.
214
+ function buildPlaceholderMap(kind, query_results, vc) {
215
+ const map = Object.create(null);
216
+ const rows = query_results && Array.isArray(query_results.rows) ? query_results.rows : [];
217
+ const top = rows.length > 0 ? rows[0] : null;
218
+
219
+ // Generic fields shared across kinds.
220
+ map.n = String(rows.length);
221
+
222
+ // Brain enrichment line (Mode A vs Mode B).
223
+ // Mode A (brain.exists + staleness fresh + has pattern_matches body):
224
+ // "Brain says: <body excerpt>."
225
+ // Mode B (brain null OR stale): empty string (no marker).
226
+ map.brain_line = '';
227
+ if (vc && vc.brain && vc.brain.exists === true && vc.brain.staleness === 'fresh') {
228
+ const sections = vc.brain.sections;
229
+ if (sections && typeof sections === 'object') {
230
+ const pm = sections.pattern_matches;
231
+ const cda = sections.cross_domain_analogies;
232
+ let bodyExcerpt = null;
233
+ if (pm && typeof pm === 'object' && typeof pm.body === 'string' && pm.body.length > 0) {
234
+ bodyExcerpt = pm.body;
235
+ } else if (cda && typeof cda === 'object' && typeof cda.body === 'string' && cda.body.length > 0) {
236
+ bodyExcerpt = cda.body;
237
+ }
238
+ if (bodyExcerpt !== null) {
239
+ const trimmed = bodyExcerpt.length > 120 ? bodyExcerpt.slice(0, 120) : bodyExcerpt;
240
+ map.brain_line = 'Brain says: ' + trimmed + '. ';
241
+ }
242
+ }
243
+ }
244
+
245
+ // Room context line (only when room context is meaningful).
246
+ map.room_line = '';
247
+ map.room_context = 'no active room context';
248
+ if (vc && vc.room && vc.room.exists === true) {
249
+ const id = typeof vc.room.identity_text === 'string' ? vc.room.identity_text : '';
250
+ if (id.length > 0) {
251
+ const idShort = id.length > 60 ? id.slice(0, 60) : id;
252
+ map.room_context = 'in your ' + idShort + ' room';
253
+ map.room_line = 'Reading the Room: ' + idShort + '. ';
254
+ }
255
+ }
256
+
257
+ // State stage (for methodology_chain template).
258
+ map.state_stage = 'unknown';
259
+ if (vc && vc.state && vc.state.exists === true) {
260
+ const gs = typeof vc.state.gap_status === 'string' ? vc.state.gap_status : '';
261
+ if (gs.length > 0) map.state_stage = gs;
262
+ }
263
+
264
+ // Kind-specific placeholders.
265
+ if (kind === 'rs_discovery') {
266
+ map.top_thesis = top && typeof top.thesis === 'string'
267
+ ? safeScalar(top.thesis, 'no thesis')
268
+ : 'no thesis';
269
+ map.top_score = top && typeof top.breakthrough_score !== 'undefined'
270
+ ? safeScalar(top.breakthrough_score, '0')
271
+ : '0';
272
+ map.classification = top && typeof top.classification === 'string'
273
+ ? safeScalar(top.classification, 'unclassified')
274
+ : 'unclassified';
275
+ // domain_count: union of all rows[].domains; cap small.
276
+ let domainSet = Object.create(null);
277
+ let domainCount = 0;
278
+ for (let i = 0; i < rows.length; i++) {
279
+ const r = rows[i];
280
+ if (r && Array.isArray(r.domains)) {
281
+ for (let j = 0; j < r.domains.length; j++) {
282
+ const d = r.domains[j];
283
+ if (typeof d === 'string' && !domainSet[d]) {
284
+ domainSet[d] = true;
285
+ domainCount++;
286
+ }
287
+ }
288
+ }
289
+ }
290
+ map.domain_count = String(domainCount > 0 ? domainCount : 1);
291
+ } else if (kind === 'expert_network') {
292
+ // Institutions list (deduped).
293
+ const instSet = Object.create(null);
294
+ const instList = [];
295
+ for (let i = 0; i < rows.length; i++) {
296
+ const r = rows[i];
297
+ if (r && typeof r.institution === 'string' && !instSet[r.institution]) {
298
+ instSet[r.institution] = true;
299
+ instList.push(safeScalar(r.institution, ''));
300
+ }
301
+ }
302
+ map.institution_count = String(instList.length > 0 ? instList.length : 1);
303
+ map.institutions = instList.length > 0 ? instList.join(', ') : 'no institutions';
304
+ // Expert list: first 3 names.
305
+ const names = [];
306
+ for (let i = 0; i < rows.length && names.length < 3; i++) {
307
+ const r = rows[i];
308
+ if (r && typeof r.name === 'string') names.push(safeScalar(r.name, ''));
309
+ }
310
+ map.expert_list = names.length > 0 ? names.join(', ') : 'no experts';
311
+ } else if (kind === 'methodology_chain') {
312
+ // Source: first row's "from" field.
313
+ map.source = top && typeof top.from === 'string'
314
+ ? safeScalar(top.from, 'unknown')
315
+ : 'unknown';
316
+ // Chain list: rows[].to deduped.
317
+ const toSet = Object.create(null);
318
+ const toList = [];
319
+ for (let i = 0; i < rows.length; i++) {
320
+ const r = rows[i];
321
+ if (r && typeof r.to === 'string' && !toSet[r.to]) {
322
+ toSet[r.to] = true;
323
+ toList.push(safeScalar(r.to, ''));
324
+ }
325
+ }
326
+ map.chain_list = toList.length > 0 ? toList.join(', ') : 'no downstream targets';
327
+ map.recommended = toList.length > 0 ? toList[0] : 'no recommendation';
328
+ } else if (kind === 'discovery_history') {
329
+ // Most-recent thesis: pick row with latest created_at; fallback to first row.
330
+ let recent = top;
331
+ let recentTime = top && typeof top.created_at === 'string' ? top.created_at : '';
332
+ for (let i = 1; i < rows.length; i++) {
333
+ const r = rows[i];
334
+ if (r && typeof r.created_at === 'string' && r.created_at > recentTime) {
335
+ recent = r;
336
+ recentTime = r.created_at;
337
+ }
338
+ }
339
+ map.recent_thesis = recent && typeof recent.thesis === 'string'
340
+ ? safeScalar(recent.thesis, 'no recent thesis')
341
+ : 'no recent thesis';
342
+ // Convergence cue: count if >1, otherwise note "single discovery".
343
+ if (rows.length > 1) {
344
+ map.convergence = rows.length + ' theses logged this room';
345
+ } else {
346
+ map.convergence = 'single discovery';
347
+ }
348
+ } else {
349
+ // fallback kind.
350
+ map.summary = rows.length === 0
351
+ ? 'no rows returned'
352
+ : (rows.length + ' rows returned');
353
+ }
354
+
355
+ return map;
356
+ }
357
+
358
+ // fillTemplate: substitute {placeholder} slots in the template using the
359
+ // placeholder map. Unknown placeholders fall back to a safe default. The
360
+ // function NEVER throws and ALWAYS returns a string.
361
+ function fillTemplate(template, placeholders) {
362
+ if (typeof template !== 'string' || template.length === 0) return '';
363
+ const safe = placeholders || Object.create(null);
364
+ // Replace every {key} segment via global regex; missing keys -> empty
365
+ // string default for graceful render.
366
+ const out = template.replace(/\{([a-z_][a-z0-9_]*)\}/gi, function (_match, key) {
367
+ if (Object.prototype.hasOwnProperty.call(safe, key)) {
368
+ const v = safe[key];
369
+ if (typeof v === 'string') return v;
370
+ if (typeof v === 'number' || typeof v === 'boolean') return String(v);
371
+ return '';
372
+ }
373
+ return '';
374
+ });
375
+ // Collapse double spaces resulting from empty {brain_line} or
376
+ // {room_line} substitutions. Two-pass collapse handles the common
377
+ // ". . " -> ". " case.
378
+ return out.replace(/\s{2,}/g, ' ').replace(/\s+([.,;:!?])/g, '$1').trim();
379
+ }
380
+
381
+ // ---------- Top-level entry point ----------
382
+
383
+ function explain(query_results, opts) {
384
+ // SEAM A: input audit. JSON.stringify-flatten the input + opts so any
385
+ // forbidden bytes nested anywhere in the row payload trip the audit
386
+ // BEFORE rendering. This catches T8/T9 input-side leaks.
387
+ const safeOpts = opts && typeof opts === 'object' ? opts : {};
388
+ const inputBundle = {
389
+ query_results: query_results === undefined ? null : query_results,
390
+ // Strip _test_quadruple_override from the audit bundle: it carries
391
+ // legitimate test fixtures whose body text would otherwise trip the
392
+ // audit (e.g. brain.sections.pattern_matches body). Production callers
393
+ // never set this field; readQuadruple loads vetted local bytes.
394
+ opts: (function () {
395
+ const copy = Object.create(null);
396
+ for (const k of Object.keys(safeOpts)) {
397
+ if (k === '_test_quadruple_override') continue;
398
+ copy[k] = safeOpts[k];
399
+ }
400
+ return copy;
401
+ })(),
402
+ };
403
+ auditQueryObject(inputBundle, 'rs-query-to-text-input');
404
+
405
+ // Detect kind, load venture context, pick template, build placeholders,
406
+ // render. Each step is graceful (never throws on missing fields).
407
+ const kind = detectKind(query_results);
408
+ const ventureContext = loadVentureContext(safeOpts);
409
+ const template = pickTemplate(kind, query_results);
410
+ const placeholders = buildPlaceholderMap(kind, query_results, ventureContext);
411
+ const rendered = fillTemplate(template, placeholders);
412
+
413
+ // SEAM B: post-render output audit. Last line of defense against
414
+ // template-substitution leaks (e.g. row text smuggling through that
415
+ // the input audit's broader regex did not catch). Throws
416
+ // ExternalEgressViolation if any FORBIDDEN_PATTERN matches.
417
+ auditQueryString(rendered, 'rs-query-to-text-output');
418
+
419
+ return rendered;
420
+ }
421
+
422
+ // ---------- Exports ----------
423
+
424
+ module.exports = {
425
+ explain: explain,
426
+ VOICE_TEMPLATES: VOICE_TEMPLATES,
427
+ KNOWN_KINDS: KNOWN_KINDS,
428
+ // Internal helpers exposed for fixture introspection only. Production
429
+ // callers MUST use explain(); the chokepoint is internal.
430
+ _test: {
431
+ detectKind: detectKind,
432
+ loadVentureContext: loadVentureContext,
433
+ pickTemplate: pickTemplate,
434
+ fillTemplate: fillTemplate,
435
+ buildPlaceholderMap: buildPlaceholderMap,
436
+ safeScalar: safeScalar,
437
+ },
438
+ };