@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,271 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ * Phase 89.2 Plan 04 -- External industry fetcher invariants validator.
4
+ *
5
+ * Registry-compatible drop-in for the Phase 88-13 guardian. Auto-discovered
6
+ * by scripts/feynman-minto-guardian.cjs's validator loader (walks
7
+ * lib/memory/validators/*.cjs). Zero guardian.cjs edits needed.
8
+ *
9
+ * Mirrors external-patents-invariants.cjs structure byte-for-byte. The
10
+ * scope is identical (telemetry lives at the GLOBAL per-user path
11
+ * ~/.mindrian/telemetry/external-papers.json, NOT per-room) so this
12
+ * validator declares scope='global'. The guardian still invokes it
13
+ * once per pass; roomPath is ignored.
14
+ *
15
+ * INDUSTRY_SOURCES gate: per-source / per-entry checks scope to industry
16
+ * sources only ('tavily' for v1.11.0). Mirrors Plan 89.2-03's
17
+ * PATENTS_SOURCES gate pattern -- prevents duplicate warnings across
18
+ * academic + patents + industry validators on the shared global ledger.
19
+ *
20
+ * Six checks (Checks A-F):
21
+ * A) Telemetry file absent -> {severity: null} (healthy default)
22
+ * B) Per-source budget exceeded in rolling 24h -> warning per source
23
+ * Scoped to industry sources: tavily.
24
+ * C) status enum membership -> warning per entry
25
+ * Allowed statuses: ok | rate_limited | api_error | network_error |
26
+ * timeout | api_key_missing
27
+ * D) Canon Part 8 audit: query_text literal -> CRITICAL canon_boundary
28
+ * The telemetry primitive guarantees query_text NEVER persists
29
+ * (only query_text_hash). If a literal query_text field ever
30
+ * appears, that is a Canon Part 8 breach by definition.
31
+ * E) query_text_hash format -> warning
32
+ * Must match /^[a-f0-9]{16}$/ (sha256 16-char hex prefix).
33
+ * F) fetched_at parseable as ISO-8601 -> warning
34
+ *
35
+ * Fail-open: unexpected throws are caught by the guardian's validator
36
+ * runner. This validator does not swallow its own exceptions; the
37
+ * guardian owns that contract. Individual I/O paths (readFileSync) are
38
+ * wrapped defensively so a missing telemetry file never produces a
39
+ * violation.
40
+ *
41
+ * Pure CJS, node built-ins only + the rs-egress-telemetry primitive
42
+ * shipped in Plan 89.2-01 for TELEMETRY_FILE + DEFAULT_BUDGETS + WINDOW_MS.
43
+ */
44
+ 'use strict';
45
+
46
+ const fs = require('node:fs');
47
+
48
+ const {
49
+ TELEMETRY_FILE,
50
+ DEFAULT_BUDGETS,
51
+ WINDOW_MS,
52
+ } = require('../../core/rs-egress-telemetry.cjs');
53
+
54
+ // ---------- Constants ----------
55
+
56
+ const SEVERITY_MAP = Object.freeze({ critical: 3, error: 2, warning: 1, info: 0 });
57
+
58
+ // Mirrors lib/core/rs-egress-telemetry.cjs ALLOWED_STATUSES set. Kept in
59
+ // sync by parity gate (any drift fails an invariant scenario downstream).
60
+ const ALLOWED_STATUSES = Object.freeze(new Set([
61
+ 'ok',
62
+ 'rate_limited',
63
+ 'api_error',
64
+ 'network_error',
65
+ 'timeout',
66
+ 'api_key_missing',
67
+ ]));
68
+
69
+ // Industry-source allow-list for Check B + per-entry checks. The validator
70
+ // scans the global ledger but only emits violations for sources owned by
71
+ // the industry fetcher. Other surfaces (academic, patents) carry their
72
+ // own validators; running every validator on every source would duplicate
73
+ // warnings (Pattern 7 from Plan 89.2-03 SUMMARY).
74
+ const INDUSTRY_SOURCES = Object.freeze(new Set(['tavily']));
75
+
76
+ // 16-char lowercase hex. sha256 prefix. Must match
77
+ // rs-egress-telemetry.cjs::hashQueryText output shape.
78
+ const CANON_PART_8_HASH_REGEX = /^[a-f0-9]{16}$/;
79
+
80
+ // Cap canon_boundary hits per validate() invocation so one poisoned
81
+ // ledger cannot spam the invariant report. Mirrors brain-substrate
82
+ // invariants and Plan 90-05 brain-md-invariants threshold.
83
+ const MAX_CANON_HITS_REPORTED = 5;
84
+
85
+ // Cap warning-class violations to bound report size on a fully-corrupt
86
+ // ledger. Critical hits are not capped (Check D never exceeds
87
+ // MAX_CANON_HITS_REPORTED on its own).
88
+ const MAX_WARNINGS_REPORTED = 25;
89
+
90
+ // ---------- Severity aggregator ----------
91
+
92
+ function aggregateSeverity(violations) {
93
+ if (!violations || violations.length === 0) return null;
94
+ let max = 0;
95
+ const inv = { 0: 'info', 1: 'warning', 2: 'error', 3: 'critical' };
96
+ for (const v of violations) {
97
+ const s = SEVERITY_MAP[v.severity];
98
+ if (typeof s === 'number' && s > max) max = s;
99
+ }
100
+ return inv[max];
101
+ }
102
+
103
+ // ---------- validate (Checks A-F) ----------
104
+ //
105
+ // scope='global'; roomPath is ignored (telemetry is per-user, not per-room).
106
+ // ctx is unused but accepted to match the validator contract.
107
+
108
+ function validate(_roomPath, _ctx) {
109
+ const violations = [];
110
+
111
+ // ---- Check A: telemetry file absent -> healthy default ----
112
+ if (!fs.existsSync(TELEMETRY_FILE)) {
113
+ return { severity: null, violations: [] };
114
+ }
115
+
116
+ // Read + parse defensively. A malformed ledger is a warning (not
117
+ // critical) because the telemetry primitive treats malformed payloads
118
+ // as cold-start; budgets just reset rather than crashing the fetcher.
119
+ let payload = null;
120
+ try {
121
+ const raw = fs.readFileSync(TELEMETRY_FILE, 'utf8');
122
+ payload = JSON.parse(raw);
123
+ } catch (err) {
124
+ violations.push({
125
+ validator: 'external-industry-invariants',
126
+ category: 'telemetry_unreadable',
127
+ severity: 'warning',
128
+ message: 'external-papers.json unreadable: ' + String(err && err.message),
129
+ action_hint: 'invalidate_telemetry',
130
+ });
131
+ return { severity: aggregateSeverity(violations), violations };
132
+ }
133
+
134
+ if (!payload || typeof payload !== 'object' || !Array.isArray(payload.entries)) {
135
+ violations.push({
136
+ validator: 'external-industry-invariants',
137
+ category: 'telemetry_malformed_root',
138
+ severity: 'warning',
139
+ message: 'external-papers.json root is not a plain object with entries[]',
140
+ action_hint: 'invalidate_telemetry',
141
+ });
142
+ return { severity: aggregateSeverity(violations), violations };
143
+ }
144
+
145
+ // ---- Check B: per-source budget exceeded in rolling 24h ----
146
+ // Aggregate counts per source within the rolling window, then compare
147
+ // against DEFAULT_BUDGETS. Only emit warnings for INDUSTRY_SOURCES so
148
+ // the academic + patents fetchers' validators own their own surfaces.
149
+ const now = Date.now();
150
+ const sourceCounts = {};
151
+ for (const entry of payload.entries) {
152
+ if (!entry || typeof entry !== 'object') continue;
153
+ if (typeof entry.source !== 'string') continue;
154
+ if (typeof entry.fetched_at !== 'string') continue;
155
+ const t = Date.parse(entry.fetched_at);
156
+ if (Number.isNaN(t)) continue;
157
+ if ((now - t) > WINDOW_MS) continue;
158
+ sourceCounts[entry.source] = (sourceCounts[entry.source] || 0) + 1;
159
+ }
160
+ for (const source of Object.keys(sourceCounts)) {
161
+ if (!INDUSTRY_SOURCES.has(source)) continue;
162
+ const cap = DEFAULT_BUDGETS[source];
163
+ if (typeof cap === 'number' && sourceCounts[source] > cap) {
164
+ violations.push({
165
+ validator: 'external-industry-invariants',
166
+ category: 'budget_exceeded',
167
+ severity: 'warning',
168
+ message: 'source ' + source + ' has ' + sourceCounts[source] +
169
+ ' calls in last 24h; budget cap ' + cap,
170
+ field: 'entries[].source=' + source,
171
+ action_hint: 'rotate_budget',
172
+ });
173
+ }
174
+ }
175
+
176
+ // ---- Checks C / D / E / F: per-entry scans ----
177
+ let canonHitCount = 0;
178
+ let warningCount = 0;
179
+ for (let i = 0; i < payload.entries.length; i += 1) {
180
+ const entry = payload.entries[i];
181
+ if (!entry || typeof entry !== 'object') continue;
182
+
183
+ // Per-entry checks scope to INDUSTRY_SOURCES so the academic +
184
+ // patents validators own their own status / hash / fetched_at
185
+ // entries on the shared ledger.
186
+ if (typeof entry.source === 'string' && !INDUSTRY_SOURCES.has(entry.source)) {
187
+ continue;
188
+ }
189
+
190
+ // ---- Check D: canon_boundary literal query_text presence ----
191
+ // The telemetry primitive guarantees query_text NEVER persists. If
192
+ // any entry carries the field at all, that is a Canon Part 8 breach.
193
+ if (Object.prototype.hasOwnProperty.call(entry, 'query_text')
194
+ && canonHitCount < MAX_CANON_HITS_REPORTED) {
195
+ violations.push({
196
+ validator: 'external-industry-invariants',
197
+ category: 'canon_boundary',
198
+ severity: 'critical',
199
+ message: 'entries[' + i + '] carries literal query_text (Canon Part 8 breach)',
200
+ field: 'entries[' + i + '].query_text',
201
+ action_hint: 'purge_telemetry',
202
+ });
203
+ canonHitCount += 1;
204
+ }
205
+
206
+ // ---- Check C: status enum membership ----
207
+ if (typeof entry.status === 'string' && !ALLOWED_STATUSES.has(entry.status)
208
+ && warningCount < MAX_WARNINGS_REPORTED) {
209
+ violations.push({
210
+ validator: 'external-industry-invariants',
211
+ category: 'status_enum_violation',
212
+ severity: 'warning',
213
+ message: 'entries[' + i + '].status is not in allowed set: ' +
214
+ String(entry.status).slice(0, 40),
215
+ field: 'entries[' + i + '].status',
216
+ action_hint: 'invalidate_telemetry',
217
+ });
218
+ warningCount += 1;
219
+ }
220
+
221
+ // ---- Check E: query_text_hash format ----
222
+ if (typeof entry.query_text_hash === 'string'
223
+ && !CANON_PART_8_HASH_REGEX.test(entry.query_text_hash)
224
+ && warningCount < MAX_WARNINGS_REPORTED) {
225
+ violations.push({
226
+ validator: 'external-industry-invariants',
227
+ category: 'hash_format_invalid',
228
+ severity: 'warning',
229
+ message: 'entries[' + i + '].query_text_hash fails /^[a-f0-9]{16}$/: ' +
230
+ String(entry.query_text_hash).slice(0, 40),
231
+ field: 'entries[' + i + '].query_text_hash',
232
+ action_hint: 'invalidate_telemetry',
233
+ });
234
+ warningCount += 1;
235
+ }
236
+
237
+ // ---- Check F: fetched_at parseable as ISO-8601 ----
238
+ if (typeof entry.fetched_at === 'string'
239
+ && Number.isNaN(Date.parse(entry.fetched_at))
240
+ && warningCount < MAX_WARNINGS_REPORTED) {
241
+ violations.push({
242
+ validator: 'external-industry-invariants',
243
+ category: 'fetched_at_malformed',
244
+ severity: 'warning',
245
+ message: 'entries[' + i + '].fetched_at not parseable as ISO-8601: ' +
246
+ String(entry.fetched_at).slice(0, 40),
247
+ field: 'entries[' + i + '].fetched_at',
248
+ action_hint: 'invalidate_telemetry',
249
+ });
250
+ warningCount += 1;
251
+ }
252
+ }
253
+
254
+ return { severity: aggregateSeverity(violations), violations };
255
+ }
256
+
257
+ // ---------- Exports ----------
258
+
259
+ module.exports = {
260
+ id: 'external-industry-invariants',
261
+ severity_map: SEVERITY_MAP,
262
+ scope: 'global',
263
+ validate: validate,
264
+ // Exported for downstream introspection + adversarial fixture suite.
265
+ // Not required by the registry loader.
266
+ ALLOWED_STATUSES: ALLOWED_STATUSES,
267
+ INDUSTRY_SOURCES: INDUSTRY_SOURCES,
268
+ CANON_PART_8_HASH_REGEX: CANON_PART_8_HASH_REGEX,
269
+ MAX_CANON_HITS_REPORTED: MAX_CANON_HITS_REPORTED,
270
+ MAX_WARNINGS_REPORTED: MAX_WARNINGS_REPORTED,
271
+ };
@@ -0,0 +1,266 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ * Phase 89.2 Plan 03 -- External patents fetcher invariants validator.
4
+ *
5
+ * Registry-compatible drop-in for the Phase 88-13 guardian. Auto-discovered
6
+ * by scripts/feynman-minto-guardian.cjs's validator loader (walks
7
+ * lib/memory/validators/*.cjs). Zero guardian.cjs edits needed.
8
+ *
9
+ * Mirrors external-academic-invariants.cjs structure byte-for-byte. The
10
+ * scope is identical (telemetry lives at the GLOBAL per-user path
11
+ * ~/.mindrian/telemetry/external-papers.json, NOT per-room) so this
12
+ * validator declares scope='global'. The guardian still invokes it
13
+ * once per pass; roomPath is ignored.
14
+ *
15
+ * Six checks (Checks A-F):
16
+ * A) Telemetry file absent -> {severity: null} (healthy default)
17
+ * B) Per-source budget exceeded in rolling 24h -> warning per source
18
+ * Scoped to patents sources: google_patents + uspto.
19
+ * C) status enum membership -> warning per entry
20
+ * Allowed statuses: ok | rate_limited | api_error | network_error |
21
+ * timeout | api_key_missing
22
+ * D) Canon Part 8 audit: query_text literal -> CRITICAL canon_boundary
23
+ * The telemetry primitive guarantees query_text NEVER persists
24
+ * (only query_text_hash). If a literal query_text field ever
25
+ * appears, that is a Canon Part 8 breach by definition.
26
+ * E) query_text_hash format -> warning
27
+ * Must match /^[a-f0-9]{16}$/ (sha256 16-char hex prefix).
28
+ * F) fetched_at parseable as ISO-8601 -> warning
29
+ *
30
+ * Fail-open: unexpected throws are caught by the guardian's validator
31
+ * runner. This validator does not swallow its own exceptions; the
32
+ * guardian owns that contract. Individual I/O paths (readFileSync) are
33
+ * wrapped defensively so a missing telemetry file never produces a
34
+ * violation.
35
+ *
36
+ * Pure CJS, node built-ins only + the rs-egress-telemetry primitive
37
+ * shipped in Plan 89.2-01 for TELEMETRY_FILE + DEFAULT_BUDGETS + WINDOW_MS.
38
+ */
39
+ 'use strict';
40
+
41
+ const fs = require('node:fs');
42
+
43
+ const {
44
+ TELEMETRY_FILE,
45
+ DEFAULT_BUDGETS,
46
+ WINDOW_MS,
47
+ } = require('../../core/rs-egress-telemetry.cjs');
48
+
49
+ // ---------- Constants ----------
50
+
51
+ const SEVERITY_MAP = Object.freeze({ critical: 3, error: 2, warning: 1, info: 0 });
52
+
53
+ // Mirrors lib/core/rs-egress-telemetry.cjs ALLOWED_STATUSES set. Kept in
54
+ // sync by parity gate (any drift fails an invariant scenario downstream).
55
+ const ALLOWED_STATUSES = Object.freeze(new Set([
56
+ 'ok',
57
+ 'rate_limited',
58
+ 'api_error',
59
+ 'network_error',
60
+ 'timeout',
61
+ 'api_key_missing',
62
+ ]));
63
+
64
+ // Patents-source allow-list for Check B. The validator scans the global
65
+ // ledger but only emits budget_exceeded warnings for sources owned by
66
+ // the patents fetcher. Other surfaces (academic, industry) carry their
67
+ // own validators; running every validator on every source would
68
+ // duplicate warnings.
69
+ const PATENTS_SOURCES = Object.freeze(new Set(['google_patents', 'uspto']));
70
+
71
+ // 16-char lowercase hex. sha256 prefix. Must match
72
+ // rs-egress-telemetry.cjs::hashQueryText output shape.
73
+ const CANON_PART_8_HASH_REGEX = /^[a-f0-9]{16}$/;
74
+
75
+ // Cap canon_boundary hits per validate() invocation so one poisoned
76
+ // ledger cannot spam the invariant report. Mirrors brain-substrate
77
+ // invariants and Plan 90-05 brain-md-invariants threshold.
78
+ const MAX_CANON_HITS_REPORTED = 5;
79
+
80
+ // Cap warning-class violations to bound report size on a fully-corrupt
81
+ // ledger. Critical hits are not capped (Check D never exceeds
82
+ // MAX_CANON_HITS_REPORTED on its own).
83
+ const MAX_WARNINGS_REPORTED = 25;
84
+
85
+ // ---------- Severity aggregator ----------
86
+
87
+ function aggregateSeverity(violations) {
88
+ if (!violations || violations.length === 0) return null;
89
+ let max = 0;
90
+ const inv = { 0: 'info', 1: 'warning', 2: 'error', 3: 'critical' };
91
+ for (const v of violations) {
92
+ const s = SEVERITY_MAP[v.severity];
93
+ if (typeof s === 'number' && s > max) max = s;
94
+ }
95
+ return inv[max];
96
+ }
97
+
98
+ // ---------- validate (Checks A-F) ----------
99
+ //
100
+ // scope='global'; roomPath is ignored (telemetry is per-user, not per-room).
101
+ // ctx is unused but accepted to match the validator contract.
102
+
103
+ function validate(_roomPath, _ctx) {
104
+ const violations = [];
105
+
106
+ // ---- Check A: telemetry file absent -> healthy default ----
107
+ if (!fs.existsSync(TELEMETRY_FILE)) {
108
+ return { severity: null, violations: [] };
109
+ }
110
+
111
+ // Read + parse defensively. A malformed ledger is a warning (not
112
+ // critical) because the telemetry primitive treats malformed payloads
113
+ // as cold-start; budgets just reset rather than crashing the fetcher.
114
+ let payload = null;
115
+ try {
116
+ const raw = fs.readFileSync(TELEMETRY_FILE, 'utf8');
117
+ payload = JSON.parse(raw);
118
+ } catch (err) {
119
+ violations.push({
120
+ validator: 'external-patents-invariants',
121
+ category: 'telemetry_unreadable',
122
+ severity: 'warning',
123
+ message: 'external-papers.json unreadable: ' + String(err && err.message),
124
+ action_hint: 'invalidate_telemetry',
125
+ });
126
+ return { severity: aggregateSeverity(violations), violations };
127
+ }
128
+
129
+ if (!payload || typeof payload !== 'object' || !Array.isArray(payload.entries)) {
130
+ violations.push({
131
+ validator: 'external-patents-invariants',
132
+ category: 'telemetry_malformed_root',
133
+ severity: 'warning',
134
+ message: 'external-papers.json root is not a plain object with entries[]',
135
+ action_hint: 'invalidate_telemetry',
136
+ });
137
+ return { severity: aggregateSeverity(violations), violations };
138
+ }
139
+
140
+ // ---- Check B: per-source budget exceeded in rolling 24h ----
141
+ // Aggregate counts per source within the rolling window, then compare
142
+ // against DEFAULT_BUDGETS. Only emit warnings for PATENTS_SOURCES so
143
+ // the academic + industry fetchers' validators own their own surfaces.
144
+ const now = Date.now();
145
+ const sourceCounts = {};
146
+ for (const entry of payload.entries) {
147
+ if (!entry || typeof entry !== 'object') continue;
148
+ if (typeof entry.source !== 'string') continue;
149
+ if (typeof entry.fetched_at !== 'string') continue;
150
+ const t = Date.parse(entry.fetched_at);
151
+ if (Number.isNaN(t)) continue;
152
+ if ((now - t) > WINDOW_MS) continue;
153
+ sourceCounts[entry.source] = (sourceCounts[entry.source] || 0) + 1;
154
+ }
155
+ for (const source of Object.keys(sourceCounts)) {
156
+ if (!PATENTS_SOURCES.has(source)) continue;
157
+ const cap = DEFAULT_BUDGETS[source];
158
+ if (typeof cap === 'number' && sourceCounts[source] > cap) {
159
+ violations.push({
160
+ validator: 'external-patents-invariants',
161
+ category: 'budget_exceeded',
162
+ severity: 'warning',
163
+ message: 'source ' + source + ' has ' + sourceCounts[source] +
164
+ ' calls in last 24h; budget cap ' + cap,
165
+ field: 'entries[].source=' + source,
166
+ action_hint: 'rotate_budget',
167
+ });
168
+ }
169
+ }
170
+
171
+ // ---- Checks C / D / E / F: per-entry scans ----
172
+ let canonHitCount = 0;
173
+ let warningCount = 0;
174
+ for (let i = 0; i < payload.entries.length; i += 1) {
175
+ const entry = payload.entries[i];
176
+ if (!entry || typeof entry !== 'object') continue;
177
+
178
+ // Per-entry checks scope to PATENTS_SOURCES so the academic +
179
+ // industry validators own their own status / hash / fetched_at
180
+ // entries on the shared ledger.
181
+ if (typeof entry.source === 'string' && !PATENTS_SOURCES.has(entry.source)) {
182
+ continue;
183
+ }
184
+
185
+ // ---- Check D: canon_boundary literal query_text presence ----
186
+ // The telemetry primitive guarantees query_text NEVER persists. If
187
+ // any entry carries the field at all, that is a Canon Part 8 breach.
188
+ if (Object.prototype.hasOwnProperty.call(entry, 'query_text')
189
+ && canonHitCount < MAX_CANON_HITS_REPORTED) {
190
+ violations.push({
191
+ validator: 'external-patents-invariants',
192
+ category: 'canon_boundary',
193
+ severity: 'critical',
194
+ message: 'entries[' + i + '] carries literal query_text (Canon Part 8 breach)',
195
+ field: 'entries[' + i + '].query_text',
196
+ action_hint: 'purge_telemetry',
197
+ });
198
+ canonHitCount += 1;
199
+ }
200
+
201
+ // ---- Check C: status enum membership ----
202
+ if (typeof entry.status === 'string' && !ALLOWED_STATUSES.has(entry.status)
203
+ && warningCount < MAX_WARNINGS_REPORTED) {
204
+ violations.push({
205
+ validator: 'external-patents-invariants',
206
+ category: 'status_enum_violation',
207
+ severity: 'warning',
208
+ message: 'entries[' + i + '].status is not in allowed set: ' +
209
+ String(entry.status).slice(0, 40),
210
+ field: 'entries[' + i + '].status',
211
+ action_hint: 'invalidate_telemetry',
212
+ });
213
+ warningCount += 1;
214
+ }
215
+
216
+ // ---- Check E: query_text_hash format ----
217
+ if (typeof entry.query_text_hash === 'string'
218
+ && !CANON_PART_8_HASH_REGEX.test(entry.query_text_hash)
219
+ && warningCount < MAX_WARNINGS_REPORTED) {
220
+ violations.push({
221
+ validator: 'external-patents-invariants',
222
+ category: 'hash_format_invalid',
223
+ severity: 'warning',
224
+ message: 'entries[' + i + '].query_text_hash fails /^[a-f0-9]{16}$/: ' +
225
+ String(entry.query_text_hash).slice(0, 40),
226
+ field: 'entries[' + i + '].query_text_hash',
227
+ action_hint: 'invalidate_telemetry',
228
+ });
229
+ warningCount += 1;
230
+ }
231
+
232
+ // ---- Check F: fetched_at parseable as ISO-8601 ----
233
+ if (typeof entry.fetched_at === 'string'
234
+ && Number.isNaN(Date.parse(entry.fetched_at))
235
+ && warningCount < MAX_WARNINGS_REPORTED) {
236
+ violations.push({
237
+ validator: 'external-patents-invariants',
238
+ category: 'fetched_at_malformed',
239
+ severity: 'warning',
240
+ message: 'entries[' + i + '].fetched_at not parseable as ISO-8601: ' +
241
+ String(entry.fetched_at).slice(0, 40),
242
+ field: 'entries[' + i + '].fetched_at',
243
+ action_hint: 'invalidate_telemetry',
244
+ });
245
+ warningCount += 1;
246
+ }
247
+ }
248
+
249
+ return { severity: aggregateSeverity(violations), violations };
250
+ }
251
+
252
+ // ---------- Exports ----------
253
+
254
+ module.exports = {
255
+ id: 'external-patents-invariants',
256
+ severity_map: SEVERITY_MAP,
257
+ scope: 'global',
258
+ validate: validate,
259
+ // Exported for downstream introspection + adversarial fixture suite.
260
+ // Not required by the registry loader.
261
+ ALLOWED_STATUSES: ALLOWED_STATUSES,
262
+ PATENTS_SOURCES: PATENTS_SOURCES,
263
+ CANON_PART_8_HASH_REGEX: CANON_PART_8_HASH_REGEX,
264
+ MAX_CANON_HITS_REPORTED: MAX_CANON_HITS_REPORTED,
265
+ MAX_WARNINGS_REPORTED: MAX_WARNINGS_REPORTED,
266
+ };
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ * Phase 88-13 first-in validator for the guardian registry.
4
+ *
5
+ * Thin adapter over lib/core/feynman-minto-invariants.cjs so the guardian
6
+ * never requires that module directly. Downstream phases register their
7
+ * own validators by dropping a .cjs file in this directory.
8
+ *
9
+ * Contract (shared with all validators):
10
+ * module.exports = {
11
+ * id: string, unique registry identifier
12
+ * severity_map: object, reference numeric levels per severity name
13
+ * validate: function, (sectionDir) -> { severity, violations[] }
14
+ * }
15
+ *
16
+ * Each returned violation carries at minimum:
17
+ * { validator: 'minto-invariants', category, severity, message, field? }
18
+ */
19
+
20
+ 'use strict';
21
+
22
+ const fs = require('node:fs');
23
+ const path = require('node:path');
24
+
25
+ const { validate: invariantsValidate } = require('../../core/feynman-minto-invariants.cjs');
26
+
27
+ module.exports = {
28
+ id: 'minto-invariants',
29
+ severity_map: { critical: 3, error: 2, warning: 1, info: 0 },
30
+ validate: function (sectionDir) {
31
+ const mintoPath = path.join(sectionDir, 'MINTO.md');
32
+ if (!fs.existsSync(mintoPath)) {
33
+ // MINTO absence is handled by the guardian existence-check layer; this
34
+ // validator is specifically about the content contract of an existing
35
+ // MINTO.md. Returning null + empty here keeps aggregation deterministic.
36
+ return { severity: null, violations: [] };
37
+ }
38
+ let result;
39
+ try {
40
+ result = invariantsValidate(mintoPath);
41
+ } catch (e) {
42
+ // Defensive: the invariants module itself must not crash the guardian.
43
+ return {
44
+ severity: 'error',
45
+ violations: [{
46
+ validator: 'minto-invariants',
47
+ category: 'invariants_module_fault',
48
+ severity: 'error',
49
+ message: 'invariants validate() threw: ' + (e && e.message || String(e)),
50
+ }],
51
+ };
52
+ }
53
+ const violations = (result && result.violations) || [];
54
+ const tagged = violations.map(function (v) {
55
+ return Object.assign({}, v, { validator: 'minto-invariants' });
56
+ });
57
+ return {
58
+ severity: result ? result.severity : null,
59
+ violations: tagged,
60
+ };
61
+ },
62
+ };