@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,280 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
* Phase 89.5 Plan 01 -- Phase 4 commercial assessor (deterministic).
|
|
4
|
+
*
|
|
5
|
+
* Deterministic 3-field commercial layer consumed by the Phase 89.5-04
|
|
6
|
+
* top-level orchestrator (kickoff §5 Phase 4 Synthesis). Reads the post-
|
|
7
|
+
* breakthrough-scorer + post-fetcher rs_discovery shape and emits:
|
|
8
|
+
*
|
|
9
|
+
* {
|
|
10
|
+
* market_size_estimate: <string from frozen 5-bucket TAM/SAM table>,
|
|
11
|
+
* value_proposition: <string from frozen classification template table>,
|
|
12
|
+
* partnership_targets: <array derived from resolved_institutions + resolved_authors>,
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Hard contract:
|
|
16
|
+
* 1. NO runtime LLM call (no fetch, no brain-client, no spawn of model
|
|
17
|
+
* process). Pure-function from a frozen table lookup + array map.
|
|
18
|
+
* 2. Deterministic: same input -> byte-identical JSON.stringify(output)
|
|
19
|
+
* across N invocations.
|
|
20
|
+
* 3. Edge-case safe: zero industry signals, single expert, missing
|
|
21
|
+
* breakthrough_score, missing classification all produce deterministic
|
|
22
|
+
* safe defaults; never throws on missing fields. Only throw paths are
|
|
23
|
+
* Canon Part 8 forbidden-pattern violations on adversarial input.
|
|
24
|
+
* 4. Canon Part 8 chokepoint: FIRST line of body is auditQueryObject on
|
|
25
|
+
* the (rs_discovery, opts) tuple. Any forbidden field anywhere in the
|
|
26
|
+
* tuple raises ExternalEgressViolation BEFORE any computation.
|
|
27
|
+
*
|
|
28
|
+
* Frozen tables:
|
|
29
|
+
* VALUE_PROP_TEMPLATES -- keyed on classification ('structural_transfer',
|
|
30
|
+
* 'semantic_implementation', 'hybrid', '_fallback'). Larry-style
|
|
31
|
+
* template stems with [bridge_concept] / [source] / [target] /
|
|
32
|
+
* [outcome] placeholders that are filled deterministically from
|
|
33
|
+
* rs_discovery scalars (no free-form generation).
|
|
34
|
+
*
|
|
35
|
+
* MARKET_SIZE_BUCKETS -- 5 frozen TAM/SAM proxy buckets keyed on the
|
|
36
|
+
* 2D quantile of (industry_signals_count, breakthrough_score):
|
|
37
|
+
* emerging-niche (signals <= 1, score < 5)
|
|
38
|
+
* small-targeted (signals 2-3, score 5-7)
|
|
39
|
+
* mid-market (signals 4-6, score 6-8)
|
|
40
|
+
* large-market (signals 7-10, score 8-9)
|
|
41
|
+
* platform-scale (signals > 10, score >= 9)
|
|
42
|
+
* Edge: missing breakthrough_score -> 'unknown-bucket' (deterministic).
|
|
43
|
+
*
|
|
44
|
+
* Bucket thresholds tuned conservatively for v1.11.0-beta.1; expanding
|
|
45
|
+
* the bucket vocabulary requires a Plan 89.5-01-N revision (canon-amend
|
|
46
|
+
* discipline).
|
|
47
|
+
*
|
|
48
|
+
* Pure CJS, zero npm deps, no Node built-ins beyond core require.
|
|
49
|
+
*/
|
|
50
|
+
'use strict';
|
|
51
|
+
|
|
52
|
+
const { ExternalEgressViolation } = require('./rs-egress-violations.cjs');
|
|
53
|
+
const { auditQueryObject } = require('./rs-egress-prompts.cjs');
|
|
54
|
+
|
|
55
|
+
// ---------- Frozen invariants ----------
|
|
56
|
+
|
|
57
|
+
// Larry-style value-proposition template stems keyed on classification.
|
|
58
|
+
// Each stem is a deterministic template with [PLACEHOLDER] tokens that
|
|
59
|
+
// are filled from rs_discovery scalars. NO free-form text generation.
|
|
60
|
+
//
|
|
61
|
+
// Stem-prefix design rule: the first 12 characters of each rendered
|
|
62
|
+
// template string MUST differ across the three real classifications +
|
|
63
|
+
// the fallback so T8 (classification table coverage) can verify table
|
|
64
|
+
// distinctness on the rendered output without coupling to internal stem
|
|
65
|
+
// keys. The leading words below ('Apply' / 'Implement' / 'Bridge' /
|
|
66
|
+
// 'Cross-domain') satisfy the 12-char-distinct invariant.
|
|
67
|
+
const VALUE_PROP_TEMPLATES = Object.freeze({
|
|
68
|
+
structural_transfer:
|
|
69
|
+
'Apply [BRIDGE] from [SOURCE] to [TARGET] to unlock cross-domain advantage',
|
|
70
|
+
semantic_implementation:
|
|
71
|
+
'Implement [BRIDGE] in [TARGET] to compress time from insight to validated decision',
|
|
72
|
+
hybrid:
|
|
73
|
+
'Bridge [SOURCE] and [TARGET] via [BRIDGE] to unlock a defensible cross-domain moat',
|
|
74
|
+
_fallback:
|
|
75
|
+
'Cross-domain opportunity: combine [SOURCE] and [TARGET] to address an underserved gap',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 5-bucket TAM/SAM proxy table. Keyed on bucket-id; each entry is a
|
|
79
|
+
// frozen string. Bucket selection is deterministic via a 2D step-function
|
|
80
|
+
// over (industry_signals_count, breakthrough_score). See bucketize() below.
|
|
81
|
+
const MARKET_SIZE_BUCKETS = Object.freeze({
|
|
82
|
+
'unknown-bucket':
|
|
83
|
+
'unknown-bucket: insufficient signal to estimate market size',
|
|
84
|
+
'emerging-niche':
|
|
85
|
+
'emerging-niche: pre-market opportunity; demand signal not yet established',
|
|
86
|
+
'small-targeted':
|
|
87
|
+
'small-targeted: focused vertical with bounded TAM; early-stage adopters',
|
|
88
|
+
'mid-market':
|
|
89
|
+
'mid-market: established demand with measurable SAM; multi-segment reach',
|
|
90
|
+
'large-market':
|
|
91
|
+
'large-market: validated demand with broad SAM; cross-segment platform potential',
|
|
92
|
+
'platform-scale':
|
|
93
|
+
'platform-scale: category-defining opportunity with cross-vertical reach',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Frozen safe-default scalars.
|
|
97
|
+
const SAFE_DEFAULT_BRIDGE = 'cross-domain bridge concept';
|
|
98
|
+
const SAFE_DEFAULT_SOURCE = 'source domain';
|
|
99
|
+
const SAFE_DEFAULT_TARGET = 'target domain';
|
|
100
|
+
|
|
101
|
+
// ---------- bucketize ----------
|
|
102
|
+
//
|
|
103
|
+
// 2D step-function over (signals, score). Pure deterministic lookup.
|
|
104
|
+
//
|
|
105
|
+
// Bucket selection rules (in order; first match wins):
|
|
106
|
+
// missing breakthrough_score (score === null) -> 'unknown-bucket'
|
|
107
|
+
// signals <= 1 AND score < 5 -> 'emerging-niche'
|
|
108
|
+
// signals between 2-3 AND score in [5, 7] -> 'small-targeted'
|
|
109
|
+
// signals between 4-6 AND score in [6, 8] -> 'mid-market'
|
|
110
|
+
// signals between 7-10 AND score in [8, 9] -> 'large-market'
|
|
111
|
+
// signals > 10 AND score >= 9 -> 'platform-scale'
|
|
112
|
+
// anything else -> nearest-neighbor by signals
|
|
113
|
+
|
|
114
|
+
function bucketize(signals, score) {
|
|
115
|
+
if (score === null || score === undefined) return 'unknown-bucket';
|
|
116
|
+
const s = (typeof signals === 'number' && isFinite(signals)) ? signals : 0;
|
|
117
|
+
const b = (typeof score === 'number' && isFinite(score)) ? score : 0;
|
|
118
|
+
// Top-down: pick the highest-bucket the input qualifies for. Each bucket
|
|
119
|
+
// requires BOTH signals AND score to satisfy its threshold pair so a
|
|
120
|
+
// single high dimension cannot inflate the estimate.
|
|
121
|
+
if (s > 10 && b >= 9) return 'platform-scale';
|
|
122
|
+
if (s >= 7 && b >= 8) return 'large-market';
|
|
123
|
+
if (s >= 4 && b >= 6) return 'mid-market';
|
|
124
|
+
if (s >= 2 && b >= 5) return 'small-targeted';
|
|
125
|
+
return 'emerging-niche';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------- buildPartnershipTargets ----------
|
|
129
|
+
//
|
|
130
|
+
// Pure-function map from resolved_institutions + resolved_authors to a
|
|
131
|
+
// deterministic ordered array of partnership targets. Empty inputs yield
|
|
132
|
+
// [] (empty array). Authors precede institutions; both are sorted by the
|
|
133
|
+
// natural input order from the upstream fetcher (no re-sort here so
|
|
134
|
+
// upstream determinism propagates).
|
|
135
|
+
|
|
136
|
+
function buildPartnershipTargets(rs_discovery) {
|
|
137
|
+
if (!rs_discovery || typeof rs_discovery !== 'object') return [];
|
|
138
|
+
const out = [];
|
|
139
|
+
const authors = Array.isArray(rs_discovery.resolved_authors) ? rs_discovery.resolved_authors : [];
|
|
140
|
+
for (let i = 0; i < authors.length; i += 1) {
|
|
141
|
+
const a = authors[i];
|
|
142
|
+
if (!a || typeof a !== 'object') continue;
|
|
143
|
+
const name = (typeof a.name === 'string' && a.name.length > 0) ? a.name : null;
|
|
144
|
+
if (!name) continue;
|
|
145
|
+
out.push({
|
|
146
|
+
name: name,
|
|
147
|
+
type: 'author',
|
|
148
|
+
// Score = 1.0 - (i / authors.length) so the upstream-natural-order
|
|
149
|
+
// first author scores highest. Deterministic from input order.
|
|
150
|
+
score: 1.0 - (i / Math.max(authors.length, 1)),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const institutions = Array.isArray(rs_discovery.resolved_institutions) ? rs_discovery.resolved_institutions : [];
|
|
154
|
+
for (let i = 0; i < institutions.length; i += 1) {
|
|
155
|
+
const inst = institutions[i];
|
|
156
|
+
if (typeof inst !== 'string' || inst.length === 0) continue;
|
|
157
|
+
out.push({
|
|
158
|
+
name: inst,
|
|
159
|
+
type: 'institution',
|
|
160
|
+
score: 1.0 - (i / Math.max(institutions.length, 1)),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------- buildValueProposition ----------
|
|
167
|
+
//
|
|
168
|
+
// Deterministic template-fill from frozen VALUE_PROP_TEMPLATES. Picks
|
|
169
|
+
// the template by classification (with '_fallback' for missing); fills
|
|
170
|
+
// [BRIDGE] / [SOURCE] / [TARGET] tokens from rs_discovery scalars when
|
|
171
|
+
// present (with safe defaults otherwise).
|
|
172
|
+
|
|
173
|
+
function buildValueProposition(rs_discovery) {
|
|
174
|
+
const cls = (rs_discovery && typeof rs_discovery.classification === 'string'
|
|
175
|
+
&& (rs_discovery.classification in VALUE_PROP_TEMPLATES))
|
|
176
|
+
? rs_discovery.classification
|
|
177
|
+
: '_fallback';
|
|
178
|
+
let stem = VALUE_PROP_TEMPLATES[cls];
|
|
179
|
+
const bridge = (rs_discovery && typeof rs_discovery.bridge_concept === 'string'
|
|
180
|
+
&& rs_discovery.bridge_concept.length > 0)
|
|
181
|
+
? rs_discovery.bridge_concept
|
|
182
|
+
: SAFE_DEFAULT_BRIDGE;
|
|
183
|
+
const source = (rs_discovery && typeof rs_discovery.query_concept === 'string'
|
|
184
|
+
&& rs_discovery.query_concept.length > 0)
|
|
185
|
+
? rs_discovery.query_concept
|
|
186
|
+
: SAFE_DEFAULT_SOURCE;
|
|
187
|
+
const target = (rs_discovery && typeof rs_discovery.doc_concept === 'string'
|
|
188
|
+
&& rs_discovery.doc_concept.length > 0)
|
|
189
|
+
? rs_discovery.doc_concept
|
|
190
|
+
: SAFE_DEFAULT_TARGET;
|
|
191
|
+
// Token replacement is deterministic global string replace; no regex
|
|
192
|
+
// escaping needed because tokens are frozen literals.
|
|
193
|
+
stem = stem.split('[BRIDGE]').join(bridge);
|
|
194
|
+
stem = stem.split('[SOURCE]').join(source);
|
|
195
|
+
stem = stem.split('[TARGET]').join(target);
|
|
196
|
+
return stem;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ---------- buildMarketSizeEstimate ----------
|
|
200
|
+
//
|
|
201
|
+
// Pure-function lookup from frozen MARKET_SIZE_BUCKETS. Reads
|
|
202
|
+
// industry_signals_count + breakthrough_score; missing breakthrough_score
|
|
203
|
+
// yields 'unknown-bucket' (the safe-default path).
|
|
204
|
+
|
|
205
|
+
function buildMarketSizeEstimate(rs_discovery) {
|
|
206
|
+
if (!rs_discovery || typeof rs_discovery !== 'object') {
|
|
207
|
+
return MARKET_SIZE_BUCKETS['unknown-bucket'];
|
|
208
|
+
}
|
|
209
|
+
const signals = (typeof rs_discovery.industry_signals_count === 'number')
|
|
210
|
+
? rs_discovery.industry_signals_count
|
|
211
|
+
: 0;
|
|
212
|
+
// Distinguish "explicitly missing breakthrough_score" (-> unknown-bucket)
|
|
213
|
+
// from "score = 0" (-> emerging-niche by bucketize). The hasOwnProperty
|
|
214
|
+
// check catches the missing case.
|
|
215
|
+
const hasScore = Object.prototype.hasOwnProperty.call(rs_discovery, 'breakthrough_score')
|
|
216
|
+
&& rs_discovery.breakthrough_score !== undefined
|
|
217
|
+
&& rs_discovery.breakthrough_score !== null;
|
|
218
|
+
const score = hasScore ? rs_discovery.breakthrough_score : null;
|
|
219
|
+
const bucketId = bucketize(signals, score);
|
|
220
|
+
return MARKET_SIZE_BUCKETS[bucketId];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ---------- assess ----------
|
|
224
|
+
//
|
|
225
|
+
// Public entry point. FIRST line of body: auditQueryObject on the
|
|
226
|
+
// composite (rs_discovery, opts) tuple. Throws ExternalEgressViolation on
|
|
227
|
+
// any forbidden field BEFORE any computation. The chokepoint is the only
|
|
228
|
+
// throw path; all other branches return deterministic safe defaults.
|
|
229
|
+
//
|
|
230
|
+
// Inputs:
|
|
231
|
+
// rs_discovery optional object (post-breakthrough-scorer shape)
|
|
232
|
+
// opts optional object (caller-supplied configuration scalars)
|
|
233
|
+
//
|
|
234
|
+
// Output:
|
|
235
|
+
// {
|
|
236
|
+
// market_size_estimate: <string from MARKET_SIZE_BUCKETS>,
|
|
237
|
+
// value_proposition: <string from VALUE_PROP_TEMPLATES>,
|
|
238
|
+
// partnership_targets: <array of {name, type, score} entries>,
|
|
239
|
+
// }
|
|
240
|
+
|
|
241
|
+
function assess(rs_discovery, opts) {
|
|
242
|
+
// Canon Part 8 chokepoint: pre-input audit on the composite tuple.
|
|
243
|
+
// Throws ExternalEgressViolation BEFORE any field is touched. Empty
|
|
244
|
+
// tuple is permitted (no-args path); only the audit-on-non-empty
|
|
245
|
+
// branch is adversarial-relevant. We always audit so a malicious
|
|
246
|
+
// opts cannot smuggle through the no-args branch.
|
|
247
|
+
auditQueryObject({
|
|
248
|
+
rs_discovery: (rs_discovery === undefined ? null : rs_discovery),
|
|
249
|
+
opts: (opts === undefined ? null : opts),
|
|
250
|
+
}, 'rs-commercial-assessor-input');
|
|
251
|
+
|
|
252
|
+
// Safe-default path: no rs_discovery -> deterministic minimal output.
|
|
253
|
+
const safeIn = (rs_discovery && typeof rs_discovery === 'object') ? rs_discovery : {};
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
market_size_estimate: buildMarketSizeEstimate(safeIn),
|
|
257
|
+
value_proposition: buildValueProposition(safeIn),
|
|
258
|
+
partnership_targets: buildPartnershipTargets(safeIn),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ---------- Exports ----------
|
|
263
|
+
|
|
264
|
+
module.exports = {
|
|
265
|
+
assess: assess,
|
|
266
|
+
// Re-export sentinel so adversarial fixtures can reference the class
|
|
267
|
+
// without a second require() round-trip.
|
|
268
|
+
ExternalEgressViolation: ExternalEgressViolation,
|
|
269
|
+
_test: {
|
|
270
|
+
VALUE_PROP_TEMPLATES: VALUE_PROP_TEMPLATES,
|
|
271
|
+
MARKET_SIZE_BUCKETS: MARKET_SIZE_BUCKETS,
|
|
272
|
+
SAFE_DEFAULT_BRIDGE: SAFE_DEFAULT_BRIDGE,
|
|
273
|
+
SAFE_DEFAULT_SOURCE: SAFE_DEFAULT_SOURCE,
|
|
274
|
+
SAFE_DEFAULT_TARGET: SAFE_DEFAULT_TARGET,
|
|
275
|
+
bucketize: bucketize,
|
|
276
|
+
buildPartnershipTargets: buildPartnershipTargets,
|
|
277
|
+
buildValueProposition: buildValueProposition,
|
|
278
|
+
buildMarketSizeEstimate: buildMarketSizeEstimate,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
* Phase 89.2 Plan 06 Task 3 -- Phase 3 dual-floor differential scorer.
|
|
4
|
+
*
|
|
5
|
+
* Pair-wise differential scorer per kickoff §5:
|
|
6
|
+
*
|
|
7
|
+
* pair passes IFF (diff > 0.3 AND LSA > 0.2 AND BERT > 0.2)
|
|
8
|
+
*
|
|
9
|
+
* where diff = |LSA - BERT|. Strict > comparisons throughout (Test 5
|
|
10
|
+
* verifies the exact-threshold case fails). The dual-floor filter is the
|
|
11
|
+
* detection signal that distinguishes structural-transfer pairs (LSA high,
|
|
12
|
+
* BERT low) from semantic-implementation pairs (BERT high, LSA low) from
|
|
13
|
+
* direct-intersection pairs (both high, low diff -- pruned by the diff floor).
|
|
14
|
+
*
|
|
15
|
+
* --------------------------------------------------------------------------
|
|
16
|
+
* CANON PART 7 CARVE-OUT (DELIBERATE, DOCUMENTED)
|
|
17
|
+
* --------------------------------------------------------------------------
|
|
18
|
+
*
|
|
19
|
+
* The pair-wise LSA cosine below uses an embedded sklearn TfidfVectorizer +
|
|
20
|
+
* TruncatedSVD subset inside lsaBridgeScript -- NOT rs_math.py's
|
|
21
|
+
* build_tfidf_svd. This is a deliberate exception to Reuse Before Build
|
|
22
|
+
* because rs_math.py's API is CORPUS-LEVEL: it expects Sequence[str] >= 3
|
|
23
|
+
* documents and fits a corpus-wide IDF + SVD basis. A pair-wise comparison
|
|
24
|
+
* (1 query_concept vs 1 doc_concept = 2-document mini-corpus) cannot consume
|
|
25
|
+
* that API without forcing degenerate corpus statistics that change the
|
|
26
|
+
* algorithm's semantics:
|
|
27
|
+
*
|
|
28
|
+
* - 2-document IDF is mathematically meaningless (IDF on a 2-document
|
|
29
|
+
* corpus collapses the whole vocabulary into one of two values; the
|
|
30
|
+
* "rare-term up-weighting" that motivates IDF stops working).
|
|
31
|
+
*
|
|
32
|
+
* - 1-component SVD (max for a 2-document matrix) does NOT correspond
|
|
33
|
+
* to Kwan 2023's algorithm, which fits ~80 components against a real
|
|
34
|
+
* corpus to capture topic structure.
|
|
35
|
+
*
|
|
36
|
+
* The pair-wise question requires a fresh per-pair TfidfVectorizer +
|
|
37
|
+
* TruncatedSVD fit specifically tuned for the pair-wise cosine -- which IS
|
|
38
|
+
* what lsaBridgeScript does. rs_math.py continues to be consumed in its
|
|
39
|
+
* CORPUS-MODE use case (e.g., scripts/rs-engine.py for corpus reverse-salient
|
|
40
|
+
* computation per Phase 89-01 / 89-03 / 89-05).
|
|
41
|
+
*
|
|
42
|
+
* To avoid future drift toward "all LSA must go through one path," this
|
|
43
|
+
* carve-out is documented in three locations:
|
|
44
|
+
*
|
|
45
|
+
* 1. The plan's must_haves block + objective (.planning/phases/89.2-.../
|
|
46
|
+
* 89.2-06-preprocessor-and-differential-scorer-PLAN.md)
|
|
47
|
+
* 2. This source file's header comment block (above)
|
|
48
|
+
* 3. The embedded Python lsaBridgeScript header (inside lsaBridgeScript)
|
|
49
|
+
*
|
|
50
|
+
* Acceptance grep enforces the carve-out comment block (>= 2 hits across
|
|
51
|
+
* the CJS header AND the embedded Python header) so refactors that strip
|
|
52
|
+
* one without the other are loud, not silent.
|
|
53
|
+
*
|
|
54
|
+
* --------------------------------------------------------------------------
|
|
55
|
+
*
|
|
56
|
+
* BERT cosine path (Canon Part 7 reuse, NO carve-out): consumes
|
|
57
|
+
* lib/core/rs-pinecone-bridge.cjs (Task 1 of this plan) which wraps the
|
|
58
|
+
* existing rs_cache.py::fetch_all_from_namespace primitive (Phase 89-03
|
|
59
|
+
* v1.10.16) for strict-1024-dim Pinecone-direct vector retrieval.
|
|
60
|
+
*
|
|
61
|
+
* Graceful degradation contract:
|
|
62
|
+
*
|
|
63
|
+
* bridge fails (no PINECONE_API_KEY, network error, namespace empty)
|
|
64
|
+
* -> {diff: <lsa>, lsa: <lsa>, bert: null, passes: lsa > LSA_FLOOR,
|
|
65
|
+
* warning: 'bert_unavailable'}
|
|
66
|
+
* -> NEVER throws on bridge failure
|
|
67
|
+
*
|
|
68
|
+
* LSA bridge fails (python3 missing, sklearn import error, parse error)
|
|
69
|
+
* -> {diff: null, lsa: null, bert: <bert>, passes: false,
|
|
70
|
+
* warning: 'lsa_unavailable'}
|
|
71
|
+
* -> Pessimistic: passes=false because LSA is the structural anchor;
|
|
72
|
+
* without LSA the differential signal is unrecoverable.
|
|
73
|
+
*
|
|
74
|
+
* Canon Part 8 (Graph Boundary): two defense-in-depth layers.
|
|
75
|
+
*
|
|
76
|
+
* Layer 1 -- pre-input scan: query_concept + doc_concept are passed
|
|
77
|
+
* through auditQueryString BEFORE either bridge is called. On
|
|
78
|
+
* FORBIDDEN_PATTERNS hit, throws ExternalEgressViolation; the bridges
|
|
79
|
+
* are NEVER invoked (Tests 9 + 10 verify call counts == 0).
|
|
80
|
+
*
|
|
81
|
+
* Layer 2 -- pre-return audit: composite output is passed through
|
|
82
|
+
* auditQueryObject before return. Throws ExternalEgressViolation on
|
|
83
|
+
* hit. Defense-in-depth so any forbidden pattern smuggled via the
|
|
84
|
+
* bridge response (warning fields, error fields) is caught at the gate.
|
|
85
|
+
*
|
|
86
|
+
* Pure CJS, zero npm deps, node built-ins only beyond the rs-egress-* +
|
|
87
|
+
* rs-pinecone-bridge primitives.
|
|
88
|
+
*/
|
|
89
|
+
'use strict';
|
|
90
|
+
|
|
91
|
+
const path = require('node:path');
|
|
92
|
+
const childProcess = require('child_process');
|
|
93
|
+
const { auditQueryString, auditQueryObject } = require('./rs-egress-prompts.cjs');
|
|
94
|
+
const pineconeBridge = require('./rs-pinecone-bridge.cjs');
|
|
95
|
+
// rs-egress-violations is required transitively by rs-egress-prompts; we do
|
|
96
|
+
// not throw ExternalEgressViolation directly from this module (the audit
|
|
97
|
+
// helpers do). The require below is a reachability witness for the audit chain.
|
|
98
|
+
require('./rs-egress-violations.cjs');
|
|
99
|
+
|
|
100
|
+
// ---------- Frozen invariants ----------
|
|
101
|
+
|
|
102
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
103
|
+
const PYTHON_BIN = process.env.MINDRIAN_PYTHON || 'python3';
|
|
104
|
+
const LSA_BRIDGE_TIMEOUT_MS = 30000;
|
|
105
|
+
|
|
106
|
+
// Dual-floor thresholds per kickoff §5. Strict > comparisons.
|
|
107
|
+
const DIFF_FLOOR = 0.3;
|
|
108
|
+
const LSA_FLOOR = 0.2;
|
|
109
|
+
const BERT_FLOOR = 0.2;
|
|
110
|
+
|
|
111
|
+
// ---------- Embedded Python LSA bridge script ----------
|
|
112
|
+
//
|
|
113
|
+
// CANON PART 7 CARVE-OUT (DELIBERATE, DOCUMENTED): see file header above
|
|
114
|
+
// for the complete justification. In short:
|
|
115
|
+
// rs_math.py::build_tfidf_svd is corpus-level (Sequence[str] >= 3 docs);
|
|
116
|
+
// pair-wise (1 vs 1) cosine cannot consume that API without forcing
|
|
117
|
+
// degenerate IDF + SVD. The script below fits a fresh per-pair
|
|
118
|
+
// TfidfVectorizer + TruncatedSVD specifically for the pair-wise question.
|
|
119
|
+
//
|
|
120
|
+
// The leading `# BSL 1.1` line plus the carve-out justification block
|
|
121
|
+
// constitute the Canon discipline marker on the embedded source surface
|
|
122
|
+
// (W4 fix per Plan 89.2-06). Acceptance grep enforces presence in both
|
|
123
|
+
// the CJS file header (above) AND this embedded Python block.
|
|
124
|
+
|
|
125
|
+
const lsaBridgeScript = [
|
|
126
|
+
'# BSL 1.1',
|
|
127
|
+
'# Copyright (c) 2026 Mindrian. Phase 89.2 Plan 06 Task 3 -- pair-wise LSA cosine.',
|
|
128
|
+
'#',
|
|
129
|
+
'# CANON PART 7 CARVE-OUT (DELIBERATE, DOCUMENTED): This script computes',
|
|
130
|
+
'# pair-wise (1 vs 1) LSA cosine. It does NOT call rs_math.py because',
|
|
131
|
+
'# rs_math.py::build_tfidf_svd is corpus-level (Sequence[str] >= 3',
|
|
132
|
+
'# documents) and would produce degenerate IDF + SVD on a 2-document pair.',
|
|
133
|
+
'# The embedded sklearn subset below fits a fresh per-pair TfidfVectorizer',
|
|
134
|
+
'# + TruncatedSVD specifically for the pair-wise question, which is the',
|
|
135
|
+
'# algorithmically correct path. rs_math.py is consumed in CORPUS mode by',
|
|
136
|
+
'# scripts/rs-engine.py.',
|
|
137
|
+
'#',
|
|
138
|
+
'# Protocol:',
|
|
139
|
+
'# stdin JSON {a: string, b: string}',
|
|
140
|
+
'# stdout JSON {success: true, cosine: number} OR {success: false, error: string}',
|
|
141
|
+
'import sys, json',
|
|
142
|
+
'try:',
|
|
143
|
+
' from sklearn.feature_extraction.text import TfidfVectorizer',
|
|
144
|
+
' from sklearn.metrics.pairwise import cosine_similarity as sk_cos',
|
|
145
|
+
' from sklearn.decomposition import TruncatedSVD',
|
|
146
|
+
' payload = json.loads(sys.stdin.read())',
|
|
147
|
+
' a = str(payload.get("a", ""))',
|
|
148
|
+
' b = str(payload.get("b", ""))',
|
|
149
|
+
' if len(a.strip()) == 0 or len(b.strip()) == 0:',
|
|
150
|
+
' sys.stdout.write(json.dumps({"success": True, "cosine": 0.0}))',
|
|
151
|
+
' sys.exit(0)',
|
|
152
|
+
' texts = [a, b]',
|
|
153
|
+
' vec = TfidfVectorizer(stop_words="english").fit_transform(texts)',
|
|
154
|
+
' if vec.shape[1] < 2:',
|
|
155
|
+
' sys.stdout.write(json.dumps({"success": True, "cosine": 0.0}))',
|
|
156
|
+
' sys.exit(0)',
|
|
157
|
+
' n_components = max(1, min(80, vec.shape[1] - 1, vec.shape[0] - 1))',
|
|
158
|
+
' svd = TruncatedSVD(n_components=n_components, random_state=256).fit(vec)',
|
|
159
|
+
' reduced = svd.transform(vec)',
|
|
160
|
+
' c = float(sk_cos(reduced[0:1], reduced[1:2])[0][0])',
|
|
161
|
+
' # Clamp to [0, 1] for downstream dual-floor consistency. Negative LSA',
|
|
162
|
+
' # cosines arise on degenerate SVD bases and are not interpretable as',
|
|
163
|
+
' # similarity in the Kwan 2023 framework.',
|
|
164
|
+
' sys.stdout.write(json.dumps({"success": True, "cosine": max(0.0, c)}))',
|
|
165
|
+
'except Exception as e:',
|
|
166
|
+
' sys.stdout.write(json.dumps({"success": False, "error": str(e)}))',
|
|
167
|
+
'',
|
|
168
|
+
].join('\n');
|
|
169
|
+
|
|
170
|
+
// ---------- computeLsaCosine ----------
|
|
171
|
+
//
|
|
172
|
+
// Spawns python3 with the embedded lsaBridgeScript, passes the two strings
|
|
173
|
+
// via JSON-over-stdin, parses the response. Returns:
|
|
174
|
+
//
|
|
175
|
+
// {success: true, cosine: number}
|
|
176
|
+
// {success: false, error: 'python_unavailable'|'python_exit_<N>'|'parse_error'|'timeout'|...}
|
|
177
|
+
|
|
178
|
+
async function computeLsaCosine(a, b) {
|
|
179
|
+
const requestEnvelope = JSON.stringify({ a: a, b: b });
|
|
180
|
+
let res;
|
|
181
|
+
try {
|
|
182
|
+
res = childProcess.spawnSync(PYTHON_BIN, ['-c', lsaBridgeScript], {
|
|
183
|
+
input: requestEnvelope,
|
|
184
|
+
encoding: 'utf8',
|
|
185
|
+
timeout: LSA_BRIDGE_TIMEOUT_MS,
|
|
186
|
+
cwd: REPO_ROOT,
|
|
187
|
+
});
|
|
188
|
+
} catch (err) {
|
|
189
|
+
return { success: false, error: 'spawn_threw', detail: String(err && err.message) };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (res && res.error) {
|
|
193
|
+
if (res.error.code === 'ENOENT') return { success: false, error: 'python_unavailable' };
|
|
194
|
+
if (res.error.code === 'ETIMEDOUT' || res.error.code === 'ERR_CHILD_PROCESS_TIMEOUT') {
|
|
195
|
+
return { success: false, error: 'timeout' };
|
|
196
|
+
}
|
|
197
|
+
return { success: false, error: 'spawn_error', detail: String(res.error.message) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (res && res.signal === 'SIGTERM') {
|
|
201
|
+
return { success: false, error: 'timeout' };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const stdout = (res && typeof res.stdout === 'string') ? res.stdout : '';
|
|
205
|
+
const stderr = (res && typeof res.stderr === 'string') ? res.stderr : '';
|
|
206
|
+
|
|
207
|
+
if (res && res.status !== 0) {
|
|
208
|
+
return {
|
|
209
|
+
success: false,
|
|
210
|
+
error: 'python_exit_' + res.status,
|
|
211
|
+
stderr: stderr.slice(0, 500),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let parsed;
|
|
216
|
+
try {
|
|
217
|
+
parsed = JSON.parse(stdout);
|
|
218
|
+
} catch (_e) {
|
|
219
|
+
return { success: false, error: 'parse_error', stdout_sample: stdout.slice(0, 200) };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
223
|
+
return { success: false, error: 'parse_error' };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (parsed.success !== true) {
|
|
227
|
+
return { success: false, error: typeof parsed.error === 'string' ? parsed.error : 'bridge_error' };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (typeof parsed.cosine !== 'number' || isNaN(parsed.cosine)) {
|
|
231
|
+
return { success: false, error: 'invalid_cosine' };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return { success: true, cosine: parsed.cosine };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ---------- computeBertCosine ----------
|
|
238
|
+
//
|
|
239
|
+
// Twin queryPineconeWithVectors calls (one per concept), then pure-JS
|
|
240
|
+
// cosineSimilarity on the resulting 1024-dim vectors. Returns:
|
|
241
|
+
//
|
|
242
|
+
// {success: true, cosine: number}
|
|
243
|
+
// {success: false, error: 'namespace_required'|'bridge_failed'|'no_hits'|'shape_error'}
|
|
244
|
+
|
|
245
|
+
async function computeBertCosine(a, b, namespace) {
|
|
246
|
+
if (typeof namespace !== 'string' || namespace.length === 0) {
|
|
247
|
+
return { success: false, error: 'namespace_required' };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const resA = await pineconeBridge.queryPineconeWithVectors(namespace, a, 1);
|
|
251
|
+
if (!resA || resA.success !== true) {
|
|
252
|
+
return { success: false, error: 'bridge_failed_a', detail: resA && resA.error };
|
|
253
|
+
}
|
|
254
|
+
const resB = await pineconeBridge.queryPineconeWithVectors(namespace, b, 1);
|
|
255
|
+
if (!resB || resB.success !== true) {
|
|
256
|
+
return { success: false, error: 'bridge_failed_b', detail: resB && resB.error };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!Array.isArray(resA.hits) || resA.hits.length === 0) {
|
|
260
|
+
return { success: false, error: 'no_hits_a' };
|
|
261
|
+
}
|
|
262
|
+
if (!Array.isArray(resB.hits) || resB.hits.length === 0) {
|
|
263
|
+
return { success: false, error: 'no_hits_b' };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const va = resA.hits[0] && resA.hits[0].values;
|
|
267
|
+
const vb = resB.hits[0] && resB.hits[0].values;
|
|
268
|
+
if (!Array.isArray(va) || !Array.isArray(vb)) {
|
|
269
|
+
return { success: false, error: 'shape_error' };
|
|
270
|
+
}
|
|
271
|
+
if (va.length !== vb.length || va.length === 0) {
|
|
272
|
+
return { success: false, error: 'dim_mismatch' };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const cos = pineconeBridge.cosineSimilarity(va, vb);
|
|
276
|
+
return { success: true, cosine: cos };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ---------- score ----------
|
|
280
|
+
//
|
|
281
|
+
// Public entry point. Pair-wise dual-floor differential scorer.
|
|
282
|
+
//
|
|
283
|
+
// Inputs:
|
|
284
|
+
// query_concept string the concept seeded from preprocessor.concepts[]
|
|
285
|
+
// doc_concept string the candidate concept (cross-domain or same-domain)
|
|
286
|
+
// opts optional:
|
|
287
|
+
// namespace string Pinecone namespace for BERT cosine (typically 'external:<topic-slug>')
|
|
288
|
+
//
|
|
289
|
+
// Output (happy path):
|
|
290
|
+
// {diff, lsa, bert, passes}
|
|
291
|
+
//
|
|
292
|
+
// Output (graceful degradation):
|
|
293
|
+
// {diff, lsa, bert: null, passes: lsa>0.2, warning: 'bert_unavailable'}
|
|
294
|
+
// {diff: null, lsa: null, bert, passes: false, warning: 'lsa_unavailable'}
|
|
295
|
+
//
|
|
296
|
+
// Throws (the only escape route -- Canon Part 8):
|
|
297
|
+
// ExternalEgressViolation if either concept matches FORBIDDEN_PATTERNS
|
|
298
|
+
|
|
299
|
+
async function score(query_concept, doc_concept, opts) {
|
|
300
|
+
// Canon Part 8 Layer 1: pre-input scan on user-controlled concepts.
|
|
301
|
+
// auditQueryString throws ExternalEgressViolation on hit; the bridges
|
|
302
|
+
// below are NEVER invoked when this throws. Tests 9 + 10 verify the
|
|
303
|
+
// call-count contract.
|
|
304
|
+
auditQueryString(typeof query_concept === 'string' ? query_concept : '', 'differential-scorer');
|
|
305
|
+
auditQueryString(typeof doc_concept === 'string' ? doc_concept : '', 'differential-scorer');
|
|
306
|
+
|
|
307
|
+
opts = opts || {};
|
|
308
|
+
const namespace = (typeof opts.namespace === 'string' && opts.namespace.length > 0)
|
|
309
|
+
? opts.namespace
|
|
310
|
+
: null;
|
|
311
|
+
|
|
312
|
+
// Run both bridges in parallel. computeLsaCosine is cheap (single Python
|
|
313
|
+
// spawn); computeBertCosine spawns the Pinecone bridge twice. Promise.all
|
|
314
|
+
// means LSA does not block on BERT's spawnSync in the parallel mock-test
|
|
315
|
+
// case. Sequential await would be equivalent for correctness; parallel
|
|
316
|
+
// is the future-proofing for real Brain latency.
|
|
317
|
+
const [lsaResult, bertResult] = await Promise.all([
|
|
318
|
+
computeLsaCosine(query_concept, doc_concept),
|
|
319
|
+
computeBertCosine(query_concept, doc_concept, namespace),
|
|
320
|
+
]);
|
|
321
|
+
|
|
322
|
+
let out;
|
|
323
|
+
if (lsaResult.success && bertResult.success) {
|
|
324
|
+
const lsa = lsaResult.cosine;
|
|
325
|
+
const bert = bertResult.cosine;
|
|
326
|
+
const diff = Math.abs(lsa - bert);
|
|
327
|
+
const passes = (diff > DIFF_FLOOR) && (lsa > LSA_FLOOR) && (bert > BERT_FLOOR);
|
|
328
|
+
out = { diff: diff, lsa: lsa, bert: bert, passes: passes };
|
|
329
|
+
} else if (lsaResult.success && !bertResult.success) {
|
|
330
|
+
// BERT unavailable: degrade to LSA-only. Per plan: bert=null, diff=lsa
|
|
331
|
+
// (treat as max divergence), passes=(lsa>LSA_FLOOR only since bert
|
|
332
|
+
// unavailable), warning='bert_unavailable'.
|
|
333
|
+
const lsa = lsaResult.cosine;
|
|
334
|
+
out = {
|
|
335
|
+
diff: lsa,
|
|
336
|
+
lsa: lsa,
|
|
337
|
+
bert: null,
|
|
338
|
+
passes: lsa > LSA_FLOOR,
|
|
339
|
+
warning: 'bert_unavailable',
|
|
340
|
+
};
|
|
341
|
+
} else {
|
|
342
|
+
// LSA failed (with or without BERT): pessimistic. Per plan: passes=false
|
|
343
|
+
// because LSA is the structural anchor; without LSA the differential
|
|
344
|
+
// signal is unrecoverable.
|
|
345
|
+
out = {
|
|
346
|
+
diff: null,
|
|
347
|
+
lsa: null,
|
|
348
|
+
bert: bertResult.success ? bertResult.cosine : null,
|
|
349
|
+
passes: false,
|
|
350
|
+
warning: 'lsa_unavailable',
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Canon Part 8 Layer 2: pre-return audit on composite output.
|
|
355
|
+
// Throws ExternalEgressViolation on any FORBIDDEN_PATTERNS hit.
|
|
356
|
+
auditQueryObject(out, 'differential-scorer');
|
|
357
|
+
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ---------- Exports ----------
|
|
362
|
+
|
|
363
|
+
module.exports = {
|
|
364
|
+
score: score,
|
|
365
|
+
_test: {
|
|
366
|
+
DIFF_FLOOR: DIFF_FLOOR,
|
|
367
|
+
LSA_FLOOR: LSA_FLOOR,
|
|
368
|
+
BERT_FLOOR: BERT_FLOOR,
|
|
369
|
+
LSA_BRIDGE_TIMEOUT_MS: LSA_BRIDGE_TIMEOUT_MS,
|
|
370
|
+
PYTHON_BIN: PYTHON_BIN,
|
|
371
|
+
REPO_ROOT: REPO_ROOT,
|
|
372
|
+
computeLsaCosine: computeLsaCosine,
|
|
373
|
+
computeBertCosine: computeBertCosine,
|
|
374
|
+
lsaBridgeScript: lsaBridgeScript,
|
|
375
|
+
},
|
|
376
|
+
};
|