agentera 3.0.0-dev.7 → 3.0.0-dev.72
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/LICENSE +201 -0
- package/README.md +118 -22
- package/bundle/CHANGELOG.md +1361 -0
- package/bundle/DESIGN.md +229 -0
- package/bundle/LICENSE +201 -0
- package/bundle/README.md +143 -0
- package/bundle/UPGRADE.md +252 -0
- package/bundle/extract-corpus-parity.json +2 -4
- package/bundle/fixtures/routing/hybrid-corpus.yaml +154 -0
- package/bundle/references/adapters/package-publication.json +488 -0
- package/bundle/references/adapters/package-registry.yaml +435 -188
- package/bundle/references/adapters/package-surface-characterization.md +66 -34
- package/bundle/references/adapters/runtime-lifecycle-adapters.yaml +74 -0
- package/bundle/references/adapters/runtime-lifecycle-authority.yaml +62 -0
- package/bundle/references/adapters/runtime-lifecycle-operation-contract.yaml +84 -0
- package/bundle/references/adapters/runtime-retired-resources.yaml +333 -0
- package/bundle/references/analysis/evidence-tier-authority.yaml +518 -0
- package/bundle/references/analysis/verification-policy.yaml +266 -0
- package/bundle/references/artifacts/artifact-registry-interface-model.yaml +17 -8
- package/bundle/references/artifacts/glossary-entry-contract.yaml +1254 -0
- package/bundle/references/artifacts/state-storage-authority.yaml +3061 -0
- package/bundle/references/artifacts/verbosity-budget-authority.yaml +42 -0
- package/bundle/references/cli/app-lifecycle-vocabulary.yaml +3 -4
- package/bundle/references/cli/capability-instruction-contract.yaml +11 -14
- package/bundle/references/cli/hybrid-route-contract.yaml +438 -0
- package/bundle/references/cli/routing-model.md +152 -93
- package/bundle/references/cli/trigger-schema-enrichment.md +57 -46
- package/bundle/references/cli/update-channels.yaml +4 -2
- package/bundle/references/cli/vocabulary-index.yaml +5 -7
- package/bundle/references/cli/vocabulary.md +51 -93
- package/bundle/references/meta/retained-reference-authority.yaml +151 -0
- package/bundle/skills/agentera/SKILL.md +183 -63
- package/bundle/skills/agentera/capabilities/audit/schemas/artifacts.yaml +27 -19
- package/bundle/skills/agentera/capabilities/audit/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/audit/schemas/triggers.yaml +13 -35
- package/bundle/skills/agentera/capabilities/audit/schemas/validation.yaml +30 -11
- package/bundle/skills/agentera/capabilities/build/schemas/artifacts.yaml +44 -21
- package/bundle/skills/agentera/capabilities/build/schemas/exit.yaml +8 -6
- package/bundle/skills/agentera/capabilities/build/schemas/triggers.yaml +14 -36
- package/bundle/skills/agentera/capabilities/build/schemas/validation.yaml +95 -21
- package/bundle/skills/agentera/capabilities/design/schemas/artifacts.yaml +6 -6
- package/bundle/skills/agentera/capabilities/design/schemas/exit.yaml +5 -5
- package/bundle/skills/agentera/capabilities/design/schemas/triggers.yaml +5 -34
- package/bundle/skills/agentera/capabilities/design/schemas/validation.yaml +2 -2
- package/bundle/skills/agentera/capabilities/discuss/schemas/artifacts.yaml +17 -13
- package/bundle/skills/agentera/capabilities/discuss/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/discuss/schemas/triggers.yaml +6 -40
- package/bundle/skills/agentera/capabilities/discuss/schemas/validation.yaml +72 -5
- package/bundle/skills/agentera/capabilities/document/schemas/artifacts.yaml +24 -17
- package/bundle/skills/agentera/capabilities/document/schemas/triggers.yaml +5 -35
- package/bundle/skills/agentera/capabilities/document/schemas/validation.yaml +13 -13
- package/bundle/skills/agentera/capabilities/optimize/schemas/artifacts.yaml +10 -10
- package/bundle/skills/agentera/capabilities/optimize/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/optimize/schemas/triggers.yaml +4 -35
- package/bundle/skills/agentera/capabilities/optimize/schemas/validation.yaml +3 -3
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml +34 -22
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/exit.yaml +9 -7
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/triggers.yaml +5 -37
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/validation.yaml +38 -37
- package/bundle/skills/agentera/capabilities/plan/schemas/artifacts.yaml +20 -16
- package/bundle/skills/agentera/capabilities/plan/schemas/triggers.yaml +8 -31
- package/bundle/skills/agentera/capabilities/plan/schemas/validation.yaml +66 -6
- package/bundle/skills/agentera/capabilities/profile/schemas/artifacts.yaml +9 -4
- package/bundle/skills/agentera/capabilities/profile/schemas/exit.yaml +4 -4
- package/bundle/skills/agentera/capabilities/profile/schemas/triggers.yaml +8 -37
- package/bundle/skills/agentera/capabilities/profile/schemas/validation.yaml +61 -3
- package/bundle/skills/agentera/capabilities/research/schemas/artifacts.yaml +6 -6
- package/bundle/skills/agentera/capabilities/research/schemas/triggers.yaml +5 -29
- package/bundle/skills/agentera/capabilities/status/schemas/artifacts.yaml +13 -12
- package/bundle/skills/agentera/capabilities/status/schemas/triggers.yaml +7 -49
- package/bundle/skills/agentera/capabilities/vision/schemas/artifacts.yaml +8 -8
- package/bundle/skills/agentera/capabilities/vision/schemas/exit.yaml +7 -6
- package/bundle/skills/agentera/capabilities/vision/schemas/triggers.yaml +7 -39
- package/bundle/skills/agentera/capabilities/vision/schemas/validation.yaml +14 -16
- package/bundle/skills/agentera/capability_schema_contract.yaml +32 -32
- package/bundle/skills/agentera/protocol.yaml +4 -4
- package/bundle/skills/agentera/route-phrases.yaml +81 -0
- package/bundle/skills/agentera/schemas/artifacts/changelog.yaml +1 -0
- package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +30 -12
- package/bundle/skills/agentera/schemas/artifacts/design.yaml +1 -0
- package/bundle/skills/agentera/schemas/artifacts/docs.yaml +7 -12
- package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +140 -9
- package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +82 -0
- package/bundle/skills/agentera/schemas/artifacts/health.yaml +56 -19
- package/bundle/skills/agentera/schemas/artifacts/objective.yaml +18 -4
- package/bundle/skills/agentera/schemas/artifacts/plan.yaml +457 -32
- package/bundle/skills/agentera/schemas/artifacts/progress.yaml +131 -18
- package/bundle/skills/agentera/schemas/artifacts/todo.yaml +302 -7
- package/dist/analytics/extractCorpus/cli.js +52 -11
- package/dist/analytics/extractCorpus/copilotSessions.js +6 -4
- package/dist/analytics/extractCorpus/core.js +40 -12
- package/dist/analytics/extractCorpus/corpus.js +39 -17
- package/dist/analytics/extractCorpus/coverageAudit.js +44 -45
- package/dist/analytics/extractCorpus/cursorSessions.js +6 -4
- package/dist/analytics/extractCorpus/evidenceTiers.js +603 -0
- package/dist/analytics/extractCorpus/extractCorpusParity.js +4 -4
- package/dist/analytics/extractCorpus/filesystemSources.js +1 -5
- package/dist/analytics/extractCorpus/index.js +3 -1
- package/dist/analytics/extractCorpus/jsonlSessions.js +24 -5
- package/dist/analytics/extractCorpus/sqliteCaps.js +0 -1
- package/dist/analytics/extractCorpus/sqliteSessions.js +0 -1
- package/dist/analytics/extractCorpus/tierReader.js +108 -0
- package/dist/analytics/extractCorpus.js +0 -1
- package/dist/analytics/glossaryAdviceResolution.js +166 -0
- package/dist/analytics/glossaryInputAcquisition.js +319 -0
- package/dist/analytics/personalGlossaryAdmission.js +133 -0
- package/dist/analytics/personalGlossaryProfile.js +219 -0
- package/dist/analytics/profileSignals.js +211 -0
- package/dist/analytics/usageStats.js +150 -23
- package/dist/audit/terminologyDrift.js +281 -0
- package/dist/bin/agentera.js +3 -2
- package/dist/capabilities/audit/instructions.js +16 -6
- package/dist/capabilities/build/instructions.js +59 -6
- package/dist/capabilities/design/instructions.js +3 -4
- package/dist/capabilities/discuss/instructions.js +29 -6
- package/dist/capabilities/document/instructions.js +11 -6
- package/dist/capabilities/index.js +16 -14
- package/dist/capabilities/optimize/instructions.js +14 -6
- package/dist/capabilities/orchestrate/instructions.js +42 -6
- package/dist/capabilities/plan/instructions.js +30 -3
- package/dist/capabilities/profile/instructions.js +70 -6
- package/dist/capabilities/research/instructions.js +4 -5
- package/dist/capabilities/status/instructions.js +15 -6
- package/dist/capabilities/status/startupInstructions.js +34 -0
- package/dist/capabilities/vision/instructions.js +3 -5
- package/dist/cli/appContext.js +14 -7
- package/dist/cli/argvalidate.js +0 -1
- package/dist/cli/capabilityContext/benchmark.js +5 -4
- package/dist/cli/capabilityContext/bespoke.js +14 -6
- package/dist/cli/capabilityContext/build.js +116 -42
- package/dist/cli/capabilityContext/closeout.js +30 -27
- package/dist/cli/capabilityContext/contract.js +18 -27
- package/dist/cli/capabilityContext/evidence.js +84 -77
- package/dist/cli/capabilityContext/index.js +0 -1
- package/dist/cli/capabilityContext/orchestration.js +42 -18
- package/dist/cli/capabilityContext/planState.js +89 -96
- package/dist/cli/capabilityContext/progress.js +51 -12
- package/dist/cli/capabilityContext/projectVerification.js +409 -0
- package/dist/cli/capabilityContext/shared.js +9 -20
- package/dist/cli/capabilityContext/slim.js +52 -8
- package/dist/cli/capabilityContext/startup.js +51 -114
- package/dist/cli/capabilityContext/startupAggregation.js +68 -0
- package/dist/cli/capabilityContext/types.js +26 -10
- package/dist/cli/capabilityContext.js +0 -1
- package/dist/cli/commands/appHome.js +0 -1
- package/dist/cli/commands/capability.js +2 -2
- package/dist/cli/commands/compact.js +163 -13
- package/dist/cli/commands/doctor.js +117 -11
- package/dist/cli/commands/durability.js +81 -0
- package/dist/cli/commands/glossaryAdvice.js +138 -0
- package/dist/cli/commands/lint.js +22 -8
- package/dist/cli/commands/personalGlossary.js +176 -0
- package/dist/cli/commands/prime/briefOrientation.js +746 -0
- package/dist/cli/commands/prime/buildExecutionRequest.js +165 -0
- package/dist/cli/commands/prime/bundleStatus.js +54 -4
- package/dist/cli/commands/prime/collectEntityOrientation.js +326 -0
- package/dist/cli/commands/prime/collectOrientationState.js +126 -63
- package/dist/cli/commands/prime/orientationOutput.js +267 -56
- package/dist/cli/commands/prime/types.js +0 -1
- package/dist/cli/commands/prime/v1Migration.js +0 -1
- package/dist/cli/commands/prime.js +76 -11
- package/dist/cli/commands/profileGrounding.js +55 -0
- package/dist/cli/commands/query.js +74 -52
- package/dist/cli/commands/report.js +73 -19
- package/dist/cli/commands/route.js +142 -0
- package/dist/cli/commands/schema.js +257 -138
- package/dist/cli/commands/state/decisions.js +40 -56
- package/dist/cli/commands/state/docs.js +58 -85
- package/dist/cli/commands/state/experimentRecords.js +151 -0
- package/dist/cli/commands/state/experiments.js +11 -65
- package/dist/cli/commands/state/get.js +129 -0
- package/dist/cli/commands/state/health.js +11 -113
- package/dist/cli/commands/state/index.js +6 -41
- package/dist/cli/commands/state/list.js +194 -0
- package/dist/cli/commands/state/objective.js +21 -65
- package/dist/cli/commands/state/plan.js +11 -170
- package/dist/cli/commands/state/planTasks.js +154 -0
- package/dist/cli/commands/state/plans.js +154 -0
- package/dist/cli/commands/state/progress.js +11 -45
- package/dist/cli/commands/state/shared.js +0 -1
- package/dist/cli/commands/state/todo.js +28 -107
- package/dist/cli/commands/state/write.js +433 -0
- package/dist/cli/commands/upgrade.js +146 -5
- package/dist/cli/commands/upgradeVerify.js +118 -0
- package/dist/cli/commands/validate.js +235 -136
- package/dist/cli/commands/verify.js +23 -8
- package/dist/cli/contracts/bundleStatus.js +0 -1
- package/dist/cli/contracts/orientationState.js +0 -1
- package/dist/cli/dispatch/argvParser.js +0 -1
- package/dist/cli/dispatch/check.js +84 -40
- package/dist/cli/dispatch/commands.js +3 -3
- package/dist/cli/dispatch/index.js +77 -52
- package/dist/cli/dispatch/lifecycle.js +117 -62
- package/dist/cli/dispatch/prime.js +37 -2
- package/dist/cli/dispatch/projections.js +17 -0
- package/dist/cli/dispatch/shared.js +1 -2
- package/dist/cli/dispatch/state.js +62 -66
- package/dist/cli/dispatch.js +0 -1
- package/dist/cli/errors.js +16 -17
- package/dist/cli/help.js +358 -39
- package/dist/cli/migrationRequired.js +122 -0
- package/dist/cli/orientation/attention.js +19 -19
- package/dist/cli/orientation/corpusCoverage.js +32 -1
- package/dist/cli/orientation.js +346 -129
- package/dist/cli/planArtifacts.js +350 -0
- package/dist/cli/planEvidence.js +157 -0
- package/dist/cli/planLifecycleState.js +36 -0
- package/dist/cli/planTaskIndex.js +11 -0
- package/dist/cli/preCutoverCommand.js +32 -0
- package/dist/cli/prime-blob.js +71 -3
- package/dist/cli/profileAcquisition.js +167 -0
- package/dist/cli/startupCompletenessContract.js +11 -8
- package/dist/cli/stateQuery.js +47 -12
- package/dist/cli/structured.js +0 -1
- package/dist/cli/todoMarkdown.js +25 -12
- package/dist/cli/todoReadinessSelection.js +192 -0
- package/dist/cli/todoSeverity.js +0 -1
- package/dist/core/atomicWriter.js +20 -0
- package/dist/core/developmentChannel.js +1 -0
- package/dist/core/developmentInvocation.js +374 -0
- package/dist/core/difflib.js +0 -1
- package/dist/core/envPaths.js +0 -1
- package/dist/core/jsonValue.js +0 -1
- package/dist/core/paths.js +0 -1
- package/dist/core/pyjson.js +0 -1
- package/dist/core/shell.js +4 -0
- package/dist/core/skillIdentity.js +23 -0
- package/dist/core/sourceRoot.js +9 -12
- package/dist/core/text.js +10 -0
- package/dist/core/toml.js +0 -1
- package/dist/core/yaml.js +8 -1
- package/dist/eval/evalSkills.js +13 -14
- package/dist/eval/hybridRouteEvaluation.js +155 -0
- package/dist/eval/semanticEval.js +0 -1
- package/dist/eval/semanticFixtures.js +0 -1
- package/dist/hooks/common.js +3 -56
- package/dist/hooks/compaction/apply.js +224 -47
- package/dist/hooks/compaction/dryRun.js +2 -1
- package/dist/hooks/compaction/index.js +5 -6
- package/dist/hooks/compaction/parse.js +73 -6
- package/dist/hooks/compaction/retention.js +28 -25
- package/dist/hooks/compaction/status.js +145 -26
- package/dist/hooks/compaction/types.js +0 -1
- package/dist/hooks/validateArtifact/agentFacing.js +0 -1
- package/dist/hooks/validateArtifact/index.js +6 -65
- package/dist/hooks/validateArtifact/markdown.js +9 -10
- package/dist/hooks/validateArtifact/schema.js +96 -9
- package/dist/hooks/validateArtifact/traversal.js +12 -11
- package/dist/hooks/validateArtifact/violations.js +5 -3
- package/dist/migrate/v2HandoffManifest.js +8 -3
- package/dist/registries/activationContract.js +2 -0
- package/dist/registries/activationTuples.js +108 -0
- package/dist/registries/artifactProtocolIds.js +2 -1
- package/dist/registries/artifactRegistry.js +207 -60
- package/dist/registries/artifactSchemaProjection.js +45 -0
- package/dist/registries/capabilityContract.js +5 -21
- package/dist/registries/evaluatorHandoffContract.js +0 -1
- package/dist/registries/evidenceTierContract.js +371 -0
- package/dist/registries/glossaryAdviceContract.js +79 -0
- package/dist/registries/glossaryCaveatContract.js +67 -0
- package/dist/registries/glossaryConsumerContractValidation.js +787 -0
- package/dist/registries/glossaryEntryContract.js +757 -0
- package/dist/registries/glossaryTermIdentity.js +17 -0
- package/dist/registries/glossaryTermOccurrence.js +20 -0
- package/dist/registries/hybridRoute.js +274 -0
- package/dist/registries/hybridRouteReceipt.js +221 -0
- package/dist/registries/packagePublication.js +273 -0
- package/dist/registries/packageRegistry.js +184 -209
- package/dist/registries/todoReadinessContract.js +448 -0
- package/dist/registries/triggerLoader.js +7 -44
- package/dist/registries/verbosityBudgetContract.js +205 -0
- package/dist/release/releaseMetadata.js +155 -5
- package/dist/runtime/lifecycleAdapterContract.js +457 -0
- package/dist/runtime/lifecycleAdapters.js +777 -0
- package/dist/runtime/lifecycleAuthority.js +453 -0
- package/dist/runtime/lifecycleOperationContract.js +123 -0
- package/dist/runtime/lifecycleOperations.js +634 -0
- package/dist/runtime/lifecycleOwnershipJournal.js +622 -0
- package/dist/runtime/lifecyclePublication.js +415 -0
- package/dist/runtime/lifecycleSnapshot.js +438 -0
- package/dist/runtime/nativeResourceCleanup.js +502 -0
- package/dist/setup/opencode.js +20 -13
- package/dist/setup/opencodeConstants.js +1 -0
- package/dist/setup/sharedSkill.js +45 -0
- package/dist/setup/smokeChecks.js +14 -75
- package/dist/state/archiveDiscovery.js +580 -0
- package/dist/state/archivePublication.js +225 -0
- package/dist/state/archiveRecovery.js +237 -0
- package/dist/state/archiveReplay.js +53 -0
- package/dist/state/canonicalMigrationRecord.js +36 -0
- package/dist/state/changelog.js +221 -0
- package/dist/state/decisionEntities.js +367 -0
- package/dist/state/decisionLegacyValidation.js +215 -0
- package/dist/state/decisionMigrationProvenance.js +199 -0
- package/dist/state/decisionOverlay.js +254 -0
- package/dist/state/decisionRevision.js +256 -0
- package/dist/state/decisionRevisionMigration.js +89 -0
- package/dist/state/directRetrieval.js +323 -0
- package/dist/state/durability.js +324 -0
- package/dist/state/entityCutover.js +459 -0
- package/dist/state/entityCutoverGit.js +127 -0
- package/dist/state/entityGlossaryAuthority.js +13 -0
- package/dist/state/entityListProjection.js +187 -0
- package/dist/state/entityListRuntimeRegistry.js +85 -0
- package/dist/state/entityMigrationCausality.js +97 -0
- package/dist/state/entityMigrationIdentity.js +5 -0
- package/dist/state/entityMigrationPreview.js +840 -0
- package/dist/state/entityMigrationTodo.js +133 -0
- package/dist/state/entityPublicationContext.js +859 -0
- package/dist/state/entityRetrievalHelp.js +506 -0
- package/dist/state/entityStorage.js +899 -0
- package/dist/state/exactReplacementRecovery.js +18 -0
- package/dist/state/experimentArchive.js +63 -0
- package/dist/state/experimentIdentity.js +202 -0
- package/dist/state/healthEntities.js +262 -0
- package/dist/state/healthEntityValidation.js +18 -0
- package/dist/state/healthRepair.js +69 -0
- package/dist/state/installRoot.js +15 -7
- package/dist/state/legacyEntityCutoverEvidence.js +65 -0
- package/dist/state/legacyIdentity.js +47 -0
- package/dist/state/legacySummaryRecord.js +6 -0
- package/dist/state/listAccounting.js +54 -0
- package/dist/state/listClassification.js +17 -0
- package/dist/state/listCursor.js +42 -0
- package/dist/state/listRetrieval.js +781 -0
- package/dist/state/migrationSourceBinding.js +30 -0
- package/dist/state/objectiveExperimentEntities.js +322 -0
- package/dist/state/planEntities.js +1027 -0
- package/dist/state/planIdentity.js +47 -0
- package/dist/state/planLineageValidation.js +52 -0
- package/dist/state/planReplacementTransaction.js +475 -0
- package/dist/state/planRetrieval.js +313 -0
- package/dist/state/planTaskRetrieval.js +294 -0
- package/dist/state/progressEntities.js +512 -0
- package/dist/state/progressGlossaryCaveat.js +168 -0
- package/dist/state/progressPublicationOrder.js +19 -0
- package/dist/state/progressWritePolicy.js +33 -0
- package/dist/state/projectRoot.js +62 -0
- package/dist/state/projectionPolicy.js +190 -0
- package/dist/state/retrievalAuthority.js +156 -0
- package/dist/state/safeProjectFile.js +155 -0
- package/dist/state/startupAnalysis/benchmark.js +70 -9
- package/dist/state/startupAnalysis/contract.js +44 -10
- package/dist/state/startupAnalysis/helpers.js +1 -2
- package/dist/state/startupAnalysis/index.js +0 -1
- package/dist/state/startupAnalysis/metrics.js +0 -1
- package/dist/state/startupAnalysis/records.js +0 -1
- package/dist/state/startupAnalysis/report.js +0 -1
- package/dist/state/startupAnalysis/threshold.js +13 -1
- package/dist/state/startupAnalysis.js +0 -1
- package/dist/state/startupProjection.js +499 -0
- package/dist/state/stateMode.js +222 -0
- package/dist/state/stateStorageAuthority.js +47 -0
- package/dist/state/summaryEntityRead.js +25 -0
- package/dist/state/summaryMigrationProvenance.js +66 -0
- package/dist/state/summarySourceRowAuthority.js +36 -0
- package/dist/state/todoActivationSafety.js +58 -0
- package/dist/state/todoDocsEntities.js +1124 -0
- package/dist/state/todoDocsEntityValidation.js +158 -0
- package/dist/state/todoMarkdownProjection.js +51 -0
- package/dist/state/todoReconciliationActivation.js +182 -0
- package/dist/state/todoReconciliationInspection.js +171 -0
- package/dist/state/todoReconciliationRepair.js +318 -0
- package/dist/state/todoReconciliationTransaction.js +595 -0
- package/dist/state/write/assign.js +20 -0
- package/dist/state/write/candidateMutation.js +269 -0
- package/dist/state/write/errors.js +11 -0
- package/dist/state/write/experimentPublication.js +192 -0
- package/dist/state/write/explain.js +377 -0
- package/dist/state/write/fields.js +61 -0
- package/dist/state/write/glossaryPublication.js +263 -0
- package/dist/state/write/grammar.js +285 -0
- package/dist/state/write/helpers.js +29 -0
- package/dist/state/write/index.js +12 -0
- package/dist/state/write/input.js +391 -0
- package/dist/state/write/lock.js +837 -0
- package/dist/state/write/mutation.js +234 -0
- package/dist/state/write/operations.js +170 -0
- package/dist/state/write/planEvaluation.js +128 -0
- package/dist/state/write/planPublication.js +179 -0
- package/dist/state/write/runtimeOperations.js +146 -0
- package/dist/state/write/serialize.js +1 -0
- package/dist/state/write/transaction.js +57 -0
- package/dist/state/write/validate.js +7 -0
- package/dist/upgrade/appContentRefresh.js +77 -36
- package/dist/upgrade/appModel.js +0 -1
- package/dist/upgrade/atomicWriter.js +1 -0
- package/dist/upgrade/bundleEvidence.js +0 -1
- package/dist/upgrade/channels.js +6 -9
- package/dist/upgrade/compatibility.js +43 -17
- package/dist/upgrade/doctor.js +55 -32
- package/dist/upgrade/doctorClassifier.js +11 -1
- package/dist/upgrade/installedHooksRetirement.js +46 -40
- package/dist/upgrade/legacyAgentCleanup.js +187 -21
- package/dist/upgrade/lifecycleUpgrade.js +113 -0
- package/dist/upgrade/migrateArtifactsV2ToV3.js +334 -64
- package/dist/upgrade/migrationPublication.js +122 -0
- package/dist/upgrade/nextMajorDoctor.js +0 -1
- package/dist/upgrade/npxPlatformStatus.js +0 -1
- package/dist/upgrade/projectIntegration.js +121 -159
- package/dist/upgrade/projectIntegrationDecision.js +42 -85
- package/dist/upgrade/retiredResourceDiagnostics.js +117 -0
- package/dist/upgrade/runtimeMigration.js +262 -453
- package/dist/upgrade/upgradeCommands.js +14 -1
- package/dist/upgrade/upgradeLock.js +85 -0
- package/dist/upgrade/upgradeOrchestrator.js +263 -59
- package/dist/upgrade/v3CapabilitySurface.js +2 -3
- package/dist/upgrade/versionResolution.js +0 -1
- package/dist/validate/activationArtifactEvidence.js +852 -0
- package/dist/validate/activationArtifactEvidenceTypes.js +12 -0
- package/dist/validate/activationConjunction.js +816 -0
- package/dist/validate/activationEvidenceManifest.js +531 -0
- package/dist/validate/activationPackageSemantics.js +29 -0
- package/dist/validate/appHomeContract.js +1 -7
- package/dist/validate/bootstrapAuthority.js +44 -0
- package/dist/validate/capability.js +11 -3
- package/dist/validate/crossCapability.js +14 -9
- package/dist/validate/retainedReferenceAuthority.js +879 -0
- package/dist/validate/selfAudit.js +39 -45
- package/dist/validate/v1LegacyCruft.js +131 -0
- package/dist/validate/vocabularyAuthority.js +8 -8
- package/package.json +41 -13
- package/bundle/references/adapters/cursor.md +0 -214
- package/bundle/references/adapters/opencode.md +0 -530
- package/bundle/references/adapters/package-manifest-interface-model.yaml +0 -337
- package/bundle/references/adapters/runtime-adapter-characterization.md +0 -79
- package/bundle/references/adapters/runtime-adapter-interface-model.yaml +0 -200
- package/bundle/references/adapters/runtime-adapter-registry.yaml +0 -554
- package/bundle/references/adapters/runtime-feature-parity.md +0 -189
- package/bundle/references/analysis/benchmark.md +0 -267
- package/bundle/references/analysis/startup-measurement-contract.yaml +0 -424
- package/bundle/references/cli/agent-ready-state-contract.yaml +0 -953
- package/bundle/references/cli/audience-namespace-cli-migration.yaml +0 -369
- package/bundle/references/cli/bundle-skill-vocabulary.yaml +0 -250
- package/bundle/references/cli/capability-tool-classification.yaml +0 -53
- package/bundle/references/cli/coexistence-probe.yaml +0 -13
- package/bundle/references/cli/parity-expected-actual-template.md +0 -30
- package/bundle/references/cli/routing-execution-vocabulary.yaml +0 -281
- package/bundle/references/cli/single-name-protocol.yaml +0 -42
- package/bundle/references/cli/upgrade-repair-wording.md +0 -45
- package/bundle/references/cli/v3-handoff-manifest.schema.yaml +0 -98
- package/bundle/references/meta/documentation-inventory.md +0 -49
- package/bundle/skills/agentera/.claude-plugin/plugin.json +0 -27
- package/bundle/skills/agentera/agents/audit.toml +0 -6
- package/bundle/skills/agentera/agents/build.toml +0 -6
- package/bundle/skills/agentera/agents/design.toml +0 -6
- package/bundle/skills/agentera/agents/discuss.toml +0 -6
- package/bundle/skills/agentera/agents/document.toml +0 -6
- package/bundle/skills/agentera/agents/optimize.toml +0 -6
- package/bundle/skills/agentera/agents/orchestrate.toml +0 -6
- package/bundle/skills/agentera/agents/plan.toml +0 -6
- package/bundle/skills/agentera/agents/profile.toml +0 -6
- package/bundle/skills/agentera/agents/research.toml +0 -6
- package/bundle/skills/agentera/agents/status.toml +0 -6
- package/bundle/skills/agentera/agents/vision.toml +0 -6
- package/bundle/skills/agentera/references/contract.md +0 -1048
- package/dist/analytics/extractCorpus/cli.js.map +0 -1
- package/dist/analytics/extractCorpus/copilotSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/core.js.map +0 -1
- package/dist/analytics/extractCorpus/corpus.js.map +0 -1
- package/dist/analytics/extractCorpus/coverageAudit.js.map +0 -1
- package/dist/analytics/extractCorpus/cursorSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/extractCorpusParity.js.map +0 -1
- package/dist/analytics/extractCorpus/filesystemSources.js.map +0 -1
- package/dist/analytics/extractCorpus/index.js.map +0 -1
- package/dist/analytics/extractCorpus/jsonlSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/sqliteCaps.js.map +0 -1
- package/dist/analytics/extractCorpus/sqliteSessions.js.map +0 -1
- package/dist/analytics/extractCorpus.js.map +0 -1
- package/dist/analytics/usageStats.js.map +0 -1
- package/dist/bin/agentera.js.map +0 -1
- package/dist/capabilities/audit/instructions.js.map +0 -1
- package/dist/capabilities/build/instructions.js.map +0 -1
- package/dist/capabilities/design/instructions.js.map +0 -1
- package/dist/capabilities/discuss/instructions.js.map +0 -1
- package/dist/capabilities/document/instructions.js.map +0 -1
- package/dist/capabilities/dokumentera/instructions.js +0 -6
- package/dist/capabilities/dokumentera/instructions.js.map +0 -1
- package/dist/capabilities/hej/instructions.js +0 -6
- package/dist/capabilities/hej/instructions.js.map +0 -1
- package/dist/capabilities/index.js.map +0 -1
- package/dist/capabilities/inspektera/instructions.js +0 -6
- package/dist/capabilities/inspektera/instructions.js.map +0 -1
- package/dist/capabilities/inspirera/instructions.js +0 -6
- package/dist/capabilities/inspirera/instructions.js.map +0 -1
- package/dist/capabilities/optimera/instructions.js +0 -6
- package/dist/capabilities/optimera/instructions.js.map +0 -1
- package/dist/capabilities/optimize/instructions.js.map +0 -1
- package/dist/capabilities/orchestrate/instructions.js.map +0 -1
- package/dist/capabilities/orkestrera/instructions.js +0 -6
- package/dist/capabilities/orkestrera/instructions.js.map +0 -1
- package/dist/capabilities/plan/instructions.js.map +0 -1
- package/dist/capabilities/planera/instructions.js +0 -6
- package/dist/capabilities/planera/instructions.js.map +0 -1
- package/dist/capabilities/profile/instructions.js.map +0 -1
- package/dist/capabilities/profilera/instructions.js +0 -6
- package/dist/capabilities/profilera/instructions.js.map +0 -1
- package/dist/capabilities/realisera/instructions.js +0 -6
- package/dist/capabilities/realisera/instructions.js.map +0 -1
- package/dist/capabilities/research/instructions.js.map +0 -1
- package/dist/capabilities/resonera/instructions.js +0 -6
- package/dist/capabilities/resonera/instructions.js.map +0 -1
- package/dist/capabilities/status/instructions.js.map +0 -1
- package/dist/capabilities/vision/instructions.js.map +0 -1
- package/dist/capabilities/visionera/instructions.js +0 -6
- package/dist/capabilities/visionera/instructions.js.map +0 -1
- package/dist/capabilities/visualisera/instructions.js +0 -5
- package/dist/capabilities/visualisera/instructions.js.map +0 -1
- package/dist/cli/appContext.js.map +0 -1
- package/dist/cli/argvalidate.js.map +0 -1
- package/dist/cli/capabilityContext/benchmark.js.map +0 -1
- package/dist/cli/capabilityContext/bespoke.js.map +0 -1
- package/dist/cli/capabilityContext/build.js.map +0 -1
- package/dist/cli/capabilityContext/closeout.js.map +0 -1
- package/dist/cli/capabilityContext/contract.js.map +0 -1
- package/dist/cli/capabilityContext/evidence.js.map +0 -1
- package/dist/cli/capabilityContext/index.js.map +0 -1
- package/dist/cli/capabilityContext/orchestration.js.map +0 -1
- package/dist/cli/capabilityContext/planState.js.map +0 -1
- package/dist/cli/capabilityContext/progress.js.map +0 -1
- package/dist/cli/capabilityContext/realisera.js +0 -174
- package/dist/cli/capabilityContext/realisera.js.map +0 -1
- package/dist/cli/capabilityContext/shared.js.map +0 -1
- package/dist/cli/capabilityContext/slim.js.map +0 -1
- package/dist/cli/capabilityContext/startup.js.map +0 -1
- package/dist/cli/capabilityContext/types.js.map +0 -1
- package/dist/cli/capabilityContext.js.map +0 -1
- package/dist/cli/commands/appHome.js.map +0 -1
- package/dist/cli/commands/backfill.js +0 -84
- package/dist/cli/commands/backfill.js.map +0 -1
- package/dist/cli/commands/capability.js.map +0 -1
- package/dist/cli/commands/compact.js.map +0 -1
- package/dist/cli/commands/doctor.js.map +0 -1
- package/dist/cli/commands/lint.js.map +0 -1
- package/dist/cli/commands/prime/bundleStatus.js.map +0 -1
- package/dist/cli/commands/prime/collectOrientationState.js.map +0 -1
- package/dist/cli/commands/prime/orientationOutput.js.map +0 -1
- package/dist/cli/commands/prime/routeOutput.js +0 -50
- package/dist/cli/commands/prime/routeOutput.js.map +0 -1
- package/dist/cli/commands/prime/types.js.map +0 -1
- package/dist/cli/commands/prime/v1Migration.js.map +0 -1
- package/dist/cli/commands/prime.js.map +0 -1
- package/dist/cli/commands/query.js.map +0 -1
- package/dist/cli/commands/report.js.map +0 -1
- package/dist/cli/commands/schema.js.map +0 -1
- package/dist/cli/commands/state/decisions.js.map +0 -1
- package/dist/cli/commands/state/docs.js.map +0 -1
- package/dist/cli/commands/state/experiments.js.map +0 -1
- package/dist/cli/commands/state/health.js.map +0 -1
- package/dist/cli/commands/state/index.js.map +0 -1
- package/dist/cli/commands/state/objective.js.map +0 -1
- package/dist/cli/commands/state/plan.js.map +0 -1
- package/dist/cli/commands/state/progress.js.map +0 -1
- package/dist/cli/commands/state/shared.js.map +0 -1
- package/dist/cli/commands/state/todo.js.map +0 -1
- package/dist/cli/commands/state.js +0 -1023
- package/dist/cli/commands/state.js.map +0 -1
- package/dist/cli/commands/upgrade.js.map +0 -1
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/commands/verify.js.map +0 -1
- package/dist/cli/contracts/bundleStatus.js.map +0 -1
- package/dist/cli/contracts/orientationState.js.map +0 -1
- package/dist/cli/dispatch/argvParser.js.map +0 -1
- package/dist/cli/dispatch/check.js.map +0 -1
- package/dist/cli/dispatch/commands.js.map +0 -1
- package/dist/cli/dispatch/index.js.map +0 -1
- package/dist/cli/dispatch/lifecycle.js.map +0 -1
- package/dist/cli/dispatch/prime.js.map +0 -1
- package/dist/cli/dispatch/shared.js.map +0 -1
- package/dist/cli/dispatch/state.js.map +0 -1
- package/dist/cli/dispatch.js.map +0 -1
- package/dist/cli/errors.js.map +0 -1
- package/dist/cli/help.js.map +0 -1
- package/dist/cli/orientation/attention.js.map +0 -1
- package/dist/cli/orientation/corpusCoverage.js.map +0 -1
- package/dist/cli/orientation.js.map +0 -1
- package/dist/cli/prime-blob.js.map +0 -1
- package/dist/cli/startupCompletenessContract.js.map +0 -1
- package/dist/cli/stateQuery.js.map +0 -1
- package/dist/cli/structured.js.map +0 -1
- package/dist/cli/todoMarkdown.js.map +0 -1
- package/dist/cli/todoSeverity.js.map +0 -1
- package/dist/core/difflib.js.map +0 -1
- package/dist/core/envPaths.js.map +0 -1
- package/dist/core/git.js +0 -43
- package/dist/core/git.js.map +0 -1
- package/dist/core/jsonValue.js.map +0 -1
- package/dist/core/paths.js.map +0 -1
- package/dist/core/pyjson.js.map +0 -1
- package/dist/core/sourceRoot.js.map +0 -1
- package/dist/core/toml.js.map +0 -1
- package/dist/core/yaml.js.map +0 -1
- package/dist/eval/evalSkills.js.map +0 -1
- package/dist/eval/semanticEval.js.map +0 -1
- package/dist/eval/semanticFixtures.js.map +0 -1
- package/dist/hooks/common.js.map +0 -1
- package/dist/hooks/compaction/apply.js.map +0 -1
- package/dist/hooks/compaction/dryRun.js.map +0 -1
- package/dist/hooks/compaction/index.js.map +0 -1
- package/dist/hooks/compaction/parse.js.map +0 -1
- package/dist/hooks/compaction/retention.js.map +0 -1
- package/dist/hooks/compaction/status.js.map +0 -1
- package/dist/hooks/compaction/todoResolved.js +0 -137
- package/dist/hooks/compaction/todoResolved.js.map +0 -1
- package/dist/hooks/compaction/types.js.map +0 -1
- package/dist/hooks/compaction.js +0 -935
- package/dist/hooks/compaction.js.map +0 -1
- package/dist/hooks/cursorPreToolUse.js +0 -19
- package/dist/hooks/cursorPreToolUse.js.map +0 -1
- package/dist/hooks/cursorSessionStart.js +0 -79
- package/dist/hooks/cursorSessionStart.js.map +0 -1
- package/dist/hooks/sessionStart.js +0 -216
- package/dist/hooks/sessionStart.js.map +0 -1
- package/dist/hooks/sessionStop.js +0 -206
- package/dist/hooks/sessionStop.js.map +0 -1
- package/dist/hooks/todoLayout.js +0 -177
- package/dist/hooks/todoLayout.js.map +0 -1
- package/dist/hooks/validateArtifact/agentFacing.js.map +0 -1
- package/dist/hooks/validateArtifact/index.js.map +0 -1
- package/dist/hooks/validateArtifact/markdown.js.map +0 -1
- package/dist/hooks/validateArtifact/runtime.js +0 -86
- package/dist/hooks/validateArtifact/runtime.js.map +0 -1
- package/dist/hooks/validateArtifact/schema.js.map +0 -1
- package/dist/hooks/validateArtifact/traversal.js.map +0 -1
- package/dist/hooks/validateArtifact/violations.js.map +0 -1
- package/dist/hooks/validateArtifact.js +0 -924
- package/dist/hooks/validateArtifact.js.map +0 -1
- package/dist/migrate/v2HandoffManifest.js.map +0 -1
- package/dist/registries/artifactProtocolIds.js.map +0 -1
- package/dist/registries/artifactRegistry.js.map +0 -1
- package/dist/registries/capabilityContract.js.map +0 -1
- package/dist/registries/evaluatorHandoffContract.js.map +0 -1
- package/dist/registries/packageRegistry.js.map +0 -1
- package/dist/registries/runtimeAdapterRegistry.js +0 -316
- package/dist/registries/runtimeAdapterRegistry.js.map +0 -1
- package/dist/registries/triggerLoader.js.map +0 -1
- package/dist/release/releaseMetadata.js.map +0 -1
- package/dist/routing/index.js +0 -2
- package/dist/routing/index.js.map +0 -1
- package/dist/routing/routeEngine.js +0 -189
- package/dist/routing/routeEngine.js.map +0 -1
- package/dist/setup/codex/agents.js +0 -96
- package/dist/setup/codex/agents.js.map +0 -1
- package/dist/setup/codex/cli.js +0 -161
- package/dist/setup/codex/cli.js.map +0 -1
- package/dist/setup/codex/configToml.js +0 -639
- package/dist/setup/codex/configToml.js.map +0 -1
- package/dist/setup/codex/constants.js +0 -29
- package/dist/setup/codex/constants.js.map +0 -1
- package/dist/setup/codex/installRoot.js +0 -64
- package/dist/setup/codex/installRoot.js.map +0 -1
- package/dist/setup/codex/state.js +0 -270
- package/dist/setup/codex/state.js.map +0 -1
- package/dist/setup/codex.js +0 -12
- package/dist/setup/codex.js.map +0 -1
- package/dist/setup/copilot.js +0 -227
- package/dist/setup/copilot.js.map +0 -1
- package/dist/setup/cursor.js +0 -129
- package/dist/setup/cursor.js.map +0 -1
- package/dist/setup/cursorSurfaces.js +0 -67
- package/dist/setup/cursorSurfaces.js.map +0 -1
- package/dist/setup/doctor/core.js +0 -300
- package/dist/setup/doctor/core.js.map +0 -1
- package/dist/setup/doctor/diagnostics.js +0 -240
- package/dist/setup/doctor/diagnostics.js.map +0 -1
- package/dist/setup/doctor/opencode.js +0 -313
- package/dist/setup/doctor/opencode.js.map +0 -1
- package/dist/setup/doctor/report.js +0 -425
- package/dist/setup/doctor/report.js.map +0 -1
- package/dist/setup/doctor.js +0 -10
- package/dist/setup/doctor.js.map +0 -1
- package/dist/setup/opencode.js.map +0 -1
- package/dist/setup/smokeChecks.js.map +0 -1
- package/dist/state/installRoot.js.map +0 -1
- package/dist/state/progressCommit.js +0 -289
- package/dist/state/progressCommit.js.map +0 -1
- package/dist/state/startupAnalysis/benchmark.js.map +0 -1
- package/dist/state/startupAnalysis/contract.js.map +0 -1
- package/dist/state/startupAnalysis/helpers.js.map +0 -1
- package/dist/state/startupAnalysis/index.js.map +0 -1
- package/dist/state/startupAnalysis/metrics.js.map +0 -1
- package/dist/state/startupAnalysis/records.js.map +0 -1
- package/dist/state/startupAnalysis/report.js.map +0 -1
- package/dist/state/startupAnalysis/threshold.js.map +0 -1
- package/dist/state/startupAnalysis.js.map +0 -1
- package/dist/upgrade/appContentRefresh.js.map +0 -1
- package/dist/upgrade/appModel.js.map +0 -1
- package/dist/upgrade/bundleEvidence.js.map +0 -1
- package/dist/upgrade/channels.js.map +0 -1
- package/dist/upgrade/cliProbe.js +0 -22
- package/dist/upgrade/cliProbe.js.map +0 -1
- package/dist/upgrade/coexistenceProbe.js +0 -107
- package/dist/upgrade/coexistenceProbe.js.map +0 -1
- package/dist/upgrade/compatibility.js.map +0 -1
- package/dist/upgrade/doctor.js.map +0 -1
- package/dist/upgrade/doctorClassifier.js.map +0 -1
- package/dist/upgrade/installedHooksRetirement.js.map +0 -1
- package/dist/upgrade/legacyAgentCleanup.js.map +0 -1
- package/dist/upgrade/migrateArtifactsV1ToV2.js +0 -570
- package/dist/upgrade/migrateArtifactsV1ToV2.js.map +0 -1
- package/dist/upgrade/migrateArtifactsV2ToV3.js.map +0 -1
- package/dist/upgrade/nextMajorDoctor.js.map +0 -1
- package/dist/upgrade/npxPlatformStatus.js.map +0 -1
- package/dist/upgrade/projectIntegration.js.map +0 -1
- package/dist/upgrade/projectIntegrationDecision.js.map +0 -1
- package/dist/upgrade/runtimeMigration.js.map +0 -1
- package/dist/upgrade/upgradeCommands.js.map +0 -1
- package/dist/upgrade/upgradeOrchestrator.js.map +0 -1
- package/dist/upgrade/v3CapabilitySurface.js.map +0 -1
- package/dist/upgrade/versionResolution.js.map +0 -1
- package/dist/validate/appHomeContract.js.map +0 -1
- package/dist/validate/capability.js.map +0 -1
- package/dist/validate/crossCapability.js.map +0 -1
- package/dist/validate/lifecycleAdapters/legacyPythonParity.js +0 -93
- package/dist/validate/lifecycleAdapters/legacyPythonParity.js.map +0 -1
- package/dist/validate/lifecycleAdapters/nodeFormChecks.js +0 -488
- package/dist/validate/lifecycleAdapters/nodeFormChecks.js.map +0 -1
- package/dist/validate/lifecycleAdapters/shared.js +0 -198
- package/dist/validate/lifecycleAdapters/shared.js.map +0 -1
- package/dist/validate/lifecycleAdapters.js +0 -62
- package/dist/validate/lifecycleAdapters.js.map +0 -1
- package/dist/validate/selfAudit.js.map +0 -1
- package/dist/validate/vocabularyAuthority.js.map +0 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 4: enforce legacy coexistence across decision mutations.
|
|
3
|
+
*
|
|
4
|
+
* The whole-artifact validation gate validates the entire decisions artifact
|
|
5
|
+
* bytes. An untouched inherited record carrying a legacy confidence label
|
|
6
|
+
* (e.g. `high`) is unsupported by the decisions schema, so the strict gate
|
|
7
|
+
* blocked append, satisfaction update, and amend even when the operation never
|
|
8
|
+
* touched the legacy record.
|
|
9
|
+
*
|
|
10
|
+
* The authority's `compatibility.legacy_label_coexistence` rule (read through
|
|
11
|
+
* `legacyLabelCoexistence`) classifies an unsupported inherited label on a
|
|
12
|
+
* record the caller did not touch as explicit legacy state: it is preserved
|
|
13
|
+
* byte- and value-semantically, reported as a caveat, never coerced to the
|
|
14
|
+
* current vocabulary, and never blocks an operation on a different target. A
|
|
15
|
+
* confidence label supplied by append or amend is new/amended content and
|
|
16
|
+
* remains strict — it must be current vocabulary or the operation rejects
|
|
17
|
+
* before side effects.
|
|
18
|
+
*
|
|
19
|
+
* This module partitions schema violations into `blocking` (which still fail
|
|
20
|
+
* the operation) and `legacy_caveats` (untouched inherited legacy confidence
|
|
21
|
+
* labels that are preserved and reported). It never coerces a value and never
|
|
22
|
+
* broadens tolerance beyond the authority-declared confidence dimension: a
|
|
23
|
+
* missing required field, a type error, an invalid satisfaction state, or any
|
|
24
|
+
* other non-confidence violation stays blocking. (Touched confidence violations
|
|
25
|
+
* — a new/amended record whose confidence is unsupported — also stay blocking:
|
|
26
|
+
* the target/new content path remains strict.)
|
|
27
|
+
*/
|
|
28
|
+
import { classifyConfidenceLabel, legacyLabelCoexistence, } from "./decisionRevision.js";
|
|
29
|
+
import { resolveSourceRoot } from "../core/sourceRoot.js";
|
|
30
|
+
function isMapping(value) {
|
|
31
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
// Matches: `decisions: invalid value 'high' for 'decisions[0].confidence' (expected one of: ...)`.
|
|
34
|
+
const CONFIDENCE_VIOLATION = /^decisions: invalid value '(?<value>[^']*)' for '(?<list>decisions|archive)\[(?<idx>\d+)\]\.confidence' \(expected one of:/;
|
|
35
|
+
function recordAt(doc, list, idx) {
|
|
36
|
+
const arr = doc[list];
|
|
37
|
+
if (!Array.isArray(arr))
|
|
38
|
+
return {};
|
|
39
|
+
const entry = arr[idx];
|
|
40
|
+
return isMapping(entry) ? entry : {};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Partition decisions schema violations. Each confidence-label violation maps
|
|
44
|
+
* to the record it names; when that record was not touched by the current
|
|
45
|
+
* operation, the unsupported label is explicit legacy state (tolerated,
|
|
46
|
+
* caveated). When the record WAS touched (new or amended content), the
|
|
47
|
+
* unsupported label is rejected — target/new content must be current
|
|
48
|
+
* vocabulary. Every other violation stays blocking, so tolerance never extends
|
|
49
|
+
* beyond the authority-declared confidence dimension.
|
|
50
|
+
*
|
|
51
|
+
* `touchedNumbers` carries the decision numbers the caller touched (new or
|
|
52
|
+
* amended targets). For whole-artifact prevalidation of the existing artifact
|
|
53
|
+
* nothing is touched yet, so callers pass an empty set.
|
|
54
|
+
*/
|
|
55
|
+
export function partitionDecisionViolations(violations, doc, coexistence, touchedNumbers = new Set()) {
|
|
56
|
+
const blocking = [];
|
|
57
|
+
const legacy_caveats = [];
|
|
58
|
+
for (const violation of violations) {
|
|
59
|
+
const match = CONFIDENCE_VIOLATION.exec(violation);
|
|
60
|
+
if (!match || !match.groups) {
|
|
61
|
+
blocking.push(violation);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const { value, list, idx } = match.groups;
|
|
65
|
+
const source = list === "archive" ? "archive" : "active";
|
|
66
|
+
const record = recordAt(doc, list, Number(idx));
|
|
67
|
+
const number = Number(record.number);
|
|
68
|
+
const classification = classifyConfidenceLabel(coexistence, value, touchedNumbers.has(number));
|
|
69
|
+
if (classification.classification === "explicit_legacy") {
|
|
70
|
+
legacy_caveats.push({ number, label: value, source, caveat: classification.caveat });
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Touched unsupported (rejected) or current-but-flagged: keep strict.
|
|
74
|
+
blocking.push(violation);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { blocking, legacy_caveats };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Classify one record's confidence for amendment/read composition. An
|
|
81
|
+
* untouched inherited unsupported label is explicit legacy state and surfaces
|
|
82
|
+
* as a single caveat (never coerced, never promoted). `touched=true` marks
|
|
83
|
+
* the confidence as new or amended content; such a value can only be current
|
|
84
|
+
* vocabulary (enforced elsewhere), so no caveat is produced. Returns `null`
|
|
85
|
+
* when the confidence is current vocabulary or absent.
|
|
86
|
+
*/
|
|
87
|
+
export function legacyConfidenceCaveat(record, coexistence, touched, source = "active") {
|
|
88
|
+
const confidence = record.confidence;
|
|
89
|
+
if (typeof confidence !== "string")
|
|
90
|
+
return null;
|
|
91
|
+
const classification = classifyConfidenceLabel(coexistence, confidence, touched);
|
|
92
|
+
if (classification.classification !== "explicit_legacy")
|
|
93
|
+
return null;
|
|
94
|
+
return {
|
|
95
|
+
number: Number(record.number),
|
|
96
|
+
label: confidence,
|
|
97
|
+
source,
|
|
98
|
+
caveat: classification.caveat,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Return a caveat only for a label declared as known v2 legacy state. Migration
|
|
103
|
+
* uses this narrower classifier so an arbitrary unsupported confidence value
|
|
104
|
+
* cannot become publishable merely because it occupies the confidence field.
|
|
105
|
+
*/
|
|
106
|
+
export function knownLegacyConfidenceCaveat(record, coexistence, source = "active") {
|
|
107
|
+
if (typeof record.confidence !== "string" || !coexistence.knownLegacyExamples.includes(record.confidence))
|
|
108
|
+
return null;
|
|
109
|
+
return legacyConfidenceCaveat(record, coexistence, false, source);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Classify a complete migration source record without interpreting validator
|
|
113
|
+
* error text. A known legacy confidence is inherited only when replacing that
|
|
114
|
+
* one field with an authority-declared current value makes the whole record
|
|
115
|
+
* valid. Projection and verified-archive migration both use this classifier.
|
|
116
|
+
*/
|
|
117
|
+
export function classifyCompleteDecisionConfidence(record, coexistence, validate, source) {
|
|
118
|
+
if (coexistence.dimensions.length !== 1 || coexistence.dimensions[0] !== "confidence") {
|
|
119
|
+
throw new Error("decision legacy coexistence must declare confidence as its sole compatibility dimension");
|
|
120
|
+
}
|
|
121
|
+
const violations = validate(record);
|
|
122
|
+
if (violations.length === 0)
|
|
123
|
+
return { status: "current", violations, caveat: null };
|
|
124
|
+
const caveat = knownLegacyConfidenceCaveat(record, coexistence, source);
|
|
125
|
+
if (!caveat || coexistence.currentVocabulary.length === 0)
|
|
126
|
+
return { status: "invalid", violations, caveat: null };
|
|
127
|
+
const strictCandidate = { ...record, confidence: coexistence.currentVocabulary[0] };
|
|
128
|
+
return validate(strictCandidate).length === 0
|
|
129
|
+
? { status: "inherited", violations, caveat }
|
|
130
|
+
: { status: "invalid", violations, caveat: null };
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Scan a parsed decisions artifact mapping for untouched inherited legacy
|
|
134
|
+
* confidence labels. Records whose number is in `touchedNumbers` are new or
|
|
135
|
+
* amended content and are excluded — they remain strict. Used to report
|
|
136
|
+
* truthful compatibility caveats that reflect the published bytes.
|
|
137
|
+
*/
|
|
138
|
+
export function collectDecisionLegacyCaveats(doc, coexistence, touchedNumbers = new Set()) {
|
|
139
|
+
const caveats = [];
|
|
140
|
+
for (const [list, source] of [
|
|
141
|
+
["decisions", "active"],
|
|
142
|
+
["archive", "archive"],
|
|
143
|
+
]) {
|
|
144
|
+
const arr = doc[list];
|
|
145
|
+
if (!Array.isArray(arr))
|
|
146
|
+
continue;
|
|
147
|
+
for (const entry of arr) {
|
|
148
|
+
if (!isMapping(entry))
|
|
149
|
+
continue;
|
|
150
|
+
const caveat = legacyConfidenceCaveat(entry, coexistence, touchedNumbers.has(Number(entry.number)), source);
|
|
151
|
+
if (caveat)
|
|
152
|
+
caveats.push(caveat);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return caveats;
|
|
156
|
+
}
|
|
157
|
+
/** Load the legacy label coexistence authority section for a project. */
|
|
158
|
+
export function decisionLegacyCoexistence(sourceRoot = resolveSourceRoot()) {
|
|
159
|
+
return legacyLabelCoexistence(sourceRoot);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Gate 1 — prevalidation of the existing artifact. When coexistence is null
|
|
163
|
+
* (non-decisions artifact), throws the standard schema-invalid error. When
|
|
164
|
+
* coexistence is active, partitions: tolerates untouched inherited legacy
|
|
165
|
+
* confidence labels only; every other violation stays blocking. Returns
|
|
166
|
+
* legacy caveats from the violations.
|
|
167
|
+
*/
|
|
168
|
+
export function gateExistingDecisions(violations, doc, coexistence, target) {
|
|
169
|
+
if (!coexistence)
|
|
170
|
+
throw new Error(`existing artifact '${target}' is schema-invalid: ${violations.join("; ")}; repair it before retrying`);
|
|
171
|
+
const partition = partitionDecisionViolations(violations, doc, coexistence, new Set());
|
|
172
|
+
if (partition.blocking.length)
|
|
173
|
+
throw new Error(`existing artifact '${target}' is schema-invalid: ${partition.blocking.join("; ")}; repair it before retrying`);
|
|
174
|
+
return partition.legacy_caveats;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Gate 2 — candidate validation. When coexistence is null (non-decisions),
|
|
178
|
+
* calls `reject` with the raw violations if any exist. When active, the
|
|
179
|
+
* new/amended record's number is touched, so unsupported confidence on it
|
|
180
|
+
* stays blocking (calls `reject`). Then re-derives caveats from the candidate
|
|
181
|
+
* doc so the envelope reflects the about-to-be-published bytes.
|
|
182
|
+
*/
|
|
183
|
+
export function gateCandidateDecisions(violations, candidate, coexistence, writtenNumber, reject) {
|
|
184
|
+
if (!coexistence) {
|
|
185
|
+
if (violations.length)
|
|
186
|
+
reject(violations);
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
const touched = new Set([writtenNumber]);
|
|
190
|
+
const partition = partitionDecisionViolations(violations, candidate, coexistence, touched);
|
|
191
|
+
if (partition.blocking.length)
|
|
192
|
+
reject(partition.blocking);
|
|
193
|
+
return collectDecisionLegacyCaveats(candidate, coexistence, touched);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Gate 3 — post-compaction invariant. When coexistence is null, throws the
|
|
197
|
+
* standard writer/compactor error if violations exist. When active, proves
|
|
198
|
+
* untouched inherited legacy labels survived compaction unchanged:
|
|
199
|
+
* partitions final violations (throws if blocking), then re-derives caveats
|
|
200
|
+
* from the published bytes.
|
|
201
|
+
*/
|
|
202
|
+
export function gateCompactedDecisions(violations, doc, coexistence, writtenNumber) {
|
|
203
|
+
if (!coexistence) {
|
|
204
|
+
if (violations.length)
|
|
205
|
+
throw new Error(`writer/compactor invariant failure: ${violations.join("; ")}`);
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const touched = new Set([writtenNumber]);
|
|
209
|
+
if (violations.length) {
|
|
210
|
+
const partition = partitionDecisionViolations(violations, doc, coexistence, touched);
|
|
211
|
+
if (partition.blocking.length)
|
|
212
|
+
throw new Error(`writer/compactor invariant failure: ${partition.blocking.join("; ")}`);
|
|
213
|
+
}
|
|
214
|
+
return collectDecisionLegacyCaveats(doc, coexistence, touched);
|
|
215
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveSourceRoot } from "../core/sourceRoot.js";
|
|
4
|
+
import { loadYamlMapping } from "../core/yaml.js";
|
|
5
|
+
import { canonicalRecordJson, numberedArchiveContract, stateCurrentProjectionPath, validateNumberedArchiveBytes, validateStateRecord } from "./archiveDiscovery.js";
|
|
6
|
+
import { canonicalMigrationRecord } from "./canonicalMigrationRecord.js";
|
|
7
|
+
import { classifyCompleteDecisionConfidence } from "./decisionLegacyValidation.js";
|
|
8
|
+
import { decisionRevisionContract, decisionRevisionViolations, legacyLabelCoexistence } from "./decisionRevision.js";
|
|
9
|
+
import { readBoundMigrationSource } from "./migrationSourceBinding.js";
|
|
10
|
+
import { entityMigrationId } from "./entityMigrationIdentity.js";
|
|
11
|
+
function mapping(value) {
|
|
12
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
/** Validate the sole authority-declared canonical migration metadata shape. */
|
|
15
|
+
export function decisionMigrationProvenanceViolations(record, provenance, declared, forbiddenAliases, sourceRoot, binding) {
|
|
16
|
+
if (declared.additionalFields !== "forbidden" || !declared.kind || declared.requiredFields.length === 0 || declared.sources.length === 0) {
|
|
17
|
+
throw new Error("invalid migration provenance authority for 'decision'");
|
|
18
|
+
}
|
|
19
|
+
const coexistence = legacyLabelCoexistence(sourceRoot ?? resolveSourceRoot());
|
|
20
|
+
const confidence = record.confidence;
|
|
21
|
+
if (typeof confidence !== "string")
|
|
22
|
+
return ["confidence must be a string from the authority-declared vocabulary"];
|
|
23
|
+
if (coexistence.currentVocabulary.includes(confidence)) {
|
|
24
|
+
return provenance === null || provenance === undefined ? [] : ["migration_provenance is allowed only for an inherited unsupported confidence"];
|
|
25
|
+
}
|
|
26
|
+
if (!coexistence.knownLegacyExamples.includes(confidence))
|
|
27
|
+
return [`unsupported decision confidence '${confidence}'`];
|
|
28
|
+
if (!mapping(provenance))
|
|
29
|
+
return ["an inherited unsupported confidence requires mapping migration_provenance"];
|
|
30
|
+
const violations = [];
|
|
31
|
+
const declaredKeys = new Set(declared.requiredFields);
|
|
32
|
+
for (const field of declared.requiredFields)
|
|
33
|
+
if (!(field in provenance))
|
|
34
|
+
violations.push(`migration_provenance.${field} is required`);
|
|
35
|
+
for (const field of Object.keys(provenance))
|
|
36
|
+
if (!declaredKeys.has(field))
|
|
37
|
+
violations.push(`migration_provenance.${field} is not allowed`);
|
|
38
|
+
if (provenance.kind !== declared.kind)
|
|
39
|
+
violations.push(`migration_provenance.kind must be '${declared.kind}'`);
|
|
40
|
+
if (typeof provenance.source !== "string" || !declared.sources.includes(provenance.source))
|
|
41
|
+
violations.push(`migration_provenance.source must be one of: ${declared.sources.join(", ")}`);
|
|
42
|
+
if (typeof provenance.source_path !== "string" || provenance.source_path.length === 0 || path.isAbsolute(provenance.source_path) || provenance.source_path.split(/[\\/]/).includes(".."))
|
|
43
|
+
violations.push("migration_provenance.source_path must be a safe project-relative path");
|
|
44
|
+
if (typeof provenance.source_record_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(provenance.source_record_sha256))
|
|
45
|
+
violations.push("migration_provenance.source_record_sha256 must be a lowercase SHA-256 digest");
|
|
46
|
+
if (provenance.confidence !== confidence)
|
|
47
|
+
violations.push("migration_provenance.confidence must match record.confidence");
|
|
48
|
+
if (violations.length)
|
|
49
|
+
return violations;
|
|
50
|
+
if (binding === undefined)
|
|
51
|
+
return ["an inherited unsupported confidence requires a source binding context"];
|
|
52
|
+
violations.push(...sourceBindingViolations(record, provenance, binding, sourceRoot ?? resolveSourceRoot(), forbiddenAliases));
|
|
53
|
+
return violations;
|
|
54
|
+
}
|
|
55
|
+
export function decisionRevisionMigrationProvenanceViolations(record, provenance, declared, sourceRoot = resolveSourceRoot(), binding) {
|
|
56
|
+
const changes = mapping(record.changes) ? record.changes : {};
|
|
57
|
+
const confidence = changes.confidence;
|
|
58
|
+
const coexistence = legacyLabelCoexistence(sourceRoot);
|
|
59
|
+
if (confidence === undefined || coexistence.currentVocabulary.includes(String(confidence))) {
|
|
60
|
+
return provenance === null || provenance === undefined ? [] : ["migration_provenance is allowed only for an inherited unsupported revision confidence"];
|
|
61
|
+
}
|
|
62
|
+
if (typeof confidence !== "string" || !coexistence.knownLegacyExamples.includes(confidence))
|
|
63
|
+
return [`unsupported decision revision confidence '${String(confidence)}'`];
|
|
64
|
+
if (!mapping(provenance))
|
|
65
|
+
return ["an inherited unsupported revision confidence requires mapping migration_provenance"];
|
|
66
|
+
const violations = [];
|
|
67
|
+
const declaredKeys = new Set(declared.requiredFields);
|
|
68
|
+
for (const field of declared.requiredFields)
|
|
69
|
+
if (!(field in provenance))
|
|
70
|
+
violations.push(`migration_provenance.${field} is required`);
|
|
71
|
+
for (const field of Object.keys(provenance))
|
|
72
|
+
if (!declaredKeys.has(field))
|
|
73
|
+
violations.push(`migration_provenance.${field} is not allowed`);
|
|
74
|
+
if (provenance.kind !== declared.kind)
|
|
75
|
+
violations.push(`migration_provenance.kind must be '${declared.kind}'`);
|
|
76
|
+
if (typeof provenance.source !== "string" || !declared.sources.includes(provenance.source))
|
|
77
|
+
violations.push(`migration_provenance.source must be one of: ${declared.sources.join(", ")}`);
|
|
78
|
+
const contract = decisionRevisionContract(sourceRoot);
|
|
79
|
+
if (provenance.source_path !== contract.location)
|
|
80
|
+
violations.push(`migration_provenance.source_path must be '${contract.location}'`);
|
|
81
|
+
if (typeof provenance.source_identity !== "string" || !/^decision_revision:decisions:[1-9][0-9]*:[0-9]+$/.test(provenance.source_identity))
|
|
82
|
+
violations.push("migration_provenance.source_identity must identify one ordered legacy decision revision");
|
|
83
|
+
if (typeof provenance.source_fingerprint !== "string" || !/^[a-f0-9]{64}$/.test(provenance.source_fingerprint))
|
|
84
|
+
violations.push("migration_provenance.source_fingerprint must be a lowercase SHA-256 digest");
|
|
85
|
+
if (typeof provenance.source_record_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(provenance.source_record_sha256))
|
|
86
|
+
violations.push("migration_provenance.source_record_sha256 must be a lowercase SHA-256 digest");
|
|
87
|
+
if (provenance.confidence !== confidence)
|
|
88
|
+
violations.push("migration_provenance.confidence must match record.changes.confidence");
|
|
89
|
+
if (violations.length)
|
|
90
|
+
return violations;
|
|
91
|
+
if (binding === undefined)
|
|
92
|
+
return ["an inherited unsupported revision confidence requires a source binding context"];
|
|
93
|
+
const match = /^decision_revision:(decisions:[1-9][0-9]*):([0-9]+)$/.exec(String(provenance.source_identity));
|
|
94
|
+
if (!match || entityMigrationId(String(provenance.source_fingerprint), match[1]) !== record.decision)
|
|
95
|
+
return ["migration_provenance source identity does not bind the canonical decision ID"];
|
|
96
|
+
if (binding.kind !== "migration_preview") {
|
|
97
|
+
const markerFile = readBoundMigrationSource(binding, ".agentera/state-mode.yaml");
|
|
98
|
+
if (markerFile.kind !== "file")
|
|
99
|
+
return ["migration_provenance requires the durable entity cutover marker"];
|
|
100
|
+
let marker;
|
|
101
|
+
try {
|
|
102
|
+
marker = loadYamlMapping(markerFile.bytes);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return [`entity cutover marker is invalid YAML: ${error.message}`];
|
|
106
|
+
}
|
|
107
|
+
if (marker.schemaVersion !== "agentera.stateMode.v1" || marker.mode !== "entities" || marker.source_fingerprint !== provenance.source_fingerprint)
|
|
108
|
+
return ["migration_provenance source_fingerprint does not match the durable entity cutover marker"];
|
|
109
|
+
}
|
|
110
|
+
const sourceFile = readBoundMigrationSource(binding, contract.location);
|
|
111
|
+
if (sourceFile.kind !== "file")
|
|
112
|
+
return [`migration_provenance source '${contract.location}' is ${sourceFile.kind === "missing" ? "missing" : `unsafe (${sourceFile.reason})`}`];
|
|
113
|
+
let document;
|
|
114
|
+
try {
|
|
115
|
+
document = loadYamlMapping(sourceFile.bytes);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
return [`migration_provenance source '${contract.location}' is invalid YAML: ${error.message}`];
|
|
119
|
+
}
|
|
120
|
+
const candidate = match && Array.isArray(document[match[1]]) ? mapping(document[match[1]][Number(match[2])]) ? document[match[1]][Number(match[2])] : null : null;
|
|
121
|
+
if (!match || !candidate)
|
|
122
|
+
return ["migration_provenance source_identity does not resolve to one legacy decision revision"];
|
|
123
|
+
if (sourceHash(candidate) !== provenance.source_record_sha256)
|
|
124
|
+
return ["migration_provenance source_record_sha256 does not match the legacy decision revision"];
|
|
125
|
+
const sourceViolations = decisionRevisionViolations({ [match[1]]: [candidate] }, contract);
|
|
126
|
+
if (sourceViolations.length)
|
|
127
|
+
return [`migration_provenance source revision is invalid: ${sourceViolations.join("; ")}`];
|
|
128
|
+
const candidateChanges = Object.fromEntries(Object.entries(candidate).filter(([field]) => !["date", "provenance", "base_sha256"].includes(field)));
|
|
129
|
+
if (canonicalRecordJson(candidateChanges) !== canonicalRecordJson(changes))
|
|
130
|
+
return ["migration_provenance source revision changes do not match the canonical revision"];
|
|
131
|
+
if ((candidate.date ?? undefined) !== (record.date ?? undefined))
|
|
132
|
+
return ["migration_provenance source revision date does not match the canonical revision"];
|
|
133
|
+
if ((candidate.provenance ?? "historical_revision") !== record.provenance)
|
|
134
|
+
return ["migration_provenance source revision provenance does not match the canonical revision"];
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
function sourceAssessment(record, sourceRoot, source) {
|
|
138
|
+
return classifyCompleteDecisionConfidence(record, legacyLabelCoexistence(sourceRoot), (candidate) => validateStateRecord(sourceRoot, "decisions", candidate), source);
|
|
139
|
+
}
|
|
140
|
+
function sourceMatchesCanonical(source, canonical, forbiddenAliases) {
|
|
141
|
+
return canonicalRecordJson(canonicalMigrationRecord("decision", source, forbiddenAliases)) === canonicalRecordJson(canonical);
|
|
142
|
+
}
|
|
143
|
+
function sourceHash(record) {
|
|
144
|
+
return createHash("sha256").update(canonicalRecordJson(record)).digest("hex");
|
|
145
|
+
}
|
|
146
|
+
function sourceBindingViolations(record, provenance, binding, sourceRoot, forbiddenAliases) {
|
|
147
|
+
const sourcePath = String(provenance.source_path);
|
|
148
|
+
const digest = String(provenance.source_record_sha256);
|
|
149
|
+
const confidence = String(provenance.confidence);
|
|
150
|
+
if (provenance.source === "current_projection") {
|
|
151
|
+
const declaredPath = path.relative("/", stateCurrentProjectionPath("/", "decisions", sourceRoot)).split(path.sep).join("/");
|
|
152
|
+
if (sourcePath !== declaredPath)
|
|
153
|
+
return [`migration_provenance.source_path must be the authority-declared current projection '${declaredPath}'`];
|
|
154
|
+
const sourceFile = readBoundMigrationSource(binding, declaredPath);
|
|
155
|
+
if (sourceFile.kind !== "file")
|
|
156
|
+
return [`migration_provenance source '${declaredPath}' is ${sourceFile.kind === "missing" ? "missing" : `unsafe (${sourceFile.reason})`}`];
|
|
157
|
+
let document;
|
|
158
|
+
try {
|
|
159
|
+
document = loadYamlMapping(sourceFile.bytes);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
return [`migration_provenance source '${declaredPath}' is invalid YAML: ${error.message}`];
|
|
163
|
+
}
|
|
164
|
+
const candidates = [document.decisions, document.archive].flatMap((value) => Array.isArray(value) ? value.filter(mapping) : []);
|
|
165
|
+
const candidate = candidates.find((source) => sourceHash(source) === digest && source.confidence === confidence && sourceMatchesCanonical(source, record, forbiddenAliases));
|
|
166
|
+
if (!candidate)
|
|
167
|
+
return ["migration_provenance does not match any complete decision in the preserved current projection"];
|
|
168
|
+
const assessment = sourceAssessment(candidate, sourceRoot, "active");
|
|
169
|
+
return assessment.status === "inherited" ? [] : ["migration_provenance current-projection source is not a complete inherited-confidence decision"];
|
|
170
|
+
}
|
|
171
|
+
const contract = numberedArchiveContract("decisions", sourceRoot);
|
|
172
|
+
const archivePrefix = path.posix.join(contract.archiveRoot, "decisions");
|
|
173
|
+
const escapedExtension = contract.archiveExtension.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
174
|
+
const match = new RegExp(`^${archivePrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/([1-9][0-9]*)${escapedExtension}$`).exec(sourcePath);
|
|
175
|
+
if (!match)
|
|
176
|
+
return [`migration_provenance.source_path must be an authority-valid numbered decision archive path under '${archivePrefix}'`];
|
|
177
|
+
const entryNumber = Number(match[1]);
|
|
178
|
+
const sourceFile = readBoundMigrationSource(binding, sourcePath);
|
|
179
|
+
if (sourceFile.kind !== "file")
|
|
180
|
+
return [`migration_provenance archive source is ${sourceFile.kind === "missing" ? "missing" : `unsafe (${sourceFile.reason})`}: ${sourcePath}`];
|
|
181
|
+
const lookup = validateNumberedArchiveBytes("decisions", entryNumber, sourceFile.bytes, {
|
|
182
|
+
sourceRoot,
|
|
183
|
+
sourcePath,
|
|
184
|
+
recordValidator: (source) => {
|
|
185
|
+
const assessment = sourceAssessment(source, sourceRoot, "archive");
|
|
186
|
+
return assessment.status === "inherited" ? [] : assessment.violations.length ? assessment.violations : ["archive decision is not inherited legacy confidence"];
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
if (!lookup.entry?.record)
|
|
190
|
+
return [`migration_provenance archive source is missing or invalid: ${lookup.rejection?.message ?? sourcePath}`];
|
|
191
|
+
const source = lookup.entry.record;
|
|
192
|
+
if (lookup.entry.recordSha256 !== digest || sourceHash(source) !== digest)
|
|
193
|
+
return ["migration_provenance source_record_sha256 does not match the authority-valid archive record"];
|
|
194
|
+
if (source.confidence !== confidence)
|
|
195
|
+
return ["migration_provenance confidence does not match the archive record"];
|
|
196
|
+
if (!sourceMatchesCanonical(source, record, forbiddenAliases))
|
|
197
|
+
return ["migration_provenance archive record does not correspond to the canonical decision content"];
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4
|
+
import { dumpYamlMapping, loadYamlMapping } from "../core/yaml.js";
|
|
5
|
+
import { resolveSourceRoot } from "../core/sourceRoot.js";
|
|
6
|
+
import { assertRealpathBoundary } from "../registries/artifactRegistry.js";
|
|
7
|
+
import { decisionOverlayContract, } from "./archiveDiscovery.js";
|
|
8
|
+
import { reject } from "./write/errors.js";
|
|
9
|
+
function isMapping(value) {
|
|
10
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function mapping(value) {
|
|
13
|
+
return isMapping(value) ? value : {};
|
|
14
|
+
}
|
|
15
|
+
function valueAt(value, field) {
|
|
16
|
+
let current = value;
|
|
17
|
+
for (const part of field.split(".")) {
|
|
18
|
+
if (!isMapping(current))
|
|
19
|
+
return undefined;
|
|
20
|
+
current = current[part];
|
|
21
|
+
}
|
|
22
|
+
return current;
|
|
23
|
+
}
|
|
24
|
+
function setAt(target, field, value) {
|
|
25
|
+
const parts = field.split(".");
|
|
26
|
+
let current = target;
|
|
27
|
+
for (const part of parts.slice(0, -1)) {
|
|
28
|
+
const next = current[part];
|
|
29
|
+
if (!isMapping(next))
|
|
30
|
+
current[part] = {};
|
|
31
|
+
current = current[part];
|
|
32
|
+
}
|
|
33
|
+
current[parts.at(-1)] = structuredClone(value);
|
|
34
|
+
}
|
|
35
|
+
function pathAllowed(field, contract) {
|
|
36
|
+
return contract.mutablePaths.some((mutable) => mutable === field || mutable.startsWith(`${field}.`));
|
|
37
|
+
}
|
|
38
|
+
function validateValueTypes(field, value, contract, violations) {
|
|
39
|
+
if (field.endsWith(".state")) {
|
|
40
|
+
if (typeof value !== "string" || !contract.stateValues.includes(value)) {
|
|
41
|
+
violations.push(`${field} must be one of: ${contract.stateValues.join(", ")}`);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (field.endsWith(".evidence") || field.endsWith(".confirmed_by") || field.endsWith(".confirmed_at")) {
|
|
46
|
+
if (typeof value !== "string")
|
|
47
|
+
violations.push(`${field} must be a string`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function validateOverlayValue(value, contract, prefix = "", violations = []) {
|
|
51
|
+
if (!isMapping(value)) {
|
|
52
|
+
violations.push(`${prefix || "overlay entry"} must be a mapping`);
|
|
53
|
+
return violations;
|
|
54
|
+
}
|
|
55
|
+
for (const [key, child] of Object.entries(value)) {
|
|
56
|
+
const field = prefix ? `${prefix}.${key}` : key;
|
|
57
|
+
if (!pathAllowed(field, contract)) {
|
|
58
|
+
violations.push(`${field} is not an authority-declared mutable overlay field`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (isMapping(child))
|
|
62
|
+
validateOverlayValue(child, contract, field, violations);
|
|
63
|
+
else
|
|
64
|
+
validateValueTypes(field, child, contract, violations);
|
|
65
|
+
}
|
|
66
|
+
return violations;
|
|
67
|
+
}
|
|
68
|
+
function decisionNumberFromId(id, contract) {
|
|
69
|
+
const prefix = `${contract.identityPrefix}:`;
|
|
70
|
+
if (!id.startsWith(prefix))
|
|
71
|
+
return null;
|
|
72
|
+
const number = id.slice(prefix.length);
|
|
73
|
+
if (!/^[1-9][0-9]*$/.test(number))
|
|
74
|
+
return null;
|
|
75
|
+
const parsed = Number(number);
|
|
76
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
|
|
77
|
+
}
|
|
78
|
+
export function decisionOverlayPath(projectRoot, sourceRoot = resolveSourceRoot()) {
|
|
79
|
+
const contract = decisionOverlayContract(sourceRoot);
|
|
80
|
+
const target = path.resolve(projectRoot, contract.location);
|
|
81
|
+
assertRealpathBoundary(projectRoot, target, "decision overlay");
|
|
82
|
+
return target;
|
|
83
|
+
}
|
|
84
|
+
export function decisionOverlayViolations(document, contract = decisionOverlayContract()) {
|
|
85
|
+
if (!isMapping(document))
|
|
86
|
+
return ["decision overlay root must be a mapping keyed by stable decision ID"];
|
|
87
|
+
const violations = [];
|
|
88
|
+
for (const [stableId, value] of Object.entries(document)) {
|
|
89
|
+
if (decisionNumberFromId(stableId, contract) === null) {
|
|
90
|
+
violations.push(`${stableId} is not a valid ${contract.identityKey} key`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
validateOverlayValue(value, contract, "", violations);
|
|
94
|
+
}
|
|
95
|
+
return violations;
|
|
96
|
+
}
|
|
97
|
+
function readOverlayDocument(projectRoot, sourceRoot = resolveSourceRoot()) {
|
|
98
|
+
const contract = decisionOverlayContract(sourceRoot);
|
|
99
|
+
const target = decisionOverlayPath(projectRoot, sourceRoot);
|
|
100
|
+
if (!fs.existsSync(target))
|
|
101
|
+
return { path: target, document: {}, contract };
|
|
102
|
+
const bytes = fs.readFileSync(target, "utf8");
|
|
103
|
+
let document;
|
|
104
|
+
try {
|
|
105
|
+
document = loadYamlMapping(bytes);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`cannot parse decision overlay '${target}': ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
const violations = decisionOverlayViolations(document, contract);
|
|
111
|
+
if (violations.length > 0)
|
|
112
|
+
throw new Error(`decision overlay '${target}' is invalid: ${violations.join("; ")}`);
|
|
113
|
+
return { path: target, document: document, contract };
|
|
114
|
+
}
|
|
115
|
+
export function loadDecisionOverlay(projectRoot = process.cwd(), sourceRoot = resolveSourceRoot()) {
|
|
116
|
+
return readOverlayDocument(projectRoot, sourceRoot).document;
|
|
117
|
+
}
|
|
118
|
+
export function hydrateDecisionRecords(entries, source = process.cwd()) {
|
|
119
|
+
const overlay = typeof source === "string" ? loadDecisionOverlay(source) : source;
|
|
120
|
+
const contract = decisionOverlayContract();
|
|
121
|
+
return entries.map((entry) => {
|
|
122
|
+
const number = entry.number;
|
|
123
|
+
const stableId = typeof number === "number" || typeof number === "string" ? `decisions:${number}` : null;
|
|
124
|
+
return composeDecisionOverlay(entry, stableId ? overlay[stableId] : undefined, contract);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
export function composeDecisionOverlay(entry, overlay, contract = decisionOverlayContract()) {
|
|
128
|
+
if (!overlay)
|
|
129
|
+
return structuredClone(entry);
|
|
130
|
+
const hydrated = structuredClone(entry);
|
|
131
|
+
const historicalSatisfaction = mapping(hydrated.satisfaction);
|
|
132
|
+
const overlaySatisfaction = mapping(overlay.satisfaction);
|
|
133
|
+
const composedSatisfaction = { ...historicalSatisfaction };
|
|
134
|
+
for (const field of contract.mutablePaths) {
|
|
135
|
+
const relative = field.startsWith("satisfaction.") ? field.slice("satisfaction.".length) : field;
|
|
136
|
+
const value = valueAt(overlaySatisfaction, relative);
|
|
137
|
+
if (value !== undefined)
|
|
138
|
+
setAt(composedSatisfaction, relative, value);
|
|
139
|
+
}
|
|
140
|
+
hydrated.satisfaction = composedSatisfaction;
|
|
141
|
+
return hydrated;
|
|
142
|
+
}
|
|
143
|
+
export function requestedSatisfaction(requested, contract) {
|
|
144
|
+
const violations = validateOverlayValue({ satisfaction: requested }, contract);
|
|
145
|
+
if (violations.length > 0) {
|
|
146
|
+
reject({
|
|
147
|
+
class: "schema_violation",
|
|
148
|
+
message: "decision satisfaction update contains invalid overlay fields",
|
|
149
|
+
violations,
|
|
150
|
+
syntax: "agentera state decisions update --id ID --satisfaction-state STATE --format json",
|
|
151
|
+
example: "agentera state decisions update --id qjtrmnpvka --satisfaction-state provisionally_satisfied --satisfaction-evidence 'verified' --format json",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const result = {};
|
|
155
|
+
for (const field of contract.mutablePaths) {
|
|
156
|
+
const relative = field.startsWith("satisfaction.") ? field.slice("satisfaction.".length) : field;
|
|
157
|
+
const value = valueAt(requested, relative);
|
|
158
|
+
if (value !== undefined)
|
|
159
|
+
setAt(result, relative, value);
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
function nonEmptyString(value) {
|
|
164
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
165
|
+
}
|
|
166
|
+
function statePath(contract) {
|
|
167
|
+
return contract.mutablePaths.find((field) => field.endsWith(".state"))?.slice("satisfaction.".length) ?? "state";
|
|
168
|
+
}
|
|
169
|
+
function evidencePath(contract) {
|
|
170
|
+
return contract.mutablePaths.find((field) => field.endsWith(".evidence"))?.slice("satisfaction.".length) ?? "evidence";
|
|
171
|
+
}
|
|
172
|
+
function confirmationPaths(contract) {
|
|
173
|
+
return contract.mutablePaths
|
|
174
|
+
.filter((field) => field.includes("user_confirmation."))
|
|
175
|
+
.map((field) => field.slice("satisfaction.".length));
|
|
176
|
+
}
|
|
177
|
+
function effectiveState(overlay, historicalSatisfaction) {
|
|
178
|
+
return valueAt(overlay?.satisfaction, "state") ?? valueAt(historicalSatisfaction, "state");
|
|
179
|
+
}
|
|
180
|
+
export function validateTransition(requested, currentOverlay, historicalSatisfaction, contract) {
|
|
181
|
+
const nextState = valueAt(requested, statePath(contract));
|
|
182
|
+
const evidence = valueAt(requested, evidencePath(contract));
|
|
183
|
+
const confirmation = mapping(requested.user_confirmation);
|
|
184
|
+
if (nextState === "provisionally_satisfied" && !nonEmptyString(evidence)) {
|
|
185
|
+
reject({
|
|
186
|
+
class: "schema_violation",
|
|
187
|
+
message: "provisionally_satisfied requires non-empty --satisfaction-evidence",
|
|
188
|
+
syntax: "agentera state decisions update --id ID --satisfaction-state STATE --satisfaction-evidence TEXT --format json",
|
|
189
|
+
example: "agentera state decisions update --id qjtrmnpvka --satisfaction-state provisionally_satisfied --satisfaction-evidence 'verified' --format json",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (nextState === "user_confirmed_satisfied") {
|
|
193
|
+
const paths = confirmationPaths(contract);
|
|
194
|
+
if (paths.some((field) => !nonEmptyString(valueAt(confirmation, field.split(".").at(-1))))) {
|
|
195
|
+
reject({
|
|
196
|
+
class: "schema_violation",
|
|
197
|
+
message: "user_confirmed_satisfied requires explicit current user confirmation metadata",
|
|
198
|
+
syntax: "agentera state decisions update --id ID --satisfaction-state user_confirmed_satisfied --confirmed-by USER --confirmed-at TIME --format json",
|
|
199
|
+
example: "agentera state decisions update --id qjtrmnpvka --satisfaction-state user_confirmed_satisfied --confirmed-by user --confirmed-at 2026-07-13T12:00:00Z --format json",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const currentState = effectiveState(currentOverlay, historicalSatisfaction);
|
|
204
|
+
if (typeof currentState === "string" && contract.stateValues.includes(currentState)) {
|
|
205
|
+
if (!contract.allowedNext[currentState]?.includes(String(nextState))) {
|
|
206
|
+
const downgradeConfirmation = confirmationPaths(contract).every((field) => nonEmptyString(valueAt(confirmation, field.split(".").at(-1))));
|
|
207
|
+
if (!(currentState === "user_confirmed_satisfied" && downgradeConfirmation)) {
|
|
208
|
+
reject({
|
|
209
|
+
class: "conflict",
|
|
210
|
+
message: `decision satisfaction cannot transition from ${currentState} to ${String(nextState)} without explicit current user confirmation`,
|
|
211
|
+
syntax: "agentera state decisions update --id ID --satisfaction-state STATE --format json",
|
|
212
|
+
example: "agentera state decisions update --id qjtrmnpvka --satisfaction-state user_confirmed_satisfied --confirmed-by user --confirmed-at 2026-07-13T12:00:00Z --format json",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
export function updateDecisionOverlay(projectRoot, decisionNumber, requested, historicalSatisfaction, transaction, publish = true, sourceRoot = resolveSourceRoot()) {
|
|
219
|
+
const current = readOverlayDocument(projectRoot, sourceRoot);
|
|
220
|
+
const stableId = `${current.contract.identityPrefix}:${decisionNumber}`;
|
|
221
|
+
const currentEntry = current.document[stableId];
|
|
222
|
+
const satisfaction = requestedSatisfaction(requested, current.contract);
|
|
223
|
+
validateTransition(satisfaction, currentEntry, historicalSatisfaction, current.contract);
|
|
224
|
+
const nextDocument = structuredClone(current.document);
|
|
225
|
+
const replay = Boolean(currentEntry && isDeepStrictEqual(currentEntry.satisfaction, satisfaction));
|
|
226
|
+
if (!replay)
|
|
227
|
+
nextDocument[stableId] = { satisfaction };
|
|
228
|
+
if (!replay && publish) {
|
|
229
|
+
const bytes = dumpYamlMapping(nextDocument);
|
|
230
|
+
const violations = decisionOverlayViolations(nextDocument, current.contract);
|
|
231
|
+
if (violations.length > 0) {
|
|
232
|
+
reject({
|
|
233
|
+
class: "schema_violation",
|
|
234
|
+
message: "decision overlay publication failed validation",
|
|
235
|
+
violations,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const stage = transaction.stageProjection(current.path, bytes);
|
|
239
|
+
try {
|
|
240
|
+
transaction.syncStaged(stage);
|
|
241
|
+
transaction.publishProjection(stage, current.path);
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
transaction.removeStage(stage);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
path: current.path,
|
|
249
|
+
satisfaction,
|
|
250
|
+
replay,
|
|
251
|
+
before: current.document,
|
|
252
|
+
after: nextDocument,
|
|
253
|
+
};
|
|
254
|
+
}
|