@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,556 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
4
|
+
*
|
|
5
|
+
* Phase 88-04-B -- atomic write contract for vault-section-minto-generator.cjs
|
|
6
|
+
* ===========================================================================
|
|
7
|
+
* 7 test cases covering:
|
|
8
|
+
*
|
|
9
|
+
* Test 1: happy path -- generator --write produces valid MINTO.md via
|
|
10
|
+
* openSync('wx') + fsync + invariants validate + acquireLock +
|
|
11
|
+
* renameSync, returns {success:true, violations:[], bytes_written>0}
|
|
12
|
+
* on stdout as JSON.
|
|
13
|
+
* Test 2: concurrent writes -- 5 forked workers race against the same
|
|
14
|
+
* section; every worker exits 0 (writes serialize via acquireLock),
|
|
15
|
+
* final MINTO.md is well-formed, no orphan .tmp.<pid>.minto files
|
|
16
|
+
* in the section directory after all workers finish.
|
|
17
|
+
* Test 3: mid-write crash -- SIGKILL a child that has fsynced its tmp but
|
|
18
|
+
* not yet renamed. Previous MINTO.md stays intact; orphan tmp file
|
|
19
|
+
* left for 88-13 guardian cleanup (naming convention verified).
|
|
20
|
+
* Test 4: invariants error rejection -- MOS_TEST=1 with
|
|
21
|
+
* --mock-invariants-fail=error forces validator to return ERROR
|
|
22
|
+
* violations. Generator returns {success:false, violations:[...]},
|
|
23
|
+
* existing MINTO.md preserved byte-for-byte, tmp file removed.
|
|
24
|
+
* Test 5: invariants warning passthrough -- --mock-invariants-fail=warning
|
|
25
|
+
* forces WARNING-only violations. Generator proceeds with rename,
|
|
26
|
+
* returns {success:true, violations:[...]} (warnings are soft).
|
|
27
|
+
* Test 6: reader safety -- 100 concurrent fs.readFileSync on MINTO.md
|
|
28
|
+
* interleaved with generator --write cycles. Every read returns
|
|
29
|
+
* either the previous full file or the new full file (valid
|
|
30
|
+
* frontmatter + body); never a truncated partial write.
|
|
31
|
+
* Test 7: fsync-before-rename ordering -- trace via a fs module wrapper
|
|
32
|
+
* that records the call order; verifies fsyncSync is invoked on
|
|
33
|
+
* the tmp fd BEFORE the renameSync call.
|
|
34
|
+
*
|
|
35
|
+
* Pure node built-ins. No npm deps. Cleanup via process.on('exit').
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
'use strict';
|
|
39
|
+
|
|
40
|
+
const assert = require('node:assert/strict');
|
|
41
|
+
const fs = require('node:fs');
|
|
42
|
+
const os = require('node:os');
|
|
43
|
+
const path = require('node:path');
|
|
44
|
+
const { spawnSync, fork } = require('node:child_process');
|
|
45
|
+
|
|
46
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
47
|
+
const GENERATOR = path.join(
|
|
48
|
+
REPO_ROOT,
|
|
49
|
+
'scripts',
|
|
50
|
+
'vault-section-minto-generator.cjs'
|
|
51
|
+
);
|
|
52
|
+
const FIXTURE_SRC = path.join(
|
|
53
|
+
REPO_ROOT,
|
|
54
|
+
'test-fixtures',
|
|
55
|
+
'feynman',
|
|
56
|
+
'sections',
|
|
57
|
+
'fixture-small'
|
|
58
|
+
);
|
|
59
|
+
const FIXTURE_NARRATIVE = path.join(
|
|
60
|
+
REPO_ROOT,
|
|
61
|
+
'test-fixtures',
|
|
62
|
+
'feynman',
|
|
63
|
+
'narratives',
|
|
64
|
+
'fixture-small.json'
|
|
65
|
+
);
|
|
66
|
+
const WORKER = path.join(
|
|
67
|
+
__dirname,
|
|
68
|
+
'vault-section-minto-generator-atomic.worker.cjs'
|
|
69
|
+
);
|
|
70
|
+
const SECTION = 'problem-definition';
|
|
71
|
+
const FROZEN_DATE = '2026-04-14';
|
|
72
|
+
const FROZEN_TIMESTAMP = '2026-04-14T00:00:00Z';
|
|
73
|
+
|
|
74
|
+
// ---------- Tmp workspace helpers ----------
|
|
75
|
+
|
|
76
|
+
const TMP_ROOTS = [];
|
|
77
|
+
process.on('exit', function () {
|
|
78
|
+
for (const r of TMP_ROOTS) {
|
|
79
|
+
try {
|
|
80
|
+
fs.rmSync(r, { recursive: true, force: true });
|
|
81
|
+
} catch (_) {
|
|
82
|
+
/* best effort */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function copyDirSync(src, dst) {
|
|
88
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
89
|
+
for (const ent of fs.readdirSync(src, { withFileTypes: true })) {
|
|
90
|
+
const s = path.join(src, ent.name);
|
|
91
|
+
const d = path.join(dst, ent.name);
|
|
92
|
+
if (ent.isDirectory()) {
|
|
93
|
+
copyDirSync(s, d);
|
|
94
|
+
} else if (ent.isFile()) {
|
|
95
|
+
fs.copyFileSync(s, d);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function makeRoom() {
|
|
101
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'fm-atomic-'));
|
|
102
|
+
TMP_ROOTS.push(tmp);
|
|
103
|
+
const roomDir = path.join(tmp, 'room');
|
|
104
|
+
copyDirSync(FIXTURE_SRC, roomDir);
|
|
105
|
+
// Mark the tmp room as a room-root so any walkers (Phase 87-01a, 88-03)
|
|
106
|
+
// treat it like a real Data Room during the test cycle.
|
|
107
|
+
fs.writeFileSync(path.join(roomDir, '.room-root'), '');
|
|
108
|
+
return roomDir;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function mintoPath(roomDir) {
|
|
112
|
+
return path.join(roomDir, SECTION, 'MINTO.md');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function cleanMinto(roomDir) {
|
|
116
|
+
const p = mintoPath(roomDir);
|
|
117
|
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function runGenerator(roomDir, extraArgs, extraEnv) {
|
|
121
|
+
const args = [GENERATOR, '--write', roomDir, '--section', SECTION];
|
|
122
|
+
if (Array.isArray(extraArgs)) {
|
|
123
|
+
for (const a of extraArgs) args.push(a);
|
|
124
|
+
}
|
|
125
|
+
return spawnSync(process.execPath, args, {
|
|
126
|
+
env: Object.assign(
|
|
127
|
+
{},
|
|
128
|
+
process.env,
|
|
129
|
+
{
|
|
130
|
+
MINTO_FROZEN_DATE: FROZEN_DATE,
|
|
131
|
+
MINTO_FROZEN_TIMESTAMP: FROZEN_TIMESTAMP,
|
|
132
|
+
},
|
|
133
|
+
extraEnv || {}
|
|
134
|
+
),
|
|
135
|
+
encoding: 'utf-8',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function listOrphanTmps(roomDir) {
|
|
140
|
+
const sectionDir = path.join(roomDir, SECTION);
|
|
141
|
+
const out = [];
|
|
142
|
+
let entries;
|
|
143
|
+
try {
|
|
144
|
+
entries = fs.readdirSync(sectionDir, { withFileTypes: true });
|
|
145
|
+
} catch (_) {
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
for (const ent of entries) {
|
|
149
|
+
if (ent.isFile() && /MINTO\.md\.tmp\.\d+\.minto$/.test(ent.name)) {
|
|
150
|
+
out.push(path.join(sectionDir, ent.name));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ---------- Runner ----------
|
|
157
|
+
|
|
158
|
+
let passed = 0;
|
|
159
|
+
let failed = 0;
|
|
160
|
+
function run(name, fn) {
|
|
161
|
+
try {
|
|
162
|
+
fn();
|
|
163
|
+
passed += 1;
|
|
164
|
+
process.stdout.write(' ok ' + name + '\n');
|
|
165
|
+
} catch (err) {
|
|
166
|
+
failed += 1;
|
|
167
|
+
process.stderr.write(' FAIL ' + name + '\n');
|
|
168
|
+
process.stderr.write(
|
|
169
|
+
' ' + (err && err.stack ? err.stack : err && err.message || err) + '\n'
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function runAsync(name, fn) {
|
|
175
|
+
try {
|
|
176
|
+
await fn();
|
|
177
|
+
passed += 1;
|
|
178
|
+
process.stdout.write(' ok ' + name + '\n');
|
|
179
|
+
} catch (err) {
|
|
180
|
+
failed += 1;
|
|
181
|
+
process.stderr.write(' FAIL ' + name + '\n');
|
|
182
|
+
process.stderr.write(
|
|
183
|
+
' ' + (err && err.stack ? err.stack : err && err.message || err) + '\n'
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------- Test 1: happy path ----------
|
|
189
|
+
|
|
190
|
+
run('Test 1: happy path returns {success:true} JSON + valid MINTO.md', function () {
|
|
191
|
+
const room = makeRoom();
|
|
192
|
+
cleanMinto(room);
|
|
193
|
+
|
|
194
|
+
const res = runGenerator(room, ['--narrative', FIXTURE_NARRATIVE]);
|
|
195
|
+
assert.equal(
|
|
196
|
+
res.status,
|
|
197
|
+
0,
|
|
198
|
+
'--write exited non-zero: ' + (res.stderr || '')
|
|
199
|
+
);
|
|
200
|
+
// JSON envelope printed to stdout.
|
|
201
|
+
const envLine = res.stdout
|
|
202
|
+
.split(/\r?\n/)
|
|
203
|
+
.filter(function (l) { return l.trim().startsWith('{'); })
|
|
204
|
+
.pop();
|
|
205
|
+
assert.ok(envLine, 'expected JSON envelope on stdout, got: ' + res.stdout);
|
|
206
|
+
const env = JSON.parse(envLine);
|
|
207
|
+
assert.equal(env.success, true, 'success flag should be true on happy path');
|
|
208
|
+
assert.ok(Array.isArray(env.violations), 'violations must be array');
|
|
209
|
+
assert.ok(
|
|
210
|
+
env.bytes_written > 0,
|
|
211
|
+
'bytes_written must be positive, got ' + env.bytes_written
|
|
212
|
+
);
|
|
213
|
+
assert.ok(
|
|
214
|
+
typeof env.elapsed_ms === 'number' && env.elapsed_ms >= 0,
|
|
215
|
+
'elapsed_ms must be non-negative number'
|
|
216
|
+
);
|
|
217
|
+
assert.equal(env.path, mintoPath(room), 'path echoed');
|
|
218
|
+
|
|
219
|
+
// MINTO.md exists and has expected structure.
|
|
220
|
+
const body = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
221
|
+
assert.ok(/^---/.test(body), 'frontmatter present');
|
|
222
|
+
assert.ok(
|
|
223
|
+
/methodology: feynman-minto|methodology: minto-pyramid/.test(body),
|
|
224
|
+
'methodology marker present'
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// No orphan tmp files post-write.
|
|
228
|
+
assert.deepEqual(
|
|
229
|
+
listOrphanTmps(room),
|
|
230
|
+
[],
|
|
231
|
+
'no orphan .tmp.<pid>.minto after success'
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ---------- Test 2: concurrent writes (5 forked workers) ----------
|
|
236
|
+
|
|
237
|
+
runAsync(
|
|
238
|
+
'Test 2: 5 concurrent forked --write all succeed, no tmp leaks',
|
|
239
|
+
async function () {
|
|
240
|
+
const room = makeRoom();
|
|
241
|
+
cleanMinto(room);
|
|
242
|
+
|
|
243
|
+
const forks = [];
|
|
244
|
+
for (let i = 0; i < 5; i++) {
|
|
245
|
+
forks.push(
|
|
246
|
+
new Promise(function (resolve) {
|
|
247
|
+
const child = fork(WORKER, [room, SECTION], { silent: true });
|
|
248
|
+
let stderrBuf = '';
|
|
249
|
+
if (child.stderr) {
|
|
250
|
+
child.stderr.on('data', function (c) {
|
|
251
|
+
stderrBuf += c.toString();
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
child.on('exit', function (code) {
|
|
255
|
+
resolve({ code: code, stderr: stderrBuf });
|
|
256
|
+
});
|
|
257
|
+
})
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const results = await Promise.all(forks);
|
|
262
|
+
for (let i = 0; i < results.length; i++) {
|
|
263
|
+
assert.equal(
|
|
264
|
+
results[i].code,
|
|
265
|
+
0,
|
|
266
|
+
'worker ' + i + ' exited ' + results[i].code + ': ' + results[i].stderr
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Final file must be well-formed (not a partial/torn write).
|
|
271
|
+
const body = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
272
|
+
assert.ok(/^---\r?\n/.test(body), 'frontmatter opening delimiter present');
|
|
273
|
+
assert.ok(/\n---\r?\n/.test(body), 'frontmatter closing delimiter present');
|
|
274
|
+
assert.ok(body.length > 100, 'final MINTO.md has content');
|
|
275
|
+
|
|
276
|
+
// No orphan .tmp.<pid>.minto sitting around.
|
|
277
|
+
const orphans = listOrphanTmps(room);
|
|
278
|
+
assert.deepEqual(
|
|
279
|
+
orphans,
|
|
280
|
+
[],
|
|
281
|
+
'expected zero orphan tmp files, got: ' + orphans.join(',')
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// ---------- Test 3: mid-write crash preserves previous MINTO.md ----------
|
|
287
|
+
|
|
288
|
+
run(
|
|
289
|
+
'Test 3: mid-write SIGKILL preserves previous MINTO.md (tmp orphan named correctly)',
|
|
290
|
+
function () {
|
|
291
|
+
const room = makeRoom();
|
|
292
|
+
cleanMinto(room);
|
|
293
|
+
|
|
294
|
+
// Seed a "previous" MINTO.md via one successful write.
|
|
295
|
+
const seed = runGenerator(room, ['--narrative', FIXTURE_NARRATIVE]);
|
|
296
|
+
assert.equal(seed.status, 0, 'seed write failed: ' + seed.stderr);
|
|
297
|
+
const before = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
298
|
+
const beforeSize = before.length;
|
|
299
|
+
assert.ok(beforeSize > 100, 'seed MINTO.md has content');
|
|
300
|
+
|
|
301
|
+
// Now simulate a mid-write crash via MOS_TEST_ABORT_AFTER_FSYNC=1 which
|
|
302
|
+
// the generator treats as "exit after fsync but before rename".
|
|
303
|
+
const crashed = runGenerator(
|
|
304
|
+
room,
|
|
305
|
+
['--narrative', FIXTURE_NARRATIVE],
|
|
306
|
+
{ MOS_TEST: '1', MOS_TEST_ABORT_AFTER_FSYNC: '1' }
|
|
307
|
+
);
|
|
308
|
+
// Non-zero exit expected on crash path.
|
|
309
|
+
assert.notEqual(
|
|
310
|
+
crashed.status,
|
|
311
|
+
0,
|
|
312
|
+
'abort-after-fsync should produce non-zero exit'
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// Previous MINTO.md must be byte-identical.
|
|
316
|
+
const after = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
317
|
+
assert.equal(
|
|
318
|
+
after,
|
|
319
|
+
before,
|
|
320
|
+
'previous MINTO.md must be preserved byte-for-byte after mid-write crash'
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// An orphan tmp file matching the guardian pattern should exist.
|
|
324
|
+
const orphans = listOrphanTmps(room);
|
|
325
|
+
assert.ok(
|
|
326
|
+
orphans.length >= 1,
|
|
327
|
+
'expected at least one orphan .tmp.<pid>.minto for guardian cleanup, got: ' +
|
|
328
|
+
orphans.join(',')
|
|
329
|
+
);
|
|
330
|
+
for (const o of orphans) {
|
|
331
|
+
assert.ok(
|
|
332
|
+
/MINTO\.md\.tmp\.\d+\.minto$/.test(o),
|
|
333
|
+
'orphan name does not match guardian pattern: ' + o
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
// ---------- Test 4: invariants ERROR rejection ----------
|
|
340
|
+
|
|
341
|
+
run(
|
|
342
|
+
'Test 4: --mock-invariants-fail=error rejects write; previous MINTO.md preserved',
|
|
343
|
+
function () {
|
|
344
|
+
const room = makeRoom();
|
|
345
|
+
cleanMinto(room);
|
|
346
|
+
|
|
347
|
+
// Seed a happy-path MINTO first.
|
|
348
|
+
const seed = runGenerator(room, ['--narrative', FIXTURE_NARRATIVE]);
|
|
349
|
+
assert.equal(seed.status, 0, 'seed failed: ' + seed.stderr);
|
|
350
|
+
const before = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
351
|
+
|
|
352
|
+
// Force an ERROR-severity violation.
|
|
353
|
+
const res = runGenerator(
|
|
354
|
+
room,
|
|
355
|
+
['--narrative', FIXTURE_NARRATIVE, '--mock-invariants-fail=error'],
|
|
356
|
+
{ MOS_TEST: '1' }
|
|
357
|
+
);
|
|
358
|
+
// Generator prints JSON envelope but does NOT hard-fail the CLI (success
|
|
359
|
+
// flag in envelope carries the outcome). Exit code remains 0.
|
|
360
|
+
assert.equal(
|
|
361
|
+
res.status,
|
|
362
|
+
0,
|
|
363
|
+
'generator should exit 0 with success=false envelope, got ' +
|
|
364
|
+
res.status +
|
|
365
|
+
': ' +
|
|
366
|
+
res.stderr
|
|
367
|
+
);
|
|
368
|
+
const envLine = res.stdout
|
|
369
|
+
.split(/\r?\n/)
|
|
370
|
+
.filter(function (l) { return l.trim().startsWith('{'); })
|
|
371
|
+
.pop();
|
|
372
|
+
assert.ok(envLine, 'JSON envelope missing');
|
|
373
|
+
const env = JSON.parse(envLine);
|
|
374
|
+
assert.equal(env.success, false, 'success must be false on ERROR rejection');
|
|
375
|
+
assert.ok(Array.isArray(env.violations) && env.violations.length > 0, 'violations populated');
|
|
376
|
+
const hasError = env.violations.some(function (v) {
|
|
377
|
+
return v.severity === 'error' || v.severity === 'critical';
|
|
378
|
+
});
|
|
379
|
+
assert.ok(hasError, 'at least one error/critical violation expected');
|
|
380
|
+
|
|
381
|
+
// Previous MINTO.md preserved.
|
|
382
|
+
const after = fs.readFileSync(mintoPath(room), 'utf-8');
|
|
383
|
+
assert.equal(
|
|
384
|
+
after,
|
|
385
|
+
before,
|
|
386
|
+
'MINTO.md must be byte-identical to pre-rejection state'
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Tmp file cleaned up on rejection path.
|
|
390
|
+
const orphans = listOrphanTmps(room);
|
|
391
|
+
assert.deepEqual(
|
|
392
|
+
orphans,
|
|
393
|
+
[],
|
|
394
|
+
'tmp must be unlinked on rejection, got orphans: ' + orphans.join(',')
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
// ---------- Test 5: WARNING-only passes through ----------
|
|
400
|
+
|
|
401
|
+
run(
|
|
402
|
+
'Test 5: --mock-invariants-fail=warning still renames (warning is soft)',
|
|
403
|
+
function () {
|
|
404
|
+
const room = makeRoom();
|
|
405
|
+
cleanMinto(room);
|
|
406
|
+
|
|
407
|
+
const res = runGenerator(
|
|
408
|
+
room,
|
|
409
|
+
['--narrative', FIXTURE_NARRATIVE, '--mock-invariants-fail=warning'],
|
|
410
|
+
{ MOS_TEST: '1' }
|
|
411
|
+
);
|
|
412
|
+
assert.equal(res.status, 0, 'generator exit 0 expected, got ' + res.status);
|
|
413
|
+
const envLine = res.stdout
|
|
414
|
+
.split(/\r?\n/)
|
|
415
|
+
.filter(function (l) { return l.trim().startsWith('{'); })
|
|
416
|
+
.pop();
|
|
417
|
+
assert.ok(envLine, 'JSON envelope missing');
|
|
418
|
+
const env = JSON.parse(envLine);
|
|
419
|
+
assert.equal(env.success, true, 'warning-only MUST pass (soft severity)');
|
|
420
|
+
assert.ok(
|
|
421
|
+
env.violations.length > 0,
|
|
422
|
+
'warning violations should still be reported'
|
|
423
|
+
);
|
|
424
|
+
// File must exist after warning-passthrough.
|
|
425
|
+
assert.ok(
|
|
426
|
+
fs.existsSync(mintoPath(room)),
|
|
427
|
+
'MINTO.md should be written on warning passthrough'
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
// ---------- Test 6: reader safety during interleaved writes ----------
|
|
433
|
+
|
|
434
|
+
runAsync(
|
|
435
|
+
'Test 6: 100 interleaved reads during repeated --write see no torn content',
|
|
436
|
+
async function () {
|
|
437
|
+
const room = makeRoom();
|
|
438
|
+
cleanMinto(room);
|
|
439
|
+
// Seed so first reads have something.
|
|
440
|
+
const seed = runGenerator(room, ['--narrative', FIXTURE_NARRATIVE]);
|
|
441
|
+
assert.equal(seed.status, 0, 'seed failed: ' + seed.stderr);
|
|
442
|
+
|
|
443
|
+
const mp = mintoPath(room);
|
|
444
|
+
|
|
445
|
+
// Writer loop (fire-and-forget in the background).
|
|
446
|
+
let writerDone = false;
|
|
447
|
+
const writerLoop = (async function () {
|
|
448
|
+
for (let i = 0; i < 10; i++) {
|
|
449
|
+
runGenerator(room, ['--narrative', FIXTURE_NARRATIVE]);
|
|
450
|
+
}
|
|
451
|
+
writerDone = true;
|
|
452
|
+
})();
|
|
453
|
+
|
|
454
|
+
// 100 reads interleaved with the writer.
|
|
455
|
+
let readCount = 0;
|
|
456
|
+
while (!writerDone || readCount < 100) {
|
|
457
|
+
if (readCount >= 100 && writerDone) break;
|
|
458
|
+
try {
|
|
459
|
+
const body = fs.readFileSync(mp, 'utf-8');
|
|
460
|
+
// Accept only well-formed frontmatter + non-empty body.
|
|
461
|
+
assert.ok(
|
|
462
|
+
/^---\r?\n[\s\S]*?\r?\n---\r?\n/.test(body),
|
|
463
|
+
'read #' + readCount + ' returned malformed frontmatter (torn write?)'
|
|
464
|
+
);
|
|
465
|
+
assert.ok(
|
|
466
|
+
body.length > 100,
|
|
467
|
+
'read #' + readCount + ' returned unexpectedly short body (' + body.length + ' bytes)'
|
|
468
|
+
);
|
|
469
|
+
} catch (e) {
|
|
470
|
+
if (e.code === 'ENOENT') {
|
|
471
|
+
// Transient ENOENT is theoretically possible on some filesystems
|
|
472
|
+
// during rename; accept it but count toward progress so the loop
|
|
473
|
+
// can terminate.
|
|
474
|
+
} else {
|
|
475
|
+
throw e;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
readCount += 1;
|
|
479
|
+
if (readCount % 10 === 0) {
|
|
480
|
+
await new Promise(function (r) { setTimeout(r, 5); });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
await writerLoop;
|
|
485
|
+
assert.ok(readCount >= 100, 'expected at least 100 reads, got ' + readCount);
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
// ---------- Test 7: fsync-before-rename ordering ----------
|
|
490
|
+
|
|
491
|
+
run(
|
|
492
|
+
'Test 7: fsyncSync invoked before renameSync (trace via MOS_TRACE_FS=1)',
|
|
493
|
+
function () {
|
|
494
|
+
const room = makeRoom();
|
|
495
|
+
cleanMinto(room);
|
|
496
|
+
|
|
497
|
+
const res = runGenerator(
|
|
498
|
+
room,
|
|
499
|
+
['--narrative', FIXTURE_NARRATIVE],
|
|
500
|
+
{ MOS_TEST: '1', MOS_TRACE_FS: '1' }
|
|
501
|
+
);
|
|
502
|
+
assert.equal(res.status, 0, 'trace run failed: ' + res.stderr);
|
|
503
|
+
const lines = res.stderr.split(/\r?\n/);
|
|
504
|
+
const fsyncIdx = lines.findIndex(function (l) {
|
|
505
|
+
return /^TRACE_FS fsyncSync/.test(l);
|
|
506
|
+
});
|
|
507
|
+
const renameIdx = lines.findIndex(function (l) {
|
|
508
|
+
return /^TRACE_FS renameSync/.test(l);
|
|
509
|
+
});
|
|
510
|
+
assert.ok(
|
|
511
|
+
fsyncIdx !== -1,
|
|
512
|
+
'expected TRACE_FS fsyncSync line, stderr: ' + res.stderr
|
|
513
|
+
);
|
|
514
|
+
assert.ok(
|
|
515
|
+
renameIdx !== -1,
|
|
516
|
+
'expected TRACE_FS renameSync line, stderr: ' + res.stderr
|
|
517
|
+
);
|
|
518
|
+
assert.ok(
|
|
519
|
+
fsyncIdx < renameIdx,
|
|
520
|
+
'fsyncSync (line ' +
|
|
521
|
+
fsyncIdx +
|
|
522
|
+
') must precede renameSync (line ' +
|
|
523
|
+
renameIdx +
|
|
524
|
+
')'
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
// ---------- Finish (async tests included) ----------
|
|
530
|
+
|
|
531
|
+
// Node top-level await is not available in CJS; we chain via a promise.
|
|
532
|
+
(async function () {
|
|
533
|
+
// runAsync tests above have already started; wait a tick so the event
|
|
534
|
+
// loop drains their microtasks before we report counts.
|
|
535
|
+
await new Promise(function (r) { setImmediate(r); });
|
|
536
|
+
|
|
537
|
+
// Give a generous window for the async tests to finish. The actual async
|
|
538
|
+
// test bodies await their own work; we just need the process to stay
|
|
539
|
+
// alive until they log.
|
|
540
|
+
const deadline = Date.now() + 60 * 1000;
|
|
541
|
+
while (passed + failed < 7 && Date.now() < deadline) {
|
|
542
|
+
await new Promise(function (r) { setTimeout(r, 50); });
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
process.stdout.write(
|
|
546
|
+
'\nvault-section-minto-generator-atomic: ' +
|
|
547
|
+
passed +
|
|
548
|
+
' passed, ' +
|
|
549
|
+
failed +
|
|
550
|
+
' failed\n'
|
|
551
|
+
);
|
|
552
|
+
process.exit(failed === 0 ? 0 : 1);
|
|
553
|
+
})().catch(function (err) {
|
|
554
|
+
process.stderr.write('driver crash: ' + (err && err.stack || err) + '\n');
|
|
555
|
+
process.exit(1);
|
|
556
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
4
|
+
*
|
|
5
|
+
* Phase 88-04-B -- vault-section-minto-generator atomic-write concurrency worker
|
|
6
|
+
* =============================================================================
|
|
7
|
+
* Forked by lib/memory/vault-section-minto-generator-atomic.test.cjs Test 2
|
|
8
|
+
* (5 concurrent tier-0 writes against the same section) and Test 6 (reader
|
|
9
|
+
* safety loop). Each worker shells out to the generator --write subcommand;
|
|
10
|
+
* exactly one process wins the rename race per cycle. No torn reads, no
|
|
11
|
+
* orphan tmp files after all workers finish.
|
|
12
|
+
*
|
|
13
|
+
* Standalone file (not inline template string in the test) to match the
|
|
14
|
+
* Phase 87-02 write-lock-atomic.worker.cjs convention. Avoids path-escape
|
|
15
|
+
* ambiguity on Windows.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* node vault-section-minto-generator-atomic.worker.cjs <roomDir> <section>
|
|
19
|
+
*
|
|
20
|
+
* Exit codes:
|
|
21
|
+
* 0 -- generator --write succeeded (valid outcome for the winner; losers
|
|
22
|
+
* also exit 0 because the generator serializes via acquireLock and
|
|
23
|
+
* each attempt emits its own tmp before rename)
|
|
24
|
+
* 1 -- unexpected error (fails the parent test)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const path = require('node:path');
|
|
30
|
+
const { spawnSync } = require('node:child_process');
|
|
31
|
+
|
|
32
|
+
const GENERATOR = path.resolve(
|
|
33
|
+
__dirname,
|
|
34
|
+
'..',
|
|
35
|
+
'..',
|
|
36
|
+
'scripts',
|
|
37
|
+
'vault-section-minto-generator.cjs'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const roomDir = process.argv[2];
|
|
41
|
+
const section = process.argv[3];
|
|
42
|
+
|
|
43
|
+
if (!roomDir || !section) {
|
|
44
|
+
process.stderr.write(
|
|
45
|
+
'vault-section-minto-generator-atomic.worker: missing argv (roomDir, section)\n'
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const res = spawnSync(
|
|
51
|
+
process.execPath,
|
|
52
|
+
[GENERATOR, '--write', roomDir, '--section', section],
|
|
53
|
+
{
|
|
54
|
+
env: Object.assign({}, process.env, {
|
|
55
|
+
MINTO_FROZEN_DATE: '2026-04-14',
|
|
56
|
+
MINTO_FROZEN_TIMESTAMP: '2026-04-14T00:00:00Z',
|
|
57
|
+
}),
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (res.status !== 0) {
|
|
63
|
+
process.stderr.write(
|
|
64
|
+
'worker generator --write exited ' +
|
|
65
|
+
res.status +
|
|
66
|
+
': stderr=' +
|
|
67
|
+
(res.stderr || '') +
|
|
68
|
+
'\n'
|
|
69
|
+
);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
process.exit(0);
|