@mnstry/atelier 0.2.0-alpha.11 → 0.2.0-alpha.13
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/CHANGELOG.md +1005 -0
- package/README.md +149 -9
- package/contracts/atelier-adoption-policy.v2.schema.json +55 -0
- package/contracts/atelier-architecture.v1.schema.json +258 -0
- package/contracts/atelier-boundary-delegations.v1.schema.json +161 -0
- package/contracts/atelier-boundary-owner-keys.v1.schema.json +98 -0
- package/contracts/atelier-build.v1.schema.json +1076 -0
- package/contracts/atelier-capability.v1.schema.json +1252 -0
- package/contracts/atelier-coordination.v1.schema.json +1050 -0
- package/contracts/atelier-evidence-navigation.v1.schema.json +603 -0
- package/contracts/atelier-harness.v1.schema.json +234 -0
- package/contracts/atelier-ingestion.v1.schema.json +806 -0
- package/contracts/atelier-inquiry.v1.schema.json +1772 -0
- package/contracts/atelier-instruction-adoption.v1.schema.json +490 -0
- package/contracts/atelier-interaction.v1.schema.json +553 -0
- package/contracts/atelier-judgment.v1.schema.json +690 -0
- package/contracts/atelier-knowledge.v1.schema.json +1512 -0
- package/contracts/atelier-learning.v1.schema.json +1095 -0
- package/contracts/atelier-migration.v3.schema.json +64 -0
- package/contracts/atelier-obsidian-generation-manifest.v2.schema.json +372 -0
- package/contracts/atelier-personal-workspace-manifest.v1.schema.json +87 -0
- package/contracts/atelier-personal-workspace-overlay.v1.schema.json +299 -0
- package/contracts/atelier-template-adoption.v1.schema.json +223 -0
- package/contracts/atelier-template-profile.v1.schema.json +1168 -0
- package/contracts/atelier-trackable.v1.schema.json +781 -0
- package/contracts/atelier-upgrade-plan.v3.schema.json +532 -0
- package/contracts/compat-baseline.json +1 -1
- package/docs/architecture.md +89 -0
- package/docs/assurance-controls.md +4 -3
- package/docs/blocks/capability-stewardship.md +17 -0
- package/docs/blocks/claims.md +16 -3
- package/docs/blocks/inquiry-harnesses.md +19 -0
- package/docs/blocks/learning-harnesses.md +17 -0
- package/docs/capability-stewardship.md +269 -0
- package/docs/coordination.md +51 -0
- package/docs/decision-practices.md +111 -0
- package/docs/decisions.md +29 -0
- package/docs/evidence-navigation.md +237 -0
- package/docs/exact-upgrades.md +3 -2
- package/docs/ingestion.md +181 -0
- package/docs/inquiry-harnesses.md +211 -0
- package/docs/install.md +80 -3
- package/docs/intake-and-guides.md +5 -0
- package/docs/integration-contract-decisions.md +24 -2
- package/docs/interaction-and-reflection.md +72 -0
- package/docs/knowledge-graph.md +20 -0
- package/docs/knowledge-health/api.md +30 -0
- package/docs/knowledge-health/assessment/api.md +96 -0
- package/docs/knowledge-health/assessment/capabilities.md +40 -0
- package/docs/knowledge-health/assessment/evaluation.md +27 -0
- package/docs/knowledge-health/assessment/facilitator.md +30 -0
- package/docs/knowledge-health/assessment/quickstart.md +61 -0
- package/docs/knowledge-health/assessment/troubleshooting.md +23 -0
- package/docs/knowledge-health/devday/facilitator.md +16 -0
- package/docs/knowledge-health/devday/participant-response.md +22 -0
- package/docs/knowledge-health/devday/public-default.md +107 -0
- package/docs/knowledge-health/devday/quickstart.md +18 -0
- package/docs/knowledge-health/devday/support.md +22 -0
- package/docs/knowledge-health/exercise.md +17 -0
- package/docs/knowledge-health/facilitator.md +20 -0
- package/docs/knowledge-health/quickstart.md +94 -0
- package/docs/knowledge-health/readme.md +15 -0
- package/docs/knowledge-health/support.md +34 -0
- package/docs/knowledge-setup.md +248 -0
- package/docs/knowledge-workspace.md +264 -0
- package/docs/learning-harnesses.md +238 -0
- package/docs/learning.md +215 -0
- package/docs/local-services.md +242 -26
- package/docs/obsidian-contract.md +878 -36
- package/docs/obsidian-plugin.md +619 -0
- package/docs/obsidian.md +809 -64
- package/docs/optional-ingestion.md +83 -0
- package/docs/personal-workspace.md +257 -0
- package/docs/practical-judgment.md +92 -0
- package/docs/progressive-ingestion-acceptance.md +89 -0
- package/docs/progressive-ingestion.md +235 -0
- package/docs/project-command-inventory.md +1 -0
- package/docs/release-engineering.md +56 -1
- package/docs/repo-boundary-guard.md +94 -0
- package/docs/research-starter-quickstart.md +66 -0
- package/docs/research-starter.md +114 -0
- package/docs/semantic-ingestion.md +198 -0
- package/docs/semantic-operation.md +317 -0
- package/docs/skill-steward.md +6 -0
- package/docs/template-profile.md +164 -0
- package/docs/template-upgrades.md +114 -0
- package/docs/trackables.md +111 -0
- package/docs/upgrade.md +68 -3
- package/fixtures/atelier-architecture/binding/invalid/document.json +19 -0
- package/fixtures/atelier-architecture/binding/valid/document.json +19 -0
- package/fixtures/atelier-architecture/catalog/invalid/document.json +290 -0
- package/fixtures/atelier-architecture/catalog/valid/document.json +343 -0
- package/fixtures/atelier-build-contract/attempt/invalid/document.json +20 -0
- package/fixtures/atelier-build-contract/attempt/valid/document.json +19 -0
- package/fixtures/atelier-build-contract/candidate/invalid/document.json +24 -0
- package/fixtures/atelier-build-contract/candidate/valid/document.json +23 -0
- package/fixtures/atelier-build-contract/decision/invalid/document.json +31 -0
- package/fixtures/atelier-build-contract/decision/valid/document.json +30 -0
- package/fixtures/atelier-build-contract/delivery/invalid/document.json +18 -0
- package/fixtures/atelier-build-contract/delivery/valid/document.json +17 -0
- package/fixtures/atelier-build-contract/gate/invalid/document.json +22 -0
- package/fixtures/atelier-build-contract/gate/valid/document.json +21 -0
- package/fixtures/atelier-build-contract/ledger/invalid/document.json +270 -0
- package/fixtures/atelier-build-contract/ledger/valid/document.json +269 -0
- package/fixtures/atelier-build-contract/objective/invalid/document.json +73 -0
- package/fixtures/atelier-build-contract/objective/valid/document.json +72 -0
- package/fixtures/atelier-build-contract/progress/invalid/document.json +18 -0
- package/fixtures/atelier-build-contract/progress/valid/document.json +17 -0
- package/fixtures/atelier-capability-contract/adoption/invalid/document.json +71 -0
- package/fixtures/atelier-capability-contract/adoption/valid/document.json +70 -0
- package/fixtures/atelier-capability-contract/event/invalid/document.json +18 -0
- package/fixtures/atelier-capability-contract/event/valid/document.json +17 -0
- package/fixtures/atelier-capability-contract/journal/invalid/document.json +382 -0
- package/fixtures/atelier-capability-contract/journal/valid/document.json +381 -0
- package/fixtures/atelier-capability-contract/notice/invalid/document.json +8 -0
- package/fixtures/atelier-capability-contract/notice/valid/document.json +7 -0
- package/fixtures/atelier-capability-contract/package/invalid/document.json +59 -0
- package/fixtures/atelier-capability-contract/package/valid/document.json +58 -0
- package/fixtures/atelier-capability-contract/plan/invalid/document.json +107 -0
- package/fixtures/atelier-capability-contract/plan/valid/document.json +106 -0
- package/fixtures/atelier-capability-contract/release/invalid/document.json +85 -0
- package/fixtures/atelier-capability-contract/release/valid/document.json +84 -0
- package/fixtures/atelier-capability-contract/state/invalid/document.json +316 -0
- package/fixtures/atelier-capability-contract/state/valid/document.json +315 -0
- package/fixtures/atelier-coordination/dependency/invalid/document.json +37 -0
- package/fixtures/atelier-coordination/dependency/valid/document.json +36 -0
- package/fixtures/atelier-coordination/directive/invalid/document.json +25 -0
- package/fixtures/atelier-coordination/directive/valid/document.json +24 -0
- package/fixtures/atelier-coordination/disposition/invalid/document.json +34 -0
- package/fixtures/atelier-coordination/disposition/valid/document.json +33 -0
- package/fixtures/atelier-coordination/outcome/invalid/document.json +39 -0
- package/fixtures/atelier-coordination/outcome/valid/document.json +38 -0
- package/fixtures/atelier-coordination/recovery/invalid/document.json +34 -0
- package/fixtures/atelier-coordination/recovery/valid/document.json +33 -0
- package/fixtures/atelier-harness-contract/handoff/invalid/document.json +25 -0
- package/fixtures/atelier-harness-contract/handoff/valid/document.json +24 -0
- package/fixtures/atelier-ingestion/invalid/authority.json +19 -0
- package/fixtures/atelier-ingestion/semantic-baseline.json +26 -0
- package/fixtures/atelier-ingestion/semantic-operation.json +75 -0
- package/fixtures/atelier-ingestion/valid/plan-input.json +18 -0
- package/fixtures/atelier-inquiry-contract/assessment/invalid/document.json +41 -0
- package/fixtures/atelier-inquiry-contract/assessment/valid/document.json +40 -0
- package/fixtures/atelier-inquiry-contract/bundle/invalid/document.json +51 -0
- package/fixtures/atelier-inquiry-contract/bundle/valid/document.json +50 -0
- package/fixtures/atelier-inquiry-contract/campaign/invalid/document.json +17 -0
- package/fixtures/atelier-inquiry-contract/campaign/valid/document.json +16 -0
- package/fixtures/atelier-inquiry-contract/decision/invalid/document.json +22 -0
- package/fixtures/atelier-inquiry-contract/decision/valid/document.json +21 -0
- package/fixtures/atelier-inquiry-contract/feedback/invalid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/feedback/valid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/handoff/invalid/document.json +92 -0
- package/fixtures/atelier-inquiry-contract/handoff/valid/document.json +91 -0
- package/fixtures/atelier-inquiry-contract/hypothesis/invalid/document.json +20 -0
- package/fixtures/atelier-inquiry-contract/hypothesis/valid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/ledger/invalid/document.json +680 -0
- package/fixtures/atelier-inquiry-contract/ledger/valid/document.json +679 -0
- package/fixtures/atelier-inquiry-contract/legacy-assessment/invalid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/legacy-assessment/valid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/request/invalid/document.json +50 -0
- package/fixtures/atelier-inquiry-contract/request/valid/document.json +49 -0
- package/fixtures/atelier-inquiry-contract/source/invalid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/source/valid/document.json +17 -0
- package/fixtures/atelier-inquiry-contract/withdrawal/invalid/document.json +16 -0
- package/fixtures/atelier-inquiry-contract/withdrawal/valid/document.json +15 -0
- package/fixtures/atelier-instruction-adoption/context-receipt/invalid/document.json +18 -0
- package/fixtures/atelier-instruction-adoption/context-receipt/valid/document.json +17 -0
- package/fixtures/atelier-instruction-adoption/plan/invalid/document.json +63 -0
- package/fixtures/atelier-instruction-adoption/plan/valid/document.json +62 -0
- package/fixtures/atelier-instruction-adoption/receipt/invalid/document.json +22 -0
- package/fixtures/atelier-instruction-adoption/receipt/valid/document.json +21 -0
- package/fixtures/atelier-instruction-adoption/state/invalid/document.json +30 -0
- package/fixtures/atelier-instruction-adoption/state/valid/document.json +29 -0
- package/fixtures/atelier-interaction/act/invalid/document.json +25 -0
- package/fixtures/atelier-interaction/act/valid/document.json +24 -0
- package/fixtures/atelier-interaction/assessment/invalid/document.json +32 -0
- package/fixtures/atelier-interaction/assessment/valid/document.json +31 -0
- package/fixtures/atelier-interaction/observation/invalid/document.json +22 -0
- package/fixtures/atelier-interaction/observation/valid/document.json +21 -0
- package/fixtures/atelier-interaction/policy/invalid/document.json +20 -0
- package/fixtures/atelier-interaction/policy/valid/document.json +19 -0
- package/fixtures/atelier-judgment/case/invalid/document.json +76 -0
- package/fixtures/atelier-judgment/case/valid/document.json +75 -0
- package/fixtures/atelier-judgment/decision/invalid/document.json +38 -0
- package/fixtures/atelier-judgment/decision/valid/document.json +37 -0
- package/fixtures/atelier-judgment/native-decision.md +3 -0
- package/fixtures/atelier-judgment/practice-reconsideration/definition.json +92 -0
- package/fixtures/atelier-judgment/practice-reconsideration/scenario.json +435 -0
- package/fixtures/atelier-knowledge-contract/activation/invalid/document.json +26 -0
- package/fixtures/atelier-knowledge-contract/activation/valid/document.json +25 -0
- package/fixtures/atelier-knowledge-contract/contribution/invalid/document.json +34 -0
- package/fixtures/atelier-knowledge-contract/contribution/valid/document.json +33 -0
- package/fixtures/atelier-knowledge-contract/domain/invalid/document.json +41 -0
- package/fixtures/atelier-knowledge-contract/domain/valid/document.json +40 -0
- package/fixtures/atelier-knowledge-contract/domain-revision/invalid/document.json +46 -0
- package/fixtures/atelier-knowledge-contract/domain-revision/valid/document.json +45 -0
- package/fixtures/atelier-knowledge-contract/evaluation/invalid/document.json +21 -0
- package/fixtures/atelier-knowledge-contract/evaluation/valid/document.json +20 -0
- package/fixtures/atelier-knowledge-contract/ledger/invalid/document.json +318 -0
- package/fixtures/atelier-knowledge-contract/ledger/valid/document.json +317 -0
- package/fixtures/atelier-knowledge-contract/relation/invalid/document.json +25 -0
- package/fixtures/atelier-knowledge-contract/relation/valid/document.json +24 -0
- package/fixtures/atelier-knowledge-contract/review/invalid/document.json +18 -0
- package/fixtures/atelier-knowledge-contract/review/valid/document.json +17 -0
- package/fixtures/atelier-knowledge-contract/withdrawal/invalid/document.json +16 -0
- package/fixtures/atelier-knowledge-contract/withdrawal/valid/document.json +15 -0
- package/fixtures/atelier-learning/invalid/authority.json +14 -0
- package/fixtures/atelier-learning/valid/capture.json +13 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/authority-key.json +17 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/nonempty-ext.json +25 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/wrong-schema.json +22 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/valid/manifest.json +22 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/authority-key.json +25 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/unknown-top-level-field.json +27 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/wrong-schema.json +24 -0
- package/fixtures/atelier-trackable/definition/invalid/document.json +15 -0
- package/fixtures/atelier-trackable/definition/valid/document.json +14 -0
- package/fixtures/atelier-trackable/request/invalid/document.json +23 -0
- package/fixtures/atelier-trackable/request/valid/document.json +22 -0
- package/fixtures/boundary-delegations/invalid/authority-key.v1.json +30 -0
- package/fixtures/boundary-delegations/invalid/push-operation.v1.json +28 -0
- package/fixtures/boundary-delegations/invalid/unsigned.v1.json +25 -0
- package/fixtures/boundary-delegations/valid/empty.v1.json +4 -0
- package/fixtures/boundary-delegations/valid/signed-operator.v1.json +30 -0
- package/fixtures/boundary-owner-keys/invalid/wrong-algorithm.v1.json +15 -0
- package/fixtures/boundary-owner-keys/invalid/wrong-curve.v1.json +15 -0
- package/fixtures/boundary-owner-keys/valid/one-owner.v1.json +17 -0
- package/fixtures/capability-packages/adoption.example.json +70 -0
- package/fixtures/capability-packages/evidence-review/capability-package.json +58 -0
- package/fixtures/capability-packages/evidence-review/capability-release.json +84 -0
- package/fixtures/capability-packages/evidence-review/evaluation.md +15 -0
- package/fixtures/capability-packages/evidence-review/skills/evidence-review/SKILL.md +22 -0
- package/fixtures/capability-packages/evidence-review/skills/evidence-review/references/ledger.md +7 -0
- package/fixtures/capability-packages/research/capability-package.json +88 -0
- package/fixtures/capability-packages/research/capability-release.json +134 -0
- package/fixtures/capability-packages/research/evaluation.md +15 -0
- package/fixtures/capability-packages/research/skills/research-integrate/SKILL.md +29 -0
- package/fixtures/capability-packages/research/skills/research-integrate/references/integration.md +10 -0
- package/fixtures/capability-packages/research/skills/research-plan/SKILL.md +27 -0
- package/fixtures/capability-packages/research/skills/research-plan/references/inquiries.md +26 -0
- package/fixtures/capability-packages/research/skills/research-synthesize/SKILL.md +23 -0
- package/fixtures/capability-packages/research/skills/research-synthesize/references/synthesis.md +12 -0
- package/fixtures/evidence-navigation/invalid/duplicate-operation.json +16 -0
- package/fixtures/evidence-navigation/invalid/instruction-kind.json +36 -0
- package/fixtures/evidence-navigation/invalid/invalid-digest.json +36 -0
- package/fixtures/evidence-navigation/invalid/invalid-time.json +36 -0
- package/fixtures/evidence-navigation/invalid/missing-attribution.json +35 -0
- package/fixtures/evidence-navigation/invalid/reserved-extension.json +19 -0
- package/fixtures/evidence-navigation/invalid/unattributed-acceptance.json +36 -0
- package/fixtures/evidence-navigation/invalid/uncoerced-version.json +16 -0
- package/fixtures/evidence-navigation/invalid/unknown-currency.json +17 -0
- package/fixtures/evidence-navigation/invalid/unknown-selector-field.json +37 -0
- package/fixtures/evidence-navigation/invalid/unsupported-operation.json +15 -0
- package/fixtures/evidence-navigation/valid/claim.json +36 -0
- package/fixtures/evidence-navigation/valid/host.json +16 -0
- package/fixtures/evidence-navigation/valid/profile.json +16 -0
- package/fixtures/evidence-navigation/valid/snapshot.json +17 -0
- package/fixtures/harness-packages/build-harness/capability-package.json +61 -0
- package/fixtures/harness-packages/build-harness/capability-release.json +82 -0
- package/fixtures/harness-packages/build-harness/evaluation.md +3 -0
- package/fixtures/harness-packages/build-harness/skills/atelier-build-harness/SKILL.md +59 -0
- package/fixtures/harness-packages/knowledge-harness/capability-package.json +61 -0
- package/fixtures/harness-packages/knowledge-harness/capability-release.json +82 -0
- package/fixtures/harness-packages/knowledge-harness/evaluation.md +3 -0
- package/fixtures/harness-packages/knowledge-harness/skills/atelier-knowledge-harness/SKILL.md +60 -0
- package/fixtures/harnesses/learning-cycle.json +780 -0
- package/fixtures/inquiry/workshop.json +675 -0
- package/fixtures/inquiry-packages/discovery-harness/capability-package.json +61 -0
- package/fixtures/inquiry-packages/discovery-harness/capability-release.json +82 -0
- package/fixtures/inquiry-packages/discovery-harness/evaluation.md +3 -0
- package/fixtures/inquiry-packages/discovery-harness/skills/atelier-discovery-harness/SKILL.md +48 -0
- package/fixtures/inquiry-packages/research-harness/capability-package.json +61 -0
- package/fixtures/inquiry-packages/research-harness/capability-release.json +82 -0
- package/fixtures/inquiry-packages/research-harness/evaluation.md +3 -0
- package/fixtures/inquiry-packages/research-harness/skills/atelier-research-harness/SKILL.md +43 -0
- package/fixtures/knowledge-health/calibration-suite.json +26 -0
- package/fixtures/knowledge-health/calibration-trial.json +37 -0
- package/fixtures/knowledge-health/corrected/checklist.md +18 -0
- package/fixtures/knowledge-health/devday/participant-record.json +19 -0
- package/fixtures/knowledge-health/expected-summary.json +27 -0
- package/fixtures/knowledge-health/workshop/README.md +20 -0
- package/fixtures/knowledge-health/workshop/atelier.project.json +7 -0
- package/fixtures/knowledge-health/workshop/knowledge-plan.json +65 -0
- package/fixtures/knowledge-health/workshop/records/checklist.md +18 -0
- package/fixtures/knowledge-health/workshop/records/workshop.md +18 -0
- package/fixtures/knowledge-health/workshop/repo-access.v1.json +5 -0
- package/fixtures/knowledge-health/workspace/atelier.project.json +18 -0
- package/fixtures/knowledge-health/workspace/knowledge-plan.json +74 -0
- package/fixtures/knowledge-health/workspace/records/checklist.md +18 -0
- package/fixtures/knowledge-health/workspace/records/pilot.md +16 -0
- package/fixtures/knowledge-health/workspace/repo-access.v1.json +9 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/case-only-collision.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/flat-note-path.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/hidden-folder.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/identity-in-the-body.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/link-breaking-name.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-identity-region.v2.json +156 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-layout-version.v2.json +159 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/note-named-like-a-folder.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/unknown-region-kind.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/v1-contract-version.v2.json +161 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/valid/three-notes.v2.json +160 -0
- package/fixtures/obsidian/edits/workspace.json +1 -1
- package/fixtures/obsidian/materialization/expected-full.json +21 -21
- package/fixtures/obsidian/materialization/expected-full.layout-1.json +99 -0
- package/fixtures/obsidian/materialization/expected-scoped.json +7 -7
- package/fixtures/obsidian/materialization/expected-scoped.layout-1.json +39 -0
- package/fixtures/personal-workspace/overlay.json +24 -0
- package/fixtures/templates/local-library.v1.json +75 -0
- package/fixtures/templates/upgrade-contracts/adoption-policy.v2/invalid.json +16 -0
- package/fixtures/templates/upgrade-contracts/adoption-policy.v2/valid.json +13 -0
- package/fixtures/templates/upgrade-contracts/migration.v3/invalid.json +24 -0
- package/fixtures/templates/upgrade-contracts/migration.v3/valid.json +21 -0
- package/fixtures/templates/upgrade-contracts/template-adoption.v1/invalid.json +60 -0
- package/fixtures/templates/upgrade-contracts/template-adoption.v1/valid.json +57 -0
- package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/invalid.json +85 -0
- package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/valid.json +82 -0
- package/package.json +64 -6
- package/plugins/obsidian/main.js +444 -0
- package/plugins/obsidian/manifest.json +9 -0
- package/plugins/obsidian/styles.css +22 -0
- package/skills/claude/atelier-build-harness/SKILL.md +59 -0
- package/skills/claude/atelier-coordination/SKILL.md +32 -0
- package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
- package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
- package/skills/claude/atelier-interaction/SKILL.md +34 -0
- package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
- package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
- package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
- package/skills/claude/atelier-research-harness/SKILL.md +43 -0
- package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
- package/skills/claude/atelier-trackables/SKILL.md +40 -0
- package/skills/codex/atelier-build-harness/SKILL.md +59 -0
- package/skills/codex/atelier-coordination/SKILL.md +32 -0
- package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
- package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
- package/skills/codex/atelier-interaction/SKILL.md +34 -0
- package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
- package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
- package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
- package/skills/codex/atelier-research-harness/SKILL.md +43 -0
- package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
- package/skills/codex/atelier-trackables/SKILL.md +40 -0
- package/src/architecture/catalog.mjs +355 -0
- package/src/architecture/index.mjs +93 -0
- package/src/boundary/content-rules.mjs +4 -2
- package/src/boundary/delegation-command.mjs +158 -0
- package/src/boundary/delegation.mjs +396 -0
- package/src/boundary/policy.mjs +52 -10
- package/src/build/git.mjs +18 -0
- package/src/build/index.mjs +3 -0
- package/src/build/ledger.mjs +88 -0
- package/src/capabilities/adoption.mjs +381 -0
- package/src/capabilities/evidence.mjs +140 -0
- package/src/capabilities/files.mjs +124 -0
- package/src/capabilities/index.mjs +4 -0
- package/src/capabilities/instructions.mjs +250 -0
- package/src/capabilities/package.mjs +136 -0
- package/src/cli/command-failure.mjs +36 -0
- package/src/cli/execute-command.mjs +16 -2
- package/src/cli/run.mjs +65 -9
- package/src/coauthor/store.mjs +43 -2
- package/src/collaboration/proposals.mjs +189 -0
- package/src/commands/architecture.mjs +27 -0
- package/src/commands/boundary.mjs +3 -0
- package/src/commands/capability.mjs +73 -0
- package/src/commands/enroll.mjs +3 -0
- package/src/commands/harness.mjs +79 -0
- package/src/commands/ingest.mjs +39 -0
- package/src/commands/init.mjs +4 -1
- package/src/commands/inquiry.mjs +66 -0
- package/src/commands/knowledge-semantic.mjs +128 -0
- package/src/commands/knowledge.mjs +119 -0
- package/src/commands/learn.mjs +61 -0
- package/src/commands/obsidian.mjs +832 -62
- package/src/commands/practice.mjs +24 -0
- package/src/commands/setup.mjs +22 -2
- package/src/commands/trackable.mjs +19 -0
- package/src/contracts/corpus.mjs +36 -0
- package/src/coordination/index.mjs +110 -0
- package/src/egress/forbidden-egress.mjs +2 -0
- package/src/evidence-navigation/contracts.mjs +60 -0
- package/src/evidence-navigation/evaluate.mjs +69 -0
- package/src/evidence-navigation/generation.mjs +22 -0
- package/src/evidence-navigation/index.mjs +2 -0
- package/src/evidence-navigation/local.mjs +167 -0
- package/src/evidence-navigation/schema.generated.mjs +604 -0
- package/src/evidence-navigation/types.mjs +12 -0
- package/src/export/atelier-export-contract.mjs +35 -8
- package/src/graph/enroll.mjs +248 -0
- package/src/graph/graph.mjs +17 -1
- package/src/graph/knowledge-graph.mjs +58 -8
- package/src/harnesses/contracts.mjs +41 -0
- package/src/harnesses/exchange.mjs +154 -0
- package/src/harnesses/feedback.mjs +16 -0
- package/src/harnesses/history.mjs +37 -0
- package/src/harnesses/index.mjs +4 -0
- package/src/harnesses/store.mjs +29 -0
- package/src/ingestion/contracts.mjs +41 -0
- package/src/ingestion/evaluation.mjs +119 -0
- package/src/ingestion/optional/composition/index.mjs +171 -0
- package/src/ingestion/optional/evaluation/index.mjs +219 -0
- package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
- package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
- package/src/ingestion/optional/graphify/graphify_supplier.py +933 -0
- package/src/ingestion/optional/graphify/json_bridge.py +163 -0
- package/src/ingestion/optional/graphify/query_receiving.py +209 -0
- package/src/ingestion/optional/index.mjs +9 -0
- package/src/ingestion/optional/jev/bridge.mjs +166 -0
- package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
- package/src/ingestion/optional/jev/judgments.mjs +174 -0
- package/src/ingestion/optional/jev/native-translation.mjs +32 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
- package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
- package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
- package/src/ingestion/optional/vanilla/index.mjs +218 -0
- package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
- package/src/ingestion/processors.mjs +218 -0
- package/src/ingestion/semantic.mjs +203 -0
- package/src/ingestion/store.mjs +372 -0
- package/src/inquiry/beliefs.mjs +32 -0
- package/src/inquiry/contracts.mjs +23 -0
- package/src/inquiry/index.mjs +5 -0
- package/src/inquiry/ledger.mjs +135 -0
- package/src/inquiry/lenses.mjs +15 -0
- package/src/inquiry/projection.mjs +77 -0
- package/src/inquiry/store.mjs +35 -0
- package/src/intake/read-scope.mjs +12 -0
- package/src/intake/store.mjs +69 -6
- package/src/interaction/index.mjs +91 -0
- package/src/judgment/index.mjs +82 -0
- package/src/judgment/practice-evaluation.mjs +70 -0
- package/src/judgment/practice.mjs +144 -0
- package/src/knowledge/context.mjs +217 -0
- package/src/knowledge/index.mjs +5 -0
- package/src/knowledge/ingestion.mjs +79 -0
- package/src/knowledge/intake.mjs +33 -0
- package/src/knowledge/ledger.mjs +110 -0
- package/src/knowledge/participatory/guidance.mjs +36 -0
- package/src/knowledge/participatory/guided-contribution.mjs +44 -0
- package/src/knowledge/participatory/index.mjs +2 -0
- package/src/knowledge/participatory/installed-workshop.mjs +108 -0
- package/src/knowledge/plan.mjs +67 -0
- package/src/knowledge/projection.mjs +43 -0
- package/src/knowledge/semantic-operation.mjs +567 -0
- package/src/knowledge/sessions.mjs +467 -0
- package/src/knowledge/workspace.mjs +295 -0
- package/src/knowledge-health/assessment.mjs +165 -0
- package/src/knowledge-health/capabilities.mjs +350 -0
- package/src/knowledge-health/context.mjs +62 -0
- package/src/knowledge-health/example.mjs +47 -0
- package/src/knowledge-health/index.mjs +10 -0
- package/src/knowledge-health/owner-join.mjs +88 -0
- package/src/knowledge-health/proof/common.mjs +24 -0
- package/src/knowledge-health/proof/installed-check.mjs +100 -0
- package/src/knowledge-health/proof/native-readback.mjs +37 -0
- package/src/knowledge-health/proof/rehearse.mjs +68 -0
- package/src/knowledge-health/proof/validate-participant.mjs +17 -0
- package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
- package/src/knowledge-health/proof/workshop-check.mjs +36 -0
- package/src/knowledge-health/rule-identity.mjs +44 -0
- package/src/knowledge-health/workshop-composition.mjs +19 -0
- package/src/knowledge-health/workshop-profile.mjs +176 -0
- package/src/knowledge-health/workshop.mjs +99 -0
- package/src/learning/adapters.mjs +68 -0
- package/src/learning/assistance.mjs +127 -0
- package/src/learning/contracts.mjs +65 -0
- package/src/learning/store.mjs +272 -0
- package/src/personal-workspace/index.mjs +391 -0
- package/src/personal-workspace/selection.mjs +385 -0
- package/src/project/config.mjs +8 -0
- package/src/project/durable-state.mjs +3 -1
- package/src/project/file-class.mjs +1 -1
- package/src/project/private-state.mjs +10 -1
- package/src/projection/obsidian/contracts.mjs +224 -18
- package/src/projection/obsidian/edits/apply.mjs +63 -19
- package/src/projection/obsidian/edits/regions.mjs +137 -42
- package/src/projection/obsidian/materialize/index.mjs +6 -3
- package/src/projection/obsidian/materialize/path-registry.mjs +443 -57
- package/src/projection/obsidian/materialize/prepare-view.mjs +382 -131
- package/src/projection/obsidian/materialize/redaction.mjs +327 -0
- package/src/projection/obsidian/materialize/settings.mjs +113 -34
- package/src/projection/obsidian/personal-workspace.mjs +436 -0
- package/src/projection/obsidian/plugin-bridge/bundle.mjs +50 -0
- package/src/projection/obsidian/plugin-bridge/channel.mjs +174 -0
- package/src/projection/obsidian/plugin-bridge/index.mjs +10 -0
- package/src/projection/obsidian/proposals/adapter.mjs +47 -8
- package/src/projection/obsidian/proposals/observation.mjs +20 -7
- package/src/projection/obsidian/publication/bridge-script.mjs +11 -5
- package/src/projection/obsidian/publication/index.mjs +2 -1
- package/src/projection/obsidian/publication/publisher.mjs +312 -36
- package/src/projection/obsidian/publication/transport.mjs +63 -8
- package/src/projection/obsidian/publication/vault-list.mjs +200 -0
- package/src/projection/obsidian/recovery/index.mjs +4 -1
- package/src/projection/obsidian/recovery/restart.mjs +3 -1
- package/src/projection/obsidian/recovery/store.mjs +168 -8
- package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
- package/src/projection/obsidian/selection-ui/focus.mjs +14 -7
- package/src/projection/obsidian/selection-ui/selection-state.mjs +2 -2
- package/src/projection/obsidian/selection-ui/selection.mjs +8 -3
- package/src/readiness/readiness.mjs +10 -3
- package/src/reflection/index.mjs +56 -0
- package/src/runtime/obsidian/app-capability.mjs +104 -12
- package/src/runtime/obsidian/app-production-seams.mjs +161 -42
- package/src/runtime/obsidian/app-registration.mjs +313 -0
- package/src/runtime/obsidian/app-restart.mjs +154 -0
- package/src/runtime/obsidian/engine.mjs +288 -29
- package/src/runtime/obsidian/extension-points.mjs +1 -1
- package/src/runtime/obsidian/index.mjs +15 -8
- package/src/runtime/obsidian/launch-plan.mjs +91 -0
- package/src/runtime/obsidian/lifecycle.mjs +193 -22
- package/src/runtime/obsidian/login-item.mjs +332 -0
- package/src/runtime/obsidian/machine-settings.mjs +119 -12
- package/src/runtime/obsidian/opening.mjs +369 -63
- package/src/runtime/obsidian/pending-edits.mjs +10 -0
- package/src/runtime/obsidian/pipeline.mjs +71 -3
- package/src/runtime/obsidian/plugin-channel.mjs +289 -0
- package/src/runtime/obsidian/plugin-choice.mjs +182 -0
- package/src/runtime/obsidian/plugin-drift.mjs +124 -0
- package/src/runtime/obsidian/plugin-presence.mjs +61 -0
- package/src/runtime/obsidian/process-identity.mjs +20 -10
- package/src/runtime/obsidian/project-views.mjs +282 -0
- package/src/runtime/obsidian/questions.mjs +48 -0
- package/src/runtime/obsidian/release-watch.mjs +56 -0
- package/src/runtime/obsidian/service-main.mjs +113 -17
- package/src/runtime/obsidian/service-manager-production.mjs +61 -0
- package/src/runtime/obsidian/service-managers.mjs +275 -0
- package/src/runtime/obsidian/service-record.mjs +105 -5
- package/src/runtime/obsidian/service-server.mjs +50 -12
- package/src/runtime/obsidian/service.mjs +134 -7
- package/src/runtime/obsidian/startup-adapters.mjs +59 -21
- package/src/runtime/obsidian/state-store.mjs +13 -1
- package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
- package/src/runtime/obsidian/vault-location.mjs +300 -0
- package/src/runtime/obsidian/view-counts.mjs +34 -0
- package/src/server/local-sidecar.mjs +193 -7
- package/src/server/server.mjs +45 -6
- package/src/template-bindings/project.mjs +92 -0
- package/src/templates/profile.mjs +225 -0
- package/src/trackables/domain.mjs +175 -0
- package/src/trackables/store.mjs +114 -0
- package/src/ui/knowledge-page.mjs +1388 -0
- package/src/upgrade/explanation.mjs +1 -1
- package/src/upgrade/template-participant.mjs +171 -0
- package/src/upgrade/transaction.mjs +72 -25
- package/src/upgrade/upgrade.mjs +2 -1
- package/templates/external-project-workspace/pack-lifecycle.json +6 -1
- package/templates/knowledge-workspace/.gitattributes +2 -0
- package/templates/knowledge-workspace/AGENTS.md +27 -0
- package/templates/knowledge-workspace/README.md +44 -0
- package/templates/knowledge-workspace/atelier.project.json +22 -0
- package/templates/knowledge-workspace/gitignore +6 -0
- package/templates/knowledge-workspace/knowledge-plan.json +111 -0
- package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
- package/templates/knowledge-workspace/records/forecast.md +22 -0
- package/templates/knowledge-workspace/records/inspection.md +25 -0
- package/templates/knowledge-workspace/records/telescope.md +24 -0
- package/templates/knowledge-workspace/repo-access.v1.json +9 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { planInstructionAdoption, applyInstructionAdoption, recoverInstructionAdoption, abandonInstructionAdoption, inspectInstructionAdoption, consumeInstructionContext } from '../capabilities/instructions.mjs'
|
|
2
|
+
import { reportCommandFailure, parseJsonRequest } from '../cli/command-failure.mjs'
|
|
3
|
+
|
|
4
|
+
const methods = { plan: planInstructionAdoption, apply: applyInstructionAdoption, recover: recoverInstructionAdoption, abandon: abandonInstructionAdoption, status: inspectInstructionAdoption, context: consumeInstructionContext }
|
|
5
|
+
const fields = {
|
|
6
|
+
plan: ['workspaceId', 'scope', 'harnessId', 'lessonId', 'target', 'slot', 'mode'],
|
|
7
|
+
apply: ['workspaceId', 'scope', 'harnessId', 'lessonId', 'target', 'slot', 'mode', 'confirm'],
|
|
8
|
+
recover: ['confirm'], abandon: ['confirm', 'destinationDigest'], status: [], context: ['target', 'slot', 'session', 'scope', 'harnessId'],
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const [command, ...rest] = process.argv.slice(2)
|
|
12
|
+
if (!methods[command] || rest.length) throw new Error('Usage: atelier practice plan|apply|recover|abandon|status|context (JSON stdin)')
|
|
13
|
+
const chunks = []; let bytes = 0
|
|
14
|
+
for await (const chunk of process.stdin) {
|
|
15
|
+
bytes += chunk.length
|
|
16
|
+
if (bytes > 256 * 1024) throw new Error('practice request exceeds limit')
|
|
17
|
+
chunks.push(chunk)
|
|
18
|
+
}
|
|
19
|
+
const body = parseJsonRequest(Buffer.concat(chunks), 'practice request')
|
|
20
|
+
if (!body || Array.isArray(body) || typeof body !== 'object' || Object.keys(body).some(k => !fields[command].includes(k))) throw new Error('invalid practice request fields')
|
|
21
|
+
console.log(JSON.stringify(methods[command]({ ...body, workspaceRoot: process.cwd() }), null, 2))
|
|
22
|
+
} catch (error) {
|
|
23
|
+
reportCommandFailure(error)
|
|
24
|
+
}
|
package/src/commands/setup.mjs
CHANGED
|
@@ -15,6 +15,14 @@ import {
|
|
|
15
15
|
import { writeAtelierLock, loadAtelierLock, checkAtelierLock } from '../upgrade/upgrade.mjs'
|
|
16
16
|
import { loadBoundaryPolicy, validateBoundaryPolicy } from '../boundary/policy.mjs'
|
|
17
17
|
import { auditRepoIdentities } from '../project/repo-identity.mjs'
|
|
18
|
+
import {
|
|
19
|
+
DEFAULT_ENROLLMENT_AUDIENCE,
|
|
20
|
+
assertAudienceAllowed,
|
|
21
|
+
assertEnrollmentAudience,
|
|
22
|
+
enrollmentReport,
|
|
23
|
+
planDocumentEnrollment,
|
|
24
|
+
writeDocumentEnrollment,
|
|
25
|
+
} from '../graph/enroll.mjs'
|
|
18
26
|
|
|
19
27
|
const PROFILE_SET = new Set(['single-repo', 'private-domain', 'shared-project', 'multi-repo', 'monorepo', 'control-workspace'])
|
|
20
28
|
const IGNORE_LINES = [
|
|
@@ -190,6 +198,13 @@ function runAdopt(argv) {
|
|
|
190
198
|
}
|
|
191
199
|
const repoName = slug(firstString(args.name) || path.basename(target))
|
|
192
200
|
const actor = slug(firstString(args.actor) || process.env.USER || 'owner')
|
|
201
|
+
if (typeof args['enroll-documents'] === 'string') throw new Error('--enroll-documents takes no value')
|
|
202
|
+
const enrollDocuments = args['enroll-documents'] === true
|
|
203
|
+
const audience = args.audience === undefined ? DEFAULT_ENROLLMENT_AUDIENCE : args.audience
|
|
204
|
+
if (args.audience !== undefined && !enrollDocuments) throw new Error('--audience applies only with --enroll-documents')
|
|
205
|
+
if (enrollDocuments) assertEnrollmentAudience(audience)
|
|
206
|
+
const include = firstString(args.include, args.includes)
|
|
207
|
+
const exclude = firstString(args.exclude, args.excludes)
|
|
193
208
|
const projectPath = path.join(target, 'atelier.project.json')
|
|
194
209
|
const existingProject = fs.existsSync(projectPath)
|
|
195
210
|
? resolveProjectConfig({ cwd: target, argv: ['--project', projectPath], writeLocalState: false }) : null
|
|
@@ -200,7 +215,7 @@ function runAdopt(argv) {
|
|
|
200
215
|
graph: { repoAccessPath: 'repo-access.v1.json', outputPath: 'atelier-output/knowledge.graph.json' },
|
|
201
216
|
projection: { outputRoot: 'atelier-output', readinessPath: 'atelier-output/atelier-readiness.json' },
|
|
202
217
|
boundaries: { policyPath: 'boundary-policy.v1.json', governanceLedgerPath: 'governance/repo-boundary-ledger.md', strictNewRepos: true },
|
|
203
|
-
setup: { profile, include
|
|
218
|
+
setup: { profile, ...(include ? { include } : {}), ...(exclude ? { exclude } : {}) },
|
|
204
219
|
repos: [{ name: repoName, path: '.', readBoundary: profile === 'shared-project' ? 'team' : 'private', role: profile }],
|
|
205
220
|
}
|
|
206
221
|
const configErrors = validateProjectConfigDoc(proposedConfig)
|
|
@@ -217,6 +232,10 @@ function runAdopt(argv) {
|
|
|
217
232
|
const proposedPolicy = priorPolicy.ok ? priorPolicy.policy : cleanUndefined(baseBoundaryPolicy({ repoName, profile, actor }))
|
|
218
233
|
const proposedPolicyErrors = validateBoundaryPolicy(proposedPolicy, proposedProject)
|
|
219
234
|
if (proposedPolicyErrors.length) throw new Error(`adopt requires a valid boundary policy: ${proposedPolicyErrors.join('; ')}`)
|
|
235
|
+
// An audience the policy would refuse is refused before any scaffold write.
|
|
236
|
+
if (enrollDocuments) {
|
|
237
|
+
assertAudienceAllowed({ policy: proposedPolicy, repoNames: (proposedProject.repos ?? []).map((repo) => repo.name), audience })
|
|
238
|
+
}
|
|
220
239
|
if (prior.lock) {
|
|
221
240
|
const report = checkAtelierLock(existingProject)
|
|
222
241
|
if (!report.ok) throw new Error(`adopt cannot accept existing lock drift: ${report.errors.join('; ')}`)
|
|
@@ -245,7 +264,8 @@ function runAdopt(argv) {
|
|
|
245
264
|
if (!fs.existsSync(lockPath)) writeAtelierLock({ project, templateId: `adopt:${profile}` })
|
|
246
265
|
const lockReport = checkAtelierLock(project)
|
|
247
266
|
if (!lockReport.ok) throw new Error(`adopt lock check failed: ${lockReport.errors.join('; ')}`)
|
|
248
|
-
|
|
267
|
+
const enrollment = enrollDocuments ? enrollmentReport(writeDocumentEnrollment(planDocumentEnrollment(project, { audience }))) : null
|
|
268
|
+
console.log(JSON.stringify({ ok: true, command: 'adopt', profile, target, projectPath, ...(enrollment ? { enrollment } : {}) }, null, 2))
|
|
249
269
|
}
|
|
250
270
|
|
|
251
271
|
function runDoctor(argv) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createTrackableStore, previewTrackable, releaseTrackable } from '../trackables/store.mjs'
|
|
2
|
+
import { reportCommandFailure, parseJsonRequest } from '../cli/command-failure.mjs'
|
|
3
|
+
try {
|
|
4
|
+
const [command, ...rest] = process.argv.slice(2)
|
|
5
|
+
if (!['preview', 'release', 'execute', 'snapshot', 'view', 'export'].includes(command) || rest.length) throw new Error('Usage: atelier trackable preview|release|execute|snapshot|view|export (JSON stdin)')
|
|
6
|
+
const chunks = []; let length = 0
|
|
7
|
+
for await (const chunk of process.stdin) { length += chunk.length; if (length > 256 * 1024) throw new Error('request exceeds limit'); chunks.push(chunk) }
|
|
8
|
+
const input = parseJsonRequest(Buffer.concat(chunks), 'trackable request')
|
|
9
|
+
const fields = command === 'preview' ? ['definition', 'subject', 'at', 'effectiveAt', 'evidence'] : command === 'release' ? ['definition'] : ['scope', 'actor', ...(command === 'execute' ? ['command'] : command === 'view' ? ['instanceId', 'at'] : [])]
|
|
10
|
+
if (!input || Array.isArray(input) || typeof input !== 'object' || Object.keys(input).some(k => !fields.includes(k))) throw new Error('invalid trackable request fields')
|
|
11
|
+
let result
|
|
12
|
+
if (command === 'preview') result = previewTrackable(input)
|
|
13
|
+
else if (command === 'release') result = releaseTrackable(input.definition)
|
|
14
|
+
else {
|
|
15
|
+
const store = createTrackableStore({ workspaceRoot: process.cwd(), scope: input.scope, actor: input.actor })
|
|
16
|
+
result = command === 'execute' ? store.execute(input.command) : command === 'view' ? store.view({ instanceId: input.instanceId, at: input.at }) : command === 'export' ? store.exportHistory() : store.snapshot()
|
|
17
|
+
}
|
|
18
|
+
console.log(JSON.stringify(result, null, 2))
|
|
19
|
+
} catch (error) { reportCommandFailure(error) }
|
package/src/contracts/corpus.mjs
CHANGED
|
@@ -26,8 +26,36 @@ import { fileURLToPath } from 'node:url'
|
|
|
26
26
|
// document, not a schema, and is deliberately absent.
|
|
27
27
|
|
|
28
28
|
export const CONTRACT_CORPUS = [
|
|
29
|
+
{ name: 'atelier-evidence-navigation', contractFile: 'contracts/atelier-evidence-navigation.v1.schema.json', fixtureRoot: 'fixtures/evidence-navigation', registry: false },
|
|
30
|
+
{ name: 'atelier-personal-workspace-manifest', contractFile: 'contracts/atelier-personal-workspace-manifest.v1.schema.json', fixtureRoot: 'fixtures/atelier-personal-workspace-contract/manifest', registry: true },
|
|
31
|
+
{ name: 'atelier-personal-workspace-overlay', contractFile: 'contracts/atelier-personal-workspace-overlay.v1.schema.json', validFiles: ['fixtures/personal-workspace/overlay.json'], invalidFiles: ['authority-key.json', 'unknown-top-level-field.json', 'wrong-schema.json'].map((file) => `fixtures/atelier-personal-workspace-contract/overlay/invalid/${file}`), registry: true },
|
|
32
|
+
{ name: 'atelier-template-profile', contractFile: 'contracts/atelier-template-profile.v1.schema.json', validFiles: ['fixtures/templates/local-library.v1.json'], registry: false },
|
|
33
|
+
...['adoption-policy.v2', 'migration.v3', 'template-adoption.v1', 'upgrade-plan.v3'].map(shape => ({
|
|
34
|
+
name: `atelier-template-${shape}`, contractFile: `contracts/atelier-${shape}.schema.json`,
|
|
35
|
+
validFiles: [`fixtures/templates/upgrade-contracts/${shape}/valid.json`],
|
|
36
|
+
invalidFiles: [`fixtures/templates/upgrade-contracts/${shape}/invalid.json`], registry: false,
|
|
37
|
+
})),
|
|
29
38
|
{ name: 'atelier-decision-request', contractFile: 'contracts/atelier-decision-request.v1.schema.json', fixtureRoot: 'fixtures/decisions/request', registry: false },
|
|
30
39
|
{ name: 'atelier-decision-result', contractFile: 'contracts/atelier-decision-result.v1.schema.json', fixtureRoot: 'fixtures/decisions/result', registry: false },
|
|
40
|
+
...Object.entries({ interaction: ['observation', 'assessment', 'act', 'policy'], coordination: ['outcome', 'dependency', 'directive', 'disposition', 'recovery'] }).flatMap(([profile, shapes]) => shapes.map(shape => ({ name: `atelier-${profile}-${shape}`, contractFile: `contracts/atelier-${profile}.v1.schema.json`, docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-${profile}/${shape}`, registry: true }))),
|
|
41
|
+
...['definition', 'request'].map(shape => ({ name: `atelier-trackable-${shape}`, contractFile: 'contracts/atelier-trackable.v1.schema.json', docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-trackable/${shape}`, registry: true })),
|
|
42
|
+
...['case', 'decision'].map(shape => ({ name: `atelier-judgment-${shape}`, contractFile: 'contracts/atelier-judgment.v1.schema.json', docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-judgment/${shape}`, registry: false })),
|
|
43
|
+
...['state', 'plan', 'receipt', 'context-receipt'].map(shape => ({ name: `atelier-instruction-${shape}`, contractFile: 'contracts/atelier-instruction-adoption.v1.schema.json', docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-instruction-adoption/${shape}`, registry: false })),
|
|
44
|
+
...['catalog', 'binding'].map(shape => ({ name: `atelier-architecture-${shape}`, contractFile: 'contracts/atelier-architecture.v1.schema.json', docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-architecture/${shape}`, registry: false })),
|
|
45
|
+
...Object.entries({ knowledge: ['domain', 'domain-revision', 'contribution', 'evaluation', 'relation', 'review', 'withdrawal', 'activation', 'ledger'], build: ['objective', 'candidate', 'attempt', 'progress', 'gate', 'decision', 'delivery', 'ledger'], harness: ['handoff'] }).flatMap(([profile, shapes]) => shapes.map(shape => ({
|
|
46
|
+
name: `atelier-${profile}-${shape}`, contractFile: `contracts/atelier-${profile}.v1.schema.json`,
|
|
47
|
+
docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-${profile}-contract/${shape}`, registry: false,
|
|
48
|
+
}))),
|
|
49
|
+
...['campaign', 'hypothesis', 'request', 'source', 'bundle', 'assessment', 'decision', 'withdrawal', 'feedback', 'legacy-assessment', 'ledger', 'handoff'].map(shape => ({
|
|
50
|
+
name: `atelier-inquiry-${shape}`, contractFile: 'contracts/atelier-inquiry.v1.schema.json',
|
|
51
|
+
docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-inquiry-contract/${shape}`, registry: true,
|
|
52
|
+
})),
|
|
53
|
+
...['package', 'release', 'adoption', 'state', 'plan', 'event', 'journal', 'notice'].map(shape => ({
|
|
54
|
+
name: `atelier-capability-${shape}`, contractFile: 'contracts/atelier-capability.v1.schema.json',
|
|
55
|
+
docPointer: `#/$defs/${shape}`, fixtureRoot: `fixtures/atelier-capability-contract/${shape}`, registry: false,
|
|
56
|
+
})),
|
|
57
|
+
{ name: 'atelier-ingestion', contractFile: 'contracts/atelier-ingestion.v1.schema.json', fixtureRoot: 'fixtures/atelier-ingestion', registry: true },
|
|
58
|
+
{ name: 'atelier-learning', contractFile: 'contracts/atelier-learning.v1.schema.json', fixtureRoot: 'fixtures/atelier-learning', registry: true },
|
|
31
59
|
{ name: 'atelier-adoption-policy-v1', contractFile: 'contracts/atelier-adoption-policy.v1.schema.json', fixtureRoot: 'fixtures/atelier-upgrade-transaction/adoption-policy', registry: false },
|
|
32
60
|
{ name: 'atelier-migration-v2', contractFile: 'contracts/atelier-migration.v2.schema.json', fixtureRoot: 'fixtures/atelier-upgrade-transaction/migration', registry: false },
|
|
33
61
|
{ name: 'atelier-upgrade-plan-v2', contractFile: 'contracts/atelier-upgrade-plan.v2.schema.json', fixtureRoot: 'fixtures/atelier-upgrade-transaction/upgrade-plan', registry: false },
|
|
@@ -69,6 +97,8 @@ export const CONTRACT_CORPUS = [
|
|
|
69
97
|
fixtureRoot: 'fixtures/boundary-policy',
|
|
70
98
|
registry: false,
|
|
71
99
|
},
|
|
100
|
+
{ name: 'atelier-boundary-delegations', contractFile: 'contracts/atelier-boundary-delegations.v1.schema.json', fixtureRoot: 'fixtures/boundary-delegations', registry: true },
|
|
101
|
+
{ name: 'atelier-boundary-owner-keys', contractFile: 'contracts/atelier-boundary-owner-keys.v1.schema.json', fixtureRoot: 'fixtures/boundary-owner-keys', registry: true },
|
|
72
102
|
{
|
|
73
103
|
name: 'atelier-export',
|
|
74
104
|
contractFile: 'contracts/atelier-export.v1.schema.json',
|
|
@@ -171,6 +201,12 @@ export const CONTRACT_CORPUS = [
|
|
|
171
201
|
name: `atelier-obsidian-${shape}`, contractFile: `contracts/atelier-obsidian-${shape}.v1.schema.json`,
|
|
172
202
|
fixtureRoot: `fixtures/obsidian/contracts/${shape}`, registry: false,
|
|
173
203
|
})),
|
|
204
|
+
// Vault layout 2's manifest: a new major, beside v1, which stays unchanged
|
|
205
|
+
// and still validates every generation an earlier release wrote.
|
|
206
|
+
{
|
|
207
|
+
name: 'atelier-obsidian-generation-manifest-v2', contractFile: 'contracts/atelier-obsidian-generation-manifest.v2.schema.json',
|
|
208
|
+
fixtureRoot: 'fixtures/obsidian/contracts/generation-manifest-v2', registry: false,
|
|
209
|
+
},
|
|
174
210
|
{
|
|
175
211
|
name: 'analysis-adapter-claim-output',
|
|
176
212
|
contractFile: 'contracts/analysis-adapter.v1.schema.json',
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import Ajv from 'ajv/dist/2020.js'
|
|
3
|
+
import addFormats from 'ajv-formats'
|
|
4
|
+
import { boundedLearningValue, learningDigest as digest } from '../learning/contracts.mjs'
|
|
5
|
+
import { buildCoordinationProposal } from '../build/index.mjs'
|
|
6
|
+
const schema = JSON.parse(fs.readFileSync(new URL('../../contracts/atelier-coordination.v1.schema.json', import.meta.url)))
|
|
7
|
+
const ajv = new Ajv({ strict: true, allErrors: true }); addFormats(ajv)
|
|
8
|
+
const validate = ajv.compile(schema)
|
|
9
|
+
const key = r => `${r.repository}/${r.id}`
|
|
10
|
+
export function validateCoordination(record) {
|
|
11
|
+
try { boundedLearningValue(record) } catch (error) { return [error.message] }
|
|
12
|
+
if (!validate(record)) return validate.errors.map(e => `${e.instancePath || '/'}: ${e.message}`)
|
|
13
|
+
const errors = []
|
|
14
|
+
if (Date.parse(record.expiresAt) <= Date.parse(record.observedAt)) errors.push('expiry must follow observation')
|
|
15
|
+
if (new Set(record.scope).size !== record.scope.length || !record.scope.length) errors.push('nonempty distinct scope required')
|
|
16
|
+
if (record.kind === 'dependency' && record.body.receiving.status !== 'missing' && record.body.receiving.receipt === null) errors.push('reported receipt or acceptance needs native receipt reference')
|
|
17
|
+
if (record.kind === 'outcome') {
|
|
18
|
+
if (new Set(record.body.gates.map(g => g.id)).size !== record.body.gates.length) errors.push('duplicate gate identity')
|
|
19
|
+
if (record.body.gates.some(g => ['passed', 'waived'].includes(g.status) && g.evidence === null)) errors.push('reported passed/waived gate needs evidence')
|
|
20
|
+
}
|
|
21
|
+
if (record.kind === 'disposition' && ['sent', 'read', 'applied', 'verified'].includes(record.body.stage) && record.body.evidence === null) errors.push('reported disposition needs native evidence')
|
|
22
|
+
return errors
|
|
23
|
+
}
|
|
24
|
+
export function coordinationReference(record) {
|
|
25
|
+
const errors = validateCoordination(record)
|
|
26
|
+
if (errors.length) throw new Error(errors.join('; '))
|
|
27
|
+
return { repository: record.repository, id: record.id, digest: digest(record) }
|
|
28
|
+
}
|
|
29
|
+
export function coordinationView({ records, at, maxAgeMs = 86400000 }) {
|
|
30
|
+
if (!Array.isArray(records) || records.length > 256 || !Number.isFinite(Date.parse(at)) || !Number.isSafeInteger(maxAgeMs) || maxAgeMs < 1 || maxAgeMs > 30 * 86400000) throw new Error('bounded coordination snapshot and time required')
|
|
31
|
+
const map = new Map(), freshness = new Map()
|
|
32
|
+
for (const record of records) {
|
|
33
|
+
coordinationReference(record)
|
|
34
|
+
if (map.has(key(record))) throw new Error('ambiguous repository record identity; select an exact snapshot')
|
|
35
|
+
map.set(key(record), record)
|
|
36
|
+
const age = Date.parse(at) - Date.parse(record.observedAt)
|
|
37
|
+
freshness.set(key(record), age < 0 ? 'unknown' : Date.parse(at) >= Date.parse(record.expiresAt) || age > maxAgeMs ? 'stale' : 'current-reported')
|
|
38
|
+
}
|
|
39
|
+
const resolves = (pin, kind) => {
|
|
40
|
+
const record = map.get(key(pin))
|
|
41
|
+
return record?.kind === kind && digest(record) === pin.digest && freshness.get(key(pin)) === 'current-reported' ? record : null
|
|
42
|
+
}
|
|
43
|
+
const dependencies = [], adjacency = new Map()
|
|
44
|
+
for (const record of records.filter(r => r.kind === 'dependency')) {
|
|
45
|
+
const { producer: pin, consumer, artifactDigest, receiving } = record.body
|
|
46
|
+
const producer = resolves(pin, 'outcome'), target = map.get(key(consumer)), reasons = []
|
|
47
|
+
if (freshness.get(key(record)) !== 'current-reported') reasons.push('dependency-report-not-current')
|
|
48
|
+
if (!producer) reasons.push('producer-missing-stale-or-changed')
|
|
49
|
+
if (!target || target.kind !== 'outcome' || freshness.get(key(consumer)) !== 'current-reported') reasons.push('consumer-missing-or-stale')
|
|
50
|
+
if (producer && (producer.body.lifecycle !== 'active' || producer.body.candidate?.artifactDigest !== artifactDigest)) reasons.push('producer-artifact-unavailable')
|
|
51
|
+
if (record.repository !== consumer.repository) reasons.push('receiving-report-outside-consumer-repository')
|
|
52
|
+
if (target && (!record.scope.every(s => target.scope.includes(s)) || (producer && !record.scope.every(s => producer.scope.includes(s))))) reasons.push('dependency-scope-differs')
|
|
53
|
+
if (receiving.status !== 'accepted') reasons.push(`receiving-${receiving.status}`)
|
|
54
|
+
if (!adjacency.has(key(consumer))) adjacency.set(key(consumer), [])
|
|
55
|
+
adjacency.get(key(consumer)).push(key(pin))
|
|
56
|
+
dependencies.push({ reference: coordinationReference(record), producer: pin, consumer, receiving, reasons, nativeReceiptVerified: false })
|
|
57
|
+
}
|
|
58
|
+
// Strongly connected components (Tarjan): every dependency inside one lies on
|
|
59
|
+
// a cycle, whatever order the records arrive in.
|
|
60
|
+
const cycles = [], component = new Map(), index = new Map(), low = new Map(), stack = [], onStack = new Set()
|
|
61
|
+
let counter = 0
|
|
62
|
+
function connect(node) {
|
|
63
|
+
index.set(node, counter); low.set(node, counter++); stack.push(node); onStack.add(node)
|
|
64
|
+
for (const next of adjacency.get(node) ?? []) {
|
|
65
|
+
if (!index.has(next)) { connect(next); low.set(node, Math.min(low.get(node), low.get(next))) }
|
|
66
|
+
else if (onStack.has(next)) low.set(node, Math.min(low.get(node), index.get(next)))
|
|
67
|
+
}
|
|
68
|
+
if (low.get(node) !== index.get(node)) return
|
|
69
|
+
const members = []
|
|
70
|
+
let member
|
|
71
|
+
do { member = stack.pop(); onStack.delete(member); members.push(member) } while (member !== node)
|
|
72
|
+
if (members.length > 1 || (adjacency.get(node) ?? []).includes(node)) {
|
|
73
|
+
members.sort()
|
|
74
|
+
for (const m of members) component.set(m, cycles.length)
|
|
75
|
+
cycles.push(members)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const node of [...adjacency.keys()].sort()) if (!index.has(node)) connect(node)
|
|
79
|
+
for (const dependency of dependencies) {
|
|
80
|
+
const group = component.get(key(dependency.consumer))
|
|
81
|
+
if (group !== undefined && group === component.get(key(dependency.producer))) dependency.reasons.push('dependency-cycle')
|
|
82
|
+
}
|
|
83
|
+
const directives = records.filter(r => r.kind === 'directive').map(directive => {
|
|
84
|
+
const pin = coordinationReference(directive)
|
|
85
|
+
const replacements = records.filter(r => r.kind === 'directive' && r.body.supersedes && digest(r.body.supersedes) === digest(pin) &&
|
|
86
|
+
r.repository === directive.repository && key(r.body.target) === key(directive.body.target) && digest([...r.scope].sort()) === digest([...directive.scope].sort()))
|
|
87
|
+
// Supersession is permanent: a replacement going stale withdraws its own
|
|
88
|
+
// report, never revives the directive it replaced.
|
|
89
|
+
const superseded = replacements.length > 0
|
|
90
|
+
const reports = records.filter(r => r.kind === 'disposition' && digest(r.body.directive) === digest(pin))
|
|
91
|
+
return { reference: pin, target: directive.body.target, freshness: freshness.get(key(directive)), supersedes: directive.body.supersedes,
|
|
92
|
+
supersededBy: replacements.map(coordinationReference), activeReported: !superseded && freshness.get(key(directive)) === 'current-reported',
|
|
93
|
+
reports: reports.map(r => ({ reference: coordinationReference(r), stage: r.body.stage, evidence: r.body.evidence,
|
|
94
|
+
applicable: !superseded && freshness.get(key(r)) === 'current-reported' && freshness.get(key(directive)) === 'current-reported' && key(r.body.recipient) === key(directive.body.target) && r.repository === directive.body.target.repository && r.scope.every(s => directive.scope.includes(s)),
|
|
95
|
+
nativeReceiptVerified: false })), executionAuthorized: false }
|
|
96
|
+
})
|
|
97
|
+
const outcomes = records.filter(r => r.kind === 'outcome').map(record => ({ reference: coordinationReference(record), owner: record.body.owner, purpose: record.body.purpose,
|
|
98
|
+
priority: record.body.priority, freshness: freshness.get(key(record)), lifecycle: record.body.lifecycle, candidate: record.body.candidate,
|
|
99
|
+
gates: record.body.gates.map(g => ({ ...g, candidateCurrent: record.body.candidate !== null && g.candidateDigest === digest(record.body.candidate), nativeEvidenceVerified: false })),
|
|
100
|
+
blockers: dependencies.filter(d => key(d.consumer) === key(record)).flatMap(d => d.reasons) }))
|
|
101
|
+
const recovery = records.filter(r => r.kind === 'recovery').map(record => ({ reference: coordinationReference(record), ...record.body,
|
|
102
|
+
freshness: freshness.get(key(record)), priorPresent: !!resolves(record.body.prior, 'outcome'), successorPresent: map.get(key(record.body.successor ?? {}))?.kind === 'outcome', owningRepository: record.repository === record.body.prior.repository, executionAuthorized: false }))
|
|
103
|
+
return { schema: 'atelier-coordination-view@v1', at, maxAgeMs, coverage: records.map(coordinationReference), outcomes, dependencies, directives, recovery, cycles,
|
|
104
|
+
freshness: 'relative-to-supplied-observations', completionVerified: false, authorityTransferred: false, executionAuthorized: false }
|
|
105
|
+
}
|
|
106
|
+
// Retain the native Build history and its own dependency/gate qualification.
|
|
107
|
+
// Additional portfolio records cannot change this result or waive its blockers.
|
|
108
|
+
export function coordinatedBuild({ records, buildRecords, dependencySnapshots = [], at, maxAgeMs }) {
|
|
109
|
+
return { coordination: coordinationView({ records, at, maxAgeMs }), build: buildCoordinationProposal(buildRecords, { dependencySnapshots }), authorityTransferred: false }
|
|
110
|
+
}
|
|
@@ -17,6 +17,8 @@ export const DEFAULT_EGRESS_SCAN_PATHS = [
|
|
|
17
17
|
'templates',
|
|
18
18
|
'examples',
|
|
19
19
|
'skills',
|
|
20
|
+
// Atelier's own Obsidian plugin: shipped, and run inside the app of every vault Atelier manages.
|
|
21
|
+
'plugins',
|
|
20
22
|
]
|
|
21
23
|
|
|
22
24
|
const SCRIPT_EXTS = new Set(['.js', '.mjs', '.cjs', '.ts', '.mts', '.sh'])
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import Ajv from 'ajv/dist/2020.js'
|
|
2
|
+
import addFormats from 'ajv-formats'
|
|
3
|
+
import { evidenceSchema } from './schema.generated.mjs'
|
|
4
|
+
|
|
5
|
+
const ajv = new Ajv({ strict: true, allErrors: true, ownProperties: true,
|
|
6
|
+
coerceTypes: false, useDefaults: false, removeAdditional: false, validateFormats: true })
|
|
7
|
+
addFormats(ajv, { mode: 'full' })
|
|
8
|
+
ajv.addSchema(evidenceSchema)
|
|
9
|
+
const validators = new Map(Object.keys(evidenceSchema.$defs).map(name =>
|
|
10
|
+
[name, ajv.getSchema(`${evidenceSchema.$id}#/$defs/${name}`)]))
|
|
11
|
+
|
|
12
|
+
export const EVIDENCE_PROTOCOL = 'atelier-evidence-navigation@v1'
|
|
13
|
+
export const EVIDENCE_LIMITS = Object.freeze({ bytes: 262144, depth: 24, members: 8192, snapshots: 256, dependencyDepth: 12 })
|
|
14
|
+
|
|
15
|
+
// Public functions consume JSON, never getters, cyclic graphs, or custom objects.
|
|
16
|
+
// Copy before validation so no validator can mutate the caller's input.
|
|
17
|
+
export function evidenceJson(value) {
|
|
18
|
+
const active = new Set()
|
|
19
|
+
let remaining = EVIDENCE_LIMITS.members
|
|
20
|
+
function copy(item, depth) {
|
|
21
|
+
if (--remaining < 0 || depth > EVIDENCE_LIMITS.depth) throw new Error('evidence value exceeds bounds')
|
|
22
|
+
if (item === null || typeof item === 'boolean') return item
|
|
23
|
+
if (typeof item === 'string' && item.length <= EVIDENCE_LIMITS.bytes && !item.includes('\u0000')) return item
|
|
24
|
+
if (typeof item === 'number' && Number.isFinite(item)) return item
|
|
25
|
+
if (typeof item !== 'object' || active.has(item)) throw new Error('evidence value must be JSON')
|
|
26
|
+
const array = Array.isArray(item)
|
|
27
|
+
const prototype = Object.getPrototypeOf(item)
|
|
28
|
+
if (array ? prototype !== Array.prototype : ![Object.prototype, null].includes(prototype)) throw new Error('evidence value must be JSON')
|
|
29
|
+
active.add(item)
|
|
30
|
+
const entries = []
|
|
31
|
+
for (const key of Reflect.ownKeys(item)) {
|
|
32
|
+
if (array && key === 'length') continue
|
|
33
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key)
|
|
34
|
+
if (typeof key !== 'string' || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) throw new Error('evidence value must be JSON')
|
|
35
|
+
entries.push([key, copy(descriptor.value, depth + 1)])
|
|
36
|
+
}
|
|
37
|
+
let result
|
|
38
|
+
if (array) {
|
|
39
|
+
const length = Object.getOwnPropertyDescriptor(item, 'length')?.value
|
|
40
|
+
if (entries.length !== length || entries.some(([key], index) => key !== String(index))) throw new Error('evidence array must be dense')
|
|
41
|
+
result = entries.map(([, value]) => value)
|
|
42
|
+
} else result = Object.fromEntries(entries)
|
|
43
|
+
active.delete(item)
|
|
44
|
+
return result
|
|
45
|
+
}
|
|
46
|
+
const result = copy(value, 0)
|
|
47
|
+
if (new TextEncoder().encode(JSON.stringify(result)).byteLength > EVIDENCE_LIMITS.bytes) throw new Error('evidence value exceeds bounds')
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function validateEvidenceDocument(shape, value) {
|
|
52
|
+
if (typeof shape !== 'string') return { valid: false, reason: 'unsupported-shape' }
|
|
53
|
+
const validate = validators.get(shape)
|
|
54
|
+
if (typeof validate !== 'function') return { valid: false, reason: 'unsupported-shape' }
|
|
55
|
+
try {
|
|
56
|
+
return validate(evidenceJson(value))
|
|
57
|
+
? { valid: true, reason: null }
|
|
58
|
+
: { valid: false, reason: 'invalid-document' }
|
|
59
|
+
} catch { return { valid: false, reason: 'invalid-document' } }
|
|
60
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EVIDENCE_LIMITS, evidenceJson, validateEvidenceDocument } from './contracts.mjs'
|
|
2
|
+
|
|
3
|
+
const result = (status, reasons = []) => ({ status, reasons: [...new Set(reasons)], executionAuthorized: false, authorityTransferred: false, semanticTruthVerified: false })
|
|
4
|
+
const valid = (shape, value) => validateEvidenceDocument(shape, value).valid
|
|
5
|
+
const logicalKey = ref => JSON.stringify([ref.owner, ref.objectId, ref.selector.type, ref.selector.version, ref.selector.value])
|
|
6
|
+
const exactRef = (a, b) => logicalKey(a) === logicalKey(b) && a.revision === b.revision && a.contentDigest === b.contentDigest
|
|
7
|
+
const canonical = value => JSON.stringify(value, function (_key, item) {
|
|
8
|
+
return item && !Array.isArray(item) && typeof item === 'object'
|
|
9
|
+
? Object.fromEntries(Object.keys(item).sort().map(key => [key, item[key]])) : item
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/** Compare declared support. This assesses compatibility, never host qualification. */
|
|
13
|
+
export function assessEvidenceCompatibility(profile, host) {
|
|
14
|
+
let input
|
|
15
|
+
try { input = evidenceJson({ profile, host }) } catch { return result('unsupported', ['invalid-document']) }
|
|
16
|
+
if (!valid('profile', input.profile) || !valid('hostCapabilities', input.host)) return result('unsupported', ['invalid-document'])
|
|
17
|
+
const reasons = []
|
|
18
|
+
if (!input.host.protocols.includes(input.profile.protocol)) reasons.push('unsupported-protocol')
|
|
19
|
+
if (input.profile.operations.some(operation => !input.host.operations.includes(operation))) reasons.push('unsupported-operation')
|
|
20
|
+
if (input.profile.requiredCapabilities.some(required => !input.host.capabilities.some(capability => capability.id === required.id && capability.version === required.version))) reasons.push('unsupported-capability')
|
|
21
|
+
return result(reasons.length ? 'unsupported' : 'compatible', reasons)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Check exact supplied snapshots. Their authenticity and read permission stay with the host. */
|
|
25
|
+
export function assessEvidenceCurrency(reference, snapshots, options = {}) {
|
|
26
|
+
let input
|
|
27
|
+
try { input = evidenceJson({ reference, snapshots, options }) } catch { return result('unknown', ['invalid-document']) }
|
|
28
|
+
if (!input.options || typeof input.options !== 'object' || Array.isArray(input.options)) return result('unknown', ['invalid-document'])
|
|
29
|
+
const { at, maxDepth = EVIDENCE_LIMITS.dependencyDepth, maxNodes = EVIDENCE_LIMITS.snapshots } = input.options
|
|
30
|
+
if (!valid('evidenceRef', input.reference) || !Array.isArray(input.snapshots) || input.snapshots.length > EVIDENCE_LIMITS.snapshots ||
|
|
31
|
+
!input.snapshots.every(snapshot => valid('snapshot', snapshot)) || typeof at !== 'string' ||
|
|
32
|
+
!valid('validInterval', { from: at, until: null }) || !Number.isFinite(Date.parse(at)) ||
|
|
33
|
+
!Number.isSafeInteger(maxDepth) || maxDepth < 0 || maxDepth > EVIDENCE_LIMITS.dependencyDepth ||
|
|
34
|
+
!Number.isSafeInteger(maxNodes) || maxNodes < 1 || maxNodes > EVIDENCE_LIMITS.snapshots) return result('unknown', ['invalid-document'])
|
|
35
|
+
const index = new Map()
|
|
36
|
+
for (const snapshot of input.snapshots) {
|
|
37
|
+
const key = logicalKey(snapshot.reference)
|
|
38
|
+
index.set(key, [...(index.get(key) ?? []), snapshot])
|
|
39
|
+
}
|
|
40
|
+
let visited = 0
|
|
41
|
+
const reasons = new Set()
|
|
42
|
+
function visit(ref, path, depth) {
|
|
43
|
+
if (++visited > maxNodes || depth > maxDepth) { reasons.add('verification-bound'); return false }
|
|
44
|
+
const key = logicalKey(ref)
|
|
45
|
+
if (path.has(key)) { reasons.add('cyclic-dependency'); return false }
|
|
46
|
+
const matches = index.get(key) ?? []
|
|
47
|
+
if (matches.length !== 1) { reasons.add(matches.length ? 'ambiguous-snapshot' : 'missing-snapshot'); return false }
|
|
48
|
+
const snapshot = matches[0]
|
|
49
|
+
if (snapshot.currency !== 'current') { reasons.add(snapshot.currency === 'withdrawn-from-use' ? 'withdrawn' : 'not-current'); return false }
|
|
50
|
+
if (!exactRef(ref, snapshot.reference)) { reasons.add('changed-reference'); return false }
|
|
51
|
+
if (snapshot.validUntil !== null && !Number.isFinite(Date.parse(snapshot.validUntil))) { reasons.add('unrepresentable-expiry'); return false }
|
|
52
|
+
if (snapshot.validUntil !== null && Date.parse(at) >= Date.parse(snapshot.validUntil)) { reasons.add('expired'); return false }
|
|
53
|
+
const next = new Set(path).add(key)
|
|
54
|
+
return snapshot.dependencies.map(dependency => visit(dependency, next, depth + 1)).every(Boolean)
|
|
55
|
+
}
|
|
56
|
+
const current = visit(input.reference, new Set(), 0)
|
|
57
|
+
return result(current ? 'current' : 'not-current', [...reasons])
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A later acceptance cannot change what kind of claim was recorded. */
|
|
61
|
+
export function assessClaimContinuity(previous, next) {
|
|
62
|
+
let input
|
|
63
|
+
try { input = evidenceJson({ previous, next }) } catch { return result('unsupported', ['invalid-document']) }
|
|
64
|
+
if (!valid('claim', input.previous) || !valid('claim', input.next)) return result('unsupported', ['invalid-document'])
|
|
65
|
+
if (input.previous.claimId !== input.next.claimId || input.previous.ownerRecordRef.owner !== input.next.ownerRecordRef.owner || input.previous.ownerRecordRef.objectId !== input.next.ownerRecordRef.objectId) return result('unsupported', ['different-claim-identity'])
|
|
66
|
+
if (input.previous.kind !== input.next.kind) return result('unsupported', ['immutable-claim-kind'])
|
|
67
|
+
if (input.previous.revision === input.next.revision && canonical(input.previous) !== canonical(input.next)) return result('unsupported', ['unchanged-claim-revision'])
|
|
68
|
+
return result('compatible')
|
|
69
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Generated from contracts. Run node scripts/generate-evidence-navigation.mjs.
|
|
2
|
+
export const evidenceGeneration = {
|
|
3
|
+
"schema": "atelier-evidence-navigation-generation@v1",
|
|
4
|
+
"contract": "https://mnstry.ai/schemas/atelier/atelier-evidence-navigation.v1.schema.json",
|
|
5
|
+
"contractDigest": "sha256:738a93062065af4dd3f3df70ca12a6ef87b9496893e9f3df68e3bdab0fb37930",
|
|
6
|
+
"generatorVersion": 2,
|
|
7
|
+
"validator": {
|
|
8
|
+
"name": "ajv",
|
|
9
|
+
"version": "8.20.0",
|
|
10
|
+
"schemaDraft": "2020-12"
|
|
11
|
+
},
|
|
12
|
+
"formats": {
|
|
13
|
+
"name": "ajv-formats",
|
|
14
|
+
"version": "3.0.1",
|
|
15
|
+
"mode": "full"
|
|
16
|
+
},
|
|
17
|
+
"distribution": "schema-and-types-with-package-validator",
|
|
18
|
+
"files": {
|
|
19
|
+
"src/evidence-navigation/schema.generated.mjs": "sha256:553f800381b92cef8550a80a6c0f4f95d310e0a744effb7a1a45e21b31bed46c",
|
|
20
|
+
"src/evidence-navigation/types.mjs": "sha256:5b4b771657a91e739de779bae00f002feafae917b4ce73ed1d8b27efa0052e5d"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto'
|
|
2
|
+
import { performance } from 'node:perf_hooks'
|
|
3
|
+
import { createIngestionStore } from '../ingestion/store.mjs'
|
|
4
|
+
import { evidenceJson } from './contracts.mjs'
|
|
5
|
+
|
|
6
|
+
const schema = 'atelier-local-evidence-result@v1'
|
|
7
|
+
const flags = { executionAuthorized: false, authorityTransferred: false, semanticTruthVerified: false }
|
|
8
|
+
const digest = text => createHash('sha256').update(text, 'utf8').digest('hex')
|
|
9
|
+
const bytes = text => Buffer.byteLength(text, 'utf8')
|
|
10
|
+
const refusal = reason => ({ schema, status: 'refused', reason, ...flags })
|
|
11
|
+
function fail(reason = 'not-available') { throw { reason } }
|
|
12
|
+
function record(input, keys) {
|
|
13
|
+
const value = evidenceJson(input)
|
|
14
|
+
if (!value || Array.isArray(value) || typeof value !== 'object' || Object.keys(value).some(key => !keys.includes(key))) fail('invalid-request')
|
|
15
|
+
return value
|
|
16
|
+
}
|
|
17
|
+
function positive(value, ceiling) { return Number.isSafeInteger(value) && value > 0 && value <= ceiling }
|
|
18
|
+
function clip(text, ceiling) {
|
|
19
|
+
if (bytes(text) <= ceiling) return { text, truncated: false }
|
|
20
|
+
let result = '', used = 0
|
|
21
|
+
for (const character of text) {
|
|
22
|
+
const size = bytes(character)
|
|
23
|
+
if (used + size > ceiling) break
|
|
24
|
+
result += character; used += size
|
|
25
|
+
}
|
|
26
|
+
return { text: result, truncated: true }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* One host-owned session over one exact, whole-plan admission. Construction
|
|
31
|
+
* options and callbacks are trusted code, never model arguments. No writes,
|
|
32
|
+
* providers, or persisted handles. A separate host must qualify actual authority.
|
|
33
|
+
*/
|
|
34
|
+
export function createLocalEvidenceReader({ workspaceRoot, workspaceId, plan,
|
|
35
|
+
admit, openStore = createIngestionStore, now = () => performance.now(), limits = {} } = {}) {
|
|
36
|
+
let binding, bounds, started
|
|
37
|
+
try {
|
|
38
|
+
binding = record(plan, ['planId', 'planDigest'])
|
|
39
|
+
bounds = { maxReads: 32, maxHandles: 32, maxTextBytes: 16384, maxTotalTextBytes: 65536, lifetimeMs: 60000,
|
|
40
|
+
...record(limits, ['maxReads', 'maxHandles', 'maxTextBytes', 'maxTotalTextBytes', 'lifetimeMs']) }
|
|
41
|
+
if (!/^plan-[a-f0-9]{40}$/.test(binding.planId) || !/^sha256:[a-f0-9]{64}$/.test(binding.planDigest) ||
|
|
42
|
+
typeof workspaceRoot !== 'string' || typeof workspaceId !== 'string' ||
|
|
43
|
+
typeof admit !== 'function' || typeof openStore !== 'function' || typeof now !== 'function' ||
|
|
44
|
+
!positive(bounds.maxReads, 128) || !positive(bounds.maxHandles, 128) ||
|
|
45
|
+
!positive(bounds.maxTextBytes, 65536) || !positive(bounds.maxTotalTextBytes, 262144) ||
|
|
46
|
+
!positive(bounds.lifetimeMs, 600000)) throw new Error()
|
|
47
|
+
started = now()
|
|
48
|
+
if (!Number.isFinite(started)) throw new Error()
|
|
49
|
+
} catch { throw new Error('Invalid local evidence reader configuration') }
|
|
50
|
+
Object.freeze(binding)
|
|
51
|
+
const handles = new Map()
|
|
52
|
+
let reads = 0, releasedBytes = 0, closed = false, busy = false, lastTime = started
|
|
53
|
+
function live() {
|
|
54
|
+
const time = now()
|
|
55
|
+
if (closed || !Number.isFinite(time) || time < lastTime || time - started >= bounds.lifetimeMs) {
|
|
56
|
+
closed = true; handles.clear(); fail()
|
|
57
|
+
}
|
|
58
|
+
lastTime = time
|
|
59
|
+
}
|
|
60
|
+
function permission(operation, expected) {
|
|
61
|
+
live()
|
|
62
|
+
let decision
|
|
63
|
+
try {
|
|
64
|
+
const response = admit(Object.freeze({ operation, ...binding, readScope: 'all-plan' }))
|
|
65
|
+
let asynchronous = false
|
|
66
|
+
// Contain native Promise rejection without invoking an untrusted then getter.
|
|
67
|
+
try { Promise.prototype.then.call(response, undefined, () => {}); asynchronous = true } catch {}
|
|
68
|
+
if (asynchronous) fail()
|
|
69
|
+
decision = record(response, ['disposition', 'revision', 'readScope'])
|
|
70
|
+
}
|
|
71
|
+
catch { fail() }
|
|
72
|
+
if (decision.disposition !== 'permit' || decision.readScope !== 'all-plan' ||
|
|
73
|
+
typeof decision.revision !== 'string' || !decision.revision || decision.revision.length > 256 ||
|
|
74
|
+
(expected !== undefined && decision.revision !== expected)) fail()
|
|
75
|
+
live()
|
|
76
|
+
return decision.revision
|
|
77
|
+
}
|
|
78
|
+
function reserve(count) {
|
|
79
|
+
if (reads + count > bounds.maxReads || releasedBytes >= bounds.maxTotalTextBytes) fail('budget-exhausted')
|
|
80
|
+
reads += count // Failed reads retain their reservation; no free retries.
|
|
81
|
+
}
|
|
82
|
+
function exact(store, reference) {
|
|
83
|
+
live()
|
|
84
|
+
const value = store.getEvidence({ ...binding, ...reference })
|
|
85
|
+
if (!value || value.schema !== 'mnstry.atelier-ingestion-evidence@v1' || value.readScope !== 'all-plan' ||
|
|
86
|
+
value.planId !== binding.planId || value.planDigest !== binding.planDigest ||
|
|
87
|
+
value.sourceId !== reference.sourceId || value.sourceDigest !== reference.sourceDigest ||
|
|
88
|
+
value.attemptId !== reference.attemptId || value.locator?.kind !== reference.locator.kind ||
|
|
89
|
+
value.locator?.value !== reference.locator.value || value.freshness !== 'current' ||
|
|
90
|
+
value.integrity !== 'verified' || value.semanticAcceptance !== 'pending' || value.synthesized !== false ||
|
|
91
|
+
typeof value.text !== 'string' || bytes(value.text) > 262144) fail()
|
|
92
|
+
live()
|
|
93
|
+
return value.text
|
|
94
|
+
}
|
|
95
|
+
function execute(input, operation, body) {
|
|
96
|
+
if (busy) return refusal('not-available')
|
|
97
|
+
busy = true
|
|
98
|
+
try {
|
|
99
|
+
live()
|
|
100
|
+
let request
|
|
101
|
+
try { request = record(input, operation === 'search' ? ['query', 'limit', 'readScope'] : ['handle', 'readScope']) }
|
|
102
|
+
catch { fail('invalid-request') }
|
|
103
|
+
if (request.readScope !== undefined && request.readScope !== 'all-plan') fail('unsupported-scope')
|
|
104
|
+
return body(request)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// Never forward backend errors, path-bearing messages, or denied counts.
|
|
107
|
+
return refusal(['invalid-request', 'unsupported-scope', 'budget-exhausted'].includes(error?.reason) ? error.reason : 'not-available')
|
|
108
|
+
} finally { busy = false }
|
|
109
|
+
}
|
|
110
|
+
return Object.freeze({
|
|
111
|
+
search(input) {
|
|
112
|
+
return execute(input, 'search', request => {
|
|
113
|
+
const limit = request.limit ?? 5
|
|
114
|
+
if (typeof request.query !== 'string' || !request.query.trim() || request.query.length > 512 ||
|
|
115
|
+
bytes(request.query) > 2048 || request.query.toLowerCase().trim().split(/\s+/u).length > 32 || !positive(limit, 5)) fail('invalid-request')
|
|
116
|
+
const revision = permission('search')
|
|
117
|
+
if (handles.size + limit > bounds.maxHandles) fail('budget-exhausted')
|
|
118
|
+
reserve(1 + limit)
|
|
119
|
+
const store = openStore({ workspaceRoot, workspaceId })
|
|
120
|
+
permission('search', revision)
|
|
121
|
+
const found = store.query({ ...binding, query: request.query, limit })
|
|
122
|
+
if (!found || found.schema !== 'mnstry.atelier-ingestion-query@v1' || found.readScope !== 'all-plan' ||
|
|
123
|
+
found.planId !== binding.planId || found.planDigest !== binding.planDigest ||
|
|
124
|
+
!Array.isArray(found.hits) || found.hits.length > limit) fail()
|
|
125
|
+
const pending = [], items = []
|
|
126
|
+
let outputBytes = 0
|
|
127
|
+
for (const hit of found.hits) {
|
|
128
|
+
permission('search', revision)
|
|
129
|
+
const reference = evidenceJson({ sourceId: hit.sourceId, sourceDigest: hit.sourceDigest,
|
|
130
|
+
attemptId: hit.attemptId, locator: hit.locator })
|
|
131
|
+
// Query text is only a pointer. Exact fetch supplies every released byte.
|
|
132
|
+
const text = exact(store, reference)
|
|
133
|
+
const remaining = bounds.maxTotalTextBytes - releasedBytes - outputBytes
|
|
134
|
+
if (remaining <= 0) fail('budget-exhausted')
|
|
135
|
+
const projected = clip(text, Math.min(bounds.maxTextBytes, remaining))
|
|
136
|
+
outputBytes += bytes(projected.text)
|
|
137
|
+
const handle = randomUUID()
|
|
138
|
+
pending.push([handle, { reference, textDigest: digest(text), revision }])
|
|
139
|
+
items.push({ handle, ...projected, kind: 'source-evidence', semanticAcceptance: 'pending' })
|
|
140
|
+
}
|
|
141
|
+
permission('search', revision)
|
|
142
|
+
for (const [key, value] of pending) handles.set(key, value)
|
|
143
|
+
releasedBytes += outputBytes
|
|
144
|
+
return { schema, status: 'ok', items, coverage: 'partial', readScope: 'all-plan', ...flags }
|
|
145
|
+
})
|
|
146
|
+
},
|
|
147
|
+
get(input) {
|
|
148
|
+
return execute(input, 'get', request => {
|
|
149
|
+
if (typeof request.handle !== 'string' || request.handle.length > 64) fail('invalid-request')
|
|
150
|
+
const revision = permission('get')
|
|
151
|
+
const held = handles.get(request.handle)
|
|
152
|
+
if (!held || held.revision !== revision) fail()
|
|
153
|
+
reserve(1)
|
|
154
|
+
const store = openStore({ workspaceRoot, workspaceId })
|
|
155
|
+
permission('get', revision)
|
|
156
|
+
const text = exact(store, held.reference)
|
|
157
|
+
if (digest(text) !== held.textDigest) fail()
|
|
158
|
+
const projected = clip(text, Math.min(bounds.maxTextBytes, bounds.maxTotalTextBytes - releasedBytes))
|
|
159
|
+
permission('get', revision)
|
|
160
|
+
releasedBytes += bytes(projected.text)
|
|
161
|
+
return { schema, status: 'ok', item: { handle: request.handle, ...projected, kind: 'source-evidence', semanticAcceptance: 'pending' },
|
|
162
|
+
coverage: 'partial', readScope: 'all-plan', ...flags }
|
|
163
|
+
})
|
|
164
|
+
},
|
|
165
|
+
close() { closed = true; handles.clear() },
|
|
166
|
+
})
|
|
167
|
+
}
|