@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,656 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
6
|
+
*
|
|
7
|
+
* Phase 91-07 -- Problem-Type Router fixture tests
|
|
8
|
+
* =================================================
|
|
9
|
+
* Exercises lib/core/problem-type-router.cjs. The router parses BRAIN.md
|
|
10
|
+
* problemtype_classification + wicked_indicators section bodies and
|
|
11
|
+
* returns canonical 4-type routing recommendations (UDP / IDP / WDP /
|
|
12
|
+
* unknown) with wicked escalation per Canon Appendix E rule R4.
|
|
13
|
+
*
|
|
14
|
+
* Canon Part 2 Appendix E (Team Composition R4): wicked problem
|
|
15
|
+
* (8-10 wickedness score) escalates to soft-systems family.
|
|
16
|
+
*
|
|
17
|
+
* Canon Part 3 (10-verb closed vocabulary): every recommended skill
|
|
18
|
+
* maps to one of the canonical verbs (Run Methodology / Reformulate /
|
|
19
|
+
* Spawn Sub-Agent / Navigate Graph / Devil's Advocate / Scenario Plan /
|
|
20
|
+
* Synthesize / Bank Opportunity / Defer / Free-Text).
|
|
21
|
+
*
|
|
22
|
+
* Canon Part 8 (Graph Boundary): ProblemType is a generic enum, not
|
|
23
|
+
* user content. The router never reads BRAIN.md directly; it only
|
|
24
|
+
* consumes already-parsed section bodies from readQuadruple.
|
|
25
|
+
*
|
|
26
|
+
* Test map:
|
|
27
|
+
* Task 1 (Tests 1-18): parser + 4-type routing + wicked escalation
|
|
28
|
+
* 1. parseProblemTypeSection happy-path UDP + confidence 0.85
|
|
29
|
+
* 2. parseProblemTypeSection (no signal) -> null
|
|
30
|
+
* 3. parseProblemTypeSection type-only (no confidence) -> tolerant
|
|
31
|
+
* 4. parseProblemTypeSection out-of-range confidence -> null
|
|
32
|
+
* 5. parseProblemTypeSection unknown type 'FOO' -> {type: unknown}
|
|
33
|
+
* 6. routeByProblemType('UDP', 0.85) -> exploration skills
|
|
34
|
+
* 7. routeByProblemType('IDP', 0.8) -> definition-seeking skills
|
|
35
|
+
* 8. routeByProblemType('WDP', 0.9) -> execution skills
|
|
36
|
+
* 9. routeByProblemType('unknown', null) -> empty + fallback reason
|
|
37
|
+
* 10. routeByProblemType(null, null) -> same as unknown
|
|
38
|
+
* 11. detectWickedEscalation(null) -> false
|
|
39
|
+
* 12. detectWickedEscalation(score 7) -> false
|
|
40
|
+
* 13. detectWickedEscalation(score 8) -> true
|
|
41
|
+
* 14. detectWickedEscalation(score 10) -> true
|
|
42
|
+
* 15. applyWickedOverride sets wicked_override:true + Appendix E R4
|
|
43
|
+
* 16. Canon Part 3 10-verb traceability across all routing tables
|
|
44
|
+
* 17. Low-confidence routing reason annotation
|
|
45
|
+
* 18. Suppress_skills array invariant + null-safe shape
|
|
46
|
+
*
|
|
47
|
+
* Task 2 (Tests 19-21): navigation-engine.cjs decide() integration
|
|
48
|
+
* 19. decide() with IDP fixture surfaces routing in chosen_rationale
|
|
49
|
+
* 20. decide() with wicked_score 9 surfaces wicked escalation
|
|
50
|
+
* 21. decide() with tier_0 (absent BRAIN.md) -- no regression
|
|
51
|
+
*
|
|
52
|
+
* Task 3 (Tests 22-24): brain-client.isAvailable() upgrade
|
|
53
|
+
* 22. Brain reachable + IDP fresh -> mode_a
|
|
54
|
+
* 23. Brain unreachable + brain_offline -> mode_b; routing still works
|
|
55
|
+
* 24. brain-client require failure -> brainAvailable=false; no throw
|
|
56
|
+
*
|
|
57
|
+
* Registered in lib/memory/run-feynman-tests.cjs.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
const assert = require('node:assert/strict');
|
|
61
|
+
const fs = require('node:fs');
|
|
62
|
+
const path = require('node:path');
|
|
63
|
+
const os = require('node:os');
|
|
64
|
+
const { spawnSync } = require('node:child_process');
|
|
65
|
+
|
|
66
|
+
const REPO = path.resolve(__dirname, '..', '..');
|
|
67
|
+
const ROUTER_PATH = path.join(REPO, 'lib/core/problem-type-router.cjs');
|
|
68
|
+
const ENGINE_PATH = path.join(REPO, 'lib/core/navigation-engine.cjs');
|
|
69
|
+
const SHARED_PATH = path.join(REPO, 'lib/core/navigation-engine-shared.cjs');
|
|
70
|
+
const CLASSIFIER_PATH = path.join(REPO, 'scripts/intent-classifier.cjs');
|
|
71
|
+
|
|
72
|
+
function requireRouter() {
|
|
73
|
+
return require(ROUTER_PATH);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function requireEngine() {
|
|
77
|
+
return require(ENGINE_PATH);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function requireShared() {
|
|
81
|
+
return require(SHARED_PATH);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---------- Test scaffolding ----------
|
|
85
|
+
|
|
86
|
+
let passed = 0;
|
|
87
|
+
let failed = 0;
|
|
88
|
+
function run(name, fn) {
|
|
89
|
+
try {
|
|
90
|
+
fn();
|
|
91
|
+
process.stdout.write('ok ' + name + '\n');
|
|
92
|
+
passed += 1;
|
|
93
|
+
} catch (err) {
|
|
94
|
+
process.stderr.write('FAIL ' + name + '\n');
|
|
95
|
+
process.stderr.write(String(err && err.stack ? err.stack : err) + '\n');
|
|
96
|
+
failed += 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ---------- Section-body fixture helpers ----------
|
|
101
|
+
|
|
102
|
+
function makeProblemTypeSection(bodyText) {
|
|
103
|
+
if (bodyText === null) return null;
|
|
104
|
+
return { body: bodyText, tokens_estimate: Math.max(1, Math.ceil(bodyText.length / 4)) };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function makeWickedSection(score) {
|
|
108
|
+
if (score === null) return null;
|
|
109
|
+
return {
|
|
110
|
+
body: '- wicked_score: ' + score + '\n- rationale: fixture',
|
|
111
|
+
tokens_estimate: 8,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// =========================================================
|
|
116
|
+
// Task 1 -- parser + routing tables (Tests 1..18)
|
|
117
|
+
// =========================================================
|
|
118
|
+
|
|
119
|
+
run('Test 1: parseProblemTypeSection happy-path UDP + confidence 0.85', () => {
|
|
120
|
+
const { parseProblemTypeSection } = requireRouter();
|
|
121
|
+
const section = makeProblemTypeSection('- type: UDP\n- confidence: 0.85\n- rationale: fixture');
|
|
122
|
+
const out = parseProblemTypeSection(section);
|
|
123
|
+
assert.equal(out.type, 'UDP');
|
|
124
|
+
assert.equal(Math.abs(out.confidence - 0.85) < 1e-9, true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
run('Test 2: parseProblemTypeSection (no signal) -> null', () => {
|
|
128
|
+
const { parseProblemTypeSection } = requireRouter();
|
|
129
|
+
const section = makeProblemTypeSection('(no signal)');
|
|
130
|
+
const out = parseProblemTypeSection(section);
|
|
131
|
+
assert.equal(out, null);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
run('Test 3: parseProblemTypeSection type-only -> tolerant {type, confidence:null}', () => {
|
|
135
|
+
const { parseProblemTypeSection } = requireRouter();
|
|
136
|
+
const section = makeProblemTypeSection('- type: UDP');
|
|
137
|
+
const out = parseProblemTypeSection(section);
|
|
138
|
+
assert.equal(out.type, 'UDP');
|
|
139
|
+
assert.equal(out.confidence, null);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
run('Test 4: parseProblemTypeSection out-of-range confidence rejected', () => {
|
|
143
|
+
const { parseProblemTypeSection } = requireRouter();
|
|
144
|
+
// > 1 rejected
|
|
145
|
+
const section1 = makeProblemTypeSection('- type: UDP\n- confidence: 1.5');
|
|
146
|
+
const out1 = parseProblemTypeSection(section1);
|
|
147
|
+
assert.equal(out1.type, 'UDP');
|
|
148
|
+
assert.equal(out1.confidence, null,
|
|
149
|
+
'confidence > 1 must be null; got ' + out1.confidence);
|
|
150
|
+
// 0.0 and 1.0 edge cases ARE permitted.
|
|
151
|
+
const section2 = makeProblemTypeSection('- type: WDP\n- confidence: 1.0');
|
|
152
|
+
const out2 = parseProblemTypeSection(section2);
|
|
153
|
+
assert.equal(out2.confidence, 1.0);
|
|
154
|
+
const section3 = makeProblemTypeSection('- type: WDP\n- confidence: 0.0');
|
|
155
|
+
const out3 = parseProblemTypeSection(section3);
|
|
156
|
+
assert.equal(out3.confidence, 0.0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
run('Test 5: parseProblemTypeSection unknown type FOO -> {type: unknown}', () => {
|
|
160
|
+
const { parseProblemTypeSection } = requireRouter();
|
|
161
|
+
const section = makeProblemTypeSection('- type: FOO\n- confidence: 0.5');
|
|
162
|
+
const out = parseProblemTypeSection(section);
|
|
163
|
+
assert.equal(out.type, 'unknown');
|
|
164
|
+
assert.equal(out.confidence, 0.5);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
run('Test 6: routeByProblemType(UDP, 0.85) -> exploration skills', () => {
|
|
168
|
+
const { routeByProblemType } = requireRouter();
|
|
169
|
+
const out = routeByProblemType('UDP', 0.85);
|
|
170
|
+
assert.deepEqual(out.recommended_skills, [
|
|
171
|
+
'explore-domains',
|
|
172
|
+
'beautiful-question',
|
|
173
|
+
'whitespace',
|
|
174
|
+
'find-analogies',
|
|
175
|
+
'find-connections',
|
|
176
|
+
]);
|
|
177
|
+
assert.deepEqual(out.suppressed_skills, []);
|
|
178
|
+
assert.equal(/Undefined/i.test(out.reason), true);
|
|
179
|
+
assert.equal(/exploration/i.test(out.reason), true);
|
|
180
|
+
assert.equal(out.wicked_override, false);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
run('Test 7: routeByProblemType(IDP, 0.8) -> definition-seeking skills', () => {
|
|
184
|
+
const { routeByProblemType } = requireRouter();
|
|
185
|
+
const out = routeByProblemType('IDP', 0.8);
|
|
186
|
+
assert.deepEqual(out.recommended_skills, [
|
|
187
|
+
'beautiful-question',
|
|
188
|
+
'structure-argument',
|
|
189
|
+
'mullins',
|
|
190
|
+
'lean-canvas',
|
|
191
|
+
'map-unknowns',
|
|
192
|
+
]);
|
|
193
|
+
assert.equal(/Ill-Defined/i.test(out.reason), true);
|
|
194
|
+
assert.equal(/definition/i.test(out.reason), true);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
run('Test 8: routeByProblemType(WDP, 0.9) -> execution skills', () => {
|
|
198
|
+
const { routeByProblemType } = requireRouter();
|
|
199
|
+
const out = routeByProblemType('WDP', 0.9);
|
|
200
|
+
assert.deepEqual(out.recommended_skills, [
|
|
201
|
+
'grade',
|
|
202
|
+
'deep-grade',
|
|
203
|
+
'score-innovation',
|
|
204
|
+
'build-thesis',
|
|
205
|
+
'challenge-assumptions',
|
|
206
|
+
]);
|
|
207
|
+
assert.equal(/Well-Defined/i.test(out.reason), true);
|
|
208
|
+
assert.equal(/execution/i.test(out.reason), true);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
run('Test 9: routeByProblemType(unknown, null) -> empty + fallback reason', () => {
|
|
212
|
+
const { routeByProblemType } = requireRouter();
|
|
213
|
+
const out = routeByProblemType('unknown', null);
|
|
214
|
+
assert.deepEqual(out.recommended_skills, []);
|
|
215
|
+
assert.deepEqual(out.suppressed_skills, []);
|
|
216
|
+
assert.equal(/unavailable|fallback/i.test(out.reason), true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
run('Test 10: routeByProblemType(null, null) -> same as unknown case', () => {
|
|
220
|
+
const { routeByProblemType } = requireRouter();
|
|
221
|
+
const out = routeByProblemType(null, null);
|
|
222
|
+
assert.deepEqual(out.recommended_skills, []);
|
|
223
|
+
assert.deepEqual(out.suppressed_skills, []);
|
|
224
|
+
assert.equal(/unavailable|fallback/i.test(out.reason), true);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
run('Test 11: detectWickedEscalation(null) -> false', () => {
|
|
228
|
+
const { detectWickedEscalation } = requireRouter();
|
|
229
|
+
assert.equal(detectWickedEscalation(null), false);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
run('Test 12: detectWickedEscalation(score 7) -> false', () => {
|
|
233
|
+
const { detectWickedEscalation } = requireRouter();
|
|
234
|
+
const section = makeWickedSection(7);
|
|
235
|
+
assert.equal(detectWickedEscalation(section), false);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
run('Test 13: detectWickedEscalation(score 8) -> true', () => {
|
|
239
|
+
const { detectWickedEscalation } = requireRouter();
|
|
240
|
+
const section = makeWickedSection(8);
|
|
241
|
+
assert.equal(detectWickedEscalation(section), true);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
run('Test 14: detectWickedEscalation(score 10) -> true', () => {
|
|
245
|
+
const { detectWickedEscalation } = requireRouter();
|
|
246
|
+
const section = makeWickedSection(10);
|
|
247
|
+
assert.equal(detectWickedEscalation(section), true);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
run('Test 15: applyWickedOverride sets wicked_override:true + Canon Appendix E R4', () => {
|
|
251
|
+
const { routeByProblemType, applyWickedOverride } = requireRouter();
|
|
252
|
+
const base = routeByProblemType('IDP', 0.8);
|
|
253
|
+
const out = applyWickedOverride(base);
|
|
254
|
+
assert.equal(out.wicked_override, true);
|
|
255
|
+
// Wicked override skills per Canon Appendix E R4 family.
|
|
256
|
+
assert.deepEqual(out.recommended_skills, [
|
|
257
|
+
'challenge-assumptions',
|
|
258
|
+
'find-bottlenecks',
|
|
259
|
+
'scenario-plan',
|
|
260
|
+
'explore-futures',
|
|
261
|
+
]);
|
|
262
|
+
assert.equal(/Wicked|Appendix E R4/i.test(out.reason), true);
|
|
263
|
+
assert.equal(/Canon Appendix E R4/.test(out.reason), true,
|
|
264
|
+
'Wicked override reason must cite Canon Appendix E R4 explicitly; got: ' + out.reason);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
run('Test 16: Canon Part 3 10-verb traceability across routing tables', () => {
|
|
268
|
+
const { TYPE_VERB_MAPPING, WICKED_VERB_MAPPING } = requireRouter();
|
|
269
|
+
const { CANONICAL_VERBS } = requireShared();
|
|
270
|
+
const canonSet = new Set(CANONICAL_VERBS);
|
|
271
|
+
// Every type table maps each skill to a canonical verb.
|
|
272
|
+
for (const typeKey of Object.keys(TYPE_VERB_MAPPING)) {
|
|
273
|
+
const skills = TYPE_VERB_MAPPING[typeKey];
|
|
274
|
+
for (const entry of skills) {
|
|
275
|
+
assert.equal(canonSet.has(entry.verb), true,
|
|
276
|
+
typeKey + ' skill ' + entry.skill + ' verb ' + entry.verb + ' not in CANONICAL_VERBS');
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Wicked table also maps to canonical verbs.
|
|
280
|
+
for (const entry of WICKED_VERB_MAPPING) {
|
|
281
|
+
assert.equal(canonSet.has(entry.verb), true,
|
|
282
|
+
'Wicked skill ' + entry.skill + ' verb ' + entry.verb + ' not in CANONICAL_VERBS');
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
run('Test 17: Low-confidence (< 0.5) routing reason annotation', () => {
|
|
287
|
+
const { routeByProblemType } = requireRouter();
|
|
288
|
+
// High-conf reason has no low-conf marker.
|
|
289
|
+
const high = routeByProblemType('UDP', 0.85);
|
|
290
|
+
assert.equal(/low confidence/i.test(high.reason), false);
|
|
291
|
+
// Low-conf reason carries the marker.
|
|
292
|
+
const low = routeByProblemType('UDP', 0.2);
|
|
293
|
+
assert.equal(/low confidence/i.test(low.reason), true);
|
|
294
|
+
// Skills still surface (caller decides whether to weight down).
|
|
295
|
+
assert.equal(low.recommended_skills.length > 0, true);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
run('Test 18: routeByProblemType output shape invariants (suppressed_skills array; wicked_override bool)', () => {
|
|
299
|
+
const { routeByProblemType, applyWickedOverride } = requireRouter();
|
|
300
|
+
for (const t of ['UDP', 'IDP', 'WDP', 'unknown', null]) {
|
|
301
|
+
const out = routeByProblemType(t, 0.5);
|
|
302
|
+
assert.equal(Array.isArray(out.recommended_skills), true);
|
|
303
|
+
assert.equal(Array.isArray(out.suppressed_skills), true);
|
|
304
|
+
assert.equal(typeof out.reason, 'string');
|
|
305
|
+
assert.equal(typeof out.wicked_override, 'boolean');
|
|
306
|
+
assert.equal(out.wicked_override, false,
|
|
307
|
+
'baseline routing must not set wicked_override');
|
|
308
|
+
const wicked = applyWickedOverride(out);
|
|
309
|
+
assert.equal(Array.isArray(wicked.recommended_skills), true);
|
|
310
|
+
assert.equal(wicked.wicked_override, true);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// =========================================================
|
|
315
|
+
// Task 2 -- decide() integration (Tests 19..21)
|
|
316
|
+
// =========================================================
|
|
317
|
+
|
|
318
|
+
function makeBrainWithProblemType(typeBody, wickedScore) {
|
|
319
|
+
return {
|
|
320
|
+
exists: true,
|
|
321
|
+
section: 'market-analysis',
|
|
322
|
+
brain_generated_at: '2026-04-27T12:00:00Z',
|
|
323
|
+
brain_graph_version: 1,
|
|
324
|
+
governing_thought_hash: 'sha256:fixture',
|
|
325
|
+
staleness: 'fresh',
|
|
326
|
+
stale_reason: null,
|
|
327
|
+
author: 'brain',
|
|
328
|
+
confidence_baseline: 0.5,
|
|
329
|
+
parse_failed: false,
|
|
330
|
+
sections: {
|
|
331
|
+
pattern_matches: null,
|
|
332
|
+
framework_chain_predictions: null,
|
|
333
|
+
cross_domain_analogies: null,
|
|
334
|
+
wicked_indicators: wickedScore !== null ? makeWickedSection(wickedScore) : null,
|
|
335
|
+
unfilled_opportunity_matches: null,
|
|
336
|
+
assessment_thinking_chain_position: null,
|
|
337
|
+
problemtype_classification: typeBody !== null ? makeProblemTypeSection(typeBody) : null,
|
|
338
|
+
flagged_contradictions_xroom: null,
|
|
339
|
+
hsi_signals: null,
|
|
340
|
+
},
|
|
341
|
+
flagged_weaknesses: [],
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function makeQuadruple(brain) {
|
|
346
|
+
return {
|
|
347
|
+
room: { exists: true, identity_text: 'fixture', references: [] },
|
|
348
|
+
state: { exists: true, artifact_count: 1, completeness_score: 0.5 },
|
|
349
|
+
reasoning: {
|
|
350
|
+
exists: true,
|
|
351
|
+
governing_thought: 'fixture thought',
|
|
352
|
+
reasoning_health_score: 0.7,
|
|
353
|
+
is_stale: false,
|
|
354
|
+
arguments: [],
|
|
355
|
+
},
|
|
356
|
+
brain: brain,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
run('Test 19: decide() with IDP classification surfaces routing in chosen_rationale', () => {
|
|
361
|
+
const { decide } = requireEngine();
|
|
362
|
+
const brain = makeBrainWithProblemType('- type: IDP\n- confidence: 0.8', null);
|
|
363
|
+
const out = decide(
|
|
364
|
+
{ sectionPath: '/tmp/fixture', sessionId: 's1' },
|
|
365
|
+
{
|
|
366
|
+
quadruple: makeQuadruple(brain),
|
|
367
|
+
brainAvailable: true,
|
|
368
|
+
userPersona: null,
|
|
369
|
+
intentSignal: null,
|
|
370
|
+
}
|
|
371
|
+
);
|
|
372
|
+
// chosen_rationale must reference IDP and definition-seeking routing.
|
|
373
|
+
const rationale = out.decision_trace.chosen_rationale || '';
|
|
374
|
+
assert.equal(/IDP/i.test(rationale), true,
|
|
375
|
+
'chosen_rationale must reference IDP; got: ' + rationale);
|
|
376
|
+
assert.equal(/definition|Ill-Defined/i.test(rationale), true,
|
|
377
|
+
'chosen_rationale must reference definition-seeking; got: ' + rationale);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
run('Test 20: decide() with wicked_score 9 surfaces wicked escalation in rationale', () => {
|
|
381
|
+
const { decide } = requireEngine();
|
|
382
|
+
// Wicked override applies regardless of base type. Provide IDP + wicked_score 9.
|
|
383
|
+
const brain = makeBrainWithProblemType('- type: IDP\n- confidence: 0.8', 9);
|
|
384
|
+
const out = decide(
|
|
385
|
+
{ sectionPath: '/tmp/fixture', sessionId: 's1' },
|
|
386
|
+
{
|
|
387
|
+
quadruple: makeQuadruple(brain),
|
|
388
|
+
brainAvailable: true,
|
|
389
|
+
userPersona: null,
|
|
390
|
+
intentSignal: null,
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
const rationale = out.decision_trace.chosen_rationale || '';
|
|
394
|
+
assert.equal(/wicked|Appendix E R4/i.test(rationale), true,
|
|
395
|
+
'wicked rationale must reference wicked escalation; got: ' + rationale);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
run('Test 21: decide() with tier_0 (absent BRAIN.md) -- no regression', () => {
|
|
399
|
+
const { decide } = requireEngine();
|
|
400
|
+
// No brain -> tier_0; problem-type routing contributes nothing.
|
|
401
|
+
const quadruple = {
|
|
402
|
+
room: { exists: true, identity_text: 'fx', references: [] },
|
|
403
|
+
state: { exists: true, artifact_count: 0, completeness_score: 0 },
|
|
404
|
+
reasoning: { exists: false, governing_thought: null, reasoning_health_score: 0, is_stale: true, arguments: [] },
|
|
405
|
+
brain: null,
|
|
406
|
+
};
|
|
407
|
+
const out = decide(
|
|
408
|
+
{ sectionPath: '/tmp/fixture', sessionId: 's1' },
|
|
409
|
+
{
|
|
410
|
+
quadruple: quadruple,
|
|
411
|
+
brainAvailable: false,
|
|
412
|
+
userPersona: null,
|
|
413
|
+
intentSignal: null,
|
|
414
|
+
}
|
|
415
|
+
);
|
|
416
|
+
assert.equal(out.decision_trace.brain_md_tier_mode, 'tier_0');
|
|
417
|
+
// Engine never throws and never claims a problem-type rationale when brain
|
|
418
|
+
// is absent.
|
|
419
|
+
const rationale = out.decision_trace.chosen_rationale || '';
|
|
420
|
+
assert.equal(/IDP|UDP|WDP/i.test(rationale), false,
|
|
421
|
+
'tier_0 rationale must NOT cite problem-type when brain is absent; got: ' + rationale);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// =========================================================
|
|
425
|
+
// Task 3 -- brain-client.isAvailable() upgrade (Tests 22..24)
|
|
426
|
+
// =========================================================
|
|
427
|
+
|
|
428
|
+
// Tests 22-24 spawn the classifier in a child process with mocked
|
|
429
|
+
// brain-client modules. We use require-cache injection in a tiny harness
|
|
430
|
+
// script to simulate isAvailable returning true / false / module-missing.
|
|
431
|
+
|
|
432
|
+
function runClassifierWithBrainMock(opts) {
|
|
433
|
+
// opts.brainAvailableValue: true | false | 'throw' | 'absent' (don't replace)
|
|
434
|
+
// opts.brainMd: optional BRAIN.md content to plant in the section
|
|
435
|
+
// opts.userMd: optional USER.md content
|
|
436
|
+
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'p91-07-mock-'));
|
|
437
|
+
try {
|
|
438
|
+
const roomsRoot = path.join(tmpRoot, 'MindrianRooms');
|
|
439
|
+
const roomDir = path.join(roomsRoot, 'fixture-room');
|
|
440
|
+
const sectionDir = path.join(roomDir, 'market-analysis');
|
|
441
|
+
fs.mkdirSync(sectionDir, { recursive: true });
|
|
442
|
+
fs.mkdirSync(path.join(roomsRoot, '.rooms'), { recursive: true });
|
|
443
|
+
fs.writeFileSync(
|
|
444
|
+
path.join(roomsRoot, '.rooms', 'registry.json'),
|
|
445
|
+
JSON.stringify({ active: 'fixture-room', rooms: { 'fixture-room': {} } }, null, 2)
|
|
446
|
+
);
|
|
447
|
+
fs.writeFileSync(
|
|
448
|
+
path.join(roomDir, 'STATE.md'),
|
|
449
|
+
'---\nproject: fixture\n---\n\n# STATE\n'
|
|
450
|
+
);
|
|
451
|
+
fs.writeFileSync(
|
|
452
|
+
path.join(roomDir, 'ROOM.md'),
|
|
453
|
+
'---\nname: fixture-room\n---\n\n# Fixture\n'
|
|
454
|
+
);
|
|
455
|
+
fs.writeFileSync(
|
|
456
|
+
path.join(sectionDir, 'ROOM.md'),
|
|
457
|
+
'---\nname: market-analysis\n---\n\n# Market Analysis\n'
|
|
458
|
+
);
|
|
459
|
+
fs.writeFileSync(
|
|
460
|
+
path.join(sectionDir, 'MINTO.md'),
|
|
461
|
+
'---\nfm_version: 88\ngoverning_thought: Customers will pay for X\nlast_generated_at: 2026-04-27T12:00:00Z\nlast_artifact_write_seen_at: 2026-04-27T11:00:00Z\nreasoning_health_score: 0.8\nflagged_weaknesses: []\ndecision_log: []\n---\n\n# MINTO\n'
|
|
462
|
+
);
|
|
463
|
+
if (opts.brainMd !== undefined) {
|
|
464
|
+
fs.writeFileSync(path.join(sectionDir, 'BRAIN.md'), opts.brainMd);
|
|
465
|
+
}
|
|
466
|
+
// Active section pointer
|
|
467
|
+
fs.mkdirSync(path.join(roomDir, '.mindrian'), { recursive: true });
|
|
468
|
+
fs.writeFileSync(
|
|
469
|
+
path.join(roomDir, '.mindrian', 'active-section.json'),
|
|
470
|
+
JSON.stringify({ section: 'market-analysis' })
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
// Build a tiny mock harness that replaces brain-client in require.cache
|
|
474
|
+
// before invoking the classifier.
|
|
475
|
+
const harness = `'use strict';
|
|
476
|
+
const Module = require('module');
|
|
477
|
+
const path = require('path');
|
|
478
|
+
const realResolve = Module._resolveFilename;
|
|
479
|
+
Module._resolveFilename = function(request, parent, isMain, options) {
|
|
480
|
+
if (typeof request === 'string' && request.indexOf('brain-client.cjs') !== -1) {
|
|
481
|
+
if (${JSON.stringify(opts.brainAvailableValue)} === 'absent') {
|
|
482
|
+
// Trigger MODULE_NOT_FOUND
|
|
483
|
+
const e = new Error("Cannot find module '" + request + "'");
|
|
484
|
+
e.code = 'MODULE_NOT_FOUND';
|
|
485
|
+
throw e;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return realResolve.call(this, request, parent, isMain, options);
|
|
489
|
+
};
|
|
490
|
+
// Pre-populate require.cache for brain-client with a mock that responds
|
|
491
|
+
// according to the value flag.
|
|
492
|
+
const realBrainPath = ${JSON.stringify(path.join(REPO, 'lib/core/brain-client.cjs'))};
|
|
493
|
+
if (${JSON.stringify(opts.brainAvailableValue)} === 'throw') {
|
|
494
|
+
require.cache[realBrainPath] = {
|
|
495
|
+
id: realBrainPath, filename: realBrainPath, loaded: true,
|
|
496
|
+
exports: { isAvailable: function() { throw new Error('mock-throw'); } },
|
|
497
|
+
};
|
|
498
|
+
} else if (${JSON.stringify(opts.brainAvailableValue)} === true) {
|
|
499
|
+
require.cache[realBrainPath] = {
|
|
500
|
+
id: realBrainPath, filename: realBrainPath, loaded: true,
|
|
501
|
+
exports: { isAvailable: function() { return true; }, schema: function() { return {}; } },
|
|
502
|
+
};
|
|
503
|
+
} else if (${JSON.stringify(opts.brainAvailableValue)} === false) {
|
|
504
|
+
require.cache[realBrainPath] = {
|
|
505
|
+
id: realBrainPath, filename: realBrainPath, loaded: true,
|
|
506
|
+
exports: { isAvailable: function() { return false; } },
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
// Now run the classifier. It reads stdin -- we feed via process.stdin manually.
|
|
510
|
+
process.env.MINDRIAN_ROOMS_ROOT = ${JSON.stringify(roomsRoot)};
|
|
511
|
+
process.env.CLAUDE_SESSION_ID = 'mock-session-22';
|
|
512
|
+
require(${JSON.stringify(CLASSIFIER_PATH)});
|
|
513
|
+
`;
|
|
514
|
+
const harnessPath = path.join(tmpRoot, 'harness.cjs');
|
|
515
|
+
fs.writeFileSync(harnessPath, harness);
|
|
516
|
+
|
|
517
|
+
const res = spawnSync(process.execPath, [harnessPath], {
|
|
518
|
+
input: 'tell me about market sizing',
|
|
519
|
+
encoding: 'utf8',
|
|
520
|
+
timeout: 10000,
|
|
521
|
+
env: Object.assign({}, process.env, {
|
|
522
|
+
MINDRIAN_ROOMS_ROOT: roomsRoot,
|
|
523
|
+
CLAUDE_SESSION_ID: 'mock-session-22',
|
|
524
|
+
MINDRIAN_COPILOT_INJECT_FINDINGS: '0',
|
|
525
|
+
}),
|
|
526
|
+
});
|
|
527
|
+
return {
|
|
528
|
+
stdout: res.stdout || '',
|
|
529
|
+
stderr: res.stderr || '',
|
|
530
|
+
status: res.status,
|
|
531
|
+
tmpRoot: tmpRoot,
|
|
532
|
+
roomDir: roomDir,
|
|
533
|
+
sectionDir: sectionDir,
|
|
534
|
+
};
|
|
535
|
+
} finally {
|
|
536
|
+
// Best-effort cleanup; tests inspect the trace inline before this fires.
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
run('Test 22: Brain reachable (isAvailable -> true) + fresh BRAIN.md IDP -> mode_a', () => {
|
|
541
|
+
// BRAIN.md fixture for IDP at confidence 0.8.
|
|
542
|
+
const brainMd =
|
|
543
|
+
'---\n' +
|
|
544
|
+
'fm_version: 90\n' +
|
|
545
|
+
'brain_generated_at: 2026-04-27T11:00:00Z\n' +
|
|
546
|
+
'brain_graph_version: 1\n' +
|
|
547
|
+
'governing_thought_hash: sha256:fixture\n' +
|
|
548
|
+
'staleness: fresh\n' +
|
|
549
|
+
'stale_reason: null\n' +
|
|
550
|
+
'author: brain\n' +
|
|
551
|
+
'confidence_baseline: 0.5\n' +
|
|
552
|
+
'flagged_weaknesses: []\n' +
|
|
553
|
+
'---\n\n' +
|
|
554
|
+
'# BRAIN.md\n\n' +
|
|
555
|
+
'## ProblemType Classification\n\n' +
|
|
556
|
+
'- type: IDP\n' +
|
|
557
|
+
'- confidence: 0.8\n' +
|
|
558
|
+
'- rationale: fixture\n';
|
|
559
|
+
const result = runClassifierWithBrainMock({
|
|
560
|
+
brainAvailableValue: true,
|
|
561
|
+
brainMd: brainMd,
|
|
562
|
+
});
|
|
563
|
+
// The classifier should have written a decision-trace JSON file.
|
|
564
|
+
const tracePath = path.join(result.roomDir, '.mindrian', 'decision-traces', 'mock-session-22.json');
|
|
565
|
+
assert.equal(fs.existsSync(tracePath), true,
|
|
566
|
+
'decision-trace must exist; stderr: ' + result.stderr);
|
|
567
|
+
const data = JSON.parse(fs.readFileSync(tracePath, 'utf8'));
|
|
568
|
+
assert.equal(Array.isArray(data.traces), true);
|
|
569
|
+
assert.equal(data.traces.length >= 1, true);
|
|
570
|
+
const last = data.traces[data.traces.length - 1];
|
|
571
|
+
// Brain reachable + fresh BRAIN.md -> mode_a.
|
|
572
|
+
assert.equal(last.brain_md_tier_mode, 'mode_a',
|
|
573
|
+
'expected mode_a; got ' + last.brain_md_tier_mode + '; stderr: ' + result.stderr);
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
run('Test 23: Brain unreachable (isAvailable -> false) + brain_offline -> mode_b; routing still works locally', () => {
|
|
577
|
+
// BRAIN.md fixture for IDP, marked stale with brain_offline reason.
|
|
578
|
+
const brainMd =
|
|
579
|
+
'---\n' +
|
|
580
|
+
'fm_version: 90\n' +
|
|
581
|
+
'brain_generated_at: 2026-04-27T11:00:00Z\n' +
|
|
582
|
+
'brain_graph_version: 1\n' +
|
|
583
|
+
'governing_thought_hash: sha256:fixture\n' +
|
|
584
|
+
'staleness: stale\n' +
|
|
585
|
+
'stale_reason: brain_offline\n' +
|
|
586
|
+
'author: brain\n' +
|
|
587
|
+
'confidence_baseline: 0.5\n' +
|
|
588
|
+
'flagged_weaknesses: []\n' +
|
|
589
|
+
'---\n\n' +
|
|
590
|
+
'# BRAIN.md\n\n' +
|
|
591
|
+
'## ProblemType Classification\n\n' +
|
|
592
|
+
'- type: IDP\n' +
|
|
593
|
+
'- confidence: 0.8\n';
|
|
594
|
+
const result = runClassifierWithBrainMock({
|
|
595
|
+
brainAvailableValue: false,
|
|
596
|
+
brainMd: brainMd,
|
|
597
|
+
});
|
|
598
|
+
const tracePath = path.join(result.roomDir, '.mindrian', 'decision-traces', 'mock-session-22.json');
|
|
599
|
+
assert.equal(fs.existsSync(tracePath), true,
|
|
600
|
+
'decision-trace must exist; stderr: ' + result.stderr);
|
|
601
|
+
const data = JSON.parse(fs.readFileSync(tracePath, 'utf8'));
|
|
602
|
+
const last = data.traces[data.traces.length - 1];
|
|
603
|
+
// Brain unreachable + brain_offline -> mode_b per Phase 90 contract.
|
|
604
|
+
assert.equal(last.brain_md_tier_mode, 'mode_b',
|
|
605
|
+
'expected mode_b; got ' + last.brain_md_tier_mode + '; stderr: ' + result.stderr);
|
|
606
|
+
// RECOMMENDED never rendered in mode_b.
|
|
607
|
+
assert.equal(last.brain_md_recommended_marker_rendered, false);
|
|
608
|
+
// Local problem-type routing still contributes (rationale should mention IDP).
|
|
609
|
+
const rationale = last.chosen_rationale || '';
|
|
610
|
+
assert.equal(/IDP/i.test(rationale), true,
|
|
611
|
+
'mode_b should still surface local IDP routing; got: ' + rationale);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
run('Test 24: brain-client require failure -> brainAvailable=false; no throw', () => {
|
|
615
|
+
// brainAvailableValue: 'throw' will inject a module that throws on isAvailable.
|
|
616
|
+
// The intent-classifier must catch and default to brainAvailable=false.
|
|
617
|
+
const brainMd =
|
|
618
|
+
'---\n' +
|
|
619
|
+
'fm_version: 90\n' +
|
|
620
|
+
'brain_generated_at: 2026-04-27T11:00:00Z\n' +
|
|
621
|
+
'brain_graph_version: 1\n' +
|
|
622
|
+
'governing_thought_hash: sha256:fixture\n' +
|
|
623
|
+
'staleness: stale\n' +
|
|
624
|
+
'stale_reason: brain_offline\n' +
|
|
625
|
+
'author: brain\n' +
|
|
626
|
+
'confidence_baseline: 0.5\n' +
|
|
627
|
+
'flagged_weaknesses: []\n' +
|
|
628
|
+
'---\n\n' +
|
|
629
|
+
'# BRAIN.md\n\n' +
|
|
630
|
+
'## ProblemType Classification\n\n' +
|
|
631
|
+
'- type: WDP\n' +
|
|
632
|
+
'- confidence: 0.7\n';
|
|
633
|
+
const result = runClassifierWithBrainMock({
|
|
634
|
+
brainAvailableValue: 'throw',
|
|
635
|
+
brainMd: brainMd,
|
|
636
|
+
});
|
|
637
|
+
// Classifier must NOT crash; exit 0 (advisory).
|
|
638
|
+
assert.equal(result.status, 0,
|
|
639
|
+
'classifier must exit 0 even when brain-client throws; got ' + result.status + '; stderr: ' + result.stderr);
|
|
640
|
+
const tracePath = path.join(result.roomDir, '.mindrian', 'decision-traces', 'mock-session-22.json');
|
|
641
|
+
assert.equal(fs.existsSync(tracePath), true);
|
|
642
|
+
const data = JSON.parse(fs.readFileSync(tracePath, 'utf8'));
|
|
643
|
+
const last = data.traces[data.traces.length - 1];
|
|
644
|
+
// brainAvailable defaults false -> mode_b (BRAIN.md is brain_offline) or tier_0.
|
|
645
|
+
assert.equal(last.brain_md_tier_mode === 'mode_b' || last.brain_md_tier_mode === 'tier_0', true,
|
|
646
|
+
'expected mode_b/tier_0 when isAvailable throws; got ' + last.brain_md_tier_mode);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
// =========================================================
|
|
650
|
+
// Suite tail
|
|
651
|
+
// =========================================================
|
|
652
|
+
|
|
653
|
+
process.stdout.write(
|
|
654
|
+
'\nProblem-Type Router tests: ' + passed + '/' + (passed + failed) + ' passed\n'
|
|
655
|
+
);
|
|
656
|
+
process.exit(failed === 0 ? 0 : 1);
|