@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.
- package/.claude-plugin/plugin.json +21 -0
- package/.mcp.json +9 -0
- package/CHANGELOG.md +3333 -0
- package/LICENSE +123 -0
- package/README.md +673 -0
- package/agents/brain-query.md +80 -0
- package/agents/framework-runner.md +237 -0
- package/agents/grading.md +188 -0
- package/agents/investor.md +128 -0
- package/agents/larry-extended.md +135 -0
- package/agents/opportunity-scanner.md +91 -0
- package/agents/persona-analyst.md +132 -0
- package/agents/research.md +89 -0
- package/agents/reverse-salient-agent.md +27 -0
- package/bin/cli.js +142 -0
- package/bin/mindrian-mcp-server.cjs +182 -0
- package/bin/mindrian-tools.cjs +765 -0
- package/commands/act.md +439 -0
- package/commands/admin.md +404 -0
- package/commands/analyze-needs.md +42 -0
- package/commands/analyze-systems.md +39 -0
- package/commands/analyze-timing.md +42 -0
- package/commands/auto-explore.md +64 -0
- package/commands/beautiful-question.md +40 -0
- package/commands/brain-derive.md +78 -0
- package/commands/build-knowledge.md +42 -0
- package/commands/build-thesis.md +46 -0
- package/commands/causal.md +234 -0
- package/commands/challenge-assumptions.md +33 -0
- package/commands/compare-ventures.md +83 -0
- package/commands/dashboard.md +110 -0
- package/commands/deep-grade.md +82 -0
- package/commands/diagnose.md +58 -0
- package/commands/diagnostics.md +151 -0
- package/commands/doctor.md +151 -0
- package/commands/dominant-designs.md +40 -0
- package/commands/explain-decision.md +87 -0
- package/commands/explore-domains.md +42 -0
- package/commands/explore-futures.md +40 -0
- package/commands/explore-trends.md +42 -0
- package/commands/export.md +103 -0
- package/commands/file-meeting.md +724 -0
- package/commands/find-analogies.md +188 -0
- package/commands/find-bottlenecks.md +62 -0
- package/commands/find-connections.md +76 -0
- package/commands/funding.md +81 -0
- package/commands/grade.md +203 -0
- package/commands/graph.md +128 -0
- package/commands/hat-briefing.md +125 -0
- package/commands/heal.md +196 -0
- package/commands/help.md +399 -0
- package/commands/hmi-status.md +172 -0
- package/commands/jtbd.md +241 -0
- package/commands/leadership.md +73 -0
- package/commands/lean-canvas.md +40 -0
- package/commands/macro-trends.md +40 -0
- package/commands/map-unknowns.md +40 -0
- package/commands/memory.md +173 -0
- package/commands/models.md +175 -0
- package/commands/mos-reason.md +285 -0
- package/commands/mullins.md +120 -0
- package/commands/new-project.md +481 -0
- package/commands/onboard.md +434 -0
- package/commands/operator.md +149 -0
- package/commands/opportunities.md +144 -0
- package/commands/organize.md +497 -0
- package/commands/persona.md +198 -0
- package/commands/pipeline.md +112 -0
- package/commands/present.md +91 -0
- package/commands/publish.md +201 -0
- package/commands/query.md +124 -0
- package/commands/radar.md +72 -0
- package/commands/reanalyze.md +91 -0
- package/commands/research.md +196 -0
- package/commands/room.md +352 -0
- package/commands/rooms.md +598 -0
- package/commands/root-cause.md +40 -0
- package/commands/rs-experts.md +85 -0
- package/commands/rs-explain.md +100 -0
- package/commands/rs-fetch.md +94 -0
- package/commands/rs-thesis.md +85 -0
- package/commands/scenario-plan.md +40 -0
- package/commands/scheduled-tasks.md +285 -0
- package/commands/score-innovation.md +43 -0
- package/commands/scout.md +239 -0
- package/commands/setup.md +618 -0
- package/commands/snapshot.md +147 -0
- package/commands/speakers.md +84 -0
- package/commands/splash.md +28 -0
- package/commands/status.md +75 -0
- package/commands/structure-argument.md +42 -0
- package/commands/suggest-next.md +80 -0
- package/commands/systems-thinking.md +40 -0
- package/commands/think-hats.md +42 -0
- package/commands/update.md +181 -0
- package/commands/user-needs.md +40 -0
- package/commands/validate.md +40 -0
- package/commands/value-proposition.md +61 -0
- package/commands/vault.md +180 -0
- package/commands/visualize.md +52 -0
- package/commands/whitespace.md +507 -0
- package/commands/wiki.md +69 -0
- package/hooks/hooks.json +381 -0
- package/hooks/run-hook.cmd +64 -0
- package/lib/__init__.py +0 -0
- package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/agents/auto-explore-agent.cjs +1043 -0
- package/lib/agents/reverse-salient-agent.cjs +679 -0
- package/lib/agents/tension-hook-agent.cjs +544 -0
- package/lib/brain/ROOM.md +44 -0
- package/lib/brain/chain-recommender.cjs +301 -0
- package/lib/chat/chat-context.js +185 -0
- package/lib/chat/chat-panel.js +721 -0
- package/lib/chat/fabric-chat.cjs +288 -0
- package/lib/chat/generative-tools.js +219 -0
- package/lib/conversation/ROOM.md +39 -0
- package/lib/conversation/classifier-rules.json +38 -0
- package/lib/conversation/classifier.cjs +264 -0
- package/lib/conversation/operator.cjs +287 -0
- package/lib/copy/115-spec-strings.cjs +55 -0
- package/lib/core/__init__.py +0 -0
- package/lib/core/__nav-stub.cjs +14 -0
- package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
- package/lib/core/artifact-id.cjs +148 -0
- package/lib/core/asset-ops.cjs +151 -0
- package/lib/core/auto-commit-throttle.cjs +129 -0
- package/lib/core/bearer-token.cjs +199 -0
- package/lib/core/brain-client.cjs +865 -0
- package/lib/core/brain-derivation-prompts.cjs +326 -0
- package/lib/core/brain-derivation-queue.cjs +431 -0
- package/lib/core/brain-derivation.cjs +580 -0
- package/lib/core/brain-md-schema.cjs +528 -0
- package/lib/core/brain-md-staleness.cjs +357 -0
- package/lib/core/brain-response-sanitize.cjs +188 -0
- package/lib/core/bridge-writer.cjs +477 -0
- package/lib/core/chat-context-builder.cjs +253 -0
- package/lib/core/cross-room-aggregator.cjs +762 -0
- package/lib/core/daily-briefing.cjs +438 -0
- package/lib/core/decision-capture.cjs +618 -0
- package/lib/core/deep-links.cjs +82 -0
- package/lib/core/dispatch-optimizer.cjs +354 -0
- package/lib/core/dual-path-detector.cjs +84 -0
- package/lib/core/dual-path-detector.test.cjs +334 -0
- package/lib/core/exports-log.cjs +79 -0
- package/lib/core/feynman-minto-invariants.cjs +605 -0
- package/lib/core/folder-memory-async.cjs +338 -0
- package/lib/core/folder-memory-shared.cjs +890 -0
- package/lib/core/folder-memory.cjs +416 -0
- package/lib/core/framework-chain-composer.cjs +411 -0
- package/lib/core/frontmatter-schemas.cjs +330 -0
- package/lib/core/git-ops.cjs +141 -0
- package/lib/core/graph-ops.cjs +258 -0
- package/lib/core/hat-persistence.cjs +362 -0
- package/lib/core/index.cjs +60 -0
- package/lib/core/integration-registry.cjs +232 -0
- package/lib/core/intelligence-cascade.cjs +661 -0
- package/lib/core/lazygraph-ops.cjs +1057 -0
- package/lib/core/lru-cache.cjs +139 -0
- package/lib/core/mcp-profiles.cjs +182 -0
- package/lib/core/meeting-ops.cjs +54 -0
- package/lib/core/memory-ops.cjs +600 -0
- package/lib/core/migrations/ROOM.md +33 -0
- package/lib/core/migrations/phase-109-nodes-provenance.cjs +339 -0
- package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
- package/lib/core/model-profiles.cjs +246 -0
- package/lib/core/mullins-scaffold.cjs +160 -0
- package/lib/core/nav-dial.cjs +316 -0
- package/lib/core/navigation/ROOM.md +15 -0
- package/lib/core/navigation/explanation.cjs +43 -0
- package/lib/core/navigation/focus.cjs +135 -0
- package/lib/core/navigation/ingestion.cjs +82 -0
- package/lib/core/navigation/insights.cjs +350 -0
- package/lib/core/navigation/memory-events.cjs +118 -0
- package/lib/core/navigation/neighborhood.cjs +78 -0
- package/lib/core/navigation/packet.cjs +182 -0
- package/lib/core/navigation/room-home.cjs +127 -0
- package/lib/core/navigation/transitions.cjs +82 -0
- package/lib/core/navigation-engine-shared.cjs +242 -0
- package/lib/core/navigation-engine.cjs +664 -0
- package/lib/core/navigation.cjs +60 -0
- package/lib/core/nl-graph-queries.cjs +164 -0
- package/lib/core/offer-presenter.cjs +406 -0
- package/lib/core/opportunity-extractor.cjs +183 -0
- package/lib/core/opportunity-ops.cjs +1371 -0
- package/lib/core/persona-ops.cjs +537 -0
- package/lib/core/persona-taxonomy.cjs +190 -0
- package/lib/core/platform-gates.cjs +120 -0
- package/lib/core/platform.cjs +257 -0
- package/lib/core/proactive-intelligence.cjs +528 -0
- package/lib/core/problem-type-router.cjs +315 -0
- package/lib/core/reasoning-ops.cjs +639 -0
- package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
- package/lib/core/room-classifier-strict-mode.cjs +229 -0
- package/lib/core/room-db.cjs +127 -0
- package/lib/core/room-ops-async.cjs +92 -0
- package/lib/core/room-ops-shared.cjs +64 -0
- package/lib/core/room-ops-sync.cjs +70 -0
- package/lib/core/room-ops.cjs +32 -0
- package/lib/core/room-type-detector.cjs +386 -0
- package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
- package/lib/core/rs-brain-substrate.cjs +570 -0
- package/lib/core/rs-breakthrough-scorer.cjs +255 -0
- package/lib/core/rs-canon-violations.cjs +82 -0
- package/lib/core/rs-chain-feeder.cjs +343 -0
- package/lib/core/rs-commercial-assessor.cjs +280 -0
- package/lib/core/rs-differential-scorer.cjs +376 -0
- package/lib/core/rs-domain-analyzer.cjs +385 -0
- package/lib/core/rs-egress-prompts.cjs +113 -0
- package/lib/core/rs-egress-telemetry.cjs +225 -0
- package/lib/core/rs-egress-violations.cjs +53 -0
- package/lib/core/rs-expert-mapper.cjs +467 -0
- package/lib/core/rs-fetcher-academic.cjs +697 -0
- package/lib/core/rs-fetcher-experts.cjs +314 -0
- package/lib/core/rs-fetcher-industry.cjs +731 -0
- package/lib/core/rs-fetcher-patents.cjs +564 -0
- package/lib/core/rs-innovation-classifier.cjs +194 -0
- package/lib/core/rs-mind-map.cjs +656 -0
- package/lib/core/rs-neo4j-writer.cjs +388 -0
- package/lib/core/rs-nl-to-query.cjs +425 -0
- package/lib/core/rs-pinecone-bridge.cjs +303 -0
- package/lib/core/rs-preprocessor.cjs +350 -0
- package/lib/core/rs-query-matrix.cjs +316 -0
- package/lib/core/rs-query-to-text.cjs +438 -0
- package/lib/core/rs-sqlite-mirror.cjs +443 -0
- package/lib/core/rs-thesis-generator.cjs +188 -0
- package/lib/core/rs_cache.py +479 -0
- package/lib/core/rs_corpus.py +468 -0
- package/lib/core/rs_hybrid.py +586 -0
- package/lib/core/rs_math.py +287 -0
- package/lib/core/rs_rooms.py +193 -0
- package/lib/core/scheduled-scanner.cjs +463 -0
- package/lib/core/scratchpad-ops.cjs +201 -0
- package/lib/core/section-8-trace-schema.cjs +138 -0
- package/lib/core/section-registry.cjs +111 -0
- package/lib/core/session-state.cjs +144 -0
- package/lib/core/shallow-doc-parser.cjs +174 -0
- package/lib/core/shallow-doc-parser.test.cjs +226 -0
- package/lib/core/skill-activation-router.cjs +284 -0
- package/lib/core/state-ops.cjs +46 -0
- package/lib/core/statusline-cache.cjs +266 -0
- package/lib/core/token-estimator.cjs +348 -0
- package/lib/core/user-archetype.cjs +239 -0
- package/lib/core/user-md-ops.cjs +524 -0
- package/lib/core/visual-ops.cjs +624 -0
- package/lib/core/write-lock.cjs +149 -0
- package/lib/graph/canvas-graph.js +467 -0
- package/lib/graph/constellation-config.cjs +299 -0
- package/lib/graph/graph-detail-panel.js +165 -0
- package/lib/hmi/ROOM.md +47 -0
- package/lib/hmi/across-session-memory.cjs +604 -0
- package/lib/hmi/cross-room-memory.cjs +575 -0
- package/lib/hmi/decoy-tier.cjs +395 -0
- package/lib/hmi/jtbd-classifier.cjs +219 -0
- package/lib/hmi/jtbd-state.cjs +199 -0
- package/lib/hmi/jtbd-taxonomy.json +392 -0
- package/lib/hmi/selector-dispatcher.cjs +546 -0
- package/lib/hmi/selector-telemetry.cjs +263 -0
- package/lib/hmi/shape-f0-renderer.cjs +139 -0
- package/lib/hmi/shape-f1-fallback.cjs +80 -0
- package/lib/hmi/shape-f1-renderer.cjs +138 -0
- package/lib/hmi/shape-f2-renderer.cjs +132 -0
- package/lib/hmi/shape-f3-renderer.cjs +66 -0
- package/lib/hmi/shape-f4-renderer.cjs +72 -0
- package/lib/hmi/shape-f5-renderer.cjs +155 -0
- package/lib/hmi/shape-f6-plan-review-renderer.cjs +312 -0
- package/lib/hmi/shape-f6-renderer.cjs +144 -0
- package/lib/hmi/shape-g-renderer.cjs +219 -0
- package/lib/hmi/shape-h-renderer.cjs +222 -0
- package/lib/hmi/tier-check.cjs +63 -0
- package/lib/import/PRECONDITIONS.md +41 -0
- package/lib/import/branding.cjs +210 -0
- package/lib/import/branding.test.cjs +235 -0
- package/lib/import/classifications-sync.cjs +104 -0
- package/lib/import/classifications-sync.test.cjs +129 -0
- package/lib/import/enricher.cjs +296 -0
- package/lib/import/enricher.test.cjs +273 -0
- package/lib/import/integration.test.cjs +376 -0
- package/lib/import/manifest.cjs +129 -0
- package/lib/import/manifest.schema.json +185 -0
- package/lib/import/manifest.test.cjs +123 -0
- package/lib/import/meeting-detector.cjs +92 -0
- package/lib/import/meeting-detector.test.cjs +100 -0
- package/lib/import/person-detector.cjs +229 -0
- package/lib/import/person-detector.test.cjs +149 -0
- package/lib/import/report.cjs +186 -0
- package/lib/import/report.test.cjs +186 -0
- package/lib/import/room-md-scaffolder.cjs +49 -0
- package/lib/import/router.cjs +224 -0
- package/lib/import/router.test.cjs +356 -0
- package/lib/import/run-all-tests.cjs +36 -0
- package/lib/import/smoke-test.cjs +213 -0
- package/lib/import/smoke-test.test.cjs +148 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +8 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +7 -0
- package/lib/import/test-fixtures/collision-vault/source/onboarding.md +5 -0
- package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +1 -0
- package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +4 -0
- package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +9 -0
- package/lib/import/test-fixtures/tiny-vault/notes/empty.md +3 -0
- package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/random.md +4 -0
- package/lib/import/undo.test.cjs +199 -0
- package/lib/import/vault-scanner.cjs +105 -0
- package/lib/import/vault-scanner.test.cjs +67 -0
- package/lib/mcp/app-html/dashboard.html +316 -0
- package/lib/mcp/app-html/graph.html +428 -0
- package/lib/mcp/app-html/mindrian-platform.html +1841 -0
- package/lib/mcp/app-html/wiki.html +383 -0
- package/lib/mcp/app-views.cjs +322 -0
- package/lib/mcp/brain-router.cjs +418 -0
- package/lib/mcp/capability-registry.cjs +62 -0
- package/lib/mcp/larry-context.cjs +46 -0
- package/lib/mcp/larry-server-instructions.md +114 -0
- package/lib/mcp/pipeline-state.cjs +275 -0
- package/lib/mcp/prompts.cjs +302 -0
- package/lib/mcp/resources.cjs +227 -0
- package/lib/mcp/session-catchup.cjs +327 -0
- package/lib/mcp/surface-detect.cjs +75 -0
- package/lib/mcp/tool-router.cjs +1034 -0
- package/lib/memory/aaak-compress.cjs +403 -0
- package/lib/memory/aaak-compress.test.cjs +288 -0
- package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
- package/lib/memory/bearer-token.test.cjs +315 -0
- package/lib/memory/brain-cache-lru.test.cjs +259 -0
- package/lib/memory/brain-client-query-shape.test.cjs +160 -0
- package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
- package/lib/memory/brain-derivation-queue.test.cjs +539 -0
- package/lib/memory/brain-derivation.test.cjs +634 -0
- package/lib/memory/brain-derive-command.test.cjs +534 -0
- package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
- package/lib/memory/brain-md-schema.test.cjs +467 -0
- package/lib/memory/brain-md-staleness.test.cjs +525 -0
- package/lib/memory/brain-server-resolution.test.cjs +314 -0
- package/lib/memory/chain-recommender.test.cjs +233 -0
- package/lib/memory/chat-context.test.cjs +128 -0
- package/lib/memory/command-registry.test.cjs +220 -0
- package/lib/memory/cross-room-aggregator.test.cjs +909 -0
- package/lib/memory/dashboard-server.test.cjs +256 -0
- package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
- package/lib/memory/decision-capture.test.cjs +632 -0
- package/lib/memory/decision-capture.worker.cjs +70 -0
- package/lib/memory/explain-decision-command.test.cjs +521 -0
- package/lib/memory/explain-decision-footer.test.cjs +316 -0
- package/lib/memory/explored-materials-store.cjs +392 -0
- package/lib/memory/feynman-minto-guardian.test.cjs +736 -0
- package/lib/memory/feynman-minto-invariants.test.cjs +511 -0
- package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
- package/lib/memory/feynman-prompts.cjs +151 -0
- package/lib/memory/feynman-prompts.test.cjs +96 -0
- package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
- package/lib/memory/folder-memory.test.cjs +503 -0
- package/lib/memory/framework-chain-composer.test.cjs +515 -0
- package/lib/memory/frontmatter-schema-validator.test.cjs +290 -0
- package/lib/memory/heal-command.test.cjs +604 -0
- package/lib/memory/index-artifact-transaction.test.cjs +333 -0
- package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
- package/lib/memory/mcp-input-validation.test.cjs +240 -0
- package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
- package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
- package/lib/memory/minto-debouncer.test.cjs +407 -0
- package/lib/memory/minto-debouncer.worker.cjs +46 -0
- package/lib/memory/minto-migration-v88.test.cjs +265 -0
- package/lib/memory/minto-schema-v88.test.cjs +390 -0
- package/lib/memory/mos-status-renderer.test.cjs +631 -0
- package/lib/memory/narrative-schema.cjs +376 -0
- package/lib/memory/narrative-schema.test.cjs +209 -0
- package/lib/memory/nav-dial.test.cjs +414 -0
- package/lib/memory/navigation-engine-core.test.cjs +722 -0
- package/lib/memory/navigation-invariants.test.cjs +483 -0
- package/lib/memory/offer-presenter.test.cjs +554 -0
- package/lib/memory/on-stop-snapshot.test.cjs +404 -0
- package/lib/memory/pending-tension-store.cjs +373 -0
- package/lib/memory/post-compact-reinjection.test.cjs +854 -0
- package/lib/memory/post-write-triple.test.cjs +317 -0
- package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
- package/lib/memory/problem-type-router.test.cjs +656 -0
- package/lib/memory/query-efficiency-telemetry.test.cjs +370 -0
- package/lib/memory/recompile-room-references.test.cjs +392 -0
- package/lib/memory/recompile-room-references.worker.cjs +42 -0
- package/lib/memory/record-decision-dual-write.test.cjs +454 -0
- package/lib/memory/room-classifier-strict-mode.test.cjs +417 -0
- package/lib/memory/room-minto-hook.test.cjs +398 -0
- package/lib/memory/rs-discovery-engine.test.cjs +323 -0
- package/lib/memory/run-feynman-tests.cjs +1247 -0
- package/lib/memory/security-trifecta.test.cjs +312 -0
- package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
- package/lib/memory/session-start-triple-injection.test.cjs +514 -0
- package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
- package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
- package/lib/memory/skill-activation-router.test.cjs +419 -0
- package/lib/memory/stamp-artifact-write.test.cjs +304 -0
- package/lib/memory/statusline-active-room.test.cjs +315 -0
- package/lib/memory/statusline-minto-segment.test.cjs +292 -0
- package/lib/memory/sync-async-entry-points.test.cjs +204 -0
- package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
- package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
- package/lib/memory/test-rs-brain-substrate.cjs +636 -0
- package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
- package/lib/memory/test-rs-canon-violations.cjs +218 -0
- package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
- package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
- package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
- package/lib/memory/test-rs-differential-scorer.cjs +480 -0
- package/lib/memory/test-rs-discovery-engine.cjs +603 -0
- package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
- package/lib/memory/test-rs-egress-primitives.cjs +420 -0
- package/lib/memory/test-rs-expert-mapper.cjs +547 -0
- package/lib/memory/test-rs-explain-command.cjs +443 -0
- package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
- package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
- package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
- package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
- package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
- package/lib/memory/test-rs-mind-map.cjs +646 -0
- package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
- package/lib/memory/test-rs-nl-to-query.cjs +449 -0
- package/lib/memory/test-rs-pinecone-bridge.cjs +277 -0
- package/lib/memory/test-rs-preprocessor.cjs +433 -0
- package/lib/memory/test-rs-query-matrix.cjs +391 -0
- package/lib/memory/test-rs-query-to-text.cjs +551 -0
- package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
- package/lib/memory/test-rs-thesis-generator.cjs +360 -0
- package/lib/memory/triple-context-formatter.cjs +473 -0
- package/lib/memory/triple-context-formatter.test.cjs +442 -0
- package/lib/memory/user-md-persona.test.cjs +565 -0
- package/lib/memory/userpromptsubmit-integration.test.cjs +690 -0
- package/lib/memory/validators/README.md +157 -0
- package/lib/memory/validators/brain-md-invariants.cjs +475 -0
- package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
- package/lib/memory/validators/external-academic-invariants.cjs +249 -0
- package/lib/memory/validators/external-industry-invariants.cjs +271 -0
- package/lib/memory/validators/external-patents-invariants.cjs +266 -0
- package/lib/memory/validators/minto-invariants.cjs +62 -0
- package/lib/memory/validators/navigation-invariants.cjs +340 -0
- package/lib/memory/validators/queue-health.cjs +95 -0
- package/lib/memory/validators/snapshot-integrity.cjs +129 -0
- package/lib/memory/validators/stale-lifecycle.cjs +116 -0
- package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
- package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
- package/lib/memory/write-lock-atomic.test.cjs +137 -0
- package/lib/memory/write-lock-atomic.worker.cjs +55 -0
- package/lib/parity/check-parity.cjs +83 -0
- package/lib/presentation/presentation-server.cjs +101 -0
- package/lib/presentation/presentation-watcher.cjs +123 -0
- package/lib/quickview/hub-server.cjs +719 -0
- package/lib/quickview/server.cjs +533 -0
- package/lib/render/JTBD-PALETTES.md +145 -0
- package/lib/render/ROOM.md +59 -0
- package/lib/render/render-v2.cjs +486 -0
- package/lib/render/render-v2.test.cjs +267 -0
- package/lib/render/render.cjs +65 -0
- package/lib/state/ROOM.md +46 -0
- package/lib/state/state-md-parser.cjs +215 -0
- package/lib/statusline/ROOM.md +38 -0
- package/lib/statusline/banner-suppression.cjs +50 -0
- package/lib/statusline/surface-detect.cjs +85 -0
- package/lib/update-bootstrap.sh.template +145 -0
- package/lib/vault/frontmatter-schema.cjs +297 -0
- package/lib/vault/room-scanner.cjs +352 -0
- package/lib/vault/wikilink-builder.cjs +231 -0
- package/lib/vault/wikilink-builder.test.cjs +182 -0
- package/lib/wiki/graph-links.cjs +281 -0
- package/lib/wiki/page-renderer.cjs +229 -0
- package/lib/wiki/wiki-chat.cjs +81 -0
- package/lib/wiki/wiki-layout.cjs +1459 -0
- package/lib/wiki/wiki-search.cjs +142 -0
- package/lib/wiki/wiki-server.cjs +678 -0
- package/lib/wiki/wiki-watcher.cjs +105 -0
- package/lib/workflow/ROOM.md +47 -0
- package/lib/workflow/command-resolver.cjs +155 -0
- package/lib/workflow/command-resolver.test.cjs +235 -0
- package/package.json +44 -0
- package/pipelines/analogy/01-decompose.md +80 -0
- package/pipelines/analogy/02-abstract.md +87 -0
- package/pipelines/analogy/03-search.md +135 -0
- package/pipelines/analogy/04-transfer.md +101 -0
- package/pipelines/analogy/05-validate.md +106 -0
- package/pipelines/analogy/CHAIN.md +56 -0
- package/pipelines/discovery/01-explore-domains.md +44 -0
- package/pipelines/discovery/02-think-hats.md +50 -0
- package/pipelines/discovery/03-analyze-needs.md +54 -0
- package/pipelines/discovery/CHAIN.md +37 -0
- package/pipelines/thesis/01-structure-argument.md +45 -0
- package/pipelines/thesis/02-challenge-assumptions.md +48 -0
- package/pipelines/thesis/03-build-thesis.md +54 -0
- package/pipelines/thesis/CHAIN.md +37 -0
- package/references/brain/causal-directives.md +91 -0
- package/references/brain/causal-enrichment.cypher +165 -0
- package/references/brain/command-triggers-schema.md +226 -0
- package/references/brain/graph-architecture.md +317 -0
- package/references/brain/query-patterns.md +460 -0
- package/references/brain/room-hierarchy-schema.md +218 -0
- package/references/brain/schema.md +76 -0
- package/references/capability-radar/capabilities-index.md +241 -0
- package/references/capability-radar/changelog-cache.md +81 -0
- package/references/causal/causal-schema.md +103 -0
- package/references/design/email-template-standard.md +155 -0
- package/references/design/graph-visualization-standard.md +178 -0
- package/references/document-generation.md +179 -0
- package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
- package/references/import-config.md +141 -0
- package/references/integrations/detection-patterns.md +101 -0
- package/references/meeting/artifact-template.md +377 -0
- package/references/meeting/cross-meeting-intelligence.md +216 -0
- package/references/meeting/cross-relationship-patterns.md +202 -0
- package/references/meeting/live-join-interface.md +244 -0
- package/references/meeting/section-mapping.md +192 -0
- package/references/meeting/segment-classification.md +258 -0
- package/references/meeting/speaker-profile-template.md +219 -0
- package/references/meeting/summary-template.md +348 -0
- package/references/meeting/transcript-patterns.md +226 -0
- package/references/methodology/analyze-needs.md +135 -0
- package/references/methodology/analyze-systems.md +121 -0
- package/references/methodology/analyze-timing.md +149 -0
- package/references/methodology/beautiful-question.md +109 -0
- package/references/methodology/build-knowledge.md +161 -0
- package/references/methodology/build-thesis.md +237 -0
- package/references/methodology/challenge-assumptions.md +127 -0
- package/references/methodology/diagnose.md +169 -0
- package/references/methodology/dominant-designs.md +212 -0
- package/references/methodology/explore-domains.md +147 -0
- package/references/methodology/explore-futures.md +163 -0
- package/references/methodology/explore-trends.md +129 -0
- package/references/methodology/find-bottlenecks.md +131 -0
- package/references/methodology/grade.md +211 -0
- package/references/methodology/index.md +97 -0
- package/references/methodology/leadership.md +200 -0
- package/references/methodology/lean-canvas.md +116 -0
- package/references/methodology/macro-trends.md +192 -0
- package/references/methodology/map-unknowns.md +137 -0
- package/references/methodology/mullins-7-domains.md +104 -0
- package/references/methodology/problem-types.md +65 -0
- package/references/methodology/root-cause.md +178 -0
- package/references/methodology/sapphire-encoding.md +355 -0
- package/references/methodology/scenario-plan.md +178 -0
- package/references/methodology/score-innovation.md +154 -0
- package/references/methodology/structure-argument.md +158 -0
- package/references/methodology/systems-thinking.md +159 -0
- package/references/methodology/think-hats.md +147 -0
- package/references/methodology/triz-matrix.json +751 -0
- package/references/methodology/triz-principles.md +501 -0
- package/references/methodology/user-needs.md +199 -0
- package/references/methodology/validate.md +163 -0
- package/references/methodology/value-proposition.md +244 -0
- package/references/opportunities/funding-lifecycle.md +103 -0
- package/references/opportunities/grant-api-patterns.md +99 -0
- package/references/opportunities/opportunity-template.md +84 -0
- package/references/personality/assessment-philosophy.md +72 -0
- package/references/personality/lexicon.md +100 -0
- package/references/personality/persona-chains.md +56 -0
- package/references/personality/pws-lexicon-full.md +499 -0
- package/references/personality/voice-dna.md +156 -0
- package/references/personas/hat-perspectives.md +76 -0
- package/references/personas/persona-template.md +63 -0
- package/references/pipeline/act-output-contract.md +88 -0
- package/references/pipeline/chains-index.md +39 -0
- package/references/pws-profile-generation.md +79 -0
- package/references/reasoning/reasoning-schema.md +143 -0
- package/references/reasoning/reasoning-template.md +68 -0
- package/references/reasoning/run-template.md +38 -0
- package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
- package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
- package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
- package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
- package/references/taxonomy/TAXONOMY.md +192 -0
- package/references/templates/MINTO.md +36 -0
- package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
- package/references/vault-kit/README.md +35 -0
- package/references/vault-kit/app.json +12 -0
- package/references/vault-kit/appearance.json +12 -0
- package/references/vault-kit/graph.json +35 -0
- package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
- package/references/vault-kit/templates/new-artifact.md +37 -0
- package/references/vault-kit/templates/new-meeting-note.md +35 -0
- package/references/vault-kit/templates/new-team-profile.md +29 -0
- package/references/vault-kit/templates/new-xref.md +35 -0
- package/references/visual/symbol-system.md +151 -0
- package/skills/MOSDeckEngine/SKILL.md +325 -0
- package/skills/brain-connector/SKILL.md +114 -0
- package/skills/context-engine/SKILL.md +147 -0
- package/skills/conversation-mode/SKILL.md +102 -0
- package/skills/larry-personality/SKILL.md +219 -0
- package/skills/larry-personality/framework-chains.md +92 -0
- package/skills/larry-personality/mode-engine.md +185 -0
- package/skills/mullins-scaffold/SKILL.md +61 -0
- package/skills/mullins-scaffold/scaffold.json +146 -0
- package/skills/pws-methodology/SKILL.md +49 -0
- package/skills/room-passive/SKILL.md +165 -0
- package/skills/room-proactive/SKILL.md +250 -0
- 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);
|