@mnstry/atelier 0.2.0-alpha.12 → 0.2.0-alpha.14
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 +894 -0
- package/README.md +159 -6
- 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-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/docs/architecture.md +89 -0
- package/docs/assurance-controls.md +2 -2
- 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 +267 -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 +210 -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 +237 -0
- package/docs/learning.md +215 -0
- package/docs/local-services.md +223 -19
- package/docs/obsidian-contract.md +246 -15
- package/docs/obsidian-plugin.md +252 -7
- package/docs/obsidian.md +874 -52
- package/docs/optional-ingestion.md +83 -0
- package/docs/personal-workspace.md +266 -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 +50 -0
- package/docs/repo-boundary-guard.md +120 -3
- 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 +318 -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 +219 -2
- 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/personal-workspace/overlay.json +24 -0
- package/fixtures/templates/local-library.v1.json +76 -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 +60 -5
- package/plugins/obsidian/main.js +57 -8
- package/plugins/obsidian/manifest.json +1 -1
- 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 +536 -69
- package/src/boundary/delegation-command.mjs +158 -0
- package/src/boundary/delegation.mjs +396 -0
- package/src/boundary/policy.mjs +185 -64
- 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 +66 -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 +772 -65
- 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 +30 -0
- package/src/coordination/index.mjs +110 -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 +30 -6
- package/src/graph/knowledge-graph.mjs +77 -9
- 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 +938 -0
- package/src/ingestion/optional/graphify/json_bridge.py +163 -0
- package/src/ingestion/optional/graphify/native-closure-pins.json +275 -0
- package/src/ingestion/optional/graphify/native-pins.json +306 -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 +49 -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 +401 -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/path-match.mjs +2 -1
- package/src/projection/obsidian/edits/apply.mjs +55 -16
- package/src/projection/obsidian/materialize/prepare-view.mjs +87 -5
- package/src/projection/obsidian/personal-workspace.mjs +519 -0
- package/src/projection/obsidian/proposals/adapter.mjs +79 -17
- package/src/projection/obsidian/proposals/observation.mjs +50 -4
- package/src/projection/obsidian/publication/publisher.mjs +214 -18
- package/src/projection/obsidian/publication/vault-list.mjs +4 -3
- package/src/projection/obsidian/recovery/index.mjs +4 -1
- package/src/projection/obsidian/recovery/store.mjs +160 -7
- package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
- package/src/projection/project.mjs +3 -2
- package/src/readiness/readiness.mjs +10 -3
- package/src/reflection/index.mjs +56 -0
- package/src/runtime/obsidian/app-production-seams.mjs +48 -16
- package/src/runtime/obsidian/app-registration.mjs +175 -28
- package/src/runtime/obsidian/app-restart.mjs +154 -0
- package/src/runtime/obsidian/engine.mjs +437 -56
- package/src/runtime/obsidian/extension-points.mjs +1 -1
- package/src/runtime/obsidian/index.mjs +10 -7
- package/src/runtime/obsidian/launch-plan.mjs +7 -4
- package/src/runtime/obsidian/lifecycle.mjs +108 -23
- package/src/runtime/obsidian/login-item.mjs +335 -0
- package/src/runtime/obsidian/machine-settings.mjs +119 -12
- package/src/runtime/obsidian/observation.mjs +36 -4
- package/src/runtime/obsidian/opening.mjs +173 -38
- package/src/runtime/obsidian/personal-selection.mjs +125 -0
- package/src/runtime/obsidian/pipeline.mjs +115 -6
- package/src/runtime/obsidian/plugin-channel.mjs +11 -3
- package/src/runtime/obsidian/plugin-choice.mjs +16 -4
- package/src/runtime/obsidian/plugin-drift.mjs +59 -11
- package/src/runtime/obsidian/plugin-presence.mjs +14 -1
- package/src/runtime/obsidian/private-lock.mjs +39 -4
- 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 +148 -19
- 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 +87 -23
- package/src/runtime/obsidian/service.mjs +102 -9
- package/src/runtime/obsidian/startup-adapters.mjs +59 -21
- 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/runtime/obsidian/view-permission.mjs +334 -0
- package/src/server/local-sidecar.mjs +169 -2
- package/src/server/server.mjs +28 -2
- 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/control-system.mjs +201 -0
- package/src/ui/html-primitives.mjs +3 -0
- package/src/ui/knowledge-page.mjs +1388 -0
- package/src/upgrade/closure-diagnostics.mjs +135 -0
- package/src/upgrade/closure.mjs +649 -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 +20 -7
- package/templates/external-project-workspace/pack-lifecycle.json +7 -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,154 @@
|
|
|
1
|
+
import { inspectInquiry } from '../inquiry/index.mjs'
|
|
2
|
+
import { inspectKnowledge } from '../knowledge/ledger.mjs'
|
|
3
|
+
import { inspectBuild } from '../build/ledger.mjs'
|
|
4
|
+
import { assertHandoff, contentDigest, harnessDigest, harnessRef, restrictiveAudience, HARNESS_LIMITS } from './contracts.mjs'
|
|
5
|
+
import { canonical } from '../capabilities/files.mjs'
|
|
6
|
+
import { createHash } from 'node:crypto'
|
|
7
|
+
|
|
8
|
+
export function inspectHarness(profile, records) {
|
|
9
|
+
if (profile === 'inquiry') return inspectInquiry(records)
|
|
10
|
+
if (profile === 'knowledge') return inspectKnowledge(records)
|
|
11
|
+
if (profile === 'build') return inspectBuild(records)
|
|
12
|
+
throw new Error('unknown harness profile')
|
|
13
|
+
}
|
|
14
|
+
function context(dependencySnapshots = [], verificationLimit = HARNESS_LIMITS.dependencyVerifications) {
|
|
15
|
+
if (!Array.isArray(dependencySnapshots) || dependencySnapshots.length > 64) throw new Error('dependency snapshot ceiling exceeded')
|
|
16
|
+
if (!Number.isSafeInteger(verificationLimit) || verificationLimit < 1 || verificationLimit > HARNESS_LIMITS.dependencyVerifications) throw new Error('invalid dependency verification limit')
|
|
17
|
+
return { snapshots: dependencySnapshots, inspections: new Map(), verified: new Map(), verificationLimit, verificationCalls: 0, historyReplays: 0, exhausted: false }
|
|
18
|
+
}
|
|
19
|
+
function inspect(profile, records, ctx) {
|
|
20
|
+
if (!ctx.inspections.has(profile)) ctx.inspections.set(profile, new Map())
|
|
21
|
+
const cache = ctx.inspections.get(profile)
|
|
22
|
+
if (!cache.has(records)) { cache.set(records, inspectHarness(profile, records)); ctx.historyReplays++ }
|
|
23
|
+
return cache.get(records)
|
|
24
|
+
}
|
|
25
|
+
const work = ctx => ({ verificationCalls: ctx.verificationCalls, historyReplays: ctx.historyReplays, verificationLimit: ctx.verificationLimit, exhausted: ctx.exhausted })
|
|
26
|
+
const bounded = depth => { if (depth > HARNESS_LIMITS.dependencyDepth) throw new Error('harness dependency depth exceeded') }
|
|
27
|
+
function artifact(profile, records, subjectId, ctx, depth) {
|
|
28
|
+
bounded(depth)
|
|
29
|
+
const state = inspect(profile, records, ctx), subject = records.find(r => r.id === subjectId)
|
|
30
|
+
if (!subject || state.reconsider.some(r => r.id === subjectId)) throw new Error('handoff subject is missing or requires reconsideration')
|
|
31
|
+
let audience, context
|
|
32
|
+
if (profile === 'knowledge') {
|
|
33
|
+
if (subject.kind !== 'contribution' || !state.accepted.includes(subject.id)) throw new Error('knowledge handoff requires an accepted contribution')
|
|
34
|
+
if (knowledgeFreshness(records, ctx, depth, [subject.id]).reconsider.some(r => r.id === subject.id)) throw new Error('knowledge import requires current source snapshots')
|
|
35
|
+
const review = records.findLast(r => r.kind === 'review' && r.data.target.id === subject.id)
|
|
36
|
+
context = [state.domain, review, ...review.data.evaluations.map(pin => records.find(r => r.id === pin.id))]
|
|
37
|
+
audience = restrictiveAudience(subject.data.audience, state.domain.data.audience)
|
|
38
|
+
} else if (profile === 'inquiry') {
|
|
39
|
+
if (subject.kind !== 'decision' || subject.data.disposition !== 'accepted') throw new Error('inquiry handoff requires an accepted decision')
|
|
40
|
+
const assessment = records.find(r => r.id === subject.data.assessment.id)
|
|
41
|
+
context = [records.find(r => r.id === assessment.data.hypothesis.id), assessment]
|
|
42
|
+
audience = state.campaign.data.audience
|
|
43
|
+
} else {
|
|
44
|
+
if (subject.kind !== 'candidate' || state.candidate?.id !== subject.id || !readiness(records, ctx, depth).readyReported) throw new Error('build handoff requires current accepted candidate and fresh dependencies')
|
|
45
|
+
context = [state.establishment, state.decision, ...state.gates]
|
|
46
|
+
audience = state.establishment.data.audience
|
|
47
|
+
}
|
|
48
|
+
return { state, audience, subject, payload: JSON.stringify({ subject, context, assurance: 'caller-reported; acceptance-is-not-truth-or-authority' }) }
|
|
49
|
+
}
|
|
50
|
+
function create({ profile, repository, records, subjectId, target }, ctx, depth) {
|
|
51
|
+
const { state, audience, subject, payload } = artifact(profile, records, subjectId, ctx, depth)
|
|
52
|
+
if (profile !== 'inquiry' && state.establishment.data.repository !== repository) throw new Error('handoff repository differs from establishment')
|
|
53
|
+
const repositoryBinding = profile === 'inquiry' ? 'caller-declared' : 'establishment-record'
|
|
54
|
+
return assertHandoff({ schema: 'atelier-harness-handoff@v1', source: { repository, repositoryBinding, profile, run: records[0].id, historyDigest: state.head, subject: harnessRef(subject) }, target, audience, payload, payloadDigest: contentDigest(payload), assurance: 'caller-reported', authority: 'none' })
|
|
55
|
+
}
|
|
56
|
+
function verify({ handoff, records }, ctx, depth) {
|
|
57
|
+
bounded(depth)
|
|
58
|
+
if (ctx.verificationCalls >= ctx.verificationLimit) { ctx.exhausted = true; throw new Error('harness dependency verification budget exhausted') }
|
|
59
|
+
ctx.verificationCalls++
|
|
60
|
+
assertHandoff(handoff)
|
|
61
|
+
if (!ctx.verified.has(records)) ctx.verified.set(records, new Map())
|
|
62
|
+
const cache = ctx.verified.get(records), key = harnessDigest(handoff), prior = cache.get(key)
|
|
63
|
+
if (prior?.active) throw new Error('harness dependency cycle detected')
|
|
64
|
+
if (prior?.result) return prior.result
|
|
65
|
+
cache.set(key, { active: true })
|
|
66
|
+
try {
|
|
67
|
+
inspect(handoff.source.profile, records, ctx)
|
|
68
|
+
const hash = createHash('sha256').update('[')
|
|
69
|
+
let extendsIssuedHistory = false
|
|
70
|
+
for (let i = 0; i < records.length; i++) {
|
|
71
|
+
if (i) hash.update(',')
|
|
72
|
+
hash.update(canonical(records[i]))
|
|
73
|
+
if (`sha256:${hash.copy().update(']').digest('hex')}` === handoff.source.historyDigest) extendsIssuedHistory = true
|
|
74
|
+
}
|
|
75
|
+
if (!extendsIssuedHistory) throw new Error('handoff source history changed or diverged')
|
|
76
|
+
const current = create({ ...handoff.source, records, subjectId: handoff.source.subject.id, target: handoff.target }, ctx, depth)
|
|
77
|
+
const observedHead = current.source.historyDigest
|
|
78
|
+
current.source.historyDigest = handoff.source.historyDigest
|
|
79
|
+
if (harnessDigest(current) !== harnessDigest(handoff)) throw new Error('handoff is stale or differs from its source history')
|
|
80
|
+
const result = { current: true, historyDigest: observedHead, issuedHistoryDigest: handoff.source.historyDigest, sourceRepositoryBinding: current.source.repositoryBinding, sourceAuthenticity: 'unverified', authority: 'none' }
|
|
81
|
+
cache.set(key, { result })
|
|
82
|
+
return result
|
|
83
|
+
} finally {
|
|
84
|
+
if (cache.get(key)?.active) cache.delete(key)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function matching(h, snapshots) {
|
|
88
|
+
return snapshots.filter(s => s.repository === h.source.repository && s.profile === h.source.profile && s.records?.[0]?.id === h.source.run)
|
|
89
|
+
}
|
|
90
|
+
function knowledgeFreshness(records, ctx, depth, subjects = null) {
|
|
91
|
+
bounded(depth)
|
|
92
|
+
const state = inspect('knowledge', records, ctx), stale = new Map(state.reconsider.map(r => [r.id, r.reasons]))
|
|
93
|
+
const needed = subjects ? new Set(subjects) : null
|
|
94
|
+
if (needed) for (const record of [...records].reverse()) if (needed.has(record.id) && record.kind === 'contribution') for (const item of record.data.basedOn) needed.add(item.contribution.id)
|
|
95
|
+
for (const record of records) {
|
|
96
|
+
if (record.kind !== 'contribution' || record.data.origin.method !== 'exchange' || (needed && !needed.has(record.id))) continue
|
|
97
|
+
const h = record.data.origin.handoff, snapshots = matching(h, ctx.snapshots)
|
|
98
|
+
let reason
|
|
99
|
+
if (snapshots.length !== 1) reason = 'import-source-missing-or-ambiguous'
|
|
100
|
+
else try { verify({ handoff: h, records: snapshots[0].records }, ctx, depth + 1) } catch { reason = ctx.exhausted ? 'import-source-verification-budget-exhausted' : 'import-source-requires-reconsideration' }
|
|
101
|
+
if (reason) stale.set(record.id, [...(stale.get(record.id) ?? []), reason])
|
|
102
|
+
}
|
|
103
|
+
// References always point backwards, so one history-order pass propagates
|
|
104
|
+
// changes discovered in external inputs through local meaning and activation.
|
|
105
|
+
for (const record of records) {
|
|
106
|
+
const d = record.data
|
|
107
|
+
const refs = record.kind === 'contribution' ? [d.domain, ...d.basedOn.map(e => e.contribution)]
|
|
108
|
+
: record.kind === 'evaluation' ? [d.contribution]
|
|
109
|
+
: record.kind === 'relation' ? [d.domain, d.subject, d.object]
|
|
110
|
+
: record.kind === 'review' ? [d.target, ...d.evaluations]
|
|
111
|
+
: record.kind === 'activation' ? d.reviews : []
|
|
112
|
+
const reasons = refs.flatMap(pin => stale.get(pin.id) ?? [])
|
|
113
|
+
if (reasons.length) stale.set(record.id, [...new Set([...(stale.get(record.id) ?? []), ...reasons])])
|
|
114
|
+
}
|
|
115
|
+
return { historyDigest: state.head, reconsider: [...stale].map(([id, reasons]) => ({ id, reasons })), freshness: 'relative-to-explicit-snapshots', canonicalMutation: false }
|
|
116
|
+
}
|
|
117
|
+
function readiness(records, ctx, depth) {
|
|
118
|
+
bounded(depth)
|
|
119
|
+
const state = inspect('build', records, ctx), blockers = []
|
|
120
|
+
if (!state.candidate) blockers.push('candidate-missing')
|
|
121
|
+
if (!state.reportedAccepted) blockers.push('current-accepted-decision-missing')
|
|
122
|
+
for (const [id, a] of Object.entries(state.attempts)) if (a.candidate === state.candidate?.id && !['completed', 'failed', 'cancelled'].includes(a.state)) blockers.push(`attempt-unsettled:${id}`)
|
|
123
|
+
for (const dependency of state.establishment?.data.dependencies ?? []) {
|
|
124
|
+
const h = dependency.handoff
|
|
125
|
+
const snapshots = matching(h, ctx.snapshots)
|
|
126
|
+
if (snapshots.length !== 1) { blockers.push(`dependency-missing-or-ambiguous:${dependency.id}`); continue }
|
|
127
|
+
try { verify({ handoff: h, records: snapshots[0].records }, ctx, depth + 1) } catch { blockers.push(`${ctx.exhausted ? 'dependency-verification-budget-exhausted' : 'dependency-requires-reconsideration'}:${dependency.id}`) }
|
|
128
|
+
}
|
|
129
|
+
return { candidate: state.candidate, readyReported: blockers.length === 0, blockers, historyDigest: state.head,
|
|
130
|
+
dependencyFreshness: 'relative-to-explicit-snapshots; no-live-observation', authenticatedAcceptance: false, executionAuthorized: false }
|
|
131
|
+
}
|
|
132
|
+
export function createHarnessHandoff(options) { return create(options, context(options.dependencySnapshots, options.verificationLimit), 0) }
|
|
133
|
+
export function verifyHarnessHandoff(options) {
|
|
134
|
+
const ctx = context(options.dependencySnapshots, options.verificationLimit)
|
|
135
|
+
return { ...verify(options, ctx, 0), dependencyWork: work(ctx) }
|
|
136
|
+
}
|
|
137
|
+
export function buildReadiness(records, { dependencySnapshots, verificationLimit } = {}) {
|
|
138
|
+
const ctx = context(dependencySnapshots, verificationLimit)
|
|
139
|
+
return { ...readiness(records, ctx, 0), dependencyWork: work(ctx) }
|
|
140
|
+
}
|
|
141
|
+
export function reconcileKnowledge(records, { dependencySnapshots, verificationLimit } = {}) {
|
|
142
|
+
const ctx = context(dependencySnapshots, verificationLimit)
|
|
143
|
+
return { ...knowledgeFreshness(records, ctx, 0), dependencyWork: work(ctx) }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// A read-only projection that a Fabric adapter or another coordinator can read.
|
|
147
|
+
// It imports no private registry, creates no tasks and grants no dispatch power.
|
|
148
|
+
export function buildCoordinationProposal(records, options = {}) {
|
|
149
|
+
const state = inspectBuild(records), readiness = buildReadiness(records, options)
|
|
150
|
+
return { schema: 'atelier-build-coordination-proposal@v1', outcome: state.establishment?.data.purpose ?? null,
|
|
151
|
+
owner: state.establishment?.data.owner ?? null, candidate: state.candidate?.data ?? null,
|
|
152
|
+
dependencies: state.establishment?.data.dependencies ?? [], gates: state.gates.map(r => ({ id: r.data.gate, status: r.data.status, evidence: r.data.evidence, record: harnessRef(r) })),
|
|
153
|
+
...readiness, reconsider: state.reconsider, acceptedByCoordinator: false }
|
|
154
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { assertDocument } from '../capabilities/package.mjs'
|
|
2
|
+
import { harnessRef } from './contracts.mjs'
|
|
3
|
+
import { inspectHarness } from './exchange.mjs'
|
|
4
|
+
export function prepareHarnessFeedback({ profile, records, subjectId, id, outcome, cause, evidenceDigest, at, by }) {
|
|
5
|
+
const state = inspectHarness(profile, records), subject = records.find(r => r.id === subjectId)
|
|
6
|
+
if (!subject) throw new Error('feedback subject missing')
|
|
7
|
+
const atSubject = inspectHarness(profile, records.slice(0, records.indexOf(subject) + 1))
|
|
8
|
+
const binding = (atSubject.domain ?? atSubject.establishment ?? atSubject.campaign)?.data.binding
|
|
9
|
+
if (!binding) throw new Error('harness establishment has no skill binding')
|
|
10
|
+
if (!['skill', 'host', 'tool', 'configuration', 'context', 'provider', 'unknown'].includes(cause)) throw new Error('unknown feedback cause')
|
|
11
|
+
const event = { schema: 'mnstry.atelier-capability-event@v1', id, kind: 'feedback', ...binding, observer: by, outcome,
|
|
12
|
+
cause: ['context', 'provider'].includes(cause) ? 'unknown' : cause, evidenceDigest, at }
|
|
13
|
+
assertDocument(event, 'event')
|
|
14
|
+
return { event, subject: harnessRef(subject), historyDigest: state.head, reportedCause: cause,
|
|
15
|
+
causeMapping: event.cause === cause ? 'exact' : 'unsupported-steward-cause-preserved-in-wrapper', recorded: false, authority: 'none' }
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { assertHarness, harnessDigest, HARNESS_LIMITS } from './contracts.mjs'
|
|
2
|
+
export const unique = (items, label) => { if (new Set(items).size !== items.length) throw new Error(`duplicate ${label}`) }
|
|
3
|
+
|
|
4
|
+
// Shared integrity mechanics; each domain retains its own states and meaning.
|
|
5
|
+
export function replay(records, profile, firstKind, visit) {
|
|
6
|
+
if (!Array.isArray(records) || records.length > HARNESS_LIMITS.records || Buffer.byteLength(JSON.stringify(records)) > HARNESS_LIMITS.bytes) throw new Error('harness history exceeds bounds')
|
|
7
|
+
const entries = new Map(), dependencies = new Map(), stale = new Map()
|
|
8
|
+
const context = {
|
|
9
|
+
entries, stale, dependencies, first: null,
|
|
10
|
+
resolve(ref, kinds, current = true) {
|
|
11
|
+
const r = entries.get(ref.id)
|
|
12
|
+
if (!r || harnessDigest(r) !== ref.digest || !kinds.includes(r.kind)) throw new Error('missing, wrong-kind or mismatched reference')
|
|
13
|
+
if (current && stale.has(r.id)) throw new Error('reference requires reconsideration')
|
|
14
|
+
return r
|
|
15
|
+
},
|
|
16
|
+
invalidate(id, reason) {
|
|
17
|
+
const queue = [id], visited = new Set()
|
|
18
|
+
while (queue.length) {
|
|
19
|
+
const next = queue.shift(); if (visited.has(next)) continue; visited.add(next)
|
|
20
|
+
stale.set(next, [...new Set([...(stale.get(next) ?? []), reason])])
|
|
21
|
+
for (const [child, refs] of dependencies) if (refs.includes(next)) queue.push(child)
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
for (const record of records) {
|
|
26
|
+
assertHarness(record, profile)
|
|
27
|
+
if (entries.has(record.id)) throw new Error('immutable record identity already exists')
|
|
28
|
+
if (!context.first) {
|
|
29
|
+
if (record.kind !== firstKind || record.id !== record.run) throw new Error('harness establishment must be first')
|
|
30
|
+
context.first = record
|
|
31
|
+
} else if (record.run !== context.first.id || record.kind === firstKind) throw new Error('harness run mismatch')
|
|
32
|
+
const refs = visit(record, context) ?? []
|
|
33
|
+
entries.set(record.id, record); dependencies.set(record.id, [...new Set(refs)])
|
|
34
|
+
for (const target of refs) for (const reason of stale.get(target) ?? []) context.invalidate(record.id, reason)
|
|
35
|
+
}
|
|
36
|
+
return { establishment: context.first, records, head: harnessDigest(records), reconsider: [...stale].map(([id, reasons]) => ({ id, kind: entries.get(id).kind, reasons })), assurance: 'caller-reported; integrity-and-consistency-only', authority: 'none' }
|
|
37
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { HARNESS_LIMITS, EMPTY_HARNESS_HEAD, harnessDigest, harnessRef, contentDigest, validateHarnessDocument } from './contracts.mjs'
|
|
2
|
+
export { inspectHarness, createHarnessHandoff, verifyHarnessHandoff, buildReadiness, buildCoordinationProposal, reconcileKnowledge } from './exchange.mjs'
|
|
3
|
+
export { appendHarness, readHarness } from './store.mjs'
|
|
4
|
+
export { prepareHarnessFeedback } from './feedback.mjs'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsonAt, replaceJson, stat, within, workspaceRoot } from '../capabilities/files.mjs'
|
|
2
|
+
import { withOperationLock } from '../capabilities/adoption.mjs'
|
|
3
|
+
import { assertHarness, EMPTY_HARNESS_HEAD, HARNESS_LIMITS } from './contracts.mjs'
|
|
4
|
+
import { inspectHarness } from './exchange.mjs'
|
|
5
|
+
function location(profile, run) {
|
|
6
|
+
if (!['knowledge', 'build'].includes(profile) || !/^[a-z][a-z0-9-]{0,63}$/.test(run ?? '')) throw new Error('invalid stored harness profile or run')
|
|
7
|
+
return `.atelier-local/harnesses/${profile}/${run}/ledger.json`
|
|
8
|
+
}
|
|
9
|
+
function read(root, profile, run) {
|
|
10
|
+
const file = location(profile, run)
|
|
11
|
+
if (!stat(within(root, file))) return inspectHarness(profile, [])
|
|
12
|
+
const ledger = assertHarness(jsonAt(root, file), profile, 'ledger'), state = inspectHarness(profile, ledger.records)
|
|
13
|
+
if (ledger.head !== state.head || state.establishment.id !== run) throw new Error('harness ledger integrity mismatch')
|
|
14
|
+
return state
|
|
15
|
+
}
|
|
16
|
+
export function readHarness({ workspaceRoot: root, profile, run }) { return read(workspaceRoot(root), profile, run) }
|
|
17
|
+
export function appendHarness({ workspaceRoot: input, profile, record, confirm }) {
|
|
18
|
+
assertHarness(record, profile)
|
|
19
|
+
const root = workspaceRoot(input, { write: true })
|
|
20
|
+
return withOperationLock(root, () => {
|
|
21
|
+
const before = read(root, profile, record.run)
|
|
22
|
+
if ((before.head ?? EMPTY_HARNESS_HEAD) !== confirm) throw new Error('append requires current harness history digest')
|
|
23
|
+
const state = inspectHarness(profile, [...before.records, record])
|
|
24
|
+
const ledger = { schema: 'atelier-harness-ledger@v1', profile, records: state.records, head: state.head }
|
|
25
|
+
if (Buffer.byteLength(JSON.stringify(ledger, null, 2)) + 1 > HARNESS_LIMITS.bytes) throw new Error('serialized harness ledger exceeds bounds')
|
|
26
|
+
replaceJson(root, location(profile, record.run), ledger)
|
|
27
|
+
return { recorded: record.id, head: state.head, reconsider: state.reconsider, authority: 'none' }
|
|
28
|
+
})
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
4
|
+
import addFormats from 'ajv-formats';
|
|
5
|
+
import { canonicalize } from '../attestation/jcs.mjs';
|
|
6
|
+
|
|
7
|
+
export const INGESTION_MAX_PLAN_BYTES = 256 * 1024;
|
|
8
|
+
export const INGESTION_MAX_EVIDENCE_ITEMS = 2000;
|
|
9
|
+
export const ingestionSchema = JSON.parse(fs.readFileSync(new URL('../../contracts/atelier-ingestion.v1.schema.json', import.meta.url), 'utf8'));
|
|
10
|
+
const ajv = new Ajv2020({ allErrors: false, strict: false }); addFormats(ajv); ajv.addSchema(ingestionSchema);
|
|
11
|
+
const validators = new Map();
|
|
12
|
+
export function ingestionDigest(value) { return `sha256:${createHash('sha256').update(canonicalize(value)).digest('hex')}`; }
|
|
13
|
+
export function validateIngestionValue(definition, value) {
|
|
14
|
+
if (!Object.hasOwn(ingestionSchema.$defs, definition)) return ['unknown ingestion definition'];
|
|
15
|
+
if (!validators.has(definition)) validators.set(definition, ajv.getSchema(`${ingestionSchema.$id}#/$defs/${definition}`));
|
|
16
|
+
return validators.get(definition)(value) ? [] : ['ingestion document does not match its contract'];
|
|
17
|
+
}
|
|
18
|
+
export function ingestionJson(value) {
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
function visit(item, depth = 0) {
|
|
21
|
+
if (depth > 24) throw new Error('ingestion JSON depth exceeded');
|
|
22
|
+
if (item === null || typeof item === 'boolean') return;
|
|
23
|
+
if (typeof item === 'string') { if (item.includes('\u0000')) throw new Error('invalid ingestion text'); return; }
|
|
24
|
+
if (typeof item === 'number' && Number.isFinite(item)) return;
|
|
25
|
+
if (typeof item !== 'object' || seen.has(item) || (!Array.isArray(item) && ![null, Object.prototype].includes(Object.getPrototypeOf(item)))) throw new Error('ingestion input must be plain JSON');
|
|
26
|
+
seen.add(item);
|
|
27
|
+
if (Reflect.ownKeys(item).length > 4096) throw new Error('ingestion member ceiling exceeded');
|
|
28
|
+
for (const key of Reflect.ownKeys(item)) {
|
|
29
|
+
if (Array.isArray(item) && key === 'length') continue;
|
|
30
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
31
|
+
if (typeof key !== 'string' || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) throw new Error('ingestion input must be plain JSON');
|
|
32
|
+
visit(descriptor.value, depth + 1);
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(item) && Object.keys(item).length !== item.length) throw new Error('ingestion arrays must be dense');
|
|
35
|
+
seen.delete(item);
|
|
36
|
+
}
|
|
37
|
+
visit(value);
|
|
38
|
+
const text = canonicalize(value);
|
|
39
|
+
if (Buffer.byteLength(text) > INGESTION_MAX_PLAN_BYTES) throw new Error('ingestion document byte ceiling exceeded');
|
|
40
|
+
return JSON.parse(text);
|
|
41
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
|
|
3
|
+
const digest = value => `sha256:${createHash('sha256').update(JSON.stringify(value)).digest('hex')}`
|
|
4
|
+
const invalid = () => { throw new Error('invalid ingestion evaluation document') }
|
|
5
|
+
function object(value, keys, required = keys) {
|
|
6
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)
|
|
7
|
+
|| Object.keys(value).some(key => !keys.includes(key))
|
|
8
|
+
|| required.some(key => !Object.hasOwn(value, key))) invalid()
|
|
9
|
+
}
|
|
10
|
+
function text(value, max = 512) { if (typeof value !== 'string' || !value.trim() || value.length > max) invalid() }
|
|
11
|
+
function count(value) { if (!Number.isSafeInteger(value) || value < 0) invalid() }
|
|
12
|
+
function measure(value) { if (value !== null && (!Number.isFinite(value) || value < 0)) invalid() }
|
|
13
|
+
function evidence(items) {
|
|
14
|
+
if (!Array.isArray(items) || items.length > 10000) invalid()
|
|
15
|
+
for (const item of items) {
|
|
16
|
+
object(item, ['locator', 'text']); object(item.locator, ['kind', 'value'])
|
|
17
|
+
if (!['line', 'csv-cell', 'json-pointer'].includes(item.locator.kind)) invalid()
|
|
18
|
+
if (typeof item.locator.value !== 'string' || item.locator.value.length > 2048
|
|
19
|
+
|| typeof item.text !== 'string' || item.text.length > 65536) invalid()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function key(item) { return JSON.stringify([item.locator.kind, item.locator.value, item.text]) }
|
|
23
|
+
function score(expected, actual) {
|
|
24
|
+
const remaining = new Map()
|
|
25
|
+
for (const item of expected) remaining.set(key(item), (remaining.get(key(item)) ?? 0) + 1)
|
|
26
|
+
let matched = 0
|
|
27
|
+
for (const item of actual) {
|
|
28
|
+
const k = key(item)
|
|
29
|
+
if (remaining.get(k) > 0) { matched++; remaining.set(k, remaining.get(k) - 1) }
|
|
30
|
+
}
|
|
31
|
+
return { expected: expected.length, returned: actual.length, matched,
|
|
32
|
+
missed: expected.length - matched, unexpected: actual.length - matched }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Score exact structural evidence against a predeclared local suite. This does
|
|
36
|
+
* not judge semantic support, authenticate supplied human assessments, execute a
|
|
37
|
+
* provider or grant model qualification. Unknown costs remain unknown. */
|
|
38
|
+
export function evaluateIngestionTrial({ suite, trial }) {
|
|
39
|
+
let serialized
|
|
40
|
+
try { serialized = JSON.stringify({ suite, trial }) } catch { invalid() }
|
|
41
|
+
if (!serialized || Buffer.byteLength(serialized) > 4 * 1024 * 1024) invalid()
|
|
42
|
+
object(suite, ['id', 'revision', 'thresholds', 'cases'])
|
|
43
|
+
text(suite.id); text(suite.revision)
|
|
44
|
+
object(suite.thresholds, ['minimumRecall', 'maximumUnexpected', 'maximumFailed'])
|
|
45
|
+
if (!Number.isFinite(suite.thresholds.minimumRecall) || suite.thresholds.minimumRecall < 0
|
|
46
|
+
|| suite.thresholds.minimumRecall > 1) invalid()
|
|
47
|
+
count(suite.thresholds.maximumUnexpected); count(suite.thresholds.maximumFailed)
|
|
48
|
+
if (!Array.isArray(suite.cases) || !suite.cases.length || suite.cases.length > 256) invalid()
|
|
49
|
+
const ids = new Set()
|
|
50
|
+
for (const item of suite.cases) {
|
|
51
|
+
object(item, ['id', 'stratum', 'split', 'sourceDigest', 'expected'])
|
|
52
|
+
text(item.id); text(item.stratum)
|
|
53
|
+
if (ids.has(item.id) || !['calibration', 'held-out'].includes(item.split)
|
|
54
|
+
|| !/^sha256:[0-9a-f]{64}$/.test(item.sourceDigest)) invalid()
|
|
55
|
+
ids.add(item.id); evidence(item.expected)
|
|
56
|
+
}
|
|
57
|
+
object(trial, ['id', 'suiteDigest', 'processor', 'currency', 'outcomes'])
|
|
58
|
+
text(trial.id)
|
|
59
|
+
if (trial.suiteDigest !== digest(suite)) throw new Error('evaluation suite digest mismatch')
|
|
60
|
+
object(trial.processor, ['id', 'version', 'configurationDigest'])
|
|
61
|
+
text(trial.processor.id); text(trial.processor.version)
|
|
62
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(trial.processor.configurationDigest)
|
|
63
|
+
|| !/^[A-Z]{3}$/.test(trial.currency)) invalid()
|
|
64
|
+
if (!Array.isArray(trial.outcomes) || trial.outcomes.length > suite.cases.length) invalid()
|
|
65
|
+
const outcomes = new Map()
|
|
66
|
+
for (const item of trial.outcomes) {
|
|
67
|
+
object(item, ['caseId', 'sourceDigest', 'status', 'evidence', 'attempts', 'elapsedMs', 'cost', 'humanAssessment'])
|
|
68
|
+
if (!ids.has(item.caseId) || outcomes.has(item.caseId)
|
|
69
|
+
|| !['complete', 'failed', 'uncertain'].includes(item.status)) invalid()
|
|
70
|
+
if (item.sourceDigest !== suite.cases.find(c => c.id === item.caseId).sourceDigest) {
|
|
71
|
+
throw new Error('evaluation source digest mismatch')
|
|
72
|
+
}
|
|
73
|
+
evidence(item.evidence); count(item.attempts); measure(item.elapsedMs); measure(item.cost)
|
|
74
|
+
if (item.attempts < 1 || (item.status !== 'complete' && item.evidence.length)) invalid()
|
|
75
|
+
if (item.humanAssessment !== null) {
|
|
76
|
+
object(item.humanAssessment, ['verdict', 'actorId', 'evidenceRef'])
|
|
77
|
+
if (!['accepted', 'rejected', 'deferred'].includes(item.humanAssessment.verdict)) invalid()
|
|
78
|
+
text(item.humanAssessment.actorId); text(item.humanAssessment.evidenceRef)
|
|
79
|
+
if (item.humanAssessment.verdict === 'accepted' && item.status !== 'complete') invalid()
|
|
80
|
+
}
|
|
81
|
+
outcomes.set(item.caseId, item)
|
|
82
|
+
}
|
|
83
|
+
const cases = suite.cases.map(item => {
|
|
84
|
+
const outcome = outcomes.get(item.id)
|
|
85
|
+
return { caseId: item.id, stratum: item.stratum, split: item.split,
|
|
86
|
+
status: outcome?.status ?? 'missing', ...score(item.expected, outcome?.evidence ?? []),
|
|
87
|
+
attempts: outcome?.attempts ?? null, elapsedMs: outcome?.elapsedMs ?? null,
|
|
88
|
+
cost: outcome?.cost ?? null, humanVerdict: outcome?.humanAssessment?.verdict ?? 'unassessed' }
|
|
89
|
+
})
|
|
90
|
+
function summarize(rows) {
|
|
91
|
+
const totals = { cases: rows.length, expected: 0, returned: 0, matched: 0, missed: 0, unexpected: 0, failed: 0 }
|
|
92
|
+
for (const row of rows) {
|
|
93
|
+
for (const k of ['expected', 'returned', 'matched', 'missed', 'unexpected']) totals[k] += row[k]
|
|
94
|
+
if (row.status !== 'complete') totals.failed++
|
|
95
|
+
}
|
|
96
|
+
const recall = totals.expected ? totals.matched / totals.expected : null
|
|
97
|
+
// A zero-evidence sample cannot establish extraction recall.
|
|
98
|
+
const passed = recall !== null && recall >= suite.thresholds.minimumRecall
|
|
99
|
+
&& totals.unexpected <= suite.thresholds.maximumUnexpected && totals.failed <= suite.thresholds.maximumFailed
|
|
100
|
+
return { ...totals, recall, passed }
|
|
101
|
+
}
|
|
102
|
+
const strata = [...new Set(cases.filter(c => c.split === 'held-out').map(c => c.stratum))]
|
|
103
|
+
.map(stratum => ({ stratum, ...summarize(cases.filter(c => c.split === 'held-out' && c.stratum === stratum)) }))
|
|
104
|
+
const heldOut = summarize(cases.filter(c => c.split === 'held-out'))
|
|
105
|
+
const accepted = cases.filter(c => c.humanVerdict === 'accepted').length
|
|
106
|
+
const unknownCostCases = cases.filter(c => c.cost === null).length
|
|
107
|
+
const knownCost = cases.reduce((total, c) => total + (c.cost ?? 0), 0)
|
|
108
|
+
if (!Number.isFinite(knownCost)) throw new Error('evaluation cost total exceeds numeric bounds')
|
|
109
|
+
const totalCost = unknownCostCases ? null : knownCost
|
|
110
|
+
return { schema: 'mnstry.atelier-ingestion-evaluation@v1', suiteDigest: digest(suite),
|
|
111
|
+
trialDigest: digest(trial), processor: structuredClone(trial.processor), cases,
|
|
112
|
+
calibration: summarize(cases.filter(c => c.split === 'calibration')), heldOut, strata,
|
|
113
|
+
structuralThresholdsPassed: heldOut.passed && strata.length > 0 && strata.every(s => s.passed),
|
|
114
|
+
costs: { currency: trial.currency, knownCost, unknownCostCases, totalCost, acceptedResults: accepted,
|
|
115
|
+
costPerAcceptedResult: accepted && totalCost !== null ? totalCost / accepted : null },
|
|
116
|
+
semanticQualification: 'not-assessed', humanAssessmentIdentity: 'caller-asserted', grantsAuthority: false }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function ingestionEvaluationDigest(value) { return digest(value) }
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { PRESENCE_PROFILES } from '../evaluation/index.mjs'
|
|
3
|
+
|
|
4
|
+
// Private host execution declarations reuse existing capability owners. This is
|
|
5
|
+
// not a capability-adoption, identity, evidence or knowledge canonical.
|
|
6
|
+
const json = value => JSON.stringify(value)
|
|
7
|
+
const digest = value => createHash('sha256').update(json(value)).digest('hex')
|
|
8
|
+
const ownValue = (object, key) => Object.getOwnPropertyDescriptor(object ?? {}, key)?.value
|
|
9
|
+
const callableFor = (bindings, step) => ownValue(ownValue(bindings, step.provider), step.operation)
|
|
10
|
+
const compiledCallables = new WeakMap()
|
|
11
|
+
|
|
12
|
+
export function compileRoute({ profile, selected, bindings, operationRoles }) {
|
|
13
|
+
if (!PRESENCE_PROFILES.includes(profile) || !selected || !ownValue(bindings, 'vanilla') || !operationRoles) throw new TypeError('Known presence profile, selected route, vanilla binding and own operation-role declarations required')
|
|
14
|
+
const present = new Set(['vanilla', ...(profile === 'vanilla' ? [] : profile.split('+'))])
|
|
15
|
+
const used = new Set(), callables = new Map()
|
|
16
|
+
const resolve = (step, role) => {
|
|
17
|
+
const callable = callableFor(bindings, step ?? {})
|
|
18
|
+
if (typeof step?.provider !== 'string' || typeof step?.operation !== 'string' || !present.has(step.provider) ||
|
|
19
|
+
typeof callable !== 'function') throw new Error(`Selected ${role} capability is unavailable in this profile`)
|
|
20
|
+
if (step.provider === 'jev' && role !== 'assess') throw new Error('Jev supplies bounded judgments rather than extraction or generation')
|
|
21
|
+
const id = `${step.provider}/${step.operation}`
|
|
22
|
+
if (used.has(id)) throw new Error('Duplicate selected operation across route roles')
|
|
23
|
+
if (ownValue(ownValue(operationRoles, step.provider), step.operation) !== role) throw new Error(`Selected operation is not declared for ${role}`)
|
|
24
|
+
used.add(id)
|
|
25
|
+
callables.set(id, callable)
|
|
26
|
+
return Object.freeze({ provider: step.provider, operation: step.operation, role, options: structuredClone(step.options ?? {}) })
|
|
27
|
+
}
|
|
28
|
+
const list = (values, role) => {
|
|
29
|
+
if (!Array.isArray(values)) throw new TypeError(`Explicit selected ${role} operations required`)
|
|
30
|
+
return values.map(x => resolve(x, role))
|
|
31
|
+
}
|
|
32
|
+
const route = { profile, extractor: selected.extractor ? resolve(selected.extractor, 'extract') : null,
|
|
33
|
+
assessors: list(selected.assessors ?? [], 'assess'), projectors: list(selected.projectors ?? [], 'project'),
|
|
34
|
+
retrievers: list(selected.retrievers ?? [], 'retrieve'), answerer: selected.answerer ? resolve(selected.answerer, 'answer') : null,
|
|
35
|
+
nativeAnswer: selected.nativeAnswer ? resolve(selected.nativeAnswer, 'native-answer') : null,
|
|
36
|
+
view: selected.view ?? 'native-exploration' }
|
|
37
|
+
if (!['native-exploration', 'accepted-knowledge'].includes(route.view)) throw new Error('Explicit native exploration or existing accepted knowledge view required')
|
|
38
|
+
if (route.answerer && !route.retrievers.length) throw new Error('Grounded answer route needs selected evidence retrieval')
|
|
39
|
+
if (route.nativeAnswer && (route.answerer || route.retrievers.length)) throw new Error('Coupled native retrieval/answer is a separate route; do not duplicate retrieval or generation')
|
|
40
|
+
const compiled = Object.freeze({ ...route, routeDigest: digest(route) })
|
|
41
|
+
compiledCallables.set(compiled, callables)
|
|
42
|
+
return compiled
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function answerReference(ref) {
|
|
46
|
+
if (!ref || ['sourceId', 'revision', 'representationId'].some(k => typeof ownValue(ref, k) !== 'string' || !ownValue(ref, k) || ownValue(ref, k).length > 256)) return null
|
|
47
|
+
const locator = ownValue(ref, 'locator')
|
|
48
|
+
if (typeof locator === 'string' ? !locator || locator.length > 16384 :
|
|
49
|
+
!locator || Object.keys(locator).sort().join(',') !== 'kind,value' || ['kind','value'].some(k => typeof ownValue(locator, k) !== 'string' || !ownValue(locator, k) || ownValue(locator, k).length > 16384)) return null
|
|
50
|
+
return { sourceId: ownValue(ref, 'sourceId'), revision: ownValue(ref, 'revision'),
|
|
51
|
+
representationId: ownValue(ref, 'representationId'), locator: typeof locator === 'string' ? locator :
|
|
52
|
+
{ kind: ownValue(locator, 'kind'), value: ownValue(locator, 'value') } }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function composeEvidence(bundles, { eligible }) {
|
|
56
|
+
if (!Array.isArray(bundles) || typeof eligible !== 'function') throw new TypeError('Located bundles and actual current evidence owner required')
|
|
57
|
+
const combined = new Map(), unresolved = [], excluded = []
|
|
58
|
+
for (const bundle of bundles) {
|
|
59
|
+
if (!bundle?.provider || !Array.isArray(bundle.hits)) throw new TypeError('Each native bundle needs provider and hits')
|
|
60
|
+
// Explicit declined native citations survive receiving and prevent a coupled
|
|
61
|
+
// answer from appearing fully grounded merely because some hits mapped.
|
|
62
|
+
for (const field of ['unresolved', 'unresolvedReferences']) {
|
|
63
|
+
if (bundle[field] !== undefined && !Array.isArray(bundle[field])) throw new TypeError('Native receiving gaps must be explicit arrays')
|
|
64
|
+
for (const gap of bundle[field] ?? []) unresolved.push({ provider: bundle.provider, receivingGap: structuredClone(gap) })
|
|
65
|
+
}
|
|
66
|
+
for (const hit of bundle.hits) {
|
|
67
|
+
// Detach the exact inspected quote/reference before asynchronous receiving.
|
|
68
|
+
const nativeHit = structuredClone(hit), reference = answerReference(nativeHit?.evidenceRef), quote = nativeHit?.quote
|
|
69
|
+
if (!reference || typeof quote !== 'string' || !quote) { unresolved.push({ provider: bundle.provider, hit: nativeHit }); continue }
|
|
70
|
+
const identity = json([reference.sourceId, reference.revision, reference.representationId, reference.locator, quote])
|
|
71
|
+
const verdict = await eligible(structuredClone(reference), { quote, provider: bundle.provider, generation: bundle.generation })
|
|
72
|
+
if (verdict?.current !== true || verdict?.permitted !== true || verdict?.supported !== true) { excluded.push({ provider: bundle.provider, hit: nativeHit, reason: verdict?.reason ?? 'exact-quote-support-unreceived' }); continue }
|
|
73
|
+
if (!combined.has(identity)) combined.set(identity, { evidenceRef: reference, quote, observations: [] })
|
|
74
|
+
combined.get(identity).observations.push({ provider: bundle.provider, generation: bundle.generation ?? null,
|
|
75
|
+
nativeHit, score: nativeHit.score ?? null, scoreSemantics: nativeHit.scoreSemantics ?? 'unmapped-native-score' })
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { hits: [...combined.values()], unresolved, excluded,
|
|
79
|
+
providerArtifacts: bundles.map(x => ({ provider: x.provider, generation: x.generation ?? null, artifactRef: x.artifactRef ?? null })),
|
|
80
|
+
distinctSourceCount: new Set([...combined.values()].map(x => x.evidenceRef.sourceId)).size,
|
|
81
|
+
combinedScore: null, acceptance: 'existing-owner-view-only' }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Only eligible located evidence reaches ordinary answer generation. Raw hits,
|
|
85
|
+
// artifacts, view content and native rejection strings stay in receipt custody.
|
|
86
|
+
function answerEvidence(evidence) {
|
|
87
|
+
return { hits: evidence.hits.map(x => ({ evidenceRef: answerReference(x.evidenceRef), quote: x.quote })),
|
|
88
|
+
distinctSourceCount: evidence.distinctSourceCount,
|
|
89
|
+
rejectionCounts: { unlocated: evidence.unresolved.length, ineligible: evidence.excluded.length } }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class CompositionFailure extends Error {
|
|
93
|
+
constructor(cause, state) {
|
|
94
|
+
super(`Selected route needs owner reconciliation: ${cause.message}`, { cause })
|
|
95
|
+
this.name = 'CompositionFailure'
|
|
96
|
+
Object.assign(this, state)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Host bridges retain actual effect admission, view and evidence authority.
|
|
101
|
+
* No implicit retry or fallback occurs. Receipt custody survives late failures.
|
|
102
|
+
*/
|
|
103
|
+
export function createComposition({ bindings, operationRoles, invoke, readKnowledgeView, eligible }) {
|
|
104
|
+
if (!operationRoles || typeof invoke !== 'function' || typeof readKnowledgeView !== 'function' || typeof eligible !== 'function') throw new TypeError('Actual operation roles, effect, knowledge-view and evidence owners required')
|
|
105
|
+
return Object.freeze({ async execute({ route, input, question, signal }) {
|
|
106
|
+
const compiled = compileRoute({ profile: route.profile, selected: route, bindings, operationRoles })
|
|
107
|
+
const receipts = [], retainedResults = [], dispatched = []
|
|
108
|
+
let failedStep = null, effectUncertain = false
|
|
109
|
+
const call = async (step, payload) => {
|
|
110
|
+
failedStep = step
|
|
111
|
+
if (signal?.aborted) throw new Error('Host cancelled selected route')
|
|
112
|
+
// Each owner receives an isolated payload; prior results remain under
|
|
113
|
+
// separate custody even when a later callable mutates its own input.
|
|
114
|
+
const invocationPayload = structuredClone(payload)
|
|
115
|
+
dispatched.push(step); effectUncertain = true
|
|
116
|
+
const returned = await invoke({ step, callable: compiledCallables.get(compiled).get(`${step.provider}/${step.operation}`), payload: invocationPayload, routeDigest: compiled.routeDigest, signal })
|
|
117
|
+
let result
|
|
118
|
+
try { result = structuredClone(returned) }
|
|
119
|
+
catch (snapshotError) {
|
|
120
|
+
// Returned data/costs remain in custody even when a snapshot cannot be
|
|
121
|
+
// made. Do not continue grounding or pretend this live value is frozen.
|
|
122
|
+
retainedResults.push({ step, result: returned, snapshotState: 'failed', snapshotError })
|
|
123
|
+
throw snapshotError
|
|
124
|
+
}
|
|
125
|
+
// Retain a detached snapshot even when its receipt is malformed.
|
|
126
|
+
retainedResults.push({ step, result, snapshotState: 'received' })
|
|
127
|
+
if (!result || !result.receiptRef) throw new Error('Selected operation must return its actual receipt reference')
|
|
128
|
+
receipts.push(structuredClone({ ...step, receiptRef: result.receiptRef, usage: result.usage ?? null }))
|
|
129
|
+
effectUncertain = false; failedStep = null
|
|
130
|
+
return structuredClone(result)
|
|
131
|
+
}
|
|
132
|
+
const counts = () => ({ selectedExtractorCount: dispatched.filter(x => x.role === 'extract').length,
|
|
133
|
+
selectedAnswererCount: dispatched.filter(x => ['answer', 'native-answer'].includes(x.role)).length })
|
|
134
|
+
try {
|
|
135
|
+
const extraction = compiled.extractor ? await call(compiled.extractor, { input }) : null
|
|
136
|
+
const assessments = []
|
|
137
|
+
for (const step of compiled.assessors) assessments.push(await call(step, { input, extraction }))
|
|
138
|
+
const view = structuredClone(await readKnowledgeView(structuredClone({ requestedView: compiled.view, input, extraction, assessments, routeDigest: compiled.routeDigest })))
|
|
139
|
+
if (!view?.ownerRef || view.kind !== compiled.view) throw new Error('Existing knowledge owner must return the selected view')
|
|
140
|
+
const projections = []
|
|
141
|
+
for (const step of compiled.projectors) projections.push(await call(step, { input, view }))
|
|
142
|
+
if (compiled.nativeAnswer) {
|
|
143
|
+
// Existing host must admit authorized current input before a coupled
|
|
144
|
+
// native model call. Final evidence validation is a separate check.
|
|
145
|
+
const native = await call(compiled.nativeAnswer, { input, question, view, projections })
|
|
146
|
+
if (!Array.isArray(native.hits)) throw new Error('Coupled native answer must return located evidence references')
|
|
147
|
+
const evidence = await composeEvidence([{ ...native, provider: compiled.nativeAnswer.provider }], { eligible })
|
|
148
|
+
const current = evidence.excluded.length === 0 && evidence.unresolved.length === 0 && evidence.hits.length > 0
|
|
149
|
+
return { routeDigest: compiled.routeDigest, extraction, assessments, view, projections, evidence,
|
|
150
|
+
answer: current ? native : null, withheldNativeResult: current ? null : native,
|
|
151
|
+
answerStatus: current ? 'current-grounding-received' : 'withheld-grounding-unreceived', receipts,
|
|
152
|
+
...counts(), nativeAnswerGroundingCurrent: current,
|
|
153
|
+
canonicalMutation: false, semanticAcceptance: 'existing-owner-only', nativeQualification: false }
|
|
154
|
+
}
|
|
155
|
+
const bundles = []
|
|
156
|
+
for (const step of compiled.retrievers) {
|
|
157
|
+
const result = await call(step, { input, question, view, projections })
|
|
158
|
+
if (!Array.isArray(result.hits)) throw new Error('Retriever must return located evidence hits')
|
|
159
|
+
bundles.push({ ...result, provider: step.provider })
|
|
160
|
+
}
|
|
161
|
+
const evidence = await composeEvidence(bundles, { eligible })
|
|
162
|
+
const answer = compiled.answerer ? await call(compiled.answerer, { question, evidence: answerEvidence(evidence),
|
|
163
|
+
view: { kind: view.kind, ownerRef: view.ownerRef } }) : null
|
|
164
|
+
return { routeDigest: compiled.routeDigest, extraction, assessments, view, projections, evidence, answer, receipts,
|
|
165
|
+
...counts(), canonicalMutation: false, semanticAcceptance: 'existing-owner-only', nativeQualification: false }
|
|
166
|
+
} catch (cause) {
|
|
167
|
+
throw new CompositionFailure(cause, { routeDigest: compiled.routeDigest, receipts, retainedResults, failedStep,
|
|
168
|
+
effectUncertain, ...counts(), retryAuthorized: false })
|
|
169
|
+
}
|
|
170
|
+
} })
|
|
171
|
+
}
|