@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,909 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
6
|
+
*
|
|
7
|
+
* Phase 90-06 -- cross-room-aggregator fixture tests (18 cases)
|
|
8
|
+
* =============================================================
|
|
9
|
+
* Tests the riskiest Canon Part 8 surface in Phase 90: cross-room
|
|
10
|
+
* contradiction aggregation across multiple Data Rooms.
|
|
11
|
+
*
|
|
12
|
+
* The test suite builds tmpdir fixtures simulating ~/MindrianRooms/
|
|
13
|
+
* layouts with .rooms/registry.json pointing at 2-5 rooms per fixture.
|
|
14
|
+
* Each test isolates one risk surface (ALLOWED_ROOT scope, GUARDRAIL.md
|
|
15
|
+
* sealing, per-room brain_cross_room:false opt-out, unreadable paths,
|
|
16
|
+
* registry absence/malformation, hash divergence detection, wall-clock
|
|
17
|
+
* budget, and the LOAD-BEARING Canon Part 8 payload audits Tests 16-18
|
|
18
|
+
* that prove NO user content leaks into aggregator output under
|
|
19
|
+
* adversarial dangerous-content fixtures).
|
|
20
|
+
*
|
|
21
|
+
* Test map:
|
|
22
|
+
* 01: 3-room fixture, 0 sealed, contradictions detected
|
|
23
|
+
* 02: sealed room (GUARDRAIL.md) -> skipped
|
|
24
|
+
* 03: opt-out room (brain_cross_room:false) -> skipped
|
|
25
|
+
* 04: registry.json missing -> graceful fallback, no throw
|
|
26
|
+
* 05: registry.json malformed -> graceful fallback + stderr warn
|
|
27
|
+
* 06: room path outside ALLOWED_ROOT -> skipped as out_of_scope
|
|
28
|
+
* 07: self-exclusion (currentRoom slug matches registry entry)
|
|
29
|
+
* 08: hash_divergence contradiction type
|
|
30
|
+
* 09: framework_contradiction contradiction type
|
|
31
|
+
* 10: problem_type_mismatch contradiction type
|
|
32
|
+
* 11: no contradictions -> empty contradictions[], non-zero scanned
|
|
33
|
+
* 12: max_rooms:2 limit -> 2 scanned, rest skipped as max_rooms_exceeded
|
|
34
|
+
* 13: per_room_timeout_ms triggers skip_reasons.timeout
|
|
35
|
+
* 14: unreadable room dir (chmod 0) -> skip_reasons.unreadable
|
|
36
|
+
* 15: wall-clock <500ms for 10-room fixture
|
|
37
|
+
* 16: CANON PART 8 payload audit -- JSON.stringify(result) contains
|
|
38
|
+
* ZERO forbidden substrings (email, currency, quoted-person,
|
|
39
|
+
* meeting fragment, SSN, phone)
|
|
40
|
+
* 17: CANON PART 8 detail_scalar shape -- every contradiction's
|
|
41
|
+
* detail_scalar is {primitive-only}; no string > 40 chars; no
|
|
42
|
+
* string matches forbidden regex set
|
|
43
|
+
* 18: deriveSection integration with cross_room_scan:true populates
|
|
44
|
+
* the 'Flagged Contradictions (cross-room)' section with
|
|
45
|
+
* slug-based entries; body contains NO user content under
|
|
46
|
+
* dangerous-content fixture
|
|
47
|
+
*
|
|
48
|
+
* Registered in lib/memory/run-feynman-tests.cjs.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
const assert = require('node:assert/strict');
|
|
52
|
+
const fs = require('node:fs');
|
|
53
|
+
const os = require('node:os');
|
|
54
|
+
const path = require('node:path');
|
|
55
|
+
const crypto = require('node:crypto');
|
|
56
|
+
|
|
57
|
+
const REPO = path.resolve(__dirname, '..', '..');
|
|
58
|
+
const AGGREGATOR_PATH = path.join(REPO, 'lib/core/cross-room-aggregator.cjs');
|
|
59
|
+
|
|
60
|
+
// ---------- Tmp workspace helpers ----------
|
|
61
|
+
|
|
62
|
+
const TMP_ROOTS = [];
|
|
63
|
+
function mkTmp(prefix) {
|
|
64
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
65
|
+
TMP_ROOTS.push(d);
|
|
66
|
+
return d;
|
|
67
|
+
}
|
|
68
|
+
process.on('exit', function cleanup() {
|
|
69
|
+
for (const d of TMP_ROOTS) {
|
|
70
|
+
try {
|
|
71
|
+
// Reset perms in case a test chmod-0ed something
|
|
72
|
+
try { walkChmod(d, 0o755); } catch (_e) { /* best effort */ }
|
|
73
|
+
fs.rmSync(d, { recursive: true, force: true });
|
|
74
|
+
} catch (_e) { /* best effort */ }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
function walkChmod(root, mode) {
|
|
79
|
+
try {
|
|
80
|
+
fs.chmodSync(root, mode);
|
|
81
|
+
const entries = fs.readdirSync(root);
|
|
82
|
+
for (const name of entries) {
|
|
83
|
+
const abs = path.join(root, name);
|
|
84
|
+
let st;
|
|
85
|
+
try { st = fs.statSync(abs); } catch (_e) { continue; }
|
|
86
|
+
if (st.isDirectory()) walkChmod(abs, mode);
|
|
87
|
+
else {
|
|
88
|
+
try { fs.chmodSync(abs, mode); } catch (_e) { /* best effort */ }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch (_e) { /* best effort */ }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---------- Fixture writers ----------
|
|
95
|
+
|
|
96
|
+
function writeFile(p, body) {
|
|
97
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
98
|
+
fs.writeFileSync(p, body, 'utf8');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeRoomMd(sectionDir, opts) {
|
|
102
|
+
const o = opts || {};
|
|
103
|
+
const fm = ['---'];
|
|
104
|
+
if (o.brain_cross_room === false) {
|
|
105
|
+
fm.push('brain_cross_room: false');
|
|
106
|
+
}
|
|
107
|
+
fm.push('section: ' + (o.section || 'market-analysis'));
|
|
108
|
+
fm.push('---');
|
|
109
|
+
fm.push('');
|
|
110
|
+
fm.push((o.identity || '# Section'));
|
|
111
|
+
writeFile(path.join(sectionDir, 'ROOM.md'), fm.join('\n') + '\n');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function writeMintoMd(sectionDir, opts) {
|
|
115
|
+
const o = opts || {};
|
|
116
|
+
const gt = o.governing_thought || '';
|
|
117
|
+
const fm = [
|
|
118
|
+
'---',
|
|
119
|
+
'schema_version: v88',
|
|
120
|
+
'governing_thought: "' + gt.replace(/"/g, "'") + '"',
|
|
121
|
+
'last_generated_at: "' + (o.last_generated_at || '2026-04-20T10:00:00Z') + '"',
|
|
122
|
+
'last_artifact_write_seen_at: "' + (o.last_artifact_write_seen_at || '2026-04-20T09:00:00Z') + '"',
|
|
123
|
+
'arguments_count: ' + (o.arguments_count != null ? o.arguments_count : 3),
|
|
124
|
+
'evidence_density: ' + (o.evidence_density != null ? o.evidence_density : 0.4),
|
|
125
|
+
'mece_status: ' + (o.mece_status || 'pass'),
|
|
126
|
+
'---',
|
|
127
|
+
'',
|
|
128
|
+
'# ' + (o.section || 'market-analysis'),
|
|
129
|
+
'',
|
|
130
|
+
'Governing Thought: ' + gt,
|
|
131
|
+
'',
|
|
132
|
+
];
|
|
133
|
+
writeFile(path.join(sectionDir, 'MINTO.md'), fm.join('\n'));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function writeBrainMd(sectionDir, opts) {
|
|
137
|
+
const o = opts || {};
|
|
138
|
+
const gtHash = o.governing_thought_hash ||
|
|
139
|
+
('sha256:' + crypto.createHash('sha256').update(o.governing_thought || '').digest('hex'));
|
|
140
|
+
const fm = [
|
|
141
|
+
'---',
|
|
142
|
+
'section: ' + (o.section || 'market-analysis'),
|
|
143
|
+
'brain_generated_at: "' + (o.brain_generated_at || '2026-04-20T11:00:00Z') + '"',
|
|
144
|
+
'brain_graph_version: ' + (o.brain_graph_version != null ? o.brain_graph_version : 1),
|
|
145
|
+
'governing_thought_hash: "' + gtHash + '"',
|
|
146
|
+
'staleness: ' + (o.staleness || 'fresh'),
|
|
147
|
+
'stale_reason: null',
|
|
148
|
+
'author: brain',
|
|
149
|
+
'problem_type: ' + (o.problem_type || 'IDP'),
|
|
150
|
+
'prompt_version: 1',
|
|
151
|
+
'cost_tokens: 100',
|
|
152
|
+
'brain_query_count: 5',
|
|
153
|
+
'---',
|
|
154
|
+
'',
|
|
155
|
+
'## Pattern Matches',
|
|
156
|
+
o.pattern_matches || '(no signal)',
|
|
157
|
+
'',
|
|
158
|
+
'## Cross-Domain Analogies',
|
|
159
|
+
'(no signal)',
|
|
160
|
+
'',
|
|
161
|
+
'## Wicked Indicators',
|
|
162
|
+
'(no signal)',
|
|
163
|
+
'',
|
|
164
|
+
'## Unfilled Opportunity Matches',
|
|
165
|
+
'(no signal)',
|
|
166
|
+
'',
|
|
167
|
+
'## Framework Chain Predictions',
|
|
168
|
+
o.framework_chain || '(no signal)',
|
|
169
|
+
'',
|
|
170
|
+
'## Assessment Thinking Chain Position',
|
|
171
|
+
'(no signal)',
|
|
172
|
+
'',
|
|
173
|
+
'## ProblemType Classification',
|
|
174
|
+
o.problem_type_body || '(no signal)',
|
|
175
|
+
'',
|
|
176
|
+
'## Flagged Contradictions (cross-room)',
|
|
177
|
+
'(no signal)',
|
|
178
|
+
'',
|
|
179
|
+
'## HSI Signals',
|
|
180
|
+
'(no signal)',
|
|
181
|
+
'',
|
|
182
|
+
];
|
|
183
|
+
writeFile(path.join(sectionDir, 'BRAIN.md'), fm.join('\n'));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Build a room under allowedRoot with N sections.
|
|
188
|
+
* sectionsSpec is an array of { name, gt, problem_type, framework_chain,
|
|
189
|
+
* sealed, opted_out, dangerous_content } entries.
|
|
190
|
+
*/
|
|
191
|
+
function buildRoom(allowedRoot, roomSlug, sectionsSpec, opts) {
|
|
192
|
+
const roomDir = path.join(allowedRoot, roomSlug);
|
|
193
|
+
fs.mkdirSync(roomDir, { recursive: true });
|
|
194
|
+
|
|
195
|
+
opts = opts || {};
|
|
196
|
+
if (opts.sealed) {
|
|
197
|
+
writeFile(path.join(roomDir, 'GUARDRAIL.md'), [
|
|
198
|
+
'---',
|
|
199
|
+
'isolation: STRICT',
|
|
200
|
+
'---',
|
|
201
|
+
'',
|
|
202
|
+
'# SEALED ROOM',
|
|
203
|
+
'',
|
|
204
|
+
].join('\n'));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Create a top-level room ROOM.md for opt-out flag (if specified)
|
|
208
|
+
// Opt-out: brain_cross_room:false in ROOM.md frontmatter
|
|
209
|
+
writeRoomMd(roomDir, {
|
|
210
|
+
section: roomSlug,
|
|
211
|
+
brain_cross_room: opts.opted_out ? false : undefined,
|
|
212
|
+
identity: opts.identity || '# Room ' + roomSlug,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
for (const spec of sectionsSpec) {
|
|
216
|
+
const sectionDir = path.join(roomDir, spec.name);
|
|
217
|
+
const dangerous = spec.dangerous_content || '';
|
|
218
|
+
writeRoomMd(sectionDir, {
|
|
219
|
+
section: spec.name,
|
|
220
|
+
identity: '# ' + spec.name + '\n\n' + dangerous,
|
|
221
|
+
});
|
|
222
|
+
writeMintoMd(sectionDir, {
|
|
223
|
+
section: spec.name,
|
|
224
|
+
governing_thought: spec.gt || (spec.name + ' governing thought'),
|
|
225
|
+
arguments_count: spec.arguments_count || 3,
|
|
226
|
+
evidence_density: spec.evidence_density != null ? spec.evidence_density : 0.4,
|
|
227
|
+
mece_status: spec.mece_status || 'pass',
|
|
228
|
+
});
|
|
229
|
+
writeBrainMd(sectionDir, {
|
|
230
|
+
section: spec.name,
|
|
231
|
+
governing_thought: spec.gt,
|
|
232
|
+
governing_thought_hash: spec.governing_thought_hash,
|
|
233
|
+
problem_type: spec.problem_type || 'IDP',
|
|
234
|
+
pattern_matches: spec.pattern_matches,
|
|
235
|
+
framework_chain: spec.framework_chain,
|
|
236
|
+
problem_type_body: spec.problem_type_body,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return roomDir;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function writeRegistry(allowedRoot, rooms, active) {
|
|
244
|
+
const dotRooms = path.join(allowedRoot, '.rooms');
|
|
245
|
+
fs.mkdirSync(dotRooms, { recursive: true });
|
|
246
|
+
const payload = {
|
|
247
|
+
version: 2,
|
|
248
|
+
root: allowedRoot,
|
|
249
|
+
active: active || (rooms[0] && rooms[0].slug) || '',
|
|
250
|
+
rooms: {},
|
|
251
|
+
};
|
|
252
|
+
for (const r of rooms) {
|
|
253
|
+
payload.rooms[r.slug] = {
|
|
254
|
+
path: r.path || r.slug,
|
|
255
|
+
venture_name: r.venture_name || r.slug,
|
|
256
|
+
venture_stage: r.venture_stage || 'Design',
|
|
257
|
+
status: r.status || 'active',
|
|
258
|
+
created: r.created || '2026-04-20T00:00:00Z',
|
|
259
|
+
last_opened: r.last_opened || '2026-04-21T00:00:00Z',
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
fs.writeFileSync(path.join(dotRooms, 'registry.json'), JSON.stringify(payload, null, 2));
|
|
263
|
+
return payload;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Override ALLOWED_ROOT for tests via env
|
|
267
|
+
function makeFixtureRoot(prefix) {
|
|
268
|
+
const root = mkTmp(prefix);
|
|
269
|
+
return root;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ---------- Forbidden content fixture catalog ----------
|
|
273
|
+
//
|
|
274
|
+
// Dangerous content strings that must NEVER appear in aggregator output.
|
|
275
|
+
// Test 16-18 stringify the result and grep against these patterns.
|
|
276
|
+
|
|
277
|
+
const DANGEROUS_CONTENT = Object.freeze([
|
|
278
|
+
'Lawrence said we should raise $5M next quarter',
|
|
279
|
+
'meeting with jonathan@mindrian.com scheduled',
|
|
280
|
+
'Dror revealed SSN 123-45-6789 during diligence',
|
|
281
|
+
'$5M revenue target confirmed by Nimrod',
|
|
282
|
+
'call Oren at +1-555-123-4567',
|
|
283
|
+
'Jonathan said the market is soft',
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
const FORBIDDEN_PATTERNS = Object.freeze([
|
|
287
|
+
/@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}/,
|
|
288
|
+
/\$[0-9][\d,.]*[KMB]?\b/,
|
|
289
|
+
/\b(Lawrence|Jonathan|Nimrod|Oren|Dror)\s+(said|revealed|told|mentioned)\b/i,
|
|
290
|
+
/\bmeeting with\b/i,
|
|
291
|
+
/\b\d{3}-\d{2}-\d{4}\b/,
|
|
292
|
+
/\b\+?1?[\s.\-]?\(?\d{3}\)?[\s.\-]?\d{3}[\s.\-]?\d{4}\b/,
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
function containsForbidden(text) {
|
|
296
|
+
if (typeof text !== 'string') return null;
|
|
297
|
+
for (const re of FORBIDDEN_PATTERNS) {
|
|
298
|
+
if (re.test(text)) return re.source;
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ---------- Require aggregator with ALLOWED_ROOT override ----------
|
|
304
|
+
|
|
305
|
+
function loadAggregator(allowedRoot) {
|
|
306
|
+
// Aggregator reads ALLOWED_ROOT from process.env.MINDRIAN_ROOMS_ROOT if set
|
|
307
|
+
delete require.cache[require.resolve(AGGREGATOR_PATH)];
|
|
308
|
+
process.env.MINDRIAN_ROOMS_ROOT = allowedRoot;
|
|
309
|
+
return require(AGGREGATOR_PATH);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ---------- Tests ----------
|
|
313
|
+
|
|
314
|
+
let passed = 0;
|
|
315
|
+
let total = 0;
|
|
316
|
+
|
|
317
|
+
function run(name, fn) {
|
|
318
|
+
total += 1;
|
|
319
|
+
try {
|
|
320
|
+
const out = fn();
|
|
321
|
+
if (out && typeof out.then === 'function') {
|
|
322
|
+
return out.then(function () {
|
|
323
|
+
passed += 1;
|
|
324
|
+
process.stdout.write('PASS ' + name + '\n');
|
|
325
|
+
}, function (err) {
|
|
326
|
+
process.stderr.write('FAIL ' + name + ': ' + (err && err.stack || err) + '\n');
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
passed += 1;
|
|
330
|
+
process.stdout.write('PASS ' + name + '\n');
|
|
331
|
+
return Promise.resolve();
|
|
332
|
+
} catch (err) {
|
|
333
|
+
process.stderr.write('FAIL ' + name + ': ' + (err && err.stack || err) + '\n');
|
|
334
|
+
return Promise.resolve();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
(async function main() {
|
|
339
|
+
// ---------------- Test 01 ----------------
|
|
340
|
+
await run('01 3-room fixture, 0 sealed, contradictions detected', async function () {
|
|
341
|
+
const root = makeFixtureRoot('xroom-t01-');
|
|
342
|
+
// current room + 2 peers, each with a 'market-analysis' section with
|
|
343
|
+
// different governing_thought_hash
|
|
344
|
+
buildRoom(root, 'current-room', [
|
|
345
|
+
{ name: 'market-analysis', gt: 'current market framing', problem_type: 'IDP' },
|
|
346
|
+
]);
|
|
347
|
+
buildRoom(root, 'peer-a', [
|
|
348
|
+
{ name: 'market-analysis', gt: 'peer-a market framing variant', problem_type: 'WDP' },
|
|
349
|
+
]);
|
|
350
|
+
buildRoom(root, 'peer-b', [
|
|
351
|
+
{ name: 'market-analysis', gt: 'peer-b market framing other', problem_type: 'UDP' },
|
|
352
|
+
]);
|
|
353
|
+
writeRegistry(root, [
|
|
354
|
+
{ slug: 'current-room' },
|
|
355
|
+
{ slug: 'peer-a' },
|
|
356
|
+
{ slug: 'peer-b' },
|
|
357
|
+
], 'current-room');
|
|
358
|
+
|
|
359
|
+
const agg = loadAggregator(root);
|
|
360
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
361
|
+
opt_in: true,
|
|
362
|
+
max_rooms: 10,
|
|
363
|
+
per_room_timeout_ms: 1000,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
assert.equal(result.scanned_rooms, 2, 'should scan 2 peers (excluding self)');
|
|
367
|
+
assert.equal(result.skipped_rooms, 0, 'no rooms skipped');
|
|
368
|
+
assert.ok(result.contradictions.length >= 1, 'at least one contradiction found');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// ---------------- Test 02 ----------------
|
|
372
|
+
await run('02 sealed room (GUARDRAIL.md) -> skipped', async function () {
|
|
373
|
+
const root = makeFixtureRoot('xroom-t02-');
|
|
374
|
+
buildRoom(root, 'current-room', [
|
|
375
|
+
{ name: 'market-analysis', gt: 'current gt', problem_type: 'IDP' },
|
|
376
|
+
]);
|
|
377
|
+
buildRoom(root, 'peer-sealed', [
|
|
378
|
+
{ name: 'market-analysis', gt: 'peer gt variant', problem_type: 'WDP' },
|
|
379
|
+
], { sealed: true });
|
|
380
|
+
buildRoom(root, 'peer-open', [
|
|
381
|
+
{ name: 'market-analysis', gt: 'peer-open gt other', problem_type: 'UDP' },
|
|
382
|
+
]);
|
|
383
|
+
writeRegistry(root, [
|
|
384
|
+
{ slug: 'current-room' },
|
|
385
|
+
{ slug: 'peer-sealed' },
|
|
386
|
+
{ slug: 'peer-open' },
|
|
387
|
+
], 'current-room');
|
|
388
|
+
|
|
389
|
+
const agg = loadAggregator(root);
|
|
390
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
391
|
+
opt_in: true, max_rooms: 10,
|
|
392
|
+
});
|
|
393
|
+
assert.equal(result.scanned_rooms, 1, 'only peer-open scanned');
|
|
394
|
+
assert.equal(result.skipped_rooms, 1, 'peer-sealed skipped');
|
|
395
|
+
assert.equal(result.skip_reasons.sealed_room, 1, 'sealed reason logged');
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// ---------------- Test 03 ----------------
|
|
399
|
+
await run('03 opt-out room (brain_cross_room:false) -> skipped', async function () {
|
|
400
|
+
const root = makeFixtureRoot('xroom-t03-');
|
|
401
|
+
buildRoom(root, 'current-room', [
|
|
402
|
+
{ name: 'market-analysis', gt: 'current gt', problem_type: 'IDP' },
|
|
403
|
+
]);
|
|
404
|
+
buildRoom(root, 'peer-opt-out', [
|
|
405
|
+
{ name: 'market-analysis', gt: 'peer gt variant', problem_type: 'WDP' },
|
|
406
|
+
], { opted_out: true });
|
|
407
|
+
buildRoom(root, 'peer-normal', [
|
|
408
|
+
{ name: 'market-analysis', gt: 'peer normal gt', problem_type: 'UDP' },
|
|
409
|
+
]);
|
|
410
|
+
writeRegistry(root, [
|
|
411
|
+
{ slug: 'current-room' },
|
|
412
|
+
{ slug: 'peer-opt-out' },
|
|
413
|
+
{ slug: 'peer-normal' },
|
|
414
|
+
], 'current-room');
|
|
415
|
+
|
|
416
|
+
const agg = loadAggregator(root);
|
|
417
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
418
|
+
opt_in: true, max_rooms: 10,
|
|
419
|
+
});
|
|
420
|
+
assert.equal(result.scanned_rooms, 1, 'only peer-normal scanned');
|
|
421
|
+
assert.equal(result.skipped_rooms, 1, 'peer-opt-out skipped');
|
|
422
|
+
assert.equal(result.skip_reasons.opt_out, 1, 'opt_out reason logged');
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// ---------------- Test 04 ----------------
|
|
426
|
+
await run('04 registry.json missing -> graceful fallback', async function () {
|
|
427
|
+
const root = makeFixtureRoot('xroom-t04-');
|
|
428
|
+
buildRoom(root, 'current-room', [
|
|
429
|
+
{ name: 'market-analysis', gt: 'current gt' },
|
|
430
|
+
]);
|
|
431
|
+
// Intentionally no .rooms/registry.json
|
|
432
|
+
|
|
433
|
+
const agg = loadAggregator(root);
|
|
434
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
435
|
+
opt_in: true,
|
|
436
|
+
});
|
|
437
|
+
assert.deepEqual(result.contradictions, []);
|
|
438
|
+
assert.equal(result.scanned_rooms, 0);
|
|
439
|
+
assert.equal(result.skipped_rooms, 0);
|
|
440
|
+
assert.equal(result.reason, 'no_registry');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// ---------------- Test 05 ----------------
|
|
444
|
+
await run('05 malformed registry.json -> graceful fallback', async function () {
|
|
445
|
+
const root = makeFixtureRoot('xroom-t05-');
|
|
446
|
+
buildRoom(root, 'current-room', [
|
|
447
|
+
{ name: 'market-analysis', gt: 'current gt' },
|
|
448
|
+
]);
|
|
449
|
+
const dotRooms = path.join(root, '.rooms');
|
|
450
|
+
fs.mkdirSync(dotRooms, { recursive: true });
|
|
451
|
+
fs.writeFileSync(path.join(dotRooms, 'registry.json'), '{ not valid json');
|
|
452
|
+
|
|
453
|
+
const agg = loadAggregator(root);
|
|
454
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
455
|
+
opt_in: true,
|
|
456
|
+
});
|
|
457
|
+
assert.deepEqual(result.contradictions, []);
|
|
458
|
+
assert.equal(result.reason, 'no_registry');
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// ---------------- Test 06 ----------------
|
|
462
|
+
await run('06 room path outside ALLOWED_ROOT -> skipped as out_of_scope', async function () {
|
|
463
|
+
const root = makeFixtureRoot('xroom-t06-');
|
|
464
|
+
buildRoom(root, 'current-room', [
|
|
465
|
+
{ name: 'market-analysis', gt: 'current gt' },
|
|
466
|
+
]);
|
|
467
|
+
// Register a room whose path escapes ALLOWED_ROOT via ../ traversal
|
|
468
|
+
const outsideRoot = makeFixtureRoot('xroom-t06-outside-');
|
|
469
|
+
buildRoom(outsideRoot, 'escape-room', [
|
|
470
|
+
{ name: 'market-analysis', gt: 'escape gt variant' },
|
|
471
|
+
]);
|
|
472
|
+
const dotRooms = path.join(root, '.rooms');
|
|
473
|
+
fs.mkdirSync(dotRooms, { recursive: true });
|
|
474
|
+
const payload = {
|
|
475
|
+
version: 2,
|
|
476
|
+
root: root,
|
|
477
|
+
active: 'current-room',
|
|
478
|
+
rooms: {
|
|
479
|
+
'current-room': { path: 'current-room' },
|
|
480
|
+
'escape-room': { path: path.relative(root, path.join(outsideRoot, 'escape-room')) },
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
fs.writeFileSync(path.join(dotRooms, 'registry.json'), JSON.stringify(payload));
|
|
484
|
+
|
|
485
|
+
const agg = loadAggregator(root);
|
|
486
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
487
|
+
opt_in: true,
|
|
488
|
+
});
|
|
489
|
+
assert.equal(result.skipped_rooms, 1);
|
|
490
|
+
assert.equal(result.skip_reasons.out_of_scope || 0, 1);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// ---------------- Test 07 ----------------
|
|
494
|
+
await run('07 self-exclusion (currentRoom matches registry entry)', async function () {
|
|
495
|
+
const root = makeFixtureRoot('xroom-t07-');
|
|
496
|
+
buildRoom(root, 'current-room', [
|
|
497
|
+
{ name: 'market-analysis', gt: 'current gt' },
|
|
498
|
+
]);
|
|
499
|
+
buildRoom(root, 'peer-a', [
|
|
500
|
+
{ name: 'market-analysis', gt: 'peer gt variant' },
|
|
501
|
+
]);
|
|
502
|
+
writeRegistry(root, [
|
|
503
|
+
{ slug: 'current-room' },
|
|
504
|
+
{ slug: 'peer-a' },
|
|
505
|
+
], 'current-room');
|
|
506
|
+
|
|
507
|
+
const agg = loadAggregator(root);
|
|
508
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
509
|
+
opt_in: true,
|
|
510
|
+
});
|
|
511
|
+
// scanned_rooms excludes self
|
|
512
|
+
assert.equal(result.scanned_rooms, 1, 'self not counted as scanned');
|
|
513
|
+
// Contradictions (if any) never reference self as peer
|
|
514
|
+
for (const c of result.contradictions) {
|
|
515
|
+
assert.notEqual(c.room_a_slug, c.room_b_slug, 'contradiction pair distinct');
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// ---------------- Test 08 ----------------
|
|
520
|
+
await run('08 hash_divergence contradiction type', async function () {
|
|
521
|
+
const root = makeFixtureRoot('xroom-t08-');
|
|
522
|
+
buildRoom(root, 'current-room', [
|
|
523
|
+
{ name: 'market-analysis', gt: 'unique current gt for hash divergence', problem_type: 'IDP' },
|
|
524
|
+
]);
|
|
525
|
+
buildRoom(root, 'peer-a', [
|
|
526
|
+
{ name: 'market-analysis', gt: 'DIFFERENT gt to trigger hash divergence', problem_type: 'IDP' },
|
|
527
|
+
]);
|
|
528
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
529
|
+
|
|
530
|
+
const agg = loadAggregator(root);
|
|
531
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
532
|
+
opt_in: true,
|
|
533
|
+
});
|
|
534
|
+
const hashDiv = result.contradictions.filter(function (c) { return c.type === 'hash_divergence'; });
|
|
535
|
+
assert.ok(hashDiv.length >= 1, 'hash_divergence found');
|
|
536
|
+
assert.equal(hashDiv[0].section, 'market-analysis');
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// ---------------- Test 09 ----------------
|
|
540
|
+
await run('09 framework_contradiction contradiction type', async function () {
|
|
541
|
+
const root = makeFixtureRoot('xroom-t09-');
|
|
542
|
+
buildRoom(root, 'current-room', [
|
|
543
|
+
{
|
|
544
|
+
name: 'market-analysis',
|
|
545
|
+
gt: 'same framing',
|
|
546
|
+
problem_type: 'IDP',
|
|
547
|
+
framework_chain: '- SWOT -> FEEDS_INTO -> Porter Five Forces',
|
|
548
|
+
},
|
|
549
|
+
]);
|
|
550
|
+
buildRoom(root, 'peer-a', [
|
|
551
|
+
{
|
|
552
|
+
name: 'market-analysis',
|
|
553
|
+
gt: 'same framing',
|
|
554
|
+
problem_type: 'IDP',
|
|
555
|
+
framework_chain: '- PESTLE -> FEEDS_INTO -> Competitive Positioning',
|
|
556
|
+
},
|
|
557
|
+
]);
|
|
558
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
559
|
+
|
|
560
|
+
const agg = loadAggregator(root);
|
|
561
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
562
|
+
opt_in: true,
|
|
563
|
+
});
|
|
564
|
+
const fw = result.contradictions.filter(function (c) { return c.type === 'framework_contradiction'; });
|
|
565
|
+
assert.ok(fw.length >= 1, 'framework_contradiction found (peer chains differ)');
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// ---------------- Test 10 ----------------
|
|
569
|
+
await run('10 problem_type_mismatch contradiction type', async function () {
|
|
570
|
+
const root = makeFixtureRoot('xroom-t10-');
|
|
571
|
+
buildRoom(root, 'current-room', [
|
|
572
|
+
{ name: 'market-analysis', gt: 'same framing P10', problem_type: 'UDP' },
|
|
573
|
+
]);
|
|
574
|
+
buildRoom(root, 'peer-a', [
|
|
575
|
+
{ name: 'market-analysis', gt: 'same framing P10', problem_type: 'WDP' },
|
|
576
|
+
]);
|
|
577
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
578
|
+
|
|
579
|
+
const agg = loadAggregator(root);
|
|
580
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
581
|
+
opt_in: true,
|
|
582
|
+
});
|
|
583
|
+
const pt = result.contradictions.filter(function (c) { return c.type === 'problem_type_mismatch'; });
|
|
584
|
+
assert.ok(pt.length >= 1, 'problem_type_mismatch found');
|
|
585
|
+
assert.equal(pt[0].detail_scalar.problem_type_a, 'UDP');
|
|
586
|
+
assert.equal(pt[0].detail_scalar.problem_type_b, 'WDP');
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// ---------------- Test 11 ----------------
|
|
590
|
+
await run('11 no contradictions -> empty contradictions, non-zero scanned', async function () {
|
|
591
|
+
const root = makeFixtureRoot('xroom-t11-');
|
|
592
|
+
// Everything identical -> no contradictions
|
|
593
|
+
const sharedGt = 'identical gt no contradictions';
|
|
594
|
+
buildRoom(root, 'current-room', [
|
|
595
|
+
{ name: 'market-analysis', gt: sharedGt, problem_type: 'IDP' },
|
|
596
|
+
]);
|
|
597
|
+
buildRoom(root, 'peer-a', [
|
|
598
|
+
{ name: 'different-section', gt: 'unrelated', problem_type: 'WDP' },
|
|
599
|
+
]);
|
|
600
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
601
|
+
|
|
602
|
+
const agg = loadAggregator(root);
|
|
603
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
604
|
+
opt_in: true,
|
|
605
|
+
});
|
|
606
|
+
// No shared section slug -> zero contradictions
|
|
607
|
+
assert.deepEqual(result.contradictions, []);
|
|
608
|
+
assert.equal(result.scanned_rooms, 1);
|
|
609
|
+
assert.equal(result.skipped_rooms, 0);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// ---------------- Test 12 ----------------
|
|
613
|
+
await run('12 max_rooms:2 limit applied', async function () {
|
|
614
|
+
const root = makeFixtureRoot('xroom-t12-');
|
|
615
|
+
buildRoom(root, 'current-room', [{ name: 'market-analysis', gt: 'g' }]);
|
|
616
|
+
buildRoom(root, 'peer-a', [{ name: 'market-analysis', gt: 'va' }]);
|
|
617
|
+
buildRoom(root, 'peer-b', [{ name: 'market-analysis', gt: 'vb' }]);
|
|
618
|
+
buildRoom(root, 'peer-c', [{ name: 'market-analysis', gt: 'vc' }]);
|
|
619
|
+
writeRegistry(root, [
|
|
620
|
+
{ slug: 'current-room' },
|
|
621
|
+
{ slug: 'peer-a' },
|
|
622
|
+
{ slug: 'peer-b' },
|
|
623
|
+
{ slug: 'peer-c' },
|
|
624
|
+
], 'current-room');
|
|
625
|
+
|
|
626
|
+
const agg = loadAggregator(root);
|
|
627
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
628
|
+
opt_in: true,
|
|
629
|
+
max_rooms: 2,
|
|
630
|
+
});
|
|
631
|
+
assert.equal(result.scanned_rooms, 2, 'max_rooms cap honored');
|
|
632
|
+
assert.ok(
|
|
633
|
+
(result.skip_reasons.max_rooms_exceeded || 0) >= 1,
|
|
634
|
+
'extras logged under max_rooms_exceeded'
|
|
635
|
+
);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// ---------------- Test 13 ----------------
|
|
639
|
+
await run('13 per_room_timeout_ms triggers skip_reasons.timeout', async function () {
|
|
640
|
+
const root = makeFixtureRoot('xroom-t13-');
|
|
641
|
+
buildRoom(root, 'current-room', [{ name: 'market-analysis', gt: 'g' }]);
|
|
642
|
+
buildRoom(root, 'peer-a', [{ name: 'market-analysis', gt: 'va' }]);
|
|
643
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
644
|
+
|
|
645
|
+
// Force timeout via env hook the aggregator honors
|
|
646
|
+
process.env.MINDRIAN_XROOM_FORCE_TIMEOUT = '1';
|
|
647
|
+
const agg = loadAggregator(root);
|
|
648
|
+
try {
|
|
649
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
650
|
+
opt_in: true,
|
|
651
|
+
per_room_timeout_ms: 1,
|
|
652
|
+
});
|
|
653
|
+
assert.equal(result.scanned_rooms, 0, 'peer timed out -> not scanned');
|
|
654
|
+
assert.equal(result.skipped_rooms, 1);
|
|
655
|
+
assert.equal(result.skip_reasons.timeout, 1);
|
|
656
|
+
} finally {
|
|
657
|
+
delete process.env.MINDRIAN_XROOM_FORCE_TIMEOUT;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
// ---------------- Test 14 ----------------
|
|
662
|
+
await run('14 unreadable room dir -> skip_reasons.unreadable', async function () {
|
|
663
|
+
// NOTE: if running as root, chmod 0 does not block reads. Skip in that case.
|
|
664
|
+
if (typeof process.getuid === 'function' && process.getuid() === 0) {
|
|
665
|
+
process.stdout.write(' (root detected; skip semantics verified via env trigger)\n');
|
|
666
|
+
}
|
|
667
|
+
const root = makeFixtureRoot('xroom-t14-');
|
|
668
|
+
buildRoom(root, 'current-room', [{ name: 'market-analysis', gt: 'g' }]);
|
|
669
|
+
const peerPath = buildRoom(root, 'peer-a', [{ name: 'market-analysis', gt: 'v' }]);
|
|
670
|
+
writeRegistry(root, [{ slug: 'current-room' }, { slug: 'peer-a' }], 'current-room');
|
|
671
|
+
|
|
672
|
+
// Force unreadable via env hook the aggregator honors (deterministic
|
|
673
|
+
// even under root).
|
|
674
|
+
process.env.MINDRIAN_XROOM_FORCE_UNREADABLE = 'peer-a';
|
|
675
|
+
const agg = loadAggregator(root);
|
|
676
|
+
try {
|
|
677
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
678
|
+
opt_in: true,
|
|
679
|
+
});
|
|
680
|
+
assert.equal(result.skipped_rooms, 1);
|
|
681
|
+
assert.equal(result.skip_reasons.unreadable, 1);
|
|
682
|
+
} finally {
|
|
683
|
+
delete process.env.MINDRIAN_XROOM_FORCE_UNREADABLE;
|
|
684
|
+
}
|
|
685
|
+
// Restore perms for cleanup
|
|
686
|
+
try { walkChmod(peerPath, 0o755); } catch (_e) { /* best effort */ }
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
// ---------------- Test 15 ----------------
|
|
690
|
+
await run('15 wall-clock <500ms for 10-room fixture', async function () {
|
|
691
|
+
const root = makeFixtureRoot('xroom-t15-');
|
|
692
|
+
const slugs = ['current-room'];
|
|
693
|
+
buildRoom(root, 'current-room', [
|
|
694
|
+
{ name: 'market-analysis', gt: 'current gt' },
|
|
695
|
+
]);
|
|
696
|
+
for (let i = 0; i < 9; i++) {
|
|
697
|
+
const slug = 'peer-' + i;
|
|
698
|
+
slugs.push(slug);
|
|
699
|
+
buildRoom(root, slug, [
|
|
700
|
+
{ name: 'market-analysis', gt: 'peer ' + i + ' gt variant' },
|
|
701
|
+
]);
|
|
702
|
+
}
|
|
703
|
+
writeRegistry(root, slugs.map(function (s) { return { slug: s }; }), 'current-room');
|
|
704
|
+
|
|
705
|
+
const agg = loadAggregator(root);
|
|
706
|
+
const t0 = Date.now();
|
|
707
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
708
|
+
opt_in: true,
|
|
709
|
+
max_rooms: 10,
|
|
710
|
+
});
|
|
711
|
+
const elapsed = Date.now() - t0;
|
|
712
|
+
assert.ok(elapsed < 500, 'wall-clock < 500ms (was ' + elapsed + 'ms)');
|
|
713
|
+
assert.equal(result.scanned_rooms, 9);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// ---------------- Test 16 (LOAD-BEARING Canon Part 8 payload audit) ----------------
|
|
717
|
+
await run('16 CANON PART 8 -- JSON.stringify(result) contains ZERO forbidden substrings', async function () {
|
|
718
|
+
const root = makeFixtureRoot('xroom-t16-');
|
|
719
|
+
// Dangerous content in EVERY room: identity text, MINTO governing
|
|
720
|
+
// thought, BRAIN.md body, and even section names.
|
|
721
|
+
buildRoom(root, 'current-room', [
|
|
722
|
+
{
|
|
723
|
+
name: 'market-analysis',
|
|
724
|
+
gt: DANGEROUS_CONTENT[0], // 'Lawrence said ... $5M ...'
|
|
725
|
+
problem_type: 'IDP',
|
|
726
|
+
dangerous_content: DANGEROUS_CONTENT[1], // 'meeting with email'
|
|
727
|
+
pattern_matches: '- ' + DANGEROUS_CONTENT[2], // SSN leak
|
|
728
|
+
framework_chain: '- ' + DANGEROUS_CONTENT[5], // 'Jonathan said ...'
|
|
729
|
+
problem_type_body: '- ' + DANGEROUS_CONTENT[3], // '$5M revenue'
|
|
730
|
+
},
|
|
731
|
+
]);
|
|
732
|
+
buildRoom(root, 'peer-a', [
|
|
733
|
+
{
|
|
734
|
+
name: 'market-analysis',
|
|
735
|
+
gt: DANGEROUS_CONTENT[3], // '$5M revenue'
|
|
736
|
+
problem_type: 'WDP',
|
|
737
|
+
dangerous_content: DANGEROUS_CONTENT[4], // 'call Oren at +1...'
|
|
738
|
+
pattern_matches: '- ' + DANGEROUS_CONTENT[0],
|
|
739
|
+
},
|
|
740
|
+
]);
|
|
741
|
+
buildRoom(root, 'peer-b', [
|
|
742
|
+
{
|
|
743
|
+
name: 'market-analysis',
|
|
744
|
+
gt: DANGEROUS_CONTENT[5], // 'Jonathan said ...'
|
|
745
|
+
problem_type: 'UDP',
|
|
746
|
+
dangerous_content: DANGEROUS_CONTENT[2],
|
|
747
|
+
pattern_matches: '- ' + DANGEROUS_CONTENT[4],
|
|
748
|
+
},
|
|
749
|
+
]);
|
|
750
|
+
writeRegistry(root, [
|
|
751
|
+
{ slug: 'current-room' },
|
|
752
|
+
{ slug: 'peer-a' },
|
|
753
|
+
{ slug: 'peer-b' },
|
|
754
|
+
], 'current-room');
|
|
755
|
+
|
|
756
|
+
const agg = loadAggregator(root);
|
|
757
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
758
|
+
opt_in: true, max_rooms: 10,
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
const serialized = JSON.stringify(result);
|
|
762
|
+
// Must have scanned 2 peers; confirms we actually read the dangerous
|
|
763
|
+
// content and STILL produced clean output.
|
|
764
|
+
assert.equal(result.scanned_rooms, 2);
|
|
765
|
+
// Assert against the exact dangerous substrings
|
|
766
|
+
for (const bad of DANGEROUS_CONTENT) {
|
|
767
|
+
// Case-insensitive whole-string search
|
|
768
|
+
const found = serialized.toLowerCase().indexOf(bad.toLowerCase()) !== -1;
|
|
769
|
+
assert.equal(found, false,
|
|
770
|
+
'Canon Part 8 breach: serialized output contains forbidden substring: ' + bad);
|
|
771
|
+
}
|
|
772
|
+
// Assert against the forbidden regex set
|
|
773
|
+
const regexHit = containsForbidden(serialized);
|
|
774
|
+
assert.equal(regexHit, null,
|
|
775
|
+
'Canon Part 8 breach: serialized output matches forbidden regex: ' + regexHit);
|
|
776
|
+
// And produce at least one contradiction (confirms the scanner DID
|
|
777
|
+
// extract structural data even while rejecting user content)
|
|
778
|
+
assert.ok(result.contradictions.length >= 1,
|
|
779
|
+
'scanner should still produce structural contradictions');
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
// ---------------- Test 17 (Canon Part 8 detail_scalar shape audit) ----------------
|
|
783
|
+
await run('17 CANON PART 8 -- detail_scalar shape is primitive-only', async function () {
|
|
784
|
+
const root = makeFixtureRoot('xroom-t17-');
|
|
785
|
+
buildRoom(root, 'current-room', [
|
|
786
|
+
{
|
|
787
|
+
name: 'market-analysis',
|
|
788
|
+
gt: DANGEROUS_CONTENT[0],
|
|
789
|
+
problem_type: 'IDP',
|
|
790
|
+
dangerous_content: DANGEROUS_CONTENT[1],
|
|
791
|
+
},
|
|
792
|
+
]);
|
|
793
|
+
buildRoom(root, 'peer-a', [
|
|
794
|
+
{
|
|
795
|
+
name: 'market-analysis',
|
|
796
|
+
gt: DANGEROUS_CONTENT[5],
|
|
797
|
+
problem_type: 'WDP',
|
|
798
|
+
dangerous_content: DANGEROUS_CONTENT[3],
|
|
799
|
+
},
|
|
800
|
+
]);
|
|
801
|
+
writeRegistry(root, [
|
|
802
|
+
{ slug: 'current-room' },
|
|
803
|
+
{ slug: 'peer-a' },
|
|
804
|
+
], 'current-room');
|
|
805
|
+
|
|
806
|
+
const agg = loadAggregator(root);
|
|
807
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
808
|
+
opt_in: true,
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
assert.ok(result.contradictions.length >= 1);
|
|
812
|
+
for (const c of result.contradictions) {
|
|
813
|
+
assert.ok(c.detail_scalar && typeof c.detail_scalar === 'object',
|
|
814
|
+
'detail_scalar is object');
|
|
815
|
+
for (const k of Object.keys(c.detail_scalar)) {
|
|
816
|
+
const v = c.detail_scalar[k];
|
|
817
|
+
const t = typeof v;
|
|
818
|
+
// Primitives only: string, number, boolean, null.
|
|
819
|
+
assert.ok(
|
|
820
|
+
t === 'string' || t === 'number' || t === 'boolean' || v === null,
|
|
821
|
+
'detail_scalar.' + k + ' must be primitive; got ' + t
|
|
822
|
+
);
|
|
823
|
+
if (t === 'string') {
|
|
824
|
+
// Structural strings (enums, slugs) MUST be <= 40 chars
|
|
825
|
+
assert.ok(v.length <= 40,
|
|
826
|
+
'detail_scalar.' + k + ' string must be <= 40 chars (was ' + v.length + '): ' + v);
|
|
827
|
+
// Must not match any forbidden regex
|
|
828
|
+
const hit = containsForbidden(v);
|
|
829
|
+
assert.equal(hit, null,
|
|
830
|
+
'detail_scalar.' + k + ' matches forbidden regex: ' + hit);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// confidence must be [0,1]
|
|
834
|
+
if (typeof c.confidence === 'number') {
|
|
835
|
+
assert.ok(c.confidence >= 0 && c.confidence <= 1);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
// ---------------- Test 18 (deriveSection integration) ----------------
|
|
841
|
+
await run('18 deriveSection integration w/ cross_room_scan:true', async function () {
|
|
842
|
+
// This test exercises the integration point: brain-derivation.cjs
|
|
843
|
+
// accepts options.cross_room_scan which, when true, calls the
|
|
844
|
+
// aggregator and populates the 'Flagged Contradictions (cross-room)'
|
|
845
|
+
// body with slug-based entries only.
|
|
846
|
+
const root = makeFixtureRoot('xroom-t18-');
|
|
847
|
+
buildRoom(root, 'current-room', [
|
|
848
|
+
{
|
|
849
|
+
name: 'market-analysis',
|
|
850
|
+
gt: DANGEROUS_CONTENT[0],
|
|
851
|
+
problem_type: 'IDP',
|
|
852
|
+
dangerous_content: DANGEROUS_CONTENT[1],
|
|
853
|
+
},
|
|
854
|
+
]);
|
|
855
|
+
buildRoom(root, 'peer-a', [
|
|
856
|
+
{
|
|
857
|
+
name: 'market-analysis',
|
|
858
|
+
gt: DANGEROUS_CONTENT[3],
|
|
859
|
+
problem_type: 'WDP',
|
|
860
|
+
dangerous_content: DANGEROUS_CONTENT[5],
|
|
861
|
+
},
|
|
862
|
+
]);
|
|
863
|
+
writeRegistry(root, [
|
|
864
|
+
{ slug: 'current-room' },
|
|
865
|
+
{ slug: 'peer-a' },
|
|
866
|
+
], 'current-room');
|
|
867
|
+
|
|
868
|
+
// Load the aggregator and render a pseudo-body through its
|
|
869
|
+
// rendering helper (the actual deriveSection integration calls
|
|
870
|
+
// renderCrossRoomSection with the aggregator result).
|
|
871
|
+
const agg = loadAggregator(root);
|
|
872
|
+
const result = await agg.aggregateContradictions(path.join(root, 'current-room'), {
|
|
873
|
+
opt_in: true,
|
|
874
|
+
});
|
|
875
|
+
const body = agg.renderCrossRoomSection(result);
|
|
876
|
+
|
|
877
|
+
// Body must contain slug-based entries when contradictions exist
|
|
878
|
+
assert.ok(typeof body === 'string');
|
|
879
|
+
// Body must contain NO dangerous substrings
|
|
880
|
+
for (const bad of DANGEROUS_CONTENT) {
|
|
881
|
+
const found = body.toLowerCase().indexOf(bad.toLowerCase()) !== -1;
|
|
882
|
+
assert.equal(found, false,
|
|
883
|
+
'rendered section body contains forbidden substring: ' + bad);
|
|
884
|
+
}
|
|
885
|
+
const hit = containsForbidden(body);
|
|
886
|
+
assert.equal(hit, null, 'rendered body matches forbidden regex: ' + hit);
|
|
887
|
+
// If contradictions exist, body references peer slug
|
|
888
|
+
if (result.contradictions.length > 0) {
|
|
889
|
+
assert.ok(/peer-a/.test(body) || /current-room/.test(body),
|
|
890
|
+
'body cites peer slug structurally');
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// Confirm brain-derivation.cjs exports the integration option
|
|
894
|
+
delete require.cache[require.resolve(path.join(REPO, 'lib/core/brain-derivation.cjs'))];
|
|
895
|
+
const deriv = require(path.join(REPO, 'lib/core/brain-derivation.cjs'));
|
|
896
|
+
const src = fs.readFileSync(path.join(REPO, 'lib/core/brain-derivation.cjs'), 'utf8');
|
|
897
|
+
assert.ok(/cross_room_scan/.test(src),
|
|
898
|
+
'brain-derivation.cjs references cross_room_scan option');
|
|
899
|
+
assert.ok(/aggregateContradictions/.test(src),
|
|
900
|
+
'brain-derivation.cjs wires aggregateContradictions');
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
// ---------- Summary ----------
|
|
904
|
+
process.stdout.write('\ncross-room-aggregator: ' + passed + '/' + total + ' passed\n');
|
|
905
|
+
if (passed < total) process.exit(1);
|
|
906
|
+
})().catch(function (err) {
|
|
907
|
+
process.stderr.write('TEST HARNESS ERROR: ' + (err && err.stack || err) + '\n');
|
|
908
|
+
process.exit(1);
|
|
909
|
+
});
|