@cassiomc1/forgeloop 1.13.0 → 2.0.0-rc.2
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/AGENT_COMPATIBILITY.md +8 -0
- package/CONTRIBUTING.md +11 -7
- package/DOCS_INDEX.md +37 -4
- package/ENG/c-development-eng.md +2 -2
- package/ENG/cpp-development-eng.md +2 -2
- package/ENG/dotnet-aspnetcore-development-eng.md +7 -1
- package/ENG/flutter-development-eng.md +4 -2
- package/ENG/go-development-eng.md +2 -2
- package/ENG/java-development-eng.md +3 -3
- package/ENG/nodejs-backend-development-eng.md +10 -6
- package/ENG/php-development-eng.md +3 -3
- package/ENG/python-development-eng.md +205 -0
- package/ENG/rust-development-eng.md +42 -1
- package/ENG/sec-code-eng.md +7 -7
- package/ENG/sql-development-eng.md +4 -4
- package/ENG/swift-development-eng.md +5 -4
- package/ENG/test-code-eng.md +1 -1
- package/ENG/typescript-development-eng.md +4 -4
- package/EXECUTION_STATE.md +12 -0
- package/GUIDE_ROUTER.md +6 -0
- package/LICENSE +133 -21
- package/LOOP_ENGINEERING.md +28 -2
- package/LOOP_SYSTEM_DESIGN.md +10 -10
- package/ORCHESTRATOR_INTEGRATION.md +9 -5
- package/PROTOCOL_INTEGRATION.md +55 -2
- package/README.md +63 -59
- package/TERMINOLOGY.md +2 -0
- package/THIRD_PARTY_NOTICES.md +3 -4
- package/THREAT_MODEL.md +140 -1
- package/completions/_forgeloop +29 -3
- package/completions/forgeloop.bash +55 -3
- package/completions/forgeloop.fish +183 -1
- package/docs/ADVISORY_CONTEXT.md +25 -0
- package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
- package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
- package/docs/AGENT_PROTOCOL_SUMMARY.md +74 -39
- package/docs/AGENT_SKILL.md +66 -0
- package/docs/ARTIFACT_REFERENCE.md +171 -35
- package/docs/AUDIT_UX.md +46 -0
- package/docs/BROWSER_VERIFICATION.md +136 -0
- package/docs/CLI_REFERENCE.md +512 -8
- package/docs/CODE_ATTESTATION.md +2 -2
- package/docs/DOCUMENTATION_GUIDE.md +34 -11
- package/docs/GETTING_STARTED.md +3 -3
- package/docs/JEV_BENCHMARKS.md +31 -0
- package/docs/MODEL_ROUTING.md +37 -0
- package/docs/OPENSRC_ADAPTER.md +241 -0
- package/docs/PACKAGE_CONTENTS.md +46 -18
- package/docs/PROVIDERS.md +126 -0
- package/docs/PROVIDER_ARCHITECTURE.md +199 -0
- package/docs/RECIPES.md +9 -0
- package/docs/RELEASE_CHECKLIST.md +116 -12
- package/docs/SECURITY_REVIEW.md +71 -0
- package/docs/SELF_HOSTED_TESTS.md +121 -0
- package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
- package/docs/TEST_INTELLIGENCE.md +29 -0
- package/docs/TEST_PRUNING.md +14 -0
- package/docs/TROUBLESHOOTING.md +198 -1
- package/docs/UNIVERSAL_INTEGRATION.md +31 -0
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
- package/docs/diagrams/README.md +13 -9
- package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
- package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
- package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
- package/docs/documentation-manifest.json +774 -16
- package/docs/protocol-requirements.json +24 -0
- package/package.json +43 -11
- package/schemas/config.schema.json +14 -0
- package/schemas/context-plan.schema.json +18 -0
- package/schemas/semantic-decision.schema.json +46 -0
- package/schemas/task-bundle.schema.json +7 -2
- package/schemas/test-utility.schema.json +44 -0
- package/scripts/CI_VALIDATORS.md +6 -6
- package/scripts/benchmark-jev.mjs +5 -0
- package/scripts/benchmark-test-intelligence.mjs +4 -0
- package/scripts/generate-agent-protocol-summary.mjs +6 -3
- package/scripts/generate-forgeloop-skill.mjs +133 -0
- package/scripts/jev-smoke.mjs +19 -0
- package/scripts/run-mcp-clean-tests.mjs +30 -0
- package/skills/forgeloop/README.md +9 -0
- package/skills/forgeloop/SKILL.md +77 -0
- package/skills/forgeloop/references/lifecycle.md +9 -0
- package/skills/forgeloop/references/recovery.md +7 -0
- package/skills/forgeloop/references/verification.md +7 -0
- package/src/adapters/agent-browser/assertions.js +47 -0
- package/src/adapters/agent-browser/commands.js +54 -0
- package/src/adapters/agent-browser/index.js +3 -0
- package/src/adapters/agent-browser/locator.js +40 -0
- package/src/adapters/agent-browser/process.js +215 -0
- package/src/adapters/agent-browser/provider.js +316 -0
- package/src/adapters/emulated-services/constants.js +24 -0
- package/src/adapters/emulated-services/index.js +7 -0
- package/src/adapters/emulated-services/process.js +162 -0
- package/src/adapters/emulated-services/provider.js +289 -0
- package/src/adapters/opensrc/normalize.js +90 -0
- package/src/adapters/opensrc/process.js +248 -0
- package/src/adapters/opensrc/provider.js +338 -0
- package/src/adapters/opensrc/search.js +264 -0
- package/src/adapters/temporary-paths.js +18 -0
- package/src/adapters/typesafe/client.js +28 -0
- package/src/adapters/typesafe/engine.js +63 -0
- package/src/adapters/typesafe/normalize.js +41 -0
- package/src/cli.js +218 -174
- package/src/commands/action-show.js +5 -2
- package/src/commands/advance.js +5 -1
- package/src/commands/baseline.js +13 -11
- package/src/commands/checkpoint-revalidate.js +192 -0
- package/src/commands/complete.js +19 -3
- package/src/commands/context-plan.js +38 -0
- package/src/commands/contract-create.js +266 -0
- package/src/commands/contract-revise.js +236 -0
- package/src/commands/decision-show.js +14 -0
- package/src/commands/decision-status.js +22 -0
- package/src/commands/discover.js +41 -0
- package/src/commands/doctor.js +51 -13
- package/src/commands/gate-record.js +194 -0
- package/src/commands/gate-revalidate.js +135 -0
- package/src/commands/handoff-list.js +6 -1
- package/src/commands/handoff-show.js +6 -1
- package/src/commands/migrate-protocol.js +2 -2
- package/src/commands/model-route.js +40 -0
- package/src/commands/next.js +7 -1
- package/src/commands/policy-diff.js +25 -4
- package/src/commands/progress.js +17 -11
- package/src/commands/record-diagnosis.js +3 -0
- package/src/commands/route.js +146 -18
- package/src/commands/semantic-plan.js +41 -0
- package/src/commands/status.js +6 -1
- package/src/commands/storage-backup.js +15 -0
- package/src/commands/storage-migrate.js +5 -0
- package/src/commands/storage-migration-resume.js +5 -0
- package/src/commands/storage-migration-status.js +44 -0
- package/src/commands/storage-restore-resume.js +7 -0
- package/src/commands/storage-restore.js +8 -0
- package/src/commands/task-abandon.js +224 -0
- package/src/commands/task-list.js +8 -43
- package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
- package/src/commands/task-migrate.js +3 -3
- package/src/commands/task-recover.js +10 -2
- package/src/commands/task-repair-contract-bootstrap.js +263 -0
- package/src/commands/task-scope.js +18 -2
- package/src/commands/task-show.js +16 -2
- package/src/commands/test-inventory.js +5 -0
- package/src/commands/test-prune-plan.js +5 -0
- package/src/commands/test-prune-probe.js +5 -0
- package/src/commands/test-utility.js +5 -0
- package/src/commands/validate-protocol.js +39 -15
- package/src/commands/validate-receipt.js +8 -1
- package/src/config/guides.json +4 -0
- package/src/core/action-ledger-projection.js +10 -3
- package/src/core/actions.js +38 -75
- package/src/core/activation.js +11 -3
- package/src/core/approvals.js +17 -51
- package/src/core/artifact-registry.js +83 -2
- package/src/core/artifacts.js +81 -27
- package/src/core/attachment-paths.js +45 -0
- package/src/core/attestation-coverage.js +6 -1
- package/src/core/attestation-verifier.js +21 -2
- package/src/core/attestation.js +17 -6
- package/src/core/audit-ux.js +514 -0
- package/src/core/audit.js +6 -1
- package/src/core/browser-verification/constants.js +149 -0
- package/src/core/browser-verification/normalize.js +254 -0
- package/src/core/browser-verification/provider.js +519 -0
- package/src/core/browser-verification/service.js +115 -0
- package/src/core/bundles.js +160 -66
- package/src/core/checkpoint-revalidation.js +321 -0
- package/src/core/cli-command-definitions.js +350 -7
- package/src/core/code-manifest.js +9 -3
- package/src/core/command-executors.js +274 -108
- package/src/core/command-input.js +136 -44
- package/src/core/completion-artifacts.js +85 -34
- package/src/core/completion-ownership.js +19 -8
- package/src/core/completion-recovery-rebind.js +11 -1
- package/src/core/completion.js +64 -15
- package/src/core/config.js +3 -0
- package/src/core/conformance.js +2 -1
- package/src/core/context-compiler/budget.js +9 -0
- package/src/core/context-compiler/candidates.js +39 -0
- package/src/core/context-compiler/compiler.js +63 -0
- package/src/core/context-compiler/fingerprint.js +11 -0
- package/src/core/context-compiler/policy.js +13 -0
- package/src/core/context-compiler/result.js +23 -0
- package/src/core/continuity-lint.js +13 -2
- package/src/core/continuity-reconciliation.js +16 -3
- package/src/core/continuity.js +16 -8
- package/src/core/contract-bootstrap-recovery.js +656 -0
- package/src/core/contract-revision.js +209 -0
- package/src/core/decision/artifact.js +70 -0
- package/src/core/decision/benchmarks.js +103 -0
- package/src/core/decision/cache.js +27 -0
- package/src/core/decision/constants.js +58 -0
- package/src/core/decision/cutover.js +34 -0
- package/src/core/decision/engine.js +22 -0
- package/src/core/decision/errors.js +68 -0
- package/src/core/decision/events.js +104 -0
- package/src/core/decision/freshness.js +19 -0
- package/src/core/decision/normalizers/index.js +115 -0
- package/src/core/decision/policy.js +18 -0
- package/src/core/decision/projection.js +16 -0
- package/src/core/decision/question-registry.js +201 -0
- package/src/core/decision/request.js +26 -0
- package/src/core/decision/resolver.js +138 -0
- package/src/core/decision/result.js +58 -0
- package/src/core/decision/service.js +181 -0
- package/src/core/decision/state-builder.js +65 -0
- package/src/core/decision/task-bindings.js +35 -0
- package/src/core/decision/test-provider.js +32 -0
- package/src/core/decision/thresholds.js +15 -0
- package/src/core/diagnosis-model.js +11 -0
- package/src/core/diagnosis.js +10 -1
- package/src/core/diagnostic-projection.js +29 -12
- package/src/core/diagnostic-record.js +28 -3
- package/src/core/efficiency.js +6 -1
- package/src/core/error-codes.js +278 -0
- package/src/core/events.js +535 -147
- package/src/core/evidence-readiness.js +9 -0
- package/src/core/execution-prerequisites.js +36 -13
- package/src/core/execution-profile.js +63 -38
- package/src/core/execution.js +26 -40
- package/src/core/filesystem.js +11 -0
- package/src/core/gate-artifact.js +105 -19
- package/src/core/gate-provenance.js +125 -0
- package/src/core/handoff.js +26 -14
- package/src/core/history.js +39 -35
- package/src/core/hypothesis-projection.js +32 -0
- package/src/core/information-gain-projection.js +104 -100
- package/src/core/inspect.js +12 -3
- package/src/core/integration-invocation-policy.js +37 -4
- package/src/core/integration-resources.js +119 -87
- package/src/core/ledger-event-collection.js +189 -0
- package/src/core/ledger-relations.js +23 -0
- package/src/core/model-router/constants.js +10 -0
- package/src/core/model-router/policy.js +103 -0
- package/src/core/model-router/router.js +37 -0
- package/src/core/native-storage.js +12 -0
- package/src/core/next-action-continuity.js +31 -9
- package/src/core/next-action-model.js +58 -0
- package/src/core/next-action-phases.js +131 -43
- package/src/core/next-action-refresh.js +43 -9
- package/src/core/next-action-review-phase.js +9 -4
- package/src/core/next-action-verification-phase.js +2 -1
- package/src/core/next-action.js +56 -9
- package/src/core/phase.js +266 -103
- package/src/core/policy-engine.js +12 -13
- package/src/core/preflight-consistency.js +89 -62
- package/src/core/preflight-loaders.js +48 -9
- package/src/core/preflight-model.js +6 -1
- package/src/core/preflight.js +29 -12
- package/src/core/progress.js +21 -10
- package/src/core/protocol-info.js +68 -0
- package/src/core/protocol-migration.js +7 -6
- package/src/core/protocol.js +20 -0
- package/src/core/reconcile-closure.js +281 -67
- package/src/core/recovery-history.js +67 -47
- package/src/core/reflection.js +72 -77
- package/src/core/responsibility.js +25 -13
- package/src/core/resumability.js +154 -44
- package/src/core/route-artifact.js +28 -4
- package/src/core/router.js +67 -1
- package/src/core/runtime-context.js +123 -61
- package/src/core/schema-validation.js +11 -3
- package/src/core/security-review/constants.js +64 -0
- package/src/core/security-review/normalize.js +245 -0
- package/src/core/security-review/provider.js +204 -0
- package/src/core/security-review/service.js +134 -0
- package/src/core/semantic-planning/constants.js +19 -0
- package/src/core/semantic-planning/projection.js +94 -0
- package/src/core/semantic-planning/service.js +15 -0
- package/src/core/settlement.js +12 -1
- package/src/core/signing/bundle-file.js +53 -0
- package/src/core/signing/bundle-reference.js +15 -0
- package/src/core/signing/sigstore.js +60 -33
- package/src/core/signing/statement-file.js +27 -0
- package/src/core/sources.js +37 -0
- package/src/core/storage-runtime-registry.js +41 -0
- package/src/core/structural-quality/artifacts.js +20 -14
- package/src/core/structural-quality/service.js +81 -56
- package/src/core/target-layout.js +1 -1
- package/src/core/task-claim-state.js +249 -15
- package/src/core/task-command.js +21 -1
- package/src/core/task-conflict-inspection.js +133 -102
- package/src/core/task-descriptor.js +29 -22
- package/src/core/task-discovery.js +288 -90
- package/src/core/task-lock.js +66 -306
- package/src/core/task-migration-validation.js +5 -5
- package/src/core/task-migration.js +17 -287
- package/src/core/task-paths.js +13 -0
- package/src/core/task-recovery.js +1 -0
- package/src/core/task-snapshot.js +51 -8
- package/src/core/task-storage-migration.js +18 -0
- package/src/core/templates.js +23 -8
- package/src/core/test-intelligence/benchmarks.js +68 -0
- package/src/core/test-intelligence/inventory.js +73 -0
- package/src/core/test-intelligence/prune.js +94 -0
- package/src/core/test-intelligence/semantic-state.js +15 -0
- package/src/core/test-intelligence/service.js +40 -0
- package/src/core/test-intelligence/utility.js +50 -0
- package/src/core/trace.js +164 -105
- package/src/core/trajectory-evaluation.js +15 -3
- package/src/core/trajectory-metrics.js +47 -32
- package/src/core/transaction.js +16 -287
- package/src/core/verification-scope.js +20 -12
- package/src/core/work-state.js +100 -59
- package/src/integration.d.ts +492 -0
- package/src/integration.js +54 -0
- package/src/providers/README.md +47 -0
- package/src/providers/capabilities.js +46 -0
- package/src/providers/errors.js +15 -0
- package/src/providers/index.js +29 -0
- package/src/providers/json-snapshot.js +105 -0
- package/src/providers/registry.js +152 -0
- package/src/repository-index/binary-manager.js +7 -5
- package/src/storage/artifact-bytes.js +22 -0
- package/src/storage/attachment-binding.js +11 -0
- package/src/storage/attachment-files.js +82 -0
- package/src/storage/attachment-references.js +36 -0
- package/src/storage/backup.js +53 -0
- package/src/storage/capabilities.js +31 -0
- package/src/storage/connection-owner.js +119 -0
- package/src/storage/connection.js +376 -0
- package/src/storage/existing-project-scope.js +45 -0
- package/src/storage/export-destination.js +44 -0
- package/src/storage/exporter.js +284 -0
- package/src/storage/file-durability.js +46 -0
- package/src/storage/importer.js +461 -0
- package/src/storage/index.js +74 -0
- package/src/storage/leases.js +63 -0
- package/src/storage/ledger-event-snapshot.js +150 -0
- package/src/storage/ledger-relations.js +220 -0
- package/src/storage/legacy-maintenance-boundary.js +18 -0
- package/src/storage/legacy-signature.js +115 -0
- package/src/storage/maintenance-handoff.js +129 -0
- package/src/storage/maintenance-owner.js +42 -0
- package/src/storage/maintenance.js +310 -0
- package/src/storage/metadata-json.js +35 -0
- package/src/storage/migration-activate.js +59 -0
- package/src/storage/migration-archive.js +57 -0
- package/src/storage/migration-attachment-root.js +61 -0
- package/src/storage/migration-candidate.js +398 -0
- package/src/storage/migration-publication.js +143 -0
- package/src/storage/migration-rollback-admission.js +54 -0
- package/src/storage/migration-rollback-preparation.js +132 -0
- package/src/storage/migration-rollback-publication.js +183 -0
- package/src/storage/migration-rollback-release.js +66 -0
- package/src/storage/migration-rollback-source-stage.js +103 -0
- package/src/storage/migration-rollback.js +43 -0
- package/src/storage/migration-source-partition.js +56 -0
- package/src/storage/migration-source.js +255 -0
- package/src/storage/migration-terminal.js +39 -0
- package/src/storage/migration-validation.js +75 -0
- package/src/storage/migration.js +43 -0
- package/src/storage/operational-attachments.js +49 -0
- package/src/storage/operational-context.js +50 -0
- package/src/storage/project-backup.js +98 -0
- package/src/storage/project-bootstrap.js +24 -0
- package/src/storage/project-boundary.js +79 -0
- package/src/storage/project-read-snapshot.js +18 -0
- package/src/storage/project-replacement.js +137 -0
- package/src/storage/project-restore.js +203 -0
- package/src/storage/record-definitions.js +45 -0
- package/src/storage/repository.js +507 -0
- package/src/storage/restore-journal.js +62 -0
- package/src/storage/restore-layout.js +30 -0
- package/src/storage/restore-preparation.js +84 -0
- package/src/storage/restore-replacement-archive.js +162 -0
- package/src/storage/restore-replacement-owner.js +31 -0
- package/src/storage/restore-replacement-preparation.js +128 -0
- package/src/storage/restore-replacement.js +142 -0
- package/src/storage/restore-terminal.js +32 -0
- package/src/storage/runtime.js +31 -0
- package/src/storage/schema.js +214 -0
- package/src/storage/singleton-import.js +84 -0
- package/src/storage/snapshot-continuity.js +16 -0
- package/src/storage/snapshot.js +36 -0
- package/src/storage/storage-marker.js +79 -0
- package/src/storage/task-guards.js +107 -0
- package/src/storage/topology.js +42 -0
- package/src/storage/transaction.js +179 -0
- package/src/storage/unit-of-work.js +663 -0
- package/src/storage/windows-process-incarnation.js +206 -0
- package/.forgeloop/forgeloop.gitignore +0 -4
- package/LICENSE-DOCS.md +0 -13
- package/src/core/transaction-maintenance.js +0 -70
package/src/core/phase.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
LIFECYCLE_MILESTONES,
|
|
6
6
|
validateEventLedger,
|
|
7
7
|
validateStateLedgerCoherence,
|
|
8
|
+
isRevisionEpochPlanRepeat,
|
|
8
9
|
} from "./events.js";
|
|
9
10
|
import { readPersistedRoute } from "./route-artifact.js";
|
|
10
11
|
import { assertWorkPhase, isValidTransition } from "./protocol.js";
|
|
@@ -13,7 +14,7 @@ import { authorizeCompletionRecoveryOrRebind } from "./completion-recovery-rebin
|
|
|
13
14
|
import { evaluateCompletion, runComplete as persistCompletion } from "./completion.js";
|
|
14
15
|
import { evaluatePreflight } from "./preflight.js";
|
|
15
16
|
import { requiredEvidenceForTarget } from "./completion-artifacts.js";
|
|
16
|
-
import { assertCompletionRelationships, assertStateIdentity } from "./completion-relationships.js";
|
|
17
|
+
import { assertCompletionRelationships, assertStateIdentity, stateIdentityErrors } from "./completion-relationships.js";
|
|
17
18
|
import { createReceipt, validateReceipt } from "./receipt.js";
|
|
18
19
|
import { assertExecutionPrerequisites, hasExecutionStarted } from "./execution-prerequisites.js";
|
|
19
20
|
import { taskArtifactPath } from "./task-paths.js";
|
|
@@ -27,6 +28,13 @@ import {
|
|
|
27
28
|
evaluateStructuredDiagnosticStall,
|
|
28
29
|
} from "./information-gain-projection.js";
|
|
29
30
|
import { assertStructuralQualityExecutionReady } from "./structural-quality/service.js";
|
|
31
|
+
import { getTaskTransaction, withTaskTransaction } from "./transaction.js";
|
|
32
|
+
import {
|
|
33
|
+
CONTRACT_BOOTSTRAP_REPAIR_EVENT,
|
|
34
|
+
ROUTE_CHECKPOINT_BOUND_EVENT,
|
|
35
|
+
resolveCanonicalPostRepairCheckpointBinding,
|
|
36
|
+
sameCanonicalGuideList,
|
|
37
|
+
} from "./contract-bootstrap-recovery.js";
|
|
30
38
|
|
|
31
39
|
function phaseError(code, message, artifacts = []) {
|
|
32
40
|
const error = new Error(message);
|
|
@@ -55,44 +63,135 @@ const LATE_PHASES = new Set([
|
|
|
55
63
|
"COMPLETE",
|
|
56
64
|
]);
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Pure prerequisite for the `DIAGNOSING -> CORRECTING` edge.
|
|
68
|
+
*
|
|
69
|
+
* Extracted so the filesystem advance and the SQLite store advance enforce the
|
|
70
|
+
* identical rule through one owner. The store implementation must not restate
|
|
71
|
+
* this; it calls this function with its own loaded evidence.
|
|
72
|
+
*
|
|
73
|
+
* Throws `E_DIAGNOSIS_REQUIRED` when no append-only diagnosis exists for the
|
|
74
|
+
* active verification cycle, and `E_DIAGNOSIS_NO_NEW_INFORMATION` when the
|
|
75
|
+
* diagnosis carries no new information.
|
|
76
|
+
*/
|
|
77
|
+
export function assertDiagnosingToCorrectingTransition({ state, events, resolveDiagnosis }) {
|
|
78
|
+
const cycle = state?.verificationCycle ?? 1;
|
|
79
|
+
const diagEvent = resolveDiagnosis(events, state?.taskId, cycle);
|
|
80
|
+
if (!diagEvent) {
|
|
81
|
+
throw phaseError(
|
|
82
|
+
"E_DIAGNOSIS_REQUIRED",
|
|
83
|
+
"DIAGNOSING -> CORRECTING requires an append-only diagnosis record for the active verification cycle",
|
|
84
|
+
[],
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const structured = diagEvent.sourceModel === "STRUCTURED_DIAGNOSTIC_CASE_V1";
|
|
88
|
+
const gainClassification = structured ? null : diagEvent.details?.informationGain;
|
|
89
|
+
if (!diagEvent.details || (structured ? false : gainClassification === "NONE")) {
|
|
90
|
+
throw phaseError(
|
|
91
|
+
"E_DIAGNOSIS_NO_NEW_INFORMATION",
|
|
92
|
+
"The proposed retry repeats the previous hypothesis with the same evidence without new information",
|
|
93
|
+
[],
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return diagEvent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function readPhaseIdentityArtifacts(target, state, toPhase, packageRoot, options, paths) {
|
|
59
100
|
const scopedTaskId = options.taskId ?? null;
|
|
60
101
|
const requireContract = LATE_PHASES.has(state.phase)
|
|
61
102
|
|| ["CONTRACT_READY", "ROUTED", "EXECUTING"].includes(toPhase);
|
|
62
|
-
const requireRoute =
|
|
103
|
+
const requireRoute = state.phase === "ROUTED"
|
|
104
|
+
|| LATE_PHASES.has(state.phase)
|
|
63
105
|
|| ["ROUTED", "EXECUTING"].includes(toPhase);
|
|
64
|
-
const contractRel = options.contractPath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "contract") : ARTIFACT_PATHS.contract);
|
|
65
|
-
const routeRel = options.routePath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "route") : ARTIFACT_PATHS.route);
|
|
66
|
-
|
|
67
106
|
let contract = null;
|
|
68
107
|
let route = null;
|
|
69
108
|
try {
|
|
70
109
|
contract = await readContract(target, packageRoot, { taskId: scopedTaskId, contractPath: options.contractPath });
|
|
71
110
|
} catch (error) {
|
|
111
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
72
112
|
if (error.code === "ARTIFACT_MISSING" && !requireContract) {
|
|
73
113
|
contract = null;
|
|
74
114
|
} else {
|
|
75
115
|
throw phaseError(
|
|
76
116
|
requireContract ? "E_PHASE_PREREQUISITE_MISSING" : error.code ?? "E_CONTRACT_INVALID",
|
|
77
117
|
`${requireContract ? `Phase ${toPhase} requires current contract` : "Unable to validate current contract"}: ${error.message}`,
|
|
78
|
-
[contractRel],
|
|
118
|
+
[paths.contractRel],
|
|
79
119
|
);
|
|
80
120
|
}
|
|
81
121
|
}
|
|
82
122
|
try {
|
|
83
123
|
route = await readPersistedRoute(target, packageRoot, { taskId: scopedTaskId, routePath: options.routePath });
|
|
84
124
|
} catch (error) {
|
|
125
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
85
126
|
if (error.code === "ARTIFACT_MISSING" && !requireRoute) {
|
|
86
127
|
route = null;
|
|
87
128
|
} else {
|
|
88
129
|
throw phaseError(
|
|
89
130
|
requireRoute ? "E_PHASE_PREREQUISITE_MISSING" : error.code ?? "E_ROUTE_INVALID",
|
|
90
131
|
`${requireRoute ? `Phase ${toPhase} requires persisted route` : "Unable to validate persisted route"}: ${error.message}`,
|
|
91
|
-
[routeRel],
|
|
132
|
+
[paths.routeRel],
|
|
92
133
|
);
|
|
93
134
|
}
|
|
94
135
|
}
|
|
136
|
+
return { contract, route };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function assertRepairedCheckpointIdentity({ contract, route, state, events, contractRel, routeRel, stateRel }) {
|
|
140
|
+
const repairMarker = events.find((event) => event.event === CONTRACT_BOOTSTRAP_REPAIR_EVENT);
|
|
141
|
+
if (!repairMarker || state.phase === "ROUTED") return false;
|
|
142
|
+
const checkpoint = resolveCanonicalPostRepairCheckpointBinding(events, repairMarker);
|
|
143
|
+
if (!checkpoint) {
|
|
144
|
+
throw phaseError(
|
|
145
|
+
"E_PHASE_CHRONOLOGY_INVALID",
|
|
146
|
+
"Repaired late-phase state requires a canonical route checkpoint binding",
|
|
147
|
+
[contractRel, routeRel],
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const identityErrors = [
|
|
151
|
+
...stateIdentityErrors({ contract, state }),
|
|
152
|
+
...stateIdentityErrors({ contract, route }),
|
|
153
|
+
];
|
|
154
|
+
if (state.routeFingerprint !== checkpoint.routeFingerprint
|
|
155
|
+
|| !sameCanonicalGuideList(state.selectedGuides, checkpoint.selectedGuides)) {
|
|
156
|
+
identityErrors.push({
|
|
157
|
+
code: "E_ROUTE_GUIDE_MISMATCH",
|
|
158
|
+
message: "Work state does not match the immutable route checkpoint identity",
|
|
159
|
+
artifacts: [routeRel, stateRel],
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (identityErrors.length > 0) {
|
|
163
|
+
const first = identityErrors[0];
|
|
164
|
+
throw phaseError(first.code, first.message, first.artifacts);
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function assertPersistedStateIdentity(target, state, toPhase, packageRoot, options = {}) {
|
|
170
|
+
const scopedTaskId = options.taskId ?? null;
|
|
171
|
+
const events = options.events ?? [];
|
|
172
|
+
const contractRel = options.contractPath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "contract") : ARTIFACT_PATHS.contract);
|
|
173
|
+
const routeRel = options.routePath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "route") : ARTIFACT_PATHS.route);
|
|
174
|
+
const stateRel = options.statePath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "state") : ARTIFACT_PATHS.state);
|
|
175
|
+
const { contract, route } = await readPhaseIdentityArtifacts(
|
|
176
|
+
target,
|
|
177
|
+
state,
|
|
178
|
+
toPhase,
|
|
179
|
+
packageRoot,
|
|
180
|
+
options,
|
|
181
|
+
{ contractRel, routeRel },
|
|
182
|
+
);
|
|
95
183
|
if (!contract && !route) return;
|
|
184
|
+
if (toPhase !== "ROUTED" && assertRepairedCheckpointIdentity({
|
|
185
|
+
contract,
|
|
186
|
+
route,
|
|
187
|
+
state,
|
|
188
|
+
events,
|
|
189
|
+
contractRel,
|
|
190
|
+
routeRel,
|
|
191
|
+
stateRel,
|
|
192
|
+
})) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
96
195
|
try {
|
|
97
196
|
assertStateIdentity({ contract, route, state });
|
|
98
197
|
} catch (error) {
|
|
@@ -116,24 +215,29 @@ function reconcileImplementationStep(state, toPhase) {
|
|
|
116
215
|
};
|
|
117
216
|
}
|
|
118
217
|
|
|
218
|
+
function isRevisionPlanRepeat(events, eventType) {
|
|
219
|
+
return eventType === "PLAN_RECORDED"
|
|
220
|
+
&& isRevisionEpochPlanRepeat(events, events.length, { event: eventType });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function assertRequiredPhaseArtifact(read, toPhase, relativePath) {
|
|
224
|
+
try { await read(); }
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
227
|
+
throw phaseError("E_PHASE_PREREQUISITE_MISSING", `Phase ${toPhase} requires ${relativePath}: ${error.message}`, [relativePath]);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
119
231
|
async function assertPhasePrerequisites(target, state, toPhase, packageRoot, authorityContext, runtimeContext, options = {}) {
|
|
120
232
|
const scopedTaskId = options.taskId ?? null;
|
|
121
233
|
const contractRel = options.contractPath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "contract") : ARTIFACT_PATHS.contract);
|
|
122
234
|
const routeRel = options.routePath ?? (scopedTaskId ? taskArtifactPath(scopedTaskId, "route") : ARTIFACT_PATHS.route);
|
|
123
235
|
|
|
124
236
|
if (toPhase === "CONTRACT_READY" || toPhase === "ROUTED" || toPhase === "EXECUTING") {
|
|
125
|
-
|
|
126
|
-
await readContract(target, packageRoot, { taskId: scopedTaskId, contractPath: options.contractPath });
|
|
127
|
-
} catch (error) {
|
|
128
|
-
throw phaseError("E_PHASE_PREREQUISITE_MISSING", `Phase ${toPhase} requires ${contractRel}: ${error.message}`, [contractRel]);
|
|
129
|
-
}
|
|
237
|
+
await assertRequiredPhaseArtifact(() => readContract(target, packageRoot, { taskId: scopedTaskId, contractPath: options.contractPath }), toPhase, contractRel);
|
|
130
238
|
}
|
|
131
239
|
if (toPhase === "ROUTED" || toPhase === "EXECUTING") {
|
|
132
|
-
|
|
133
|
-
await readPersistedRoute(target, packageRoot, { taskId: scopedTaskId, routePath: options.routePath });
|
|
134
|
-
} catch (error) {
|
|
135
|
-
throw phaseError("E_PHASE_PREREQUISITE_MISSING", `Phase ${toPhase} requires ${routeRel}: ${error.message}`, [routeRel]);
|
|
136
|
-
}
|
|
240
|
+
await assertRequiredPhaseArtifact(() => readPersistedRoute(target, packageRoot, { taskId: scopedTaskId, routePath: options.routePath }), toPhase, routeRel);
|
|
137
241
|
}
|
|
138
242
|
if (toPhase === "EXECUTING" && scopedTaskId) {
|
|
139
243
|
try {
|
|
@@ -146,6 +250,7 @@ async function assertPhasePrerequisites(target, state, toPhase, packageRoot, aut
|
|
|
146
250
|
try {
|
|
147
251
|
await assertExecutionPrerequisites({ target, state, packageRoot, ...options, taskId: scopedTaskId, runtimeContext });
|
|
148
252
|
} catch (error) {
|
|
253
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
149
254
|
throw phaseError(error.code, error.message, error.artifacts);
|
|
150
255
|
}
|
|
151
256
|
}
|
|
@@ -160,8 +265,106 @@ async function assertPhasePrerequisites(target, state, toPhase, packageRoot, aut
|
|
|
160
265
|
}
|
|
161
266
|
}
|
|
162
267
|
|
|
268
|
+
async function appendRepairRouteCheckpoint({ target, packageRoot, taskId, state, events, stateRel, eventsRel }) {
|
|
269
|
+
const repairMarker = events.find((event) => event.event === CONTRACT_BOOTSTRAP_REPAIR_EVENT);
|
|
270
|
+
const checkpointAlreadyBound = events.some((event) => event.event === ROUTE_CHECKPOINT_BOUND_EVENT);
|
|
271
|
+
if (!repairMarker || state.phase !== "ROUTED" || checkpointAlreadyBound) return;
|
|
272
|
+
if (typeof state.routeFingerprint !== "string") {
|
|
273
|
+
throw phaseError("E_ROUTE_GUIDE_MISMATCH", "ROUTED state requires a route fingerprint before checkpoint binding", [stateRel, eventsRel]);
|
|
274
|
+
}
|
|
275
|
+
await appendProtocolEvent(target, {
|
|
276
|
+
taskId: state.taskId,
|
|
277
|
+
event: ROUTE_CHECKPOINT_BOUND_EVENT,
|
|
278
|
+
details: {
|
|
279
|
+
routeFingerprint: state.routeFingerprint,
|
|
280
|
+
contractFingerprint: state.contractFingerprint,
|
|
281
|
+
selectedGuides: [...state.selectedGuides].sort(),
|
|
282
|
+
},
|
|
283
|
+
}, packageRoot, { taskId, eventsPath: eventsRel });
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Shared receipt refresh used by phase advancement on either storage source. */
|
|
287
|
+
export async function preparePhaseReceipt({ target, packageRoot, taskId, state, next, receiptRel, contractPath = null, routePath = null, statePath = null, authorityContext, runtimeContext, readers = null }) {
|
|
288
|
+
let nextReceipt = null;
|
|
289
|
+
try {
|
|
290
|
+
const receipt = await (readers?.readReceipt ?? readJsonArtifact)(target, receiptRel, "execution-receipt", packageRoot);
|
|
291
|
+
const contract = await (readers?.readContract ?? readContract)(target, packageRoot, { taskId, contractPath });
|
|
292
|
+
const route = await (readers?.readRoute ?? readPersistedRoute)(target, packageRoot, { taskId, routePath });
|
|
293
|
+
const preflight = await evaluatePreflight({ target, packageRoot, taskId, contractPath, routePath, statePath, readers });
|
|
294
|
+
const requiredEvidence = await requiredEvidenceForTarget({
|
|
295
|
+
target,
|
|
296
|
+
contract,
|
|
297
|
+
route,
|
|
298
|
+
packageRoot,
|
|
299
|
+
additionalEvidence: preflight.policy?.requiredEvidence ?? [],
|
|
300
|
+
});
|
|
301
|
+
await validateReceipt(receipt.value, packageRoot, {
|
|
302
|
+
target,
|
|
303
|
+
taskId: contract?.value?.taskId,
|
|
304
|
+
authorityContext,
|
|
305
|
+
runtimeContext,
|
|
306
|
+
});
|
|
307
|
+
assertCompletionRelationships({
|
|
308
|
+
contract,
|
|
309
|
+
route,
|
|
310
|
+
state,
|
|
311
|
+
receipt: receipt.value,
|
|
312
|
+
requiredEvidence,
|
|
313
|
+
requireRequiredChecks: false,
|
|
314
|
+
requireReceiptStateFingerprint: false,
|
|
315
|
+
target,
|
|
316
|
+
taskId: contract?.value?.taskId,
|
|
317
|
+
authorityContext,
|
|
318
|
+
runtimeContext,
|
|
319
|
+
});
|
|
320
|
+
nextReceipt = await createReceipt({
|
|
321
|
+
...receipt.value,
|
|
322
|
+
stateFingerprint: canonicalFingerprint(next),
|
|
323
|
+
verificationCycle: next.verificationCycle ?? receipt.value.verificationCycle ?? 1,
|
|
324
|
+
}, packageRoot, {
|
|
325
|
+
target,
|
|
326
|
+
taskId: contract?.value?.taskId,
|
|
327
|
+
authorityContext,
|
|
328
|
+
runtimeContext,
|
|
329
|
+
});
|
|
330
|
+
assertCompletionRelationships({
|
|
331
|
+
contract,
|
|
332
|
+
route,
|
|
333
|
+
state: next,
|
|
334
|
+
receipt: nextReceipt,
|
|
335
|
+
requiredEvidence,
|
|
336
|
+
requireRequiredChecks: false,
|
|
337
|
+
target,
|
|
338
|
+
taskId: contract?.value?.taskId,
|
|
339
|
+
authorityContext,
|
|
340
|
+
runtimeContext,
|
|
341
|
+
});
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (error.code !== "ARTIFACT_MISSING") throw error;
|
|
344
|
+
}
|
|
345
|
+
return nextReceipt;
|
|
346
|
+
}
|
|
347
|
+
|
|
163
348
|
export async function advanceWorkState(target, toPhase, options = {}) {
|
|
164
|
-
|
|
349
|
+
assertWorkPhase(toPhase);
|
|
350
|
+
let normalizedOptions = typeof options === "string" ? { packageRoot: options } : options;
|
|
351
|
+
if (!normalizedOptions.taskId) {
|
|
352
|
+
const state = await readWorkState(target, normalizedOptions);
|
|
353
|
+
normalizedOptions = { ...normalizedOptions, taskId: state?.taskId };
|
|
354
|
+
}
|
|
355
|
+
if (!normalizedOptions.taskId || await getTaskTransaction(target)) {
|
|
356
|
+
return advanceWorkStateInternal(target, toPhase, normalizedOptions);
|
|
357
|
+
}
|
|
358
|
+
return withTaskTransaction({
|
|
359
|
+
target,
|
|
360
|
+
taskId: normalizedOptions.taskId,
|
|
361
|
+
operation: "advance",
|
|
362
|
+
packageRoot: normalizedOptions.packageRoot,
|
|
363
|
+
recordCommitEvent: true,
|
|
364
|
+
}, async () => advanceWorkStateInternal(target, toPhase, normalizedOptions));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function advanceWorkStateInternal(target, toPhase, normalizedOptions) {
|
|
165
368
|
const {
|
|
166
369
|
packageRoot,
|
|
167
370
|
now = new Date().toISOString(),
|
|
@@ -174,8 +377,6 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
174
377
|
receiptPath = null,
|
|
175
378
|
eventsPath = null,
|
|
176
379
|
} = normalizedOptions;
|
|
177
|
-
assertWorkPhase(toPhase);
|
|
178
|
-
|
|
179
380
|
let state = await readWorkState(target, { packageRoot, taskId, statePath });
|
|
180
381
|
const stateRel = statePath ?? (taskId ? taskArtifactPath(taskId, "state") : ARTIFACT_PATHS.state);
|
|
181
382
|
if (!state) throw phaseError("E_PHASE_PREREQUISITE_MISSING", "Cannot advance without work state", [stateRel]);
|
|
@@ -211,7 +412,6 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
211
412
|
}
|
|
212
413
|
|
|
213
414
|
await assertPhasePrerequisites(target, state, toPhase, packageRoot, authorityContext, runtimeContext, { taskId, statePath, contractPath, routePath, receiptPath, eventsPath });
|
|
214
|
-
await assertPersistedStateIdentity(target, state, toPhase, packageRoot, { taskId, contractPath, routePath });
|
|
215
415
|
|
|
216
416
|
if (toPhase === "EXECUTING" && taskId) {
|
|
217
417
|
// Multi-task checkout scope checks
|
|
@@ -259,6 +459,12 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
259
459
|
if (coherenceErrors.length > 0) {
|
|
260
460
|
throw phaseError(coherenceErrors[0].code, coherenceErrors[0].message, [stateRel, eventsRel]);
|
|
261
461
|
}
|
|
462
|
+
await assertPersistedStateIdentity(target, state, toPhase, packageRoot, {
|
|
463
|
+
taskId,
|
|
464
|
+
contractPath,
|
|
465
|
+
routePath,
|
|
466
|
+
events: ledger.events,
|
|
467
|
+
});
|
|
262
468
|
const eventType = PHASE_EVENTS[toPhase];
|
|
263
469
|
const reenteringVerification = toPhase === "VERIFYING" && ["CORRECTING", "REVIEWING"].includes(state.phase);
|
|
264
470
|
if (toPhase === "VERIFYING" && state.phase === "REVIEWING") {
|
|
@@ -287,35 +493,35 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
287
493
|
}
|
|
288
494
|
}
|
|
289
495
|
if (toPhase === "CORRECTING" && state.phase === "DIAGNOSING") {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
496
|
+
// Shared rule owner: the same pure prerequisite used by the SQLite store
|
|
497
|
+
// advance, so the two backends cannot drift on this edge.
|
|
498
|
+
let cycle = state.verificationCycle ?? 1;
|
|
499
|
+
let diagEvent;
|
|
500
|
+
try {
|
|
501
|
+
diagEvent = assertDiagnosingToCorrectingTransition({
|
|
502
|
+
state,
|
|
503
|
+
events: ledger.events,
|
|
504
|
+
resolveDiagnosis: resolveCurrentCycleDiagnostic,
|
|
505
|
+
});
|
|
506
|
+
} catch (error) {
|
|
507
|
+
throw phaseError(error.code, error.message, [eventsRel]);
|
|
298
508
|
}
|
|
299
|
-
|
|
509
|
+
cycle = state.verificationCycle ?? 1;
|
|
300
510
|
if (diagEvent.sourceModel === "STRUCTURED_DIAGNOSTIC_CASE_V1") {
|
|
301
|
-
//
|
|
511
|
+
// The shared rule intentionally omits the structured-stall evaluation,
|
|
512
|
+
// which depends on progress/reflect projections. Re-check it here so the
|
|
513
|
+
// filesystem behavior is unchanged.
|
|
302
514
|
const stall = evaluateStructuredDiagnosticStall(
|
|
303
515
|
buildInformationGainProjection(ledger.events, state.taskId),
|
|
304
516
|
{ verificationCycle: cycle },
|
|
305
517
|
);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|| (diagEvent.sourceModel !== "STRUCTURED_DIAGNOSTIC_CASE_V1" && gainClassification === "NONE")) {
|
|
314
|
-
throw phaseError(
|
|
315
|
-
"E_DIAGNOSIS_NO_NEW_INFORMATION",
|
|
316
|
-
"The proposed retry repeats the previous hypothesis with the same evidence without new information",
|
|
317
|
-
[eventsRel],
|
|
318
|
-
);
|
|
518
|
+
if (stall.stalled) {
|
|
519
|
+
throw phaseError(
|
|
520
|
+
"E_DIAGNOSIS_NO_NEW_INFORMATION",
|
|
521
|
+
"The proposed retry repeats the previous hypothesis with the same evidence without new information",
|
|
522
|
+
[eventsRel],
|
|
523
|
+
);
|
|
524
|
+
}
|
|
319
525
|
}
|
|
320
526
|
}
|
|
321
527
|
if (toPhase === "VERIFYING" && state.phase === "CORRECTING") {
|
|
@@ -338,11 +544,15 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
338
544
|
}
|
|
339
545
|
const repeatedReview = state.phase === "VERIFYING" && toPhase === "REVIEWING"
|
|
340
546
|
&& ledger.events.some((event) => event.taskId === state.taskId && event.event === "REVIEW_STARTED");
|
|
547
|
+
const revisionPlanRepeat = isRevisionPlanRepeat(ledger.events, eventType);
|
|
341
548
|
if (eventType && !reenteringVerification && !repeatedReview
|
|
549
|
+
&& !revisionPlanRepeat
|
|
342
550
|
&& ledger.events.some((event) => event.taskId === state.taskId && event.event === eventType)) {
|
|
343
551
|
throw phaseError("E_PHASE_CHRONOLOGY_INVALID", `Lifecycle milestone already exists: ${eventType}`, [eventsRel]);
|
|
344
552
|
}
|
|
345
|
-
const milestoneIndex = reenteringVerification || repeatedReview
|
|
553
|
+
const milestoneIndex = reenteringVerification || repeatedReview || revisionPlanRepeat
|
|
554
|
+
? -1
|
|
555
|
+
: LIFECYCLE_MILESTONES.indexOf(eventType);
|
|
346
556
|
if (milestoneIndex >= 0) {
|
|
347
557
|
const lastMilestone = ledger.events.reduce((last, event) => Math.max(last, LIFECYCLE_MILESTONES.indexOf(event.event)), -1);
|
|
348
558
|
if (lastMilestone !== milestoneIndex - 1) {
|
|
@@ -361,63 +571,16 @@ export async function advanceWorkState(target, toPhase, options = {}) {
|
|
|
361
571
|
}
|
|
362
572
|
if (reenteringVerification) delete next.lastCompletionAttempt;
|
|
363
573
|
next.revision = (state.revision ?? 0) + 1;
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
packageRoot,
|
|
375
|
-
additionalEvidence: preflight.policy?.requiredEvidence ?? [],
|
|
376
|
-
});
|
|
377
|
-
await validateReceipt(receipt.value, packageRoot, {
|
|
378
|
-
target,
|
|
379
|
-
taskId: contract?.value?.taskId,
|
|
380
|
-
authorityContext,
|
|
381
|
-
runtimeContext,
|
|
382
|
-
});
|
|
383
|
-
assertCompletionRelationships({
|
|
384
|
-
contract,
|
|
385
|
-
route,
|
|
386
|
-
state,
|
|
387
|
-
receipt: receipt.value,
|
|
388
|
-
requiredEvidence,
|
|
389
|
-
requireRequiredChecks: false,
|
|
390
|
-
requireReceiptStateFingerprint: false,
|
|
391
|
-
target,
|
|
392
|
-
taskId: contract?.value?.taskId,
|
|
393
|
-
authorityContext,
|
|
394
|
-
runtimeContext,
|
|
395
|
-
});
|
|
396
|
-
nextReceipt = await createReceipt({
|
|
397
|
-
...receipt.value,
|
|
398
|
-
stateFingerprint: canonicalFingerprint(next),
|
|
399
|
-
verificationCycle: next.verificationCycle ?? receipt.value.verificationCycle ?? 1,
|
|
400
|
-
}, packageRoot, {
|
|
401
|
-
target,
|
|
402
|
-
taskId: contract?.value?.taskId,
|
|
403
|
-
authorityContext,
|
|
404
|
-
runtimeContext,
|
|
405
|
-
});
|
|
406
|
-
assertCompletionRelationships({
|
|
407
|
-
contract,
|
|
408
|
-
route,
|
|
409
|
-
state: next,
|
|
410
|
-
receipt: nextReceipt,
|
|
411
|
-
requiredEvidence,
|
|
412
|
-
requireRequiredChecks: false,
|
|
413
|
-
target,
|
|
414
|
-
taskId: contract?.value?.taskId,
|
|
415
|
-
authorityContext,
|
|
416
|
-
runtimeContext,
|
|
417
|
-
});
|
|
418
|
-
} catch (error) {
|
|
419
|
-
if (error.code !== "ARTIFACT_MISSING") throw error;
|
|
420
|
-
}
|
|
574
|
+
await appendRepairRouteCheckpoint({
|
|
575
|
+
target,
|
|
576
|
+
packageRoot,
|
|
577
|
+
taskId,
|
|
578
|
+
state,
|
|
579
|
+
events: ledger.events,
|
|
580
|
+
stateRel,
|
|
581
|
+
eventsRel,
|
|
582
|
+
});
|
|
583
|
+
const nextReceipt = await preparePhaseReceipt({ target, packageRoot, taskId, state, next, receiptRel, contractPath, routePath, statePath, authorityContext, runtimeContext });
|
|
421
584
|
await mutateWorkState(target, {
|
|
422
585
|
expectedRevision: state.revision ?? 0,
|
|
423
586
|
packageRoot,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { withNativeReadScope } from "./native-storage.js";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileExists } from "./filesystem.js";
|
|
4
5
|
import { PROJECT_ARTIFACT_PATHS, taskArtifactPath } from "./task-paths.js";
|
|
5
6
|
import { assertJsonLimits } from "./json-safety.js";
|
|
6
7
|
import { assertSchema, readSchema } from "./schema-validation.js";
|
|
7
|
-
import { canonicalFingerprint, writeJsonArtifact } from "./artifacts.js";
|
|
8
|
+
import { canonicalFingerprint, readJsonArtifact, writeJsonArtifact } from "./artifacts.js";
|
|
8
9
|
import { sha256 } from "./manifest.js";
|
|
9
10
|
import { BUILTIN_POLICY_RULES, discoverPolicy } from "./policy-discovery.js";
|
|
10
11
|
import { getPolicyAdapter } from "./policy-adapters.js";
|
|
@@ -82,24 +83,22 @@ export async function writePolicyLock(target, lock, packageRoot) {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export async function readTaskPolicySnapshot(target, taskId, packageRoot) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
assertSchema(parsed, schema, "policy-snapshot");
|
|
95
|
-
return parsed;
|
|
86
|
+
return withNativeReadScope(target, async () => {
|
|
87
|
+
const relPath = taskArtifactPath(taskId, "policySnapshot");
|
|
88
|
+
try {
|
|
89
|
+
return (await readJsonArtifact(target, relPath, "policy-snapshot", packageRoot)).value;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error.code === "ARTIFACT_MISSING") return null;
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
export async function writeTaskPolicySnapshot(target, taskId, snapshot, packageRoot) {
|
|
99
98
|
const relPath = taskArtifactPath(taskId, "policySnapshot");
|
|
100
99
|
const schema = await readSchema("policy-snapshot", packageRoot);
|
|
101
100
|
assertSchema(snapshot, schema, "policy-snapshot");
|
|
102
|
-
await writeJsonArtifact(target, relPath, snapshot, "policy-snapshot", packageRoot);
|
|
101
|
+
await writeJsonArtifact(target, relPath, snapshot, "policy-snapshot", packageRoot, { taskId });
|
|
103
102
|
return snapshot;
|
|
104
103
|
}
|
|
105
104
|
|