@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,420 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
6
+ * Phase 89.2 Plan 01 -- Egress primitives adversarial fixture suite.
7
+ *
8
+ * 8 scenarios covering the three Wave-1 foundation modules:
9
+ * rs-egress-violations.cjs
10
+ * rs-egress-prompts.cjs
11
+ * rs-egress-telemetry.cjs
12
+ *
13
+ * Test 1 (violation throws): ExternalEgressViolation shape + meta
14
+ * Test 2 (FORBIDDEN_PATTERNS parity gate): byte-for-byte from cross-room-aggregator
15
+ * Test 3 (auditQueryString happy path): clean query passes through
16
+ * Test 4 (auditQueryString forbidden hits): all 6 FORBIDDEN_PATTERNS throw
17
+ * Test 5 (auditQueryObject happy path): clean object passes through
18
+ * Test 6 (telemetry append+read): hash-not-literal proof
19
+ * Test 7 (budget across 24h window): rolling window math
20
+ * Test 8 (graceful fs-error degradation): writeFileSync EACCES + readFileSync ENOENT
21
+ *
22
+ * Suite-end audits:
23
+ * A1: every captured request payload + every persisted telemetry record
24
+ * JSON.stringify scanned against FORBIDDEN_PATTERNS; assert ZERO hits
25
+ * A2: glob TELEMETRY_DIR for tmpfile orphans; assert ZERO after suite
26
+ *
27
+ * Pure CJS, zero npm deps, node built-ins only (assert, fs, os, path).
28
+ */
29
+
30
+ const assert = require('node:assert/strict');
31
+ const fs = require('node:fs');
32
+ const os = require('node:os');
33
+ const path = require('node:path');
34
+ const crypto = require('node:crypto');
35
+
36
+ // ---------- Suite bookkeeping ----------
37
+
38
+ let passed = 0;
39
+ let failed = 0;
40
+ const failures = [];
41
+
42
+ // Captured outputs from happy-path tests (audited at A1 sweep).
43
+ const SCENARIO_RESULTS = [];
44
+
45
+ // Telemetry path is determined by the module under test; we relocate to a
46
+ // scoped tmpdir per scenario via env override + module re-require so the
47
+ // real ~/.mindrian/telemetry path is never touched.
48
+ let testHomeDir = null;
49
+ let originalHome = null;
50
+
51
+ // ---------- Tmpdir setup + cleanup ----------
52
+
53
+ const ALL_TMP_ROOTS = [];
54
+
55
+ process.on('exit', function () {
56
+ // Restore HOME first so any stray require in cleanup hits original paths.
57
+ if (originalHome !== null) {
58
+ process.env.HOME = originalHome;
59
+ }
60
+ for (const d of ALL_TMP_ROOTS) {
61
+ try { fs.rmSync(d, { recursive: true, force: true }); } catch (_e) { /* best effort */ }
62
+ }
63
+ });
64
+
65
+ function setupScopedHome() {
66
+ if (originalHome === null) {
67
+ originalHome = process.env.HOME;
68
+ }
69
+ testHomeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rsegress-home-'));
70
+ ALL_TMP_ROOTS.push(testHomeDir);
71
+ process.env.HOME = testHomeDir;
72
+ // Force require.cache reset so TELEMETRY_DIR is recomputed against new HOME.
73
+ resetRequireCache();
74
+ }
75
+
76
+ function resetRequireCache() {
77
+ const targets = [
78
+ '../core/rs-egress-violations.cjs',
79
+ '../core/rs-egress-prompts.cjs',
80
+ '../core/rs-egress-telemetry.cjs',
81
+ '../core/cross-room-aggregator.cjs',
82
+ ];
83
+ for (const t of targets) {
84
+ try {
85
+ const p = require.resolve(t);
86
+ delete require.cache[p];
87
+ } catch (_e) { /* best effort */ }
88
+ }
89
+ }
90
+
91
+ // ---------- Scenario runner ----------
92
+
93
+ function runScenario(name, fn) {
94
+ const start = Date.now();
95
+ try {
96
+ fn();
97
+ passed += 1;
98
+ process.stdout.write(' ok ' + name + ' (' + (Date.now() - start) + 'ms)\n');
99
+ } catch (err) {
100
+ failed += 1;
101
+ failures.push({ name: name, err: err });
102
+ process.stderr.write(' FAIL ' + name + '\n');
103
+ process.stderr.write(' ' + (err && err.stack ? err.stack : err) + '\n');
104
+ } finally {
105
+ resetRequireCache();
106
+ }
107
+ }
108
+
109
+ // ---------- A1 + A2 sweep helpers ----------
110
+
111
+ function getForbiddenPatternsFromAggregator() {
112
+ const aggregator = require('../core/cross-room-aggregator.cjs');
113
+ return aggregator.FORBIDDEN_PATTERNS;
114
+ }
115
+
116
+ function scanAgainstForbidden(stringified) {
117
+ const patterns = getForbiddenPatternsFromAggregator();
118
+ for (const re of patterns) {
119
+ if (re.test(stringified)) {
120
+ return { hit: true, pattern: re.source };
121
+ }
122
+ }
123
+ return { hit: false };
124
+ }
125
+
126
+ // ---------- Scenarios ----------
127
+
128
+ console.log('=== 89.2-01 egress-primitives suite: starting ===');
129
+
130
+ // Initialize scoped HOME so telemetry tests use a sandbox path.
131
+ setupScopedHome();
132
+
133
+ // ---------- Test 1: violation throws ----------
134
+
135
+ runScenario('Test 1: ExternalEgressViolation construction shape', function () {
136
+ const { ExternalEgressViolation } = require('../core/rs-egress-violations.cjs');
137
+ let threw = null;
138
+ try {
139
+ throw new ExternalEgressViolation('msg', { surface: 'academic' });
140
+ } catch (e) {
141
+ threw = e;
142
+ }
143
+ assert.ok(threw, 'expected throw');
144
+ assert.equal(threw.name, 'ExternalEgressViolation', 'name field');
145
+ assert.equal(threw.message, 'msg', 'message field');
146
+ assert.deepEqual(threw.meta, { surface: 'academic' }, 'meta field');
147
+ assert.ok(threw instanceof Error, 'instanceof Error');
148
+
149
+ // Default meta when omitted should be {} (no undefined leak).
150
+ const e2 = new ExternalEgressViolation('m2');
151
+ assert.deepEqual(e2.meta, {}, 'default meta is empty object');
152
+ });
153
+
154
+ // ---------- Test 2: FORBIDDEN_PATTERNS parity gate ----------
155
+
156
+ runScenario('Test 2: FORBIDDEN_PATTERNS byte-for-byte parity with cross-room-aggregator', function () {
157
+ const promptsModule = require('../core/rs-egress-prompts.cjs');
158
+ const aggregator = require('../core/cross-room-aggregator.cjs');
159
+ const ours = promptsModule.FORBIDDEN_PATTERNS;
160
+ const truth = aggregator.FORBIDDEN_PATTERNS;
161
+ assert.ok(Array.isArray(ours), 'ours is array');
162
+ assert.ok(Array.isArray(truth), 'truth is array');
163
+ assert.equal(ours.length, truth.length, 'lengths match');
164
+ assert.ok(ours.length >= 6, 'expected >= 6 patterns; got ' + ours.length);
165
+ for (let i = 0; i < truth.length; i++) {
166
+ assert.equal(ours[i].source, truth[i].source, 'pattern source mismatch at index ' + i);
167
+ assert.equal(ours[i].flags, truth[i].flags, 'pattern flags mismatch at index ' + i);
168
+ }
169
+ });
170
+
171
+ // ---------- Test 3: auditQueryString happy path ----------
172
+
173
+ runScenario('Test 3: auditQueryString clean input passes through', function () {
174
+ const { auditQueryString } = require('../core/rs-egress-prompts.cjs');
175
+ const inputs = [
176
+ 'cancer immunotherapy biomarkers',
177
+ 'graphene heat conductivity',
178
+ 'CAR-T cell therapy clinical trials 2024',
179
+ 'reverse salient theory hughes electrification',
180
+ ];
181
+ for (const s of inputs) {
182
+ const out = auditQueryString(s, 'academic');
183
+ assert.equal(out, s, 'expected pass-through for clean input: ' + s);
184
+ SCENARIO_RESULTS.push({ test: 'T3', surface: 'academic', payload: out });
185
+ }
186
+ });
187
+
188
+ // ---------- Test 4: auditQueryString forbidden hits (all 6 FORBIDDEN_PATTERNS) ----------
189
+
190
+ runScenario('Test 4: auditQueryString throws on every FORBIDDEN_PATTERNS hit', function () {
191
+ const { auditQueryString } = require('../core/rs-egress-prompts.cjs');
192
+ const adversarial = [
193
+ { name: 'email', input: 'jonathan@mindrian.com cancer biomarkers' },
194
+ { name: 'currency', input: 'venture raised $5M last quarter' },
195
+ { name: 'quoted-person', input: 'Lawrence said the deal closes' },
196
+ { name: 'meeting', input: 'meeting with the FDA next Tuesday' },
197
+ { name: 'ssn', input: 'patient id 123-45-6789 protocol' },
198
+ { name: 'phone', input: 'contact +1 (415) 555-1234 today' },
199
+ ];
200
+ for (const adv of adversarial) {
201
+ let threw = null;
202
+ try {
203
+ auditQueryString(adv.input, 'academic');
204
+ } catch (e) {
205
+ threw = e;
206
+ }
207
+ assert.ok(threw, 'expected throw for adversarial case: ' + adv.name);
208
+ assert.equal(threw.name, 'ExternalEgressViolation',
209
+ 'expected ExternalEgressViolation for case ' + adv.name + '; got ' + threw.name);
210
+ assert.equal(threw.meta.surface, 'academic',
211
+ 'meta.surface for case ' + adv.name + ': ' + threw.meta.surface);
212
+ assert.ok(typeof threw.meta.matched_pattern === 'string' && threw.meta.matched_pattern.length > 0,
213
+ 'meta.matched_pattern present for case ' + adv.name);
214
+ }
215
+
216
+ // TypeError on non-string input.
217
+ let typeThrew = null;
218
+ try { auditQueryString(123, 'academic'); } catch (e) { typeThrew = e; }
219
+ assert.ok(typeThrew && typeThrew.name === 'TypeError', 'TypeError on non-string input');
220
+ });
221
+
222
+ // ---------- Test 5: auditQueryObject happy path + adversarial ----------
223
+
224
+ runScenario('Test 5: auditQueryObject clean + adversarial', function () {
225
+ const { auditQueryObject } = require('../core/rs-egress-prompts.cjs');
226
+ const clean = { q: 'cancer biomarkers', filter: 'year:2024' };
227
+ const out = auditQueryObject(clean, 'patents');
228
+ assert.deepEqual(out, clean, 'clean object pass-through');
229
+ SCENARIO_RESULTS.push({ test: 'T5', surface: 'patents', payload: out });
230
+
231
+ // Adversarial: email tucked inside a nested field.
232
+ let threw = null;
233
+ try {
234
+ auditQueryObject({ q: 'cancer', meta: { contact: 'lawrence@mindrian.com' } }, 'patents');
235
+ } catch (e) {
236
+ threw = e;
237
+ }
238
+ assert.ok(threw, 'expected throw on adversarial nested object');
239
+ assert.equal(threw.name, 'ExternalEgressViolation', 'class name');
240
+ assert.equal(threw.meta.surface, 'patents', 'surface meta');
241
+ });
242
+
243
+ // ---------- Test 6: telemetry append+read (hash-not-literal proof) ----------
244
+
245
+ runScenario('Test 6: recordTelemetry hashes query_text + persists structured record', function () {
246
+ const telemetry = require('../core/rs-egress-telemetry.cjs');
247
+ const result = telemetry.recordTelemetry({
248
+ source: 'openalex',
249
+ query_text: 'cancer biomarkers',
250
+ status: 'ok',
251
+ http_status: 200,
252
+ rate_limit_remaining: 99,
253
+ });
254
+ assert.equal(result.success, true, 'telemetry record success');
255
+
256
+ // Read back from disk and audit shape.
257
+ const filePath = telemetry.TELEMETRY_FILE;
258
+ assert.ok(fs.existsSync(filePath), 'telemetry file exists at ' + filePath);
259
+ const payload = JSON.parse(fs.readFileSync(filePath, 'utf8'));
260
+ assert.equal(payload.schema_version, '1.0', 'schema_version field');
261
+ assert.ok(Array.isArray(payload.entries), 'entries is array');
262
+ assert.equal(payload.entries.length, 1, 'one entry');
263
+ const entry = payload.entries[0];
264
+ assert.equal(entry.source, 'openalex', 'source field');
265
+ assert.ok(/^[a-f0-9]{16}$/.test(entry.query_text_hash),
266
+ 'query_text_hash matches 16-char hex; got ' + entry.query_text_hash);
267
+ assert.equal(entry.query_text, undefined, 'literal query_text NEVER persisted');
268
+ assert.equal(entry.status, 'ok', 'status field');
269
+ assert.equal(entry.http_status, 200, 'http_status field');
270
+ assert.equal(entry.rate_limit_remaining, 99, 'rate_limit_remaining field');
271
+ assert.ok(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(entry.fetched_at),
272
+ 'fetched_at ISO-8601');
273
+ // Capture the persisted record for A1 sweep.
274
+ SCENARIO_RESULTS.push({ test: 'T6', surface: 'telemetry', payload: payload });
275
+
276
+ // Verify hash matches expected sha256 of query text (independent oracle).
277
+ const expectedHash = crypto.createHash('sha256').update('cancer biomarkers').digest('hex').slice(0, 16);
278
+ assert.equal(entry.query_text_hash, expectedHash, 'hash matches independent sha256 oracle');
279
+ });
280
+
281
+ // ---------- Test 7: budget computation across 24h window ----------
282
+
283
+ runScenario('Test 7: computeRemainingBudget honors rolling 24h window', function () {
284
+ // Reset HOME for isolation: clean telemetry file for this scenario.
285
+ setupScopedHome();
286
+ const telemetry = require('../core/rs-egress-telemetry.cjs');
287
+
288
+ // Seed: 50 entries within last 24h + 60 entries older than 24h, all source=arxiv.
289
+ const now = Date.now();
290
+ const entries = [];
291
+ for (let i = 0; i < 50; i++) {
292
+ entries.push({
293
+ source: 'arxiv',
294
+ query_text_hash: 'aaaaaaaaaaaaaaaa',
295
+ status: 'ok',
296
+ fetched_at: new Date(now - (i * 60 * 1000)).toISOString(), // last 50 minutes
297
+ });
298
+ }
299
+ for (let i = 0; i < 60; i++) {
300
+ entries.push({
301
+ source: 'arxiv',
302
+ query_text_hash: 'bbbbbbbbbbbbbbbb',
303
+ status: 'ok',
304
+ fetched_at: new Date(now - (25 * 60 * 60 * 1000) - (i * 60 * 1000)).toISOString(), // > 24h ago
305
+ });
306
+ }
307
+ const payload = { schema_version: '1.0', entries: entries };
308
+ fs.mkdirSync(path.dirname(telemetry.TELEMETRY_FILE), { recursive: true });
309
+ fs.writeFileSync(telemetry.TELEMETRY_FILE, JSON.stringify(payload, null, 2));
310
+
311
+ // 100 default budget -> 50 remaining.
312
+ assert.equal(telemetry.computeRemainingBudget('arxiv', 100), 50,
313
+ 'budget 100 with 50 in-window -> 50 remaining');
314
+ // 30 budget with 50 in-window -> 0 (clamped non-negative).
315
+ assert.equal(telemetry.computeRemainingBudget('arxiv', 30), 0,
316
+ 'budget 30 with 50 in-window -> 0 (clamped)');
317
+ // Other source unaffected.
318
+ assert.equal(telemetry.computeRemainingBudget('openalex', 100), 100,
319
+ 'openalex unaffected by arxiv entries');
320
+
321
+ // Capture for A1 sweep.
322
+ SCENARIO_RESULTS.push({ test: 'T7', surface: 'telemetry', payload: payload });
323
+ });
324
+
325
+ // ---------- Test 8: graceful fs-error degradation ----------
326
+
327
+ runScenario('Test 8: recordTelemetry graceful on EACCES; computeRemainingBudget graceful on ENOENT', function () {
328
+ // Fresh HOME so no telemetry exists.
329
+ setupScopedHome();
330
+ const telemetry = require('../core/rs-egress-telemetry.cjs');
331
+
332
+ // Cold-start computeRemainingBudget -> returns full default (no telemetry file).
333
+ const cold = telemetry.computeRemainingBudget('openalex', 100);
334
+ assert.equal(cold, 100, 'cold start returns full default budget');
335
+
336
+ // Mock writeFileSync to throw EACCES; verify recordTelemetry returns
337
+ // {success:false, error:'fs_error'} without throwing.
338
+ const realWrite = fs.writeFileSync;
339
+ let mockedThrows = 0;
340
+ fs.writeFileSync = function (file, data, opts) {
341
+ if (typeof file === 'string' && file.indexOf('external-papers.json') !== -1) {
342
+ mockedThrows += 1;
343
+ const err = new Error('EACCES: permission denied');
344
+ err.code = 'EACCES';
345
+ throw err;
346
+ }
347
+ return realWrite(file, data, opts);
348
+ };
349
+ try {
350
+ const result = telemetry.recordTelemetry({
351
+ source: 'arxiv',
352
+ query_text: 'graceful test',
353
+ status: 'ok',
354
+ });
355
+ assert.equal(result.success, false, 'success false on fs error');
356
+ assert.equal(result.error, 'fs_error', 'error tag');
357
+ assert.ok(mockedThrows >= 1, 'mock fired at least once');
358
+ } finally {
359
+ fs.writeFileSync = realWrite;
360
+ }
361
+
362
+ // Mock readFileSync to throw ENOENT for the telemetry path; verify
363
+ // computeRemainingBudget returns the full default.
364
+ const realRead = fs.readFileSync;
365
+ fs.readFileSync = function (file, opts) {
366
+ if (typeof file === 'string' && file.indexOf('external-papers.json') !== -1) {
367
+ const err = new Error('ENOENT: no such file');
368
+ err.code = 'ENOENT';
369
+ throw err;
370
+ }
371
+ return realRead(file, opts);
372
+ };
373
+ try {
374
+ const remaining = telemetry.computeRemainingBudget('arxiv', 100);
375
+ assert.equal(remaining, 100, 'ENOENT fallback returns full default');
376
+ } finally {
377
+ fs.readFileSync = realRead;
378
+ }
379
+ });
380
+
381
+ // ---------- Suite-end A1 sweep: zero forbidden matches in any captured output ----------
382
+
383
+ runScenario('A1: zero forbidden matches across captured payloads', function () {
384
+ for (const rec of SCENARIO_RESULTS) {
385
+ const stringified = JSON.stringify(rec.payload);
386
+ const hit = scanAgainstForbidden(stringified);
387
+ assert.equal(hit.hit, false,
388
+ 'A1 violation in ' + rec.test + '/' + rec.surface +
389
+ ' against pattern ' + (hit.pattern || 'n/a'));
390
+ }
391
+ });
392
+
393
+ // ---------- Suite-end A2 sweep: zero orphan tmpfiles in TELEMETRY_DIR ----------
394
+
395
+ runScenario('A2: zero orphan tmpfiles in TELEMETRY_DIR', function () {
396
+ // Re-require to read the module's TELEMETRY_DIR (HOME may have shifted).
397
+ const telemetry = require('../core/rs-egress-telemetry.cjs');
398
+ const dir = path.dirname(telemetry.TELEMETRY_FILE);
399
+ if (!fs.existsSync(dir)) {
400
+ return; // nothing to scan
401
+ }
402
+ const orphans = fs.readdirSync(dir).filter(function (f) {
403
+ return /^external-papers\.json\.tmp\.\d+\.\d+$/.test(f);
404
+ });
405
+ assert.equal(orphans.length, 0,
406
+ 'A2 found orphan tmpfiles: ' + JSON.stringify(orphans));
407
+ });
408
+
409
+ // ---------- Final report ----------
410
+
411
+ if (failed > 0) {
412
+ console.error('\n=== ' + failed + ' FAILURES ===');
413
+ for (const f of failures) {
414
+ console.error(' ' + f.name);
415
+ }
416
+ process.exit(1);
417
+ }
418
+
419
+ console.log('=== 89.2-01 egress-primitives suite: 8/8 passed ===');
420
+ process.exit(0);