@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,333 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Plan 87-06 Test: indexArtifact transaction wrap + lock-release semantics
6
+ * ========================================================================
7
+ *
8
+ * BSL 1.1. Copyright (c) Mindrian 2026.
9
+ *
10
+ * Closes CASCADE-04. Proves three independent invariants of the indexArtifact
11
+ * flow (lib/core/graph-ops.cjs -> lib/core/lazygraph-ops.cjs):
12
+ *
13
+ * 1. Happy path: filing a single artifact produces the expected Artifact
14
+ * and Section nodes, and the outer enqueueWrite lock is released on
15
+ * success (write.lock file absent after call).
16
+ *
17
+ * 2. Mid-transaction rollback (R-87-06-ROLLBACK): when an error is
18
+ * injected INSIDE the BEGIN/COMMIT boundary (after the first INSERT has
19
+ * fired but before COMMIT), SQLite must roll back the partial writes.
20
+ * We assert countAfter === countBefore on the Artifact node count;
21
+ * if the rollback did not fire, the first INSERT would persist and
22
+ * the assertion would fail.
23
+ *
24
+ * 3. Lock release after commit (testLockReleaseAfterCommit): a DIFFERENT
25
+ * failure mode -- the caller's fn inside enqueueWrite throws OUTSIDE
26
+ * the SQLite transaction (here: fs.readFileSync on a nonexistent
27
+ * path). The outer try/finally in enqueueWrite must still release the
28
+ * write-lock. This tests the lock-release semantic, not the txn
29
+ * rollback semantic; both matter, both are tested separately.
30
+ *
31
+ * 4. Rollback does not leak the lock (testRollbackDoesNotLeakLock): a
32
+ * throw INSIDE the transaction (same injection strategy as Test 2)
33
+ * must still release the enqueueWrite write-lock. This combines the
34
+ * two concerns: ROLLBACK happens AND the outer finally fires.
35
+ * Distinct from Test 3 because Test 3 throws BEFORE the txn even
36
+ * starts; this one throws WITH an active BEGIN/COMMIT block that
37
+ * must be rolled back.
38
+ *
39
+ * Why three failure tests (2, 3, 4 are distinct):
40
+ * - Test 2 exercises the BEGIN/COMMIT/ROLLBACK inside indexArtifact.
41
+ * - Test 3 exercises the acquireLock/releaseLock finally when no txn
42
+ * was ever opened.
43
+ * - Test 4 exercises BOTH: txn rolls back AND lock releases.
44
+ * Either one failing silently would leave a different kind of breakage in
45
+ * prod. Bundling them into one test would mask which guarantee regressed.
46
+ *
47
+ * Exit codes:
48
+ * 0 -- all tests passed
49
+ * 1 -- any test failed (real regression)
50
+ *
51
+ * Business Source License 1.1 -- see repository LICENSE.
52
+ */
53
+
54
+ const assert = require('node:assert/strict');
55
+ const fs = require('node:fs');
56
+ const os = require('node:os');
57
+ const path = require('node:path');
58
+ const { DatabaseSync } = require('node:sqlite');
59
+
60
+ const lazygraph = require('../core/lazygraph-ops.cjs');
61
+ const graphOps = require('../core/graph-ops.cjs');
62
+
63
+ const FIXTURE = path.resolve(__dirname, '../../test/fixtures/cascade-e2e/seed-room');
64
+
65
+ // ----------------------------------------------------------------------------
66
+ // Test 1: Happy path -- indexArtifact via graph-ops wrapper (lock + txn OK)
67
+ // ----------------------------------------------------------------------------
68
+
69
+ async function testHappyPath(tmpRoom, dbPath, goodFile, mindrian) {
70
+ const res = await graphOps.indexArtifact(tmpRoom, goodFile);
71
+ assert.strictEqual(res.success, true, 'happy path must return success');
72
+
73
+ const db1 = new DatabaseSync(dbPath, { readOnly: true });
74
+ const nodeCount1 = db1.prepare("SELECT COUNT(*) as n FROM nodes WHERE type = 'Artifact'").get().n;
75
+ db1.close();
76
+ assert.ok(nodeCount1 >= 1, `happy path must insert at least one Artifact node (got ${nodeCount1})`);
77
+
78
+ // Write lock released after successful call (enqueueWrite finally)
79
+ const lockPath = path.join(mindrian, 'write.lock');
80
+ assert.strictEqual(fs.existsSync(lockPath), false, 'write lock must be released after happy path');
81
+ return nodeCount1;
82
+ }
83
+
84
+ // ----------------------------------------------------------------------------
85
+ // Test 2: Mid-transaction rollback (R-87-06-ROLLBACK)
86
+ // ----------------------------------------------------------------------------
87
+ //
88
+ // Injection strategy: patch conn.prepare so the FIRST prepare (BEGIN) returns
89
+ // the real stmt, the SECOND prepare (first INSERT) returns a stmt whose
90
+ // .run() throws. That places the throw AFTER BEGIN has fired but BEFORE any
91
+ // INSERT commits. With the BEGIN/COMMIT wrap in place, indexArtifact's catch
92
+ // issues ROLLBACK and the Artifact count stays identical to the pre-call
93
+ // value. Without the wrap, the first INSERT would persist and the assertion
94
+ // would fail. This is the concrete proof of rollback behavior.
95
+ //
96
+ // We call lazygraph.indexArtifact directly (not graphOps.indexArtifact) so
97
+ // we control the conn that is patched; graphOps opens its own conn inside
98
+ // enqueueWrite and we cannot intercept it at the lazygraph-body level.
99
+
100
+ async function testMidTransactionRollback(tmpRoom, dbPath) {
101
+ const db2 = new DatabaseSync(dbPath);
102
+ lazygraph.initSchema(db2); // idempotent
103
+
104
+ // Capture pre-call Artifact count
105
+ const countBefore = db2.prepare("SELECT COUNT(*) as n FROM nodes WHERE type = 'Artifact'").get().n;
106
+
107
+ // Patch: intercept conn.prepare so the 3rd prepare (the 2nd INSERT in the
108
+ // indexArtifact body, AFTER BEGIN and AFTER the first Artifact INSERT) gets
109
+ // a stmt whose .run() throws. This guarantees:
110
+ // prepare #1 -> 'BEGIN' -> real run() fires, txn starts
111
+ // prepare #2 -> INSERT Artifact node -> real run() fires, row written
112
+ // prepare #3 -> INSERT Section node -> stub run() throws mid-txn
113
+ //
114
+ // That placement matters: at least ONE INSERT has already hit the database
115
+ // inside the BEGIN block before the throw. If indexArtifact lacks the
116
+ // BEGIN/COMMIT wrap, that first INSERT auto-commits and countAfter would
117
+ // be countBefore + 1 (regression caught). With the wrap in place, the
118
+ // catch block issues ROLLBACK and undoes the first INSERT, so
119
+ // countAfter === countBefore. This is the ONLY injection point that
120
+ // proves rollback actually fired (vs. "the throw happened before any
121
+ // write, so there was nothing to roll back").
122
+ //
123
+ // runCount >= 2 is the canonical marker per plan: "throw after the 2nd
124
+ // stmt.run() invocation" -- our prepareCount === 3 means two real run()
125
+ // calls already succeeded (BEGIN + first INSERT).
126
+ const origPrepare = db2.prepare.bind(db2);
127
+ let prepareCount = 0;
128
+ db2.prepare = function (sql) {
129
+ prepareCount++;
130
+ const stmt = origPrepare(sql);
131
+ if (prepareCount === 3) {
132
+ stmt.run = function (..._args) {
133
+ // Restore prepare() BEFORE throwing so ROLLBACK (which also goes
134
+ // through db2.prepare) reaches the real implementation. Otherwise
135
+ // ROLLBACK would loop back into this stub.
136
+ db2.prepare = origPrepare;
137
+ throw new Error('injected mid-transaction failure at prepare #' + prepareCount + ' (runCount >= 2)');
138
+ };
139
+ }
140
+ return stmt;
141
+ };
142
+
143
+ // Try to index an artifact -- should throw due to injection
144
+ const anotherFile = path.join(tmpRoom, 'market-analysis', 's-curve-mature-market.md');
145
+ let threw = false;
146
+ let threwMsg = '';
147
+ try {
148
+ await lazygraph.indexArtifact(db2, tmpRoom, anotherFile);
149
+ } catch (e) {
150
+ threw = true;
151
+ threwMsg = e.message;
152
+ }
153
+
154
+ // Safety: restore prepare in case the stub was never triggered
155
+ db2.prepare = origPrepare;
156
+
157
+ assert.ok(threw, 'injected failure must propagate to caller');
158
+ assert.ok(
159
+ threwMsg.includes('injected mid-transaction') || threwMsg.includes('runCount >= 2'),
160
+ `error message should carry injection marker, got: ${threwMsg}`
161
+ );
162
+
163
+ // The critical assertion: ROLLBACK reverted the partial write.
164
+ const countAfter = db2.prepare("SELECT COUNT(*) as n FROM nodes WHERE type = 'Artifact'").get().n;
165
+ assert.strictEqual(
166
+ countAfter,
167
+ countBefore,
168
+ `ROLLBACK FAILED: node count changed from ${countBefore} to ${countAfter} -- partial write survived`
169
+ );
170
+
171
+ db2.close();
172
+ return { countBefore, countAfter };
173
+ }
174
+
175
+ // ----------------------------------------------------------------------------
176
+ // Test 3: testLockReleaseAfterCommit -- distinct failure mode, distinct name
177
+ // ----------------------------------------------------------------------------
178
+ //
179
+ // This test is INTENTIONALLY distinct from testMidTransactionRollback. It
180
+ // verifies that enqueueWrite's try/finally releases the lock even when the
181
+ // caller's fn throws OUTSIDE the SQLite transaction (here: fs.readFileSync
182
+ // fails on a nonexistent file, before any prepare() runs). That is a lock
183
+ // release semantic, not a transaction rollback semantic.
184
+ //
185
+ // Why the name: "after commit" refers to "after the transaction boundary
186
+ // is complete OR was never entered". Both paths exercise the same finally
187
+ // block in enqueueWrite. If a future refactor moves BEGIN before the
188
+ // fs.readFileSync (shouldn't happen, but defensive), this test still
189
+ // catches a lock leak because fs.readFileSync throwing before any INSERT
190
+ // would hit the ROLLBACK path and then the finally.
191
+
192
+ async function testLockReleaseAfterCommit(tmpRoom, mindrian) {
193
+ const lockPath = path.join(mindrian, 'write.lock');
194
+ let graphOpsThrewOnBadFile = false;
195
+ try {
196
+ await graphOps.indexArtifact(tmpRoom, path.join(tmpRoom, 'does-not-exist.md'));
197
+ } catch (_) {
198
+ graphOpsThrewOnBadFile = true;
199
+ }
200
+
201
+ assert.ok(graphOpsThrewOnBadFile, 'bad file path must cause indexArtifact to throw');
202
+ assert.strictEqual(
203
+ fs.existsSync(lockPath),
204
+ false,
205
+ 'write lock must be released even when indexArtifact throws (enqueueWrite finally)'
206
+ );
207
+ }
208
+
209
+ // ----------------------------------------------------------------------------
210
+ // Test 4: testRollbackDoesNotLeakLock -- combined concern
211
+ // ----------------------------------------------------------------------------
212
+ //
213
+ // This test proves that BOTH the SQLite ROLLBACK AND the enqueueWrite
214
+ // finally fire when the inner transaction body throws. We go through the
215
+ // public graphOps.indexArtifact API so enqueueWrite is in the stack, and
216
+ // we monkey-patch lazygraph.indexArtifact so that the call opens its own
217
+ // BEGIN, issues one INSERT, then throws. The patched version includes its
218
+ // own ROLLBACK on catch -- same pattern as production indexArtifact --
219
+ // so we verify (a) the throw propagates out through enqueueWrite's fn
220
+ // callback, (b) enqueueWrite's finally still fires releaseLock, (c) the
221
+ // partial INSERT did not survive.
222
+
223
+ async function testRollbackDoesNotLeakLock(tmpRoom, dbPath, mindrian) {
224
+ const lockPath = path.join(mindrian, 'write.lock');
225
+ assert.strictEqual(fs.existsSync(lockPath), false, 'precondition: no lock before test');
226
+
227
+ // Capture pre-test Artifact count
228
+ const dbRead = new DatabaseSync(dbPath, { readOnly: true });
229
+ const countBefore = dbRead.prepare("SELECT COUNT(*) as n FROM nodes WHERE type = 'Artifact'").get().n;
230
+ dbRead.close();
231
+
232
+ // Save the real indexArtifact so we can restore after
233
+ const realIndex = lazygraph.indexArtifact;
234
+
235
+ // Replace with a version that simulates "threw inside the transaction"
236
+ // after one real INSERT fires. This mirrors the production flow: BEGIN,
237
+ // one INSERT, throw, ROLLBACK, throw-out. The caller (enqueueWrite) must
238
+ // still hit its finally.
239
+ lazygraph.indexArtifact = async function (conn, roomDir, _filePath) {
240
+ conn.prepare('BEGIN').run();
241
+ try {
242
+ conn.prepare(
243
+ "INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET properties = excluded.properties"
244
+ ).run('t4-partial-artifact', 'Artifact', '{"title":"will-not-survive"}');
245
+ throw new Error('injected mid-transaction failure for testRollbackDoesNotLeakLock');
246
+ // unreachable:
247
+ // eslint-disable-next-line no-unreachable
248
+ conn.prepare('COMMIT').run();
249
+ } catch (err) {
250
+ try { conn.prepare('ROLLBACK').run(); } catch (_) {}
251
+ throw err;
252
+ }
253
+ };
254
+
255
+ let threw = false;
256
+ try {
257
+ await graphOps.indexArtifact(tmpRoom, path.join(tmpRoom, 'market-analysis', 's-curve-mature-market.md'));
258
+ } catch (_) {
259
+ threw = true;
260
+ }
261
+
262
+ // Restore
263
+ lazygraph.indexArtifact = realIndex;
264
+
265
+ assert.ok(threw, 'injected mid-transaction failure must propagate out of graphOps.indexArtifact');
266
+
267
+ // Lock released in enqueueWrite finally, even though the inner fn threw.
268
+ assert.strictEqual(
269
+ fs.existsSync(lockPath),
270
+ false,
271
+ 'write lock MUST be released even when the inner transaction rolled back'
272
+ );
273
+
274
+ // Partial INSERT did not survive (ROLLBACK fired correctly).
275
+ const dbRead2 = new DatabaseSync(dbPath, { readOnly: true });
276
+ const countAfter = dbRead2.prepare("SELECT COUNT(*) as n FROM nodes WHERE type = 'Artifact'").get().n;
277
+ dbRead2.close();
278
+ assert.strictEqual(
279
+ countAfter,
280
+ countBefore,
281
+ `ROLLBACK FAILED in testRollbackDoesNotLeakLock: ${countBefore} -> ${countAfter}`
282
+ );
283
+
284
+ return { countBefore, countAfter };
285
+ }
286
+
287
+ // ----------------------------------------------------------------------------
288
+ // Test runner
289
+ // ----------------------------------------------------------------------------
290
+
291
+ async function run() {
292
+ const tmpRoom = fs.mkdtempSync(path.join(os.tmpdir(), 'indexart-'));
293
+ try {
294
+ fs.cpSync(FIXTURE, tmpRoom, { recursive: true });
295
+ const mindrian = path.join(tmpRoom, '.mindrian');
296
+ fs.mkdirSync(mindrian, { recursive: true });
297
+
298
+ const dbPath = path.join(mindrian, 'room.db');
299
+ const goodFile = path.join(tmpRoom, 'problem-definition', 'jtbd-underservice.md');
300
+
301
+ // Test 1: happy path
302
+ const nodeCount1 = await testHappyPath(tmpRoom, dbPath, goodFile, mindrian);
303
+
304
+ // Test 2: REAL mid-transaction rollback
305
+ const rollback = await testMidTransactionRollback(tmpRoom, dbPath);
306
+
307
+ // Test 3: lock release after commit (distinct concern)
308
+ await testLockReleaseAfterCommit(tmpRoom, mindrian);
309
+
310
+ // Test 4: combined -- rollback inside txn AND lock released
311
+ const t4 = await testRollbackDoesNotLeakLock(tmpRoom, dbPath, mindrian);
312
+
313
+ process.stdout.write(
314
+ `index-artifact-transaction: all tests passed` +
315
+ ` (happy-path nodes=${nodeCount1}, rollback-countBefore=${rollback.countBefore},` +
316
+ ` rollback-countAfter=${rollback.countAfter},` +
317
+ ` t4-lock-released-after-rollback=${t4.countBefore}==${t4.countAfter})\n`
318
+ );
319
+ process.exit(0);
320
+ } catch (e) {
321
+ process.stderr.write('FAIL: ' + e.message + '\n');
322
+ if (e.stack) process.stderr.write(e.stack + '\n');
323
+ process.exit(1);
324
+ } finally {
325
+ try {
326
+ fs.rmSync(tmpRoom, { recursive: true, force: true });
327
+ } catch (_) {
328
+ /* ignore */
329
+ }
330
+ }
331
+ }
332
+
333
+ run();
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ *
7
+ * Regression test for the rs_discoveries SQL view (graph-on-graph P0 cont., 2026-05-11).
8
+ * =====================================================================================
9
+ * The RS SQLite mirror (rs-sqlite-mirror.cjs) writes RSDiscovery records into
10
+ * the `nodes` table with the payload in a JSON `properties` bag. The RS NL/SQL
11
+ * readers (rs-nl-to-query.cjs SQL templates, scripts/rs-thesis-command.cjs)
12
+ * query `FROM rs_discoveries` -- a table that did not exist, so queryGraph
13
+ * swallowed the "no such table" error as []. lazygraph-ops.cjs initSchema now
14
+ * creates a `rs_discoveries` VIEW over `nodes WHERE type = 'RSDiscovery'` that
15
+ * json_extract's the payload keys into the columns the readers expect, renaming
16
+ * the writer's `room_id` -> reader's `room_slug` and `classification` -> `rs_type`.
17
+ *
18
+ * This test:
19
+ * - opens a throwaway room.db via openGraph
20
+ * - inserts two RSDiscovery nodes directly into `nodes` (one fintech, one biotech)
21
+ * - queries `SELECT * FROM rs_discoveries WHERE room_slug = ?` with a bound param
22
+ * -> asserts the WHERE filter works AND thesis/rs_type/breakthrough_score/room_slug
23
+ * come back populated
24
+ * - queries the rs-thesis-shaped read `SELECT id, thesis, rs_type, breakthrough_score,
25
+ * room_slug, created_at FROM rs_discoveries WHERE id = ? LIMIT 1`
26
+ *
27
+ * Self-contained: no live Brain, no live Aura. Pure CJS, node built-ins only
28
+ * (assert + os + fs + path).
29
+ */
30
+
31
+ const assert = require('node:assert/strict');
32
+ const os = require('os');
33
+ const fs = require('fs');
34
+ const path = require('path');
35
+
36
+ const lg = require('../core/lazygraph-ops.cjs');
37
+
38
+ let passed = 0;
39
+ let failed = 0;
40
+ const failures = [];
41
+
42
+ (async function main() {
43
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rsv-'));
44
+ let db;
45
+ try {
46
+ const opened = await lg.openGraph(tmpDir);
47
+ db = opened.db;
48
+ const conn = opened.conn;
49
+
50
+ // Insert two RSDiscovery nodes directly into `nodes` (mirrors what
51
+ // rs-sqlite-mirror.cjs writes: type='RSDiscovery', properties=JSON bag).
52
+ conn.prepare('INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?)').run(
53
+ 'd1', 'RSDiscovery', JSON.stringify({
54
+ thesis: 'fraud-graph mapping',
55
+ classification: 'structural_transfer',
56
+ breakthrough_score: 8,
57
+ room_id: 'fintech',
58
+ created_at: '2026-01-02T00:00:00Z',
59
+ bridge_concept: 'graph similarity',
60
+ dominant_dimension: 'magnitude',
61
+ diff: 0.2,
62
+ lsa: 0.7,
63
+ bert: 0.65,
64
+ domain: 'fintech',
65
+ })
66
+ );
67
+ conn.prepare('INSERT INTO nodes (id, type, properties) VALUES (?, ?, ?)').run(
68
+ 'd2', 'RSDiscovery', JSON.stringify({
69
+ thesis: 'CRISPR delivery analogue',
70
+ classification: 'semantic_implementation',
71
+ breakthrough_score: 6,
72
+ room_id: 'biotech',
73
+ created_at: '2026-01-01T00:00:00Z',
74
+ bridge_concept: 'vector packaging',
75
+ dominant_dimension: 'feasibility',
76
+ diff: 0.1,
77
+ lsa: 0.5,
78
+ bert: 0.55,
79
+ domain: 'biotech',
80
+ })
81
+ );
82
+
83
+ // (1) rs-nl-to-query-shaped read with a bound room_slug param.
84
+ const rows = await lg.queryGraph(
85
+ conn,
86
+ 'SELECT * FROM rs_discoveries WHERE room_slug = ? ORDER BY created_at DESC',
87
+ ['fintech']
88
+ );
89
+ assert.strictEqual(rows.length, 1, 'WHERE room_slug = ? must return exactly the fintech row');
90
+ assert.strictEqual(rows[0].thesis, 'fraud-graph mapping', 'thesis column populated from $.thesis');
91
+ assert.strictEqual(rows[0].rs_type, 'structural_transfer', 'rs_type column mapped from $.classification');
92
+ assert.strictEqual(Number(rows[0].breakthrough_score), 8, 'breakthrough_score column populated');
93
+ assert.strictEqual(rows[0].room_slug, 'fintech', 'room_slug column mapped from $.room_id');
94
+
95
+ // (2) rs-thesis-command-shaped read by id.
96
+ const t = await lg.queryGraph(
97
+ conn,
98
+ 'SELECT id, thesis, rs_type, breakthrough_score, room_slug, created_at FROM rs_discoveries WHERE id = ? LIMIT 1',
99
+ ['d1']
100
+ );
101
+ assert.strictEqual(t.length, 1, 'WHERE id = ? must return exactly one row');
102
+ assert.strictEqual(t[0].id, 'd1', 'id column passthrough');
103
+ assert.strictEqual(t[0].thesis, 'fraud-graph mapping', 'thesis column populated in id-shaped read');
104
+ assert.strictEqual(t[0].rs_type, 'structural_transfer', 'rs_type column populated in id-shaped read');
105
+
106
+ passed = 2;
107
+ } catch (err) {
108
+ failed = 1;
109
+ failures.push(err && err.message ? err.message : String(err));
110
+ } finally {
111
+ try { if (db) await lg.closeGraph(db); } catch (_e) { /* ignore */ }
112
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) { /* ignore */ }
113
+ }
114
+
115
+ if (failed > 0) {
116
+ process.stderr.write('lazygraph-rs-discoveries-view: FAIL\n');
117
+ for (const f of failures) process.stderr.write(' - ' + f + '\n');
118
+ process.exit(1);
119
+ }
120
+ process.stdout.write('lazygraph-rs-discoveries-view: all assertions passed (bound-param room_slug read + id-shaped read over the view)\n');
121
+ process.exit(0);
122
+ })();