@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,518 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
6
|
+
* Phase 89.3 Plan 01 -- Aura Cypher writer fixture suite.
|
|
7
|
+
*
|
|
8
|
+
* writeDiscovery(pair, opts) is the Tier 1 (Aura-connected) writer in the
|
|
9
|
+
* dual-tier output layer. The writer takes a scored+classified+thesis-bearing
|
|
10
|
+
* pair (from Plan 89.2-07's generateThesis output) and persists it into the
|
|
11
|
+
* user's own LazyGraph Aura via idempotent MERGE Cypher with deterministic
|
|
12
|
+
* sha256-derived ids (REAL Aura idempotency, not mock-state tracking).
|
|
13
|
+
*
|
|
14
|
+
* 12 scenarios + A1 sweep:
|
|
15
|
+
* 1 Happy path (minimal pair, no opts.context)
|
|
16
|
+
* 2 REAL idempotency via deterministic ids (byte-identical ids on repeat)
|
|
17
|
+
* 3 Full happy path with opts.context (papers + experts)
|
|
18
|
+
* 4 All 5 edge types created (DISCOVERED + DERIVED_FROM + ENABLES + AUTHORED_BY + AFFILIATED_WITH)
|
|
19
|
+
* 5 Rollback Cypher captured + valid
|
|
20
|
+
* 6 Missing classification throws TypeError
|
|
21
|
+
* 7 Missing thesis throws TypeError
|
|
22
|
+
* 8 Aura unreachable throws AuraUnreachableError
|
|
23
|
+
* 9 CANON PART 8 adversarial -- forbidden in pair.thesis
|
|
24
|
+
* 10 CANON PART 8 adversarial -- forbidden in pair.bridge_concept
|
|
25
|
+
* 11 CANON PART 8 adversarial -- forbidden in pair.query_concept
|
|
26
|
+
* 12 CANON PART 8 adversarial -- forbidden smuggled via opts.context.experts[0].name (UNWIND input vector)
|
|
27
|
+
*
|
|
28
|
+
* End-of-suite sweep:
|
|
29
|
+
* A1: re-scan every captured Cypher op log + input fixture (JSON.stringify)
|
|
30
|
+
* against FORBIDDEN_PATTERNS as cross-scenario Canon Part 8 guarantee.
|
|
31
|
+
* For throw-scenarios, op log is empty by design (audit fires before
|
|
32
|
+
* driver call); A1 sweeps op-log captures from non-throw scenarios.
|
|
33
|
+
*
|
|
34
|
+
* Pure CJS, zero npm deps, node built-ins only (assert, path).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const assert = require('node:assert/strict');
|
|
38
|
+
const path = require('node:path');
|
|
39
|
+
|
|
40
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
41
|
+
|
|
42
|
+
// Source of truth for parity gate.
|
|
43
|
+
const crossRoomAggregator = require('../core/cross-room-aggregator.cjs');
|
|
44
|
+
const FORBIDDEN_PATTERNS = crossRoomAggregator.FORBIDDEN_PATTERNS;
|
|
45
|
+
|
|
46
|
+
// Every Cypher op captured for end-of-suite A1 sweep.
|
|
47
|
+
const capturedOpLogs = [];
|
|
48
|
+
|
|
49
|
+
let passed = 0;
|
|
50
|
+
let failed = 0;
|
|
51
|
+
const failures = [];
|
|
52
|
+
|
|
53
|
+
function resetRequireCache() {
|
|
54
|
+
const targets = [
|
|
55
|
+
'../core/rs-egress-violations.cjs',
|
|
56
|
+
'../core/rs-egress-prompts.cjs',
|
|
57
|
+
'../core/cross-room-aggregator.cjs',
|
|
58
|
+
'../core/lazygraph-ops.cjs',
|
|
59
|
+
'../core/rs-neo4j-writer.cjs',
|
|
60
|
+
];
|
|
61
|
+
for (const t of targets) {
|
|
62
|
+
try {
|
|
63
|
+
const p = require.resolve(t);
|
|
64
|
+
delete require.cache[p];
|
|
65
|
+
} catch (_e) { /* best effort */ }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function runScenario(name, fn) {
|
|
70
|
+
const start = Date.now();
|
|
71
|
+
try {
|
|
72
|
+
await fn();
|
|
73
|
+
passed += 1;
|
|
74
|
+
process.stdout.write(' ok ' + name + ' (' + (Date.now() - start) + 'ms)\n');
|
|
75
|
+
} catch (err) {
|
|
76
|
+
failed += 1;
|
|
77
|
+
failures.push({ name: name, err: err });
|
|
78
|
+
process.stderr.write(' FAIL ' + name + '\n');
|
|
79
|
+
process.stderr.write(' ' + (err && err.stack ? err.stack : err) + '\n');
|
|
80
|
+
} finally {
|
|
81
|
+
resetRequireCache();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function captureOpLog(name, opLog) {
|
|
86
|
+
capturedOpLogs.push({ scenario: name, opLog: opLog });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------- Mock driver factory ----------
|
|
90
|
+
//
|
|
91
|
+
// Mirrors the neo4j-driver session/run/close API surface that
|
|
92
|
+
// rs-neo4j-writer.cjs invokes. Each call to session.run(cypher, params)
|
|
93
|
+
// pushes {cypher, params} onto driver.opLog and returns a Promise that
|
|
94
|
+
// resolves with a result object whose summary.counters reflects the
|
|
95
|
+
// configured behavior (firstRunCounters vs subsequentRunCounters).
|
|
96
|
+
//
|
|
97
|
+
// opts.simulateConnectionError: throw on session.run (Test 8)
|
|
98
|
+
// opts.firstRunCounters: counters for the first session.run call
|
|
99
|
+
// opts.subsequentRunCounters: counters for subsequent calls (idempotency proof)
|
|
100
|
+
|
|
101
|
+
function makeMockDriver(opts) {
|
|
102
|
+
opts = opts || {};
|
|
103
|
+
const driver = {
|
|
104
|
+
opLog: [],
|
|
105
|
+
runCount: 0,
|
|
106
|
+
sessionsClosed: 0,
|
|
107
|
+
session: function () {
|
|
108
|
+
const drv = this;
|
|
109
|
+
return {
|
|
110
|
+
run: async function (cypher, params) {
|
|
111
|
+
drv.opLog.push({ cypher: cypher, params: params });
|
|
112
|
+
drv.runCount += 1;
|
|
113
|
+
if (opts.simulateConnectionError) {
|
|
114
|
+
throw new Error('connect ECONNREFUSED 127.0.0.1:7687');
|
|
115
|
+
}
|
|
116
|
+
const counters = (drv.runCount === 1)
|
|
117
|
+
? (opts.firstRunCounters || { nodesCreated: 3, relationshipsCreated: 3 })
|
|
118
|
+
: (opts.subsequentRunCounters || { nodesCreated: 0, relationshipsCreated: 0 });
|
|
119
|
+
return {
|
|
120
|
+
records: [],
|
|
121
|
+
summary: { counters: counters },
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
close: async function () {
|
|
125
|
+
drv.sessionsClosed += 1;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
return driver;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------- Fixture builders ----------
|
|
134
|
+
|
|
135
|
+
function makeCleanPair(overrides) {
|
|
136
|
+
const base = {
|
|
137
|
+
query_concept: 'CRISPR delivery',
|
|
138
|
+
doc_concept: 'liposome targeting',
|
|
139
|
+
diff: 0.4,
|
|
140
|
+
lsa: 0.5,
|
|
141
|
+
bert: 0.1,
|
|
142
|
+
passes: true,
|
|
143
|
+
classification: 'structural_transfer',
|
|
144
|
+
bridge_concept: 'cross-domain isomorphism',
|
|
145
|
+
breakthrough: {
|
|
146
|
+
score: 5.9,
|
|
147
|
+
breakdown: { feasibility: 2, market: 1.5, magnitude: 1, advantage: 1.4, impact: 0 },
|
|
148
|
+
dominant_dimension: 'feasibility',
|
|
149
|
+
},
|
|
150
|
+
thesis: 'By applying CRISPR delivery to liposome targeting, achieve feasible novel transfer because isomorphic structure transfers under cross-domain isomorphism.',
|
|
151
|
+
};
|
|
152
|
+
if (overrides) {
|
|
153
|
+
for (const k of Object.keys(overrides)) {
|
|
154
|
+
base[k] = overrides[k];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return base;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function makeFullContext() {
|
|
161
|
+
return {
|
|
162
|
+
papers: [
|
|
163
|
+
{
|
|
164
|
+
id: 'openalex:W123',
|
|
165
|
+
title: 'CRISPR delivery via liposomes',
|
|
166
|
+
authors: [{ name: 'Smith, Jane', orcid: '0000-0001-2345-6789', institution: 'Stanford' }],
|
|
167
|
+
doi: '10.1038/sample.2026',
|
|
168
|
+
source: 'openalex',
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
experts: [
|
|
172
|
+
{
|
|
173
|
+
name: 'Smith, Jane',
|
|
174
|
+
orcid: '0000-0001-2345-6789',
|
|
175
|
+
institution: 'Stanford',
|
|
176
|
+
paper_count: 1,
|
|
177
|
+
h_index_estimate: 1,
|
|
178
|
+
public_email_or_null: null,
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
room_id: 'test-room',
|
|
182
|
+
domain: 'biotech',
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ---------- Scenarios ----------
|
|
187
|
+
|
|
188
|
+
async function scenario1HappyPathMinimal() {
|
|
189
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
190
|
+
const pair = makeCleanPair();
|
|
191
|
+
const driver = makeMockDriver({ firstRunCounters: { nodesCreated: 3, relationshipsCreated: 3 } });
|
|
192
|
+
const result = await m.writeDiscovery(pair, { driver: driver });
|
|
193
|
+
captureOpLog('1-happy-minimal', driver.opLog);
|
|
194
|
+
|
|
195
|
+
assert.equal(result.wrote_node_count, 3, 'wrote_node_count must be 3, got ' + result.wrote_node_count);
|
|
196
|
+
assert.equal(result.wrote_edge_count, 3, 'wrote_edge_count must be 3, got ' + result.wrote_edge_count);
|
|
197
|
+
assert.equal(result.schema_version, '1.0', 'schema_version must be 1.0');
|
|
198
|
+
assert.ok(typeof result.aura_op_id === 'string' && result.aura_op_id.length > 0, 'aura_op_id must be non-empty string');
|
|
199
|
+
assert.ok(typeof result.rollback_cypher === 'string' && result.rollback_cypher.length > 0, 'rollback_cypher must be non-empty string');
|
|
200
|
+
// Three DETACH DELETE statements (one per core node).
|
|
201
|
+
const detachCount = (result.rollback_cypher.match(/DETACH DELETE/g) || []).length;
|
|
202
|
+
assert.equal(detachCount, 3, 'rollback_cypher must contain 3 DETACH DELETE statements, got ' + detachCount);
|
|
203
|
+
assert.equal(driver.runCount, 1, 'driver.session.run must be called exactly once');
|
|
204
|
+
assert.ok(driver.sessionsClosed >= 1, 'driver session must be closed');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function scenario2RealIdempotencyViaDeterministicIds() {
|
|
208
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
209
|
+
const pair = makeCleanPair();
|
|
210
|
+
|
|
211
|
+
// Part A: buildDeterministicIds returns byte-identical ids on repeat calls.
|
|
212
|
+
assert.ok(m._test && m._test.buildDeterministicIds, '_test.buildDeterministicIds must be exposed');
|
|
213
|
+
const ids1 = m._test.buildDeterministicIds(pair);
|
|
214
|
+
const ids2 = m._test.buildDeterministicIds(pair);
|
|
215
|
+
assert.equal(ids1.discovery_id, ids2.discovery_id, 'discovery_id must be byte-identical across calls');
|
|
216
|
+
assert.equal(ids1.rs_id, ids2.rs_id, 'rs_id must be byte-identical across calls');
|
|
217
|
+
assert.equal(ids1.innovation_id, ids2.innovation_id, 'innovation_id must be byte-identical across calls');
|
|
218
|
+
// Sanity: ids should have the prefix scheme from buildDeterministicIds.
|
|
219
|
+
assert.ok(/^rsd-[0-9a-f]{16}$/.test(ids1.discovery_id), 'discovery_id format must be rsd-<16-hex>, got ' + ids1.discovery_id);
|
|
220
|
+
assert.ok(/^rs-[0-9a-f]{16}$/.test(ids1.rs_id), 'rs_id format must be rs-<16-hex>, got ' + ids1.rs_id);
|
|
221
|
+
assert.ok(/^inn-[0-9a-f]{16}$/.test(ids1.innovation_id), 'innovation_id format must be inn-<16-hex>, got ' + ids1.innovation_id);
|
|
222
|
+
|
|
223
|
+
// Part B: writeDiscovery invoked twice with same pair; second call inspects
|
|
224
|
+
// params on driver.opLog -- discovery_id, rs_id, innovation_id MUST be identical.
|
|
225
|
+
// Mock driver simulates MERGE-matched on second call (zero new nodes/edges).
|
|
226
|
+
const driver = makeMockDriver({
|
|
227
|
+
firstRunCounters: { nodesCreated: 3, relationshipsCreated: 3 },
|
|
228
|
+
subsequentRunCounters: { nodesCreated: 0, relationshipsCreated: 0 },
|
|
229
|
+
});
|
|
230
|
+
const result1 = await m.writeDiscovery(pair, { driver: driver });
|
|
231
|
+
const result2 = await m.writeDiscovery(pair, { driver: driver });
|
|
232
|
+
captureOpLog('2-idempotency', driver.opLog);
|
|
233
|
+
|
|
234
|
+
assert.equal(driver.opLog.length, 2, 'driver must have logged 2 ops, got ' + driver.opLog.length);
|
|
235
|
+
const params1 = driver.opLog[0].params;
|
|
236
|
+
const params2 = driver.opLog[1].params;
|
|
237
|
+
assert.equal(params1.discovery_id, params2.discovery_id, 'discovery_id MUST be identical across calls (real Aura MERGE matches by PRIMARY KEY)');
|
|
238
|
+
assert.equal(params1.rs_id, params2.rs_id, 'rs_id MUST be identical across calls');
|
|
239
|
+
assert.equal(params1.innovation_id, params2.innovation_id, 'innovation_id MUST be identical across calls');
|
|
240
|
+
// Confirm ids match the deterministic helper output.
|
|
241
|
+
assert.equal(params1.discovery_id, ids1.discovery_id, 'params.discovery_id must equal buildDeterministicIds output');
|
|
242
|
+
|
|
243
|
+
// Counters reflect MERGE semantics: second call records 0 new nodes/edges.
|
|
244
|
+
assert.equal(result2.wrote_node_count, 0, 'second call wrote_node_count must be 0 (MERGE matched), got ' + result2.wrote_node_count);
|
|
245
|
+
assert.equal(result2.wrote_edge_count, 0, 'second call wrote_edge_count must be 0 (MERGE matched), got ' + result2.wrote_edge_count);
|
|
246
|
+
|
|
247
|
+
// aura_op_id is per-op telemetry: random and DIFFERENT across calls.
|
|
248
|
+
assert.notEqual(result1.aura_op_id, result2.aura_op_id, 'aura_op_id must differ across calls (random per-op telemetry, NOT a node id)');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function scenario3FullHappyPathWithContext() {
|
|
252
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
253
|
+
const pair = makeCleanPair();
|
|
254
|
+
const ctx = makeFullContext();
|
|
255
|
+
const driver = makeMockDriver({ firstRunCounters: { nodesCreated: 6, relationshipsCreated: 6 } });
|
|
256
|
+
const result = await m.writeDiscovery(pair, { driver: driver, context: ctx });
|
|
257
|
+
captureOpLog('3-full-context', driver.opLog);
|
|
258
|
+
|
|
259
|
+
assert.equal(result.wrote_node_count, 6, 'wrote_node_count must be 6 (3 core + Paper + Author + Institution), got ' + result.wrote_node_count);
|
|
260
|
+
assert.equal(result.wrote_edge_count, 6, 'wrote_edge_count must be 6, got ' + result.wrote_edge_count);
|
|
261
|
+
|
|
262
|
+
// params.paper_author_pairs MUST be constructed from ctx.papers
|
|
263
|
+
const params = driver.opLog[0].params;
|
|
264
|
+
assert.ok(Array.isArray(params.paper_author_pairs), 'paper_author_pairs must be array');
|
|
265
|
+
assert.equal(params.paper_author_pairs.length, 1, 'paper_author_pairs must have 1 entry from 1 paper x 1 author');
|
|
266
|
+
assert.equal(params.paper_author_pairs[0].paper_id, 'openalex:W123');
|
|
267
|
+
assert.equal(params.paper_author_pairs[0].author_key, 'Smith, Jane|0000-0001-2345-6789');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function scenario4AllFiveEdgeTypesIncludingAuthoredByUnwind() {
|
|
271
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
272
|
+
const pair = makeCleanPair();
|
|
273
|
+
const ctx = makeFullContext();
|
|
274
|
+
const driver = makeMockDriver({ firstRunCounters: { nodesCreated: 6, relationshipsCreated: 6 } });
|
|
275
|
+
await m.writeDiscovery(pair, { driver: driver, context: ctx });
|
|
276
|
+
captureOpLog('4-all-edges', driver.opLog);
|
|
277
|
+
|
|
278
|
+
// Walk Cypher op string; assert each edge type present.
|
|
279
|
+
const allCypher = driver.opLog.map(function (op) { return op.cypher; }).join('\n');
|
|
280
|
+
const requiredEdges = ['DISCOVERED', 'DERIVED_FROM', 'ENABLES', 'AUTHORED_BY', 'AFFILIATED_WITH'];
|
|
281
|
+
for (const edge of requiredEdges) {
|
|
282
|
+
assert.ok(allCypher.indexOf(edge) !== -1, 'Cypher must contain edge type ' + edge);
|
|
283
|
+
}
|
|
284
|
+
// AUTHORED_BY must appear in an UNWIND $paper_author_pairs context.
|
|
285
|
+
assert.ok(/UNWIND\s+\$paper_author_pairs/i.test(allCypher), 'Cypher must include UNWIND $paper_author_pairs for AUTHORED_BY edges');
|
|
286
|
+
// paper_author_pairs construction validation (as in Test 3, but cross-checked for path).
|
|
287
|
+
const params = driver.opLog[0].params;
|
|
288
|
+
assert.equal(params.paper_author_pairs[0].author_key, 'Smith, Jane|0000-0001-2345-6789');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function scenario5RollbackCypherCaptured() {
|
|
292
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
293
|
+
const pair = makeCleanPair();
|
|
294
|
+
const driver = makeMockDriver({ firstRunCounters: { nodesCreated: 3, relationshipsCreated: 3 } });
|
|
295
|
+
const result = await m.writeDiscovery(pair, { driver: driver });
|
|
296
|
+
captureOpLog('5-rollback', driver.opLog);
|
|
297
|
+
|
|
298
|
+
assert.ok(typeof result.rollback_cypher === 'string', 'rollback_cypher must be a string');
|
|
299
|
+
assert.ok(result.rollback_cypher.length > 0, 'rollback_cypher must be non-empty');
|
|
300
|
+
// Exactly 3 DETACH DELETE statements (one per core node).
|
|
301
|
+
const detachCount = (result.rollback_cypher.match(/DETACH DELETE/g) || []).length;
|
|
302
|
+
assert.equal(detachCount, 3, 'rollback_cypher must have exactly 3 DETACH DELETE, got ' + detachCount);
|
|
303
|
+
// RSDiscovery + ReverseSalient + Innovation must be the targets.
|
|
304
|
+
assert.ok(/RSDiscovery/.test(result.rollback_cypher), 'rollback must target RSDiscovery');
|
|
305
|
+
assert.ok(/ReverseSalient/.test(result.rollback_cypher), 'rollback must target ReverseSalient');
|
|
306
|
+
assert.ok(/Innovation/.test(result.rollback_cypher), 'rollback must target Innovation');
|
|
307
|
+
// Paper / Author / Institution NOT in rollback (they may be shared).
|
|
308
|
+
assert.ok(!/DETACH DELETE.*Paper/.test(result.rollback_cypher), 'rollback must NOT delete Paper (may be shared)');
|
|
309
|
+
assert.ok(!/DETACH DELETE.*Author/.test(result.rollback_cypher), 'rollback must NOT delete Author (may be shared)');
|
|
310
|
+
assert.ok(!/DETACH DELETE.*Institution/.test(result.rollback_cypher), 'rollback must NOT delete Institution (may be shared)');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function scenario6MissingClassificationThrows() {
|
|
314
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
315
|
+
const pair = makeCleanPair({ classification: undefined });
|
|
316
|
+
const driver = makeMockDriver({});
|
|
317
|
+
let threw = null;
|
|
318
|
+
try {
|
|
319
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
320
|
+
} catch (err) {
|
|
321
|
+
threw = err;
|
|
322
|
+
}
|
|
323
|
+
assert.ok(threw, 'must throw on missing classification');
|
|
324
|
+
assert.ok(threw instanceof TypeError, 'must throw TypeError, got ' + (threw && threw.name));
|
|
325
|
+
assert.ok(/classification/.test(threw.message), 'error must mention classification, got: ' + threw.message);
|
|
326
|
+
assert.equal(driver.opLog.length, 0, 'mock driver must record ZERO ops on shape error');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function scenario7MissingThesisThrows() {
|
|
330
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
331
|
+
const pair = makeCleanPair({ thesis: undefined });
|
|
332
|
+
const driver = makeMockDriver({});
|
|
333
|
+
let threw = null;
|
|
334
|
+
try {
|
|
335
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
336
|
+
} catch (err) {
|
|
337
|
+
threw = err;
|
|
338
|
+
}
|
|
339
|
+
assert.ok(threw, 'must throw on missing thesis');
|
|
340
|
+
assert.ok(threw instanceof TypeError, 'must throw TypeError, got ' + (threw && threw.name));
|
|
341
|
+
assert.ok(/thesis/.test(threw.message), 'error must mention thesis, got: ' + threw.message);
|
|
342
|
+
assert.equal(driver.opLog.length, 0, 'mock driver must record ZERO ops on shape error');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function scenario8AuraUnreachableThrows() {
|
|
346
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
347
|
+
const pair = makeCleanPair();
|
|
348
|
+
const driver = makeMockDriver({ simulateConnectionError: true });
|
|
349
|
+
let threw = null;
|
|
350
|
+
try {
|
|
351
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
352
|
+
} catch (err) {
|
|
353
|
+
threw = err;
|
|
354
|
+
}
|
|
355
|
+
assert.ok(threw, 'must throw on Aura unreachable');
|
|
356
|
+
assert.equal(threw.name, 'AuraUnreachableError', 'must throw AuraUnreachableError, got ' + (threw && threw.name));
|
|
357
|
+
// Must NOT be ExternalEgressViolation -- this is a tier-dispatch signal, not a security violation.
|
|
358
|
+
assert.notEqual(threw.name, 'ExternalEgressViolation', 'must NOT confuse with ExternalEgressViolation');
|
|
359
|
+
assert.ok(threw.meta, 'AuraUnreachableError must carry meta');
|
|
360
|
+
// No captureOpLog -- driver opLog still records the failed run attempt; we don't sweep it.
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function scenario9AdvForbiddenInThesis() {
|
|
364
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
365
|
+
// FORBIDDEN_PATTERNS[3] matches /\bmeeting with\b/i.
|
|
366
|
+
const pair = makeCleanPair({
|
|
367
|
+
thesis: 'By applying X to Y, achieve Z because mechanism. Decided in meeting with Genentech.',
|
|
368
|
+
});
|
|
369
|
+
const driver = makeMockDriver({});
|
|
370
|
+
let threw = null;
|
|
371
|
+
try {
|
|
372
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
373
|
+
} catch (err) {
|
|
374
|
+
threw = err;
|
|
375
|
+
}
|
|
376
|
+
assert.ok(threw, 'must throw on forbidden in thesis');
|
|
377
|
+
assert.equal(threw.name, 'ExternalEgressViolation', 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
|
|
378
|
+
assert.equal(threw.meta.surface, 'rs-neo4j-writer', 'meta.surface must be rs-neo4j-writer');
|
|
379
|
+
assert.ok(threw.meta.matched_pattern, 'meta.matched_pattern must be present');
|
|
380
|
+
assert.equal(driver.opLog.length, 0, 'driver opLog must be empty (audit fires before driver call)');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function scenario10AdvForbiddenInBridgeConcept() {
|
|
384
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
385
|
+
// FORBIDDEN_PATTERNS[2] matches /\b(Lawrence|Jonathan|...)\s+(said|...)\b/i.
|
|
386
|
+
const pair = makeCleanPair({
|
|
387
|
+
bridge_concept: 'Lawrence said this is a cross-domain isomorphism',
|
|
388
|
+
});
|
|
389
|
+
const driver = makeMockDriver({});
|
|
390
|
+
let threw = null;
|
|
391
|
+
try {
|
|
392
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
393
|
+
} catch (err) {
|
|
394
|
+
threw = err;
|
|
395
|
+
}
|
|
396
|
+
assert.ok(threw, 'must throw on forbidden in bridge_concept');
|
|
397
|
+
assert.equal(threw.name, 'ExternalEgressViolation', 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
|
|
398
|
+
assert.equal(threw.meta.surface, 'rs-neo4j-writer');
|
|
399
|
+
assert.equal(driver.opLog.length, 0, 'driver opLog must be empty');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async function scenario11AdvForbiddenInQueryConcept() {
|
|
403
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
404
|
+
// FORBIDDEN_PATTERNS[3] matches /\bmeeting with\b/i.
|
|
405
|
+
const pair = makeCleanPair({
|
|
406
|
+
query_concept: 'shared during meeting with the team',
|
|
407
|
+
});
|
|
408
|
+
const driver = makeMockDriver({});
|
|
409
|
+
let threw = null;
|
|
410
|
+
try {
|
|
411
|
+
await m.writeDiscovery(pair, { driver: driver });
|
|
412
|
+
} catch (err) {
|
|
413
|
+
threw = err;
|
|
414
|
+
}
|
|
415
|
+
assert.ok(threw, 'must throw on forbidden in query_concept');
|
|
416
|
+
assert.equal(threw.name, 'ExternalEgressViolation', 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
|
|
417
|
+
assert.equal(driver.opLog.length, 0, 'driver opLog must be empty');
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async function scenario12AdvForbiddenInExpertsUnwindInput() {
|
|
421
|
+
// CANON PART 8 strongest UNWIND-input vector: forbidden bytes inside
|
|
422
|
+
// opts.context.experts[0].name. The audit covers JSON.stringify of the
|
|
423
|
+
// entire Cypher params object, including UNWIND $experts input arrays.
|
|
424
|
+
const m = require('../core/rs-neo4j-writer.cjs');
|
|
425
|
+
const pair = makeCleanPair();
|
|
426
|
+
const ctx = {
|
|
427
|
+
papers: [],
|
|
428
|
+
experts: [{
|
|
429
|
+
name: 'Prof Lawrence said this',
|
|
430
|
+
orcid: null,
|
|
431
|
+
institution: 'X University',
|
|
432
|
+
paper_count: 1,
|
|
433
|
+
h_index_estimate: 1,
|
|
434
|
+
public_email_or_null: null,
|
|
435
|
+
}],
|
|
436
|
+
room_id: 'test',
|
|
437
|
+
domain: 'biotech',
|
|
438
|
+
};
|
|
439
|
+
const driver = makeMockDriver({});
|
|
440
|
+
let threw = null;
|
|
441
|
+
try {
|
|
442
|
+
await m.writeDiscovery(pair, { driver: driver, context: ctx });
|
|
443
|
+
} catch (err) {
|
|
444
|
+
threw = err;
|
|
445
|
+
}
|
|
446
|
+
assert.ok(threw, 'must throw on forbidden in experts UNWIND input');
|
|
447
|
+
assert.equal(threw.name, 'ExternalEgressViolation', 'must throw ExternalEgressViolation, got ' + (threw && threw.name));
|
|
448
|
+
assert.equal(threw.meta.surface, 'rs-neo4j-writer');
|
|
449
|
+
assert.equal(driver.opLog.length, 0, 'driver opLog must be empty');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ---------- A1 end-of-suite sweep ----------
|
|
453
|
+
|
|
454
|
+
function a1Sweep() {
|
|
455
|
+
let hits = 0;
|
|
456
|
+
for (const rec of capturedOpLogs) {
|
|
457
|
+
const json = JSON.stringify(rec.opLog);
|
|
458
|
+
for (const re of FORBIDDEN_PATTERNS) {
|
|
459
|
+
if (re.test(json)) {
|
|
460
|
+
hits += 1;
|
|
461
|
+
process.stderr.write(
|
|
462
|
+
' A1 HIT scenario=' + rec.scenario +
|
|
463
|
+
' pattern=' + re.source + '\n'
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return hits;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ---------- Main ----------
|
|
472
|
+
|
|
473
|
+
(async function main() {
|
|
474
|
+
process.stdout.write('=== 89.3-01 rs-neo4j-writer suite (REPO_ROOT=' +
|
|
475
|
+
REPO_ROOT + ') ===\n');
|
|
476
|
+
|
|
477
|
+
await runScenario('1-happy-minimal', scenario1HappyPathMinimal);
|
|
478
|
+
await runScenario('2-real-idempotency-deterministic-ids', scenario2RealIdempotencyViaDeterministicIds);
|
|
479
|
+
await runScenario('3-full-happy-with-context', scenario3FullHappyPathWithContext);
|
|
480
|
+
await runScenario('4-all-five-edge-types-AUTHORED_BY-UNWIND', scenario4AllFiveEdgeTypesIncludingAuthoredByUnwind);
|
|
481
|
+
await runScenario('5-rollback-cypher-captured', scenario5RollbackCypherCaptured);
|
|
482
|
+
await runScenario('6-missing-classification-throws', scenario6MissingClassificationThrows);
|
|
483
|
+
await runScenario('7-missing-thesis-throws', scenario7MissingThesisThrows);
|
|
484
|
+
await runScenario('8-aura-unreachable-throws', scenario8AuraUnreachableThrows);
|
|
485
|
+
await runScenario('9-adv-CANON-PART-8-thesis', scenario9AdvForbiddenInThesis);
|
|
486
|
+
await runScenario('10-adv-CANON-PART-8-bridge_concept', scenario10AdvForbiddenInBridgeConcept);
|
|
487
|
+
await runScenario('11-adv-CANON-PART-8-query_concept', scenario11AdvForbiddenInQueryConcept);
|
|
488
|
+
await runScenario('12-adv-CANON-PART-8-experts-UNWIND-input', scenario12AdvForbiddenInExpertsUnwindInput);
|
|
489
|
+
|
|
490
|
+
const sweepHits = a1Sweep();
|
|
491
|
+
if (sweepHits > 0) {
|
|
492
|
+
failed += 1;
|
|
493
|
+
failures.push({
|
|
494
|
+
name: 'A1-sweep',
|
|
495
|
+
err: new Error('A1 sweep found ' + sweepHits + ' forbidden-pattern hits'),
|
|
496
|
+
});
|
|
497
|
+
process.stderr.write(' FAIL A1-sweep (' + sweepHits + ' hits)\n');
|
|
498
|
+
} else {
|
|
499
|
+
process.stdout.write(' ok A1-sweep (zero forbidden-pattern hits)\n');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (failed > 0) {
|
|
503
|
+
process.stdout.write('=== 89.3-01 rs-neo4j-writer suite: ' +
|
|
504
|
+
passed + '/12 passed' +
|
|
505
|
+
' (' + failed + ' failed) ===\n');
|
|
506
|
+
for (const f of failures) {
|
|
507
|
+
process.stderr.write(' FAILURE: ' + f.name + ': ' +
|
|
508
|
+
(f.err && f.err.message ? f.err.message : String(f.err)) + '\n');
|
|
509
|
+
}
|
|
510
|
+
process.exit(1);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
process.stdout.write('=== 89.3-01 rs-neo4j-writer suite: 12/12 passed ===\n');
|
|
514
|
+
process.exit(0);
|
|
515
|
+
})().catch(function (err) {
|
|
516
|
+
process.stderr.write('FATAL: ' + (err && err.stack ? err.stack : err) + '\n');
|
|
517
|
+
process.exit(2);
|
|
518
|
+
});
|