@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,370 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ *
7
+ * Phase 88.1-16 -- query efficiency telemetry acceptance tests.
8
+ *
9
+ * Verifies the pure token-estimator + aggregation-math contract of the module
10
+ * at lib/core/token-estimator.cjs. This module is consumed by the PostToolUse
11
+ * hook at scripts/query-efficiency-telemetry.cjs (measures tokens_used per
12
+ * query) and the /mos:scout aggregator wrapper at
13
+ * scripts/scout-telemetry-aggregator.cjs (renders the median-ratio summary).
14
+ *
15
+ * Canon references:
16
+ * Part 6 Product-as-Venture -- the 57x efficiency claim is a VENTURE claim.
17
+ * Measure it or retune the copy. No third option. This module is the
18
+ * measurement arm.
19
+ * Part 8 Graph Boundary -- the estimator + aggregator are LOCAL-by-
20
+ * construction: pure token math + room-tree walk. No network surface.
21
+ * The hook persists scalar integer counts (tokens_used /
22
+ * tokens_naive_estimate) to ~/.mindrian/telemetry/query-efficiency.jsonl,
23
+ * never user artifact bytes.
24
+ *
25
+ * Test map (12 cases, one-to-one with the PLAN <behavior> block for Task 1):
26
+ * 1. estimateTokens("hello") -> 2 (5 chars / 4 = 1.25 -> ceil -> 2)
27
+ * 2. estimateTokens("") -> 0
28
+ * 3. estimateTokens(null) -> 0 (graceful on null/undefined/non-string)
29
+ * 4. estimateRoomTokens on valid room returns positive integer
30
+ * 5. estimateRoomTokens cache: second call returns same value without
31
+ * re-walking the filesystem (verified by assertion on a sentinel file
32
+ * written BETWEEN the two calls -- cached value must ignore it)
33
+ * 6. estimateRoomTokens on invalid room returns null (graceful)
34
+ * 7. clearCache() resets the session cache
35
+ * 8. estimateRoomTokens skips non-.md files (only .md counted)
36
+ * 9. ratio computation sanity: 50000 / 1000 -> 50.0
37
+ * 10. event-shape validator: ensures emitted JSONL has exactly the
38
+ * 8 required fields from the <interfaces> block
39
+ * 11. classifyRatio: 5.2 -> 'warn'; 42.0 -> 'normal'; 10.0 boundary -> 'normal'
40
+ * 12. aggregateEvents(10 events with known ratios) -> median/mean match
41
+ * hand-computed; top5 ranked descending by ratio; count = 10
42
+ *
43
+ * Registered in lib/memory/run-feynman-tests.cjs.
44
+ */
45
+
46
+ const assert = require('node:assert/strict');
47
+ const fs = require('node:fs');
48
+ const path = require('node:path');
49
+ const os = require('node:os');
50
+
51
+ const REPO = path.resolve(__dirname, '..', '..');
52
+ const ESTIMATOR_PATH = path.join(REPO, 'lib/core/token-estimator.cjs');
53
+
54
+ // Defensive reload so repeated invocations reload fresh.
55
+ try { delete require.cache[require.resolve(ESTIMATOR_PATH)]; } catch (_) {}
56
+ const estimator = require(ESTIMATOR_PATH);
57
+
58
+ assert.equal(typeof estimator.estimateTokens, 'function',
59
+ 'module must export estimateTokens()');
60
+ assert.equal(typeof estimator.estimateRoomTokens, 'function',
61
+ 'module must export estimateRoomTokens()');
62
+ assert.equal(typeof estimator.clearCache, 'function',
63
+ 'module must export clearCache()');
64
+ assert.equal(typeof estimator.aggregateEvents, 'function',
65
+ 'module must export aggregateEvents()');
66
+ assert.equal(typeof estimator.classifyRatio, 'function',
67
+ 'module must export classifyRatio()');
68
+ assert.equal(typeof estimator.validateEventShape, 'function',
69
+ 'module must export validateEventShape()');
70
+
71
+ // ---------- Fixture scaffolding ----------
72
+
73
+ function mkTmpDir(prefix) {
74
+ const base = path.join(os.tmpdir(), 'mos-88-1-16-' + prefix + '-' + process.pid + '-' + Date.now().toString(36));
75
+ fs.mkdirSync(base, { recursive: true });
76
+ return base;
77
+ }
78
+
79
+ function rmRf(p) {
80
+ try { fs.rmSync(p, { recursive: true, force: true }); } catch (_) {}
81
+ }
82
+
83
+ // ---------- Test 1: estimateTokens small string ----------
84
+
85
+ (function test1SmallString() {
86
+ const result = estimator.estimateTokens('hello');
87
+ assert.equal(result, 2,
88
+ 'estimateTokens("hello") must ceil(5/4) = 2, got ' + result);
89
+ console.log('PASS test 1: estimateTokens("hello") -> 2');
90
+ })();
91
+
92
+ // ---------- Test 2: estimateTokens empty string ----------
93
+
94
+ (function test2EmptyString() {
95
+ const result = estimator.estimateTokens('');
96
+ assert.equal(result, 0,
97
+ 'estimateTokens("") must return 0, got ' + result);
98
+ console.log('PASS test 2: estimateTokens("") -> 0');
99
+ })();
100
+
101
+ // ---------- Test 3: estimateTokens graceful on null / non-string ----------
102
+
103
+ (function test3GracefulNull() {
104
+ assert.equal(estimator.estimateTokens(null), 0,
105
+ 'estimateTokens(null) must return 0');
106
+ assert.equal(estimator.estimateTokens(undefined), 0,
107
+ 'estimateTokens(undefined) must return 0');
108
+ assert.equal(estimator.estimateTokens(123), 0,
109
+ 'estimateTokens(non-string) must return 0');
110
+ console.log('PASS test 3: estimateTokens graceful on null/undefined/non-string');
111
+ })();
112
+
113
+ // ---------- Test 4: estimateRoomTokens returns positive integer ----------
114
+
115
+ (function test4ValidRoom() {
116
+ estimator.clearCache();
117
+ const tmp = mkTmpDir('room-valid');
118
+ try {
119
+ fs.writeFileSync(path.join(tmp, 'ROOM.md'), '# Room\n'.repeat(100));
120
+ fs.writeFileSync(path.join(tmp, 'notes.md'), 'x'.repeat(4000));
121
+ const result = estimator.estimateRoomTokens(tmp);
122
+ assert.equal(typeof result, 'number',
123
+ 'estimateRoomTokens must return a number on valid room');
124
+ assert.ok(Number.isFinite(result) && Number.isInteger(result),
125
+ 'estimateRoomTokens must return finite integer, got ' + result);
126
+ assert.ok(result > 0,
127
+ 'estimateRoomTokens on non-empty room must be > 0, got ' + result);
128
+ // Sanity: ~ (700 + 4000) / 4 = ~1175 tokens. Allow envelope for overhead.
129
+ assert.ok(result >= 1000 && result <= 1500,
130
+ 'estimateRoomTokens must approximate chars/4; got ' + result);
131
+ console.log('PASS test 4: estimateRoomTokens valid room -> ' + result);
132
+ } finally {
133
+ rmRf(tmp);
134
+ estimator.clearCache();
135
+ }
136
+ })();
137
+
138
+ // ---------- Test 5: estimateRoomTokens caches per session ----------
139
+
140
+ (function test5Cache() {
141
+ estimator.clearCache();
142
+ const tmp = mkTmpDir('room-cache');
143
+ try {
144
+ fs.writeFileSync(path.join(tmp, 'a.md'), 'x'.repeat(2000));
145
+ const first = estimator.estimateRoomTokens(tmp);
146
+ // Write a LARGE new artifact after first call. If the second call re-
147
+ // walks the fs, it will report a much larger number. If it uses the
148
+ // cache, it must return the same value as `first`.
149
+ fs.writeFileSync(path.join(tmp, 'b.md'), 'y'.repeat(100000));
150
+ const second = estimator.estimateRoomTokens(tmp);
151
+ assert.equal(second, first,
152
+ 'second estimateRoomTokens call must return cached value; ' +
153
+ 'got first=' + first + ' second=' + second);
154
+ // Clear cache and confirm it now picks up the new artifact.
155
+ estimator.clearCache();
156
+ const third = estimator.estimateRoomTokens(tmp);
157
+ assert.ok(third > first,
158
+ 'after clearCache, estimate must reflect new artifact: ' +
159
+ 'first=' + first + ' third=' + third);
160
+ console.log('PASS test 5: estimateRoomTokens cache hit (first=' + first +
161
+ ' second=' + second + ' after-clear=' + third + ')');
162
+ } finally {
163
+ rmRf(tmp);
164
+ estimator.clearCache();
165
+ }
166
+ })();
167
+
168
+ // ---------- Test 6: estimateRoomTokens invalid room -> null ----------
169
+
170
+ (function test6InvalidRoom() {
171
+ estimator.clearCache();
172
+ const nonexistent = path.join(os.tmpdir(), 'mos-88-1-16-DOES-NOT-EXIST-' + Date.now());
173
+ const result = estimator.estimateRoomTokens(nonexistent);
174
+ assert.equal(result, null,
175
+ 'estimateRoomTokens on nonexistent path must return null, got ' + result);
176
+ assert.equal(estimator.estimateRoomTokens(null), null,
177
+ 'estimateRoomTokens(null) must return null');
178
+ assert.equal(estimator.estimateRoomTokens(''), null,
179
+ 'estimateRoomTokens("") must return null');
180
+ console.log('PASS test 6: estimateRoomTokens invalid room -> null');
181
+ })();
182
+
183
+ // ---------- Test 7: clearCache resets ----------
184
+
185
+ (function test7ClearCache() {
186
+ estimator.clearCache();
187
+ const tmp = mkTmpDir('room-clear');
188
+ try {
189
+ fs.writeFileSync(path.join(tmp, 'a.md'), 'x'.repeat(2000));
190
+ const first = estimator.estimateRoomTokens(tmp);
191
+ // Delete the room dir, clear cache, re-query. Without clearCache the
192
+ // stale value would still be returned; after clearCache, null.
193
+ rmRf(tmp);
194
+ estimator.clearCache();
195
+ const result = estimator.estimateRoomTokens(tmp);
196
+ assert.equal(result, null,
197
+ 'after clearCache + rmdir, estimateRoomTokens must return null; got ' + result);
198
+ assert.ok(first > 0, 'sanity: first call was > 0 (' + first + ')');
199
+ console.log('PASS test 7: clearCache resets session cache');
200
+ } finally {
201
+ rmRf(tmp);
202
+ estimator.clearCache();
203
+ }
204
+ })();
205
+
206
+ // ---------- Test 8: estimateRoomTokens skips non-.md files ----------
207
+
208
+ (function test8SkipsBinary() {
209
+ estimator.clearCache();
210
+ const tmp = mkTmpDir('room-skip');
211
+ try {
212
+ // Only the .md file should count. Binary .bin + .png + non-.md .txt
213
+ // must be ignored by the walker.
214
+ fs.writeFileSync(path.join(tmp, 'a.md'), 'x'.repeat(4000));
215
+ fs.writeFileSync(path.join(tmp, 'ignored.bin'), Buffer.alloc(100000));
216
+ fs.writeFileSync(path.join(tmp, 'ignored.png'), Buffer.alloc(50000));
217
+ fs.writeFileSync(path.join(tmp, 'ignored.txt'), 'z'.repeat(100000));
218
+ const result = estimator.estimateRoomTokens(tmp);
219
+ // Expect only the .md to contribute: 4000 chars / 4 = 1000 tokens.
220
+ assert.ok(result >= 900 && result <= 1100,
221
+ 'estimateRoomTokens must count only .md; got ' + result + ' (expected ~1000)');
222
+ console.log('PASS test 8: estimateRoomTokens skips non-.md files (got ' + result + ')');
223
+ } finally {
224
+ rmRf(tmp);
225
+ estimator.clearCache();
226
+ }
227
+ })();
228
+
229
+ // ---------- Test 9: ratio computation sanity ----------
230
+
231
+ (function test9RatioComputation() {
232
+ const naive = 50000;
233
+ const used = 1000;
234
+ const ratio = naive / used;
235
+ assert.equal(ratio, 50,
236
+ 'ratio 50000 / 1000 must equal 50');
237
+ // The hook will compute this division directly. Sanity only.
238
+ console.log('PASS test 9: ratio computation (50000 / 1000 = 50)');
239
+ })();
240
+
241
+ // ---------- Test 10: event shape validator ----------
242
+
243
+ (function test10EventShape() {
244
+ const good = {
245
+ event: 'query.served',
246
+ ts: '2026-04-23T00:00:00Z',
247
+ command: '/mos:whitespace',
248
+ tool: 'Read',
249
+ tokens_used: 100,
250
+ tokens_naive_estimate: 5000,
251
+ ratio: 50.0,
252
+ room_slug: 'example-room',
253
+ };
254
+ const gResult = estimator.validateEventShape(good);
255
+ assert.equal(gResult.valid, true,
256
+ 'fully-specified event must validate: ' + JSON.stringify(gResult));
257
+ assert.deepEqual(gResult.missing, [],
258
+ 'good event must have no missing fields');
259
+
260
+ // Missing one field -> invalid with that field listed in `missing`.
261
+ const badOne = Object.assign({}, good);
262
+ delete badOne.ratio;
263
+ const bResult = estimator.validateEventShape(badOne);
264
+ assert.equal(bResult.valid, false,
265
+ 'event missing ratio must fail validation');
266
+ assert.ok(bResult.missing.indexOf('ratio') >= 0,
267
+ 'missing array must include "ratio", got ' + JSON.stringify(bResult.missing));
268
+
269
+ // Empty object -> every field missing.
270
+ const empty = estimator.validateEventShape({});
271
+ assert.equal(empty.valid, false, '{} must fail validation');
272
+ assert.equal(empty.missing.length, 8,
273
+ 'empty object must report all 8 fields missing, got ' + empty.missing.length);
274
+
275
+ // Non-object -> invalid.
276
+ const nullRes = estimator.validateEventShape(null);
277
+ assert.equal(nullRes.valid, false, 'null must fail validation');
278
+
279
+ console.log('PASS test 10: event shape validator (8 required fields)');
280
+ })();
281
+
282
+ // ---------- Test 11: classifyRatio below/at threshold ----------
283
+
284
+ (function test11ClassifyRatio() {
285
+ assert.equal(estimator.classifyRatio(5.2), 'warn',
286
+ 'ratio 5.2 must classify as warn (< 10x)');
287
+ assert.equal(estimator.classifyRatio(42.0), 'normal',
288
+ 'ratio 42.0 must classify as normal (>= 10x)');
289
+ assert.equal(estimator.classifyRatio(10.0), 'normal',
290
+ 'ratio 10.0 at boundary must classify as normal (>= 10x)');
291
+ assert.equal(estimator.classifyRatio(9.99), 'warn',
292
+ 'ratio 9.99 just below boundary must classify as warn');
293
+ assert.equal(estimator.classifyRatio(0), 'warn',
294
+ 'ratio 0 must classify as warn');
295
+ // Non-numeric -> warn (defensive: ratio was never computed correctly).
296
+ assert.equal(estimator.classifyRatio(null), 'warn',
297
+ 'null ratio must classify as warn (defensive)');
298
+ assert.equal(estimator.classifyRatio(NaN), 'warn',
299
+ 'NaN ratio must classify as warn (defensive)');
300
+ console.log('PASS test 11: classifyRatio thresholds (10x)');
301
+ })();
302
+
303
+ // ---------- Test 12: aggregateEvents median + mean + top5 ----------
304
+
305
+ (function test12Aggregate() {
306
+ const events = [
307
+ { command: '/mos:whitespace', ratio: 60, tokens_used: 100, tokens_naive_estimate: 6000, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
308
+ { command: '/mos:whitespace', ratio: 55, tokens_used: 100, tokens_naive_estimate: 5500, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
309
+ { command: '/mos:status', ratio: 50, tokens_used: 100, tokens_naive_estimate: 5000, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
310
+ { command: '/mos:find-bottlenecks', ratio: 45, tokens_used: 100, tokens_naive_estimate: 4500, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
311
+ { command: '/mos:find-bottlenecks', ratio: 48, tokens_used: 100, tokens_naive_estimate: 4800, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
312
+ { command: '/mos:scout', ratio: 40, tokens_used: 100, tokens_naive_estimate: 4000, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
313
+ { command: '/mos:whitespace', ratio: 70, tokens_used: 100, tokens_naive_estimate: 7000, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
314
+ { command: '/mos:grade', ratio: 35, tokens_used: 100, tokens_naive_estimate: 3500, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
315
+ { command: '/mos:reason', ratio: 42, tokens_used: 100, tokens_naive_estimate: 4200, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
316
+ { command: '/mos:persona', ratio: 38, tokens_used: 100, tokens_naive_estimate: 3800, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
317
+ ];
318
+ const agg = estimator.aggregateEvents(events);
319
+
320
+ // count
321
+ assert.equal(agg.count, 10, 'count must equal events.length, got ' + agg.count);
322
+
323
+ // sorted ratios: [35, 38, 40, 42, 45, 48, 50, 55, 60, 70]
324
+ // median (even) = (45 + 48) / 2 = 46.5
325
+ assert.equal(agg.median, 46.5,
326
+ 'median must be 46.5 (even-length average), got ' + agg.median);
327
+
328
+ // mean = (60+55+50+45+48+40+70+35+42+38) / 10 = 483 / 10 = 48.3
329
+ assert.equal(agg.mean, 48.3,
330
+ 'mean must be 48.3, got ' + agg.mean);
331
+
332
+ // top5 by ratio: whitespace has 3 entries -> use BEST ratio per command (by convention)
333
+ // OR aggregate per command with averages. Either interpretation: whitespace tops.
334
+ // PLAN says "top-5 commands by ratio" -- commands with their best/median ratio.
335
+ // Our contract: per-command aggregate (max ratio), sort desc, slice 5.
336
+ assert.ok(Array.isArray(agg.top5), 'top5 must be array');
337
+ assert.equal(agg.top5.length, 5, 'top5 must have exactly 5 entries when >= 5 commands');
338
+
339
+ // Top entry must be the highest-ratio command (whitespace best: 70).
340
+ assert.equal(agg.top5[0].command, '/mos:whitespace',
341
+ 'top5[0] must be /mos:whitespace (max ratio 70), got ' + agg.top5[0].command);
342
+ assert.equal(agg.top5[0].ratio, 70,
343
+ 'top5[0].ratio must be 70, got ' + agg.top5[0].ratio);
344
+
345
+ // Ratios must be strictly non-increasing.
346
+ for (let i = 1; i < agg.top5.length; i++) {
347
+ assert.ok(agg.top5[i].ratio <= agg.top5[i - 1].ratio,
348
+ 'top5 must be sorted desc by ratio at index ' + i);
349
+ }
350
+
351
+ // Empty events -> zero count, null median, null mean, [] top5.
352
+ const emptyAgg = estimator.aggregateEvents([]);
353
+ assert.equal(emptyAgg.count, 0, 'empty events -> count 0');
354
+ assert.equal(emptyAgg.median, null, 'empty events -> median null');
355
+ assert.equal(emptyAgg.mean, null, 'empty events -> mean null');
356
+ assert.deepEqual(emptyAgg.top5, [], 'empty events -> top5 []');
357
+
358
+ // Odd-length median check (sorted: 10, 20, 30 -> median 20).
359
+ const oddAgg = estimator.aggregateEvents([
360
+ { command: '/a', ratio: 10, tokens_used: 1, tokens_naive_estimate: 10, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
361
+ { command: '/b', ratio: 30, tokens_used: 1, tokens_naive_estimate: 30, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
362
+ { command: '/c', ratio: 20, tokens_used: 1, tokens_naive_estimate: 20, tool: 'Read', ts: 't', event: 'query.served', room_slug: 'r' },
363
+ ]);
364
+ assert.equal(oddAgg.median, 20, 'odd-length median must pick middle value');
365
+
366
+ console.log('PASS test 12: aggregateEvents (median=' + agg.median +
367
+ ', mean=' + agg.mean + ', top5[0]=' + agg.top5[0].command + '@' + agg.top5[0].ratio + ')');
368
+ })();
369
+
370
+ console.log('\nquery-efficiency-telemetry: 12/12 tests passed');