@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
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { needsExistingProjectScope } from "../storage/existing-project-scope.js";
|
|
2
|
+
import { getOperationalStore } from "../storage/operational-context.js";
|
|
3
|
+
import { ledgerTypeSummary } from "./ledger-event-collection.js";
|
|
1
4
|
import {
|
|
2
5
|
E_COMPLETION_OWNERSHIP_UNPROVEN,
|
|
3
6
|
E_TASK_CLAIM_OWNERSHIP_INCONSISTENT,
|
|
@@ -6,8 +9,8 @@ import {
|
|
|
6
9
|
E_TASK_RECOVERY_INCONSISTENT,
|
|
7
10
|
} from "./error-codes.js";
|
|
8
11
|
import { validateCompletionOwnershipProof } from "./completion-ownership.js";
|
|
9
|
-
import { validateEventLedger } from "./events.js";
|
|
10
|
-
import { classifyRecoveryHistory } from "./recovery-history.js";
|
|
12
|
+
import { validateEventLedger, validatePortableEventLedger, validateStateLedgerCoherence, withEventLedgerAudit } from "./events.js";
|
|
13
|
+
import { classifyRecoveryHistory, summarizeRecoveryHistory } from "./recovery-history.js";
|
|
11
14
|
import { readTaskDescriptor } from "./task-descriptor.js";
|
|
12
15
|
import { normalizeWriteClaims } from "./task-scope.js";
|
|
13
16
|
import {
|
|
@@ -15,6 +18,35 @@ import {
|
|
|
15
18
|
validateTaskRecoveryConsistency,
|
|
16
19
|
} from "./task-recovery.js";
|
|
17
20
|
import { readWorkState } from "./work-state.js";
|
|
21
|
+
import { readContract } from "./contract.js";
|
|
22
|
+
import { readPersistedRoute } from "./route-artifact.js";
|
|
23
|
+
import {
|
|
24
|
+
CONTRACT_BOOTSTRAP_REPAIR_EVENT,
|
|
25
|
+
resolveEffectiveContractBootstrapRepairAnchor,
|
|
26
|
+
resolveCanonicalPostRepairCheckpointBinding,
|
|
27
|
+
resolveCanonicalPostRepairRouteBinding,
|
|
28
|
+
sameCanonicalGuideList,
|
|
29
|
+
} from "./contract-bootstrap-recovery.js";
|
|
30
|
+
import { canonicalFingerprint } from "./artifacts.js";
|
|
31
|
+
import { stateIdentityErrors } from "./completion-relationships.js";
|
|
32
|
+
import { routeCheckpointMustMatchCurrentRoute } from "./resumability.js";
|
|
33
|
+
|
|
34
|
+
const REPAIR_PHASE_EVENTS = Object.freeze({
|
|
35
|
+
CONTRACT_READY: "CONTRACT_VALIDATED",
|
|
36
|
+
ROUTED: "ROUTE_VALIDATED",
|
|
37
|
+
DESIGNING: "DESIGN_GATE_STARTED",
|
|
38
|
+
PLANNED: "PLAN_RECORDED",
|
|
39
|
+
EXECUTING: "EXECUTION_STARTED",
|
|
40
|
+
VERIFYING: "VERIFICATION_STARTED",
|
|
41
|
+
DIAGNOSING: "VERIFICATION_STARTED",
|
|
42
|
+
CORRECTING: "VERIFICATION_STARTED",
|
|
43
|
+
REVIEWING: "REVIEW_STARTED",
|
|
44
|
+
COMPLETE: "COMPLETION_VALIDATED",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const REPAIR_ROUTE_PHASES = new Set([
|
|
48
|
+
"ROUTED", "DESIGNING", "PLANNED", "EXECUTING", "VERIFYING", "DIAGNOSING", "CORRECTING", "REVIEWING", "COMPLETE",
|
|
49
|
+
]);
|
|
18
50
|
|
|
19
51
|
function ownershipError(message, cause = null) {
|
|
20
52
|
return {
|
|
@@ -24,10 +56,173 @@ function ownershipError(message, cause = null) {
|
|
|
24
56
|
};
|
|
25
57
|
}
|
|
26
58
|
|
|
59
|
+
function repairInvalid(message) {
|
|
60
|
+
return ownershipError(message, { code: "E_CONTRACT_BOOTSTRAP_REPAIR_INVALID" });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function lateRouteCheckpointErrors(events, state, marker) {
|
|
64
|
+
if (routeCheckpointMustMatchCurrentRoute(state.phase) || !REPAIR_PHASE_EVENTS[state.phase]) return [];
|
|
65
|
+
const checkpoint = resolveCanonicalPostRepairCheckpointBinding(events, marker);
|
|
66
|
+
if (!checkpoint) {
|
|
67
|
+
return [repairInvalid("Repaired late-phase state lacks an immutable route checkpoint binding")];
|
|
68
|
+
}
|
|
69
|
+
if (state.routeFingerprint !== checkpoint.routeFingerprint
|
|
70
|
+
|| !sameCanonicalGuideList(state.selectedGuides, checkpoint.selectedGuides)) {
|
|
71
|
+
return [repairInvalid("Late-phase checkpoint route identity was rewritten after the canonical checkpoint binding")];
|
|
72
|
+
}
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function repairArtifactErrors(artifacts) {
|
|
77
|
+
return [
|
|
78
|
+
...(artifacts?.contractError
|
|
79
|
+
? [repairInvalid(`Current contract artifact is invalid after a recorded repair: ${artifacts.contractError}`)]
|
|
80
|
+
: []),
|
|
81
|
+
...(artifacts?.routeError
|
|
82
|
+
? [repairInvalid(`Current route artifact is invalid after a recorded repair: ${artifacts.routeError}`)]
|
|
83
|
+
: []),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function repairAnchorErrors(details, state, artifacts) {
|
|
88
|
+
const errors = [];
|
|
89
|
+
if (state.phase !== details.reconstructedPhase) {
|
|
90
|
+
errors.push(repairInvalid(
|
|
91
|
+
`Work-state phase ${state.phase} does not match repair anchor phase ${details.reconstructedPhase}`,
|
|
92
|
+
));
|
|
93
|
+
}
|
|
94
|
+
if (canonicalFingerprint(state) !== details.reconstructedStateFingerprint) {
|
|
95
|
+
errors.push(repairInvalid("Work-state fingerprint does not match the repair anchor"));
|
|
96
|
+
}
|
|
97
|
+
const stateRouteFingerprint = state.routeFingerprint ?? null;
|
|
98
|
+
const currentRouteFingerprint = artifacts?.route?.fingerprint ?? null;
|
|
99
|
+
if (stateRouteFingerprint !== details.routeFingerprint
|
|
100
|
+
|| currentRouteFingerprint !== details.routeFingerprint) {
|
|
101
|
+
errors.push(repairInvalid("Current route identity does not match the repair anchor"));
|
|
102
|
+
}
|
|
103
|
+
return errors;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function evolvedRepairErrors(anchor, events, state, artifacts) {
|
|
107
|
+
const errors = [];
|
|
108
|
+
const contract = artifacts?.contract ?? null;
|
|
109
|
+
const route = artifacts?.route ?? null;
|
|
110
|
+
if (!contract) errors.push(repairInvalid("Current contract is unavailable after a recorded repair"));
|
|
111
|
+
const routeRequired = REPAIR_ROUTE_PHASES.has(state.phase) || state.routeFingerprint !== undefined;
|
|
112
|
+
if (routeRequired && !route) {
|
|
113
|
+
errors.push(repairInvalid("Current route is required by the evolved task state but is unavailable"));
|
|
114
|
+
}
|
|
115
|
+
if (contract) {
|
|
116
|
+
const routeErrors = stateIdentityErrors({ contract, route, state });
|
|
117
|
+
const checkpointMustMatch = routeCheckpointMustMatchCurrentRoute(state.phase);
|
|
118
|
+
errors.push(...routeErrors
|
|
119
|
+
.filter((error) => checkpointMustMatch || error.code !== "E_ROUTE_GUIDE_MISMATCH")
|
|
120
|
+
.map((error) => repairInvalid(error.message)));
|
|
121
|
+
}
|
|
122
|
+
const currentRouteFingerprint = route?.fingerprint ?? null;
|
|
123
|
+
const binding = currentRouteFingerprint !== anchor.details.routeFingerprint
|
|
124
|
+
? resolveCanonicalPostRepairRouteBinding(events, anchor.sourceMarker, currentRouteFingerprint)
|
|
125
|
+
: null;
|
|
126
|
+
if (currentRouteFingerprint !== anchor.details.routeFingerprint && !binding) {
|
|
127
|
+
errors.push(repairInvalid("Changed route identity lacks a canonical post-repair route binding"));
|
|
128
|
+
}
|
|
129
|
+
errors.push(...lateRouteCheckpointErrors(events, state, anchor.sourceMarker));
|
|
130
|
+
errors.push(...validateStateLedgerCoherence(state, events).map((error) => repairInvalid(error.message)));
|
|
131
|
+
const requiredEvent = REPAIR_PHASE_EVENTS[state.phase];
|
|
132
|
+
if (requiredEvent && !ledgerTypeSummary(events, requiredEvent).count) {
|
|
133
|
+
errors.push(repairInvalid(`Current work-state phase ${state.phase} is not supported by the repair ledger history`));
|
|
134
|
+
}
|
|
135
|
+
return errors;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function validateContractBootstrapRepairConsistency(taskId, events, state, artifacts) {
|
|
139
|
+
const anchor = resolveEffectiveContractBootstrapRepairAnchor(events);
|
|
140
|
+
if (!anchor) {
|
|
141
|
+
if (!ledgerTypeSummary(events, CONTRACT_BOOTSTRAP_REPAIR_EVENT).count) return [];
|
|
142
|
+
return [repairInvalid("Contract bootstrap repair marker is invalid")];
|
|
143
|
+
}
|
|
144
|
+
if (!state) return [repairInvalid("Work-state is missing after a recorded contract bootstrap repair")];
|
|
145
|
+
const details = anchor.details;
|
|
146
|
+
const errors = [];
|
|
147
|
+
if (state.taskId !== taskId) errors.push(repairInvalid("Work-state taskId does not match the repaired task"));
|
|
148
|
+
if (!Number.isInteger(state.revision) || state.revision < 0) {
|
|
149
|
+
return [...errors, repairInvalid("Work-state revision is missing or invalid after a recorded repair")];
|
|
150
|
+
}
|
|
151
|
+
const anchorRevision = details.reconstructedStateRevision;
|
|
152
|
+
if (state.revision < anchorRevision) {
|
|
153
|
+
return [...errors, repairInvalid("Work-state revision rolled back behind the repair anchor")];
|
|
154
|
+
}
|
|
155
|
+
if (state.contractFingerprint !== details.contractFingerprint) {
|
|
156
|
+
errors.push(repairInvalid("Work-state contract fingerprint does not match repair-time contract identity"));
|
|
157
|
+
}
|
|
158
|
+
errors.push(...repairArtifactErrors(artifacts));
|
|
159
|
+
return state.revision === anchorRevision
|
|
160
|
+
? [...errors, ...repairAnchorErrors(details, state, artifacts)]
|
|
161
|
+
: [...errors, ...evolvedRepairErrors(anchor, events, state, artifacts)];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Async cross-artifact consistency collector for a recorded contract bootstrap
|
|
166
|
+
* repair. The pure classifier stays filesystem-free; this reads the current
|
|
167
|
+
* task-scoped contract and route artifacts through their canonical readers so
|
|
168
|
+
* schema validation, artifact bounds, task-scoped paths, and fingerprint
|
|
169
|
+
* semantics stay consistent with the rest of the protocol.
|
|
170
|
+
*
|
|
171
|
+
* With no repair marker this performs no extra work.
|
|
172
|
+
*/
|
|
173
|
+
async function collectContractBootstrapRepairConsistency(target, packageRoot, taskId, events, state) {
|
|
174
|
+
const anchor = resolveEffectiveContractBootstrapRepairAnchor(events);
|
|
175
|
+
if (!anchor) return null;
|
|
176
|
+
const details = anchor.details;
|
|
177
|
+
const artifacts = { contract: null, route: null, contractError: null, routeError: null };
|
|
178
|
+
|
|
179
|
+
// Contract binding: the current contract must exist, validate, and bind to
|
|
180
|
+
// the marker and work state.
|
|
181
|
+
try {
|
|
182
|
+
const contract = await readContract(target, packageRoot, { taskId });
|
|
183
|
+
artifacts.contract = contract;
|
|
184
|
+
if (contract.fingerprint !== details.contractFingerprint) {
|
|
185
|
+
artifacts.contractError = `contract fingerprint ${contract.fingerprint} does not match marker contract fingerprint ${details.contractFingerprint}`;
|
|
186
|
+
} else if (state && state.contractFingerprint !== details.contractFingerprint) {
|
|
187
|
+
artifacts.contractError = "work-state contract fingerprint does not match marker contract fingerprint";
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
191
|
+
artifacts.contractError = error.code === "ARTIFACT_MISSING"
|
|
192
|
+
? "contract artifact is missing after a recorded repair"
|
|
193
|
+
: `contract artifact is invalid after a recorded repair: ${error.message}`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Route binding is anchored exactly at repair time, then follows the
|
|
197
|
+
// current state/route identity after the checkpoint advances.
|
|
198
|
+
const routeRequired = state && (REPAIR_ROUTE_PHASES.has(state.phase)
|
|
199
|
+
|| state.routeFingerprint !== undefined);
|
|
200
|
+
if (routeRequired || details.routeFingerprint !== null) {
|
|
201
|
+
try {
|
|
202
|
+
const route = await readPersistedRoute(target, packageRoot, { taskId });
|
|
203
|
+
artifacts.route = route;
|
|
204
|
+
if (route.value?.contractFingerprint !== undefined
|
|
205
|
+
&& route.value.contractFingerprint !== details.contractFingerprint) {
|
|
206
|
+
artifacts.routeError = "route artifact contract binding does not match repair anchor contract fingerprint";
|
|
207
|
+
}
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
210
|
+
artifacts.routeError = error.code === "ARTIFACT_MISSING"
|
|
211
|
+
? "route artifact is missing after a routed repair"
|
|
212
|
+
: `route artifact is invalid after a routed repair: ${error.message}`;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return artifacts;
|
|
217
|
+
}
|
|
218
|
+
|
|
27
219
|
function appendClaims(target, claims, errors, source) {
|
|
28
220
|
if (claims === undefined || claims === null) return;
|
|
29
221
|
try {
|
|
30
|
-
|
|
222
|
+
const normalized = normalizeWriteClaims(claims);
|
|
223
|
+
if (target instanceof Set || typeof target.add === "function") {
|
|
224
|
+
for (const claim of normalized) target.add(claim);
|
|
225
|
+
} else target.push(...normalized);
|
|
31
226
|
} catch (error) {
|
|
32
227
|
errors.push(ownershipError(`Invalid ${source} write claims: ${error.message}`, error));
|
|
33
228
|
}
|
|
@@ -39,12 +234,12 @@ function appendClaims(target, claims, errors, source) {
|
|
|
39
234
|
* classified recovery history. Classification is a pure function of this
|
|
40
235
|
* evidence, so conflict inspection can reuse it without rereading artifacts.
|
|
41
236
|
*/
|
|
42
|
-
|
|
237
|
+
async function collectClaimEvidence(target, {
|
|
43
238
|
taskId,
|
|
44
239
|
packageRoot,
|
|
45
240
|
descriptor: suppliedDescriptor = null,
|
|
46
241
|
state: suppliedState = null,
|
|
47
|
-
} = {}) {
|
|
242
|
+
} = {}, suppliedLedger = null) {
|
|
48
243
|
const errors = [];
|
|
49
244
|
let descriptor = suppliedDescriptor;
|
|
50
245
|
let state = suppliedState;
|
|
@@ -55,6 +250,7 @@ export async function collectTaskClaimEvidence(target, {
|
|
|
55
250
|
try {
|
|
56
251
|
descriptor = (await readTaskDescriptor(target, taskId, packageRoot)).value;
|
|
57
252
|
} catch (error) {
|
|
253
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
58
254
|
errors.push(ownershipError(`Task descriptor cannot establish claim ownership: ${error.message}`, error));
|
|
59
255
|
}
|
|
60
256
|
}
|
|
@@ -62,6 +258,7 @@ export async function collectTaskClaimEvidence(target, {
|
|
|
62
258
|
try {
|
|
63
259
|
state = await readWorkState(target, { taskId, packageRoot });
|
|
64
260
|
} catch (error) {
|
|
261
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
65
262
|
errors.push(ownershipError(`Task work state cannot establish claim ownership: ${error.message}`, error));
|
|
66
263
|
}
|
|
67
264
|
}
|
|
@@ -69,14 +266,27 @@ export async function collectTaskClaimEvidence(target, {
|
|
|
69
266
|
try {
|
|
70
267
|
recovery = (await readTaskRecovery(target, { taskId, packageRoot }))?.value ?? null;
|
|
71
268
|
} catch (error) {
|
|
269
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
72
270
|
errors.push(ownershipError(`Task recovery artifact cannot establish claim ownership: ${error.message}`, error));
|
|
73
271
|
}
|
|
74
272
|
|
|
75
273
|
try {
|
|
76
|
-
ledger = await validateEventLedger(target, packageRoot, { taskId });
|
|
274
|
+
ledger = suppliedLedger ?? await (getOperationalStore(target) || await needsExistingProjectScope(target) ? validateEventLedger : validatePortableEventLedger)(target, packageRoot, { taskId });
|
|
77
275
|
} catch (error) {
|
|
276
|
+
if (error.code === "E_STATE_REVISION_CONFLICT") throw error;
|
|
78
277
|
errors.push(ownershipError(`Task event ledger cannot establish claim ownership: ${error.message}`, error));
|
|
79
278
|
}
|
|
279
|
+
const repairArtifacts = await collectContractBootstrapRepairConsistency(target, packageRoot, taskId, ledger.events, state);
|
|
280
|
+
return buildTaskClaimEvidence({ taskId, descriptor, state, recovery, ledger, repairArtifacts, initialErrors: errors });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export async function collectTaskClaimEvidence(target, options = {}) {
|
|
284
|
+
return collectClaimEvidence(target, options);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Shared pure ownership evidence projection for filesystem and store snapshots. */
|
|
288
|
+
export function buildTaskClaimEvidence({ taskId, descriptor, state, recovery, ledger, repairArtifacts = null, initialErrors = [] }) {
|
|
289
|
+
const errors = [...initialErrors];
|
|
80
290
|
if (!ledger.valid) {
|
|
81
291
|
for (const error of ledger.errors) {
|
|
82
292
|
errors.push(ownershipError(`Task event ledger is invalid: ${error.message}`, error));
|
|
@@ -85,16 +295,29 @@ export async function collectTaskClaimEvidence(target, {
|
|
|
85
295
|
if (ledger.events.some((event) => event.taskId !== taskId)) {
|
|
86
296
|
errors.push(ownershipError(`Task event ledger contains an event for a different task`));
|
|
87
297
|
}
|
|
298
|
+
if (state) {
|
|
299
|
+
for (const error of validateStateLedgerCoherence(state, ledger.events)) {
|
|
300
|
+
if (![
|
|
301
|
+
"E_CHECKPOINT_REVALIDATION_UNSAFE",
|
|
302
|
+
"E_CONTRACT_REVISION_UNSAFE",
|
|
303
|
+
].includes(error.code)) continue;
|
|
304
|
+
errors.push(ownershipError(`Task state and event ledger are incoherent: ${error.message}`, error));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const repairConsistencyErrors = validateContractBootstrapRepairConsistency(taskId, ledger.events, state, repairArtifacts);
|
|
309
|
+
errors.push(...repairConsistencyErrors);
|
|
88
310
|
|
|
89
|
-
const history = classifyRecoveryHistory(ledger.events);
|
|
90
311
|
const descriptorClaims = [];
|
|
91
312
|
appendClaims(descriptorClaims, descriptor?.writeClaims, errors, "descriptor");
|
|
92
313
|
const normalizedDescriptorClaims = normalizeWriteClaims(descriptorClaims);
|
|
93
314
|
|
|
94
|
-
const historicalClaims =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
315
|
+
const historicalClaims = new Set(normalizedDescriptorClaims);
|
|
316
|
+
const observeRecovery = cycle => appendClaims(historicalClaims, cycle.event?.details?.releasedClaims, errors, "recovery ledger");
|
|
317
|
+
const history = Array.isArray(ledger.events)
|
|
318
|
+
? classifyRecoveryHistory(ledger.events)
|
|
319
|
+
: summarizeRecoveryHistory(ledger.events, observeRecovery);
|
|
320
|
+
if (Array.isArray(ledger.events)) for (const cycle of history.recoveries) observeRecovery(cycle);
|
|
98
321
|
appendClaims(historicalClaims, recovery?.releasedClaims, errors, "recovery artifact");
|
|
99
322
|
|
|
100
323
|
return {
|
|
@@ -106,7 +329,7 @@ export async function collectTaskClaimEvidence(target, {
|
|
|
106
329
|
ledger,
|
|
107
330
|
history,
|
|
108
331
|
normalizedDescriptorClaims,
|
|
109
|
-
historicalWriteClaims: normalizeWriteClaims(historicalClaims),
|
|
332
|
+
historicalWriteClaims: normalizeWriteClaims([...historicalClaims]),
|
|
110
333
|
errors,
|
|
111
334
|
};
|
|
112
335
|
}
|
|
@@ -229,7 +452,7 @@ export function classifyTaskClaimState(evidence) {
|
|
|
229
452
|
claimState: "ACTIVE",
|
|
230
453
|
mutationAllowed: true,
|
|
231
454
|
recovery: null,
|
|
232
|
-
recoveryStatus: history.completedRecoveries.length > 0 ? "COMPLETED" : "ABSENT",
|
|
455
|
+
recoveryStatus: (history.completedRecoveryCount ?? history.completedRecoveries.length) > 0 ? "COMPLETED" : "ABSENT",
|
|
233
456
|
valid: true,
|
|
234
457
|
ownershipValid: true,
|
|
235
458
|
reasonCodes: [],
|
|
@@ -243,9 +466,20 @@ export function classifyTaskClaimState(evidence) {
|
|
|
243
466
|
* tombstone, and the complete validated task ledger. Any disagreement retains
|
|
244
467
|
* every claim that can be recovered from validated inputs and fails closed.
|
|
245
468
|
*/
|
|
469
|
+
export async function withTaskClaimEvidence(target, options, callback) {
|
|
470
|
+
let store;
|
|
471
|
+
try { store = getOperationalStore(target); } catch { /* Preserve collected fail-closed evidence for invalid contexts. */ }
|
|
472
|
+
if (store && !store.hasPreparedMutations()
|
|
473
|
+
&& typeof options.taskId === "string" && options.taskId) {
|
|
474
|
+
return withEventLedgerAudit(target, options.packageRoot, { taskId: options.taskId }, async ledger => (
|
|
475
|
+
callback(await collectClaimEvidence(target, options, ledger))
|
|
476
|
+
));
|
|
477
|
+
}
|
|
478
|
+
return callback(await collectTaskClaimEvidence(target, options));
|
|
479
|
+
}
|
|
480
|
+
|
|
246
481
|
export async function resolveTaskClaimState(target, options = {}) {
|
|
247
|
-
|
|
248
|
-
return classifyTaskClaimState(evidence);
|
|
482
|
+
return withTaskClaimEvidence(target, options, classifyTaskClaimState);
|
|
249
483
|
}
|
|
250
484
|
|
|
251
485
|
export async function assertTaskMutationAllowed(target, options = {}) {
|
package/src/core/task-command.js
CHANGED
|
@@ -2,6 +2,8 @@ import { resolveTaskContext, TASK_SELECTION_MODES } from "./task-context.js";
|
|
|
2
2
|
import { withTaskTransaction } from "./transaction.js";
|
|
3
3
|
import { assertTaskMutationAllowed } from "./task-claim-state.js";
|
|
4
4
|
import { assertWorkspaceBinding } from "./workspace-binding.js";
|
|
5
|
+
import { getOperationalStore } from "../storage/operational-context.js";
|
|
6
|
+
import { withTaskLock } from "./task-lock.js";
|
|
5
7
|
|
|
6
8
|
export async function withResolvedTask(
|
|
7
9
|
target,
|
|
@@ -27,15 +29,33 @@ export async function withTaskMutation(
|
|
|
27
29
|
callback,
|
|
28
30
|
{ explicitRequired = false, skipWorkspaceBinding = false } = {},
|
|
29
31
|
) {
|
|
32
|
+
if (!getOperationalStore(target)) {
|
|
33
|
+
const { withProjectStorage } = await import("../storage/project-boundary.js");
|
|
34
|
+
return withProjectStorage(target, () => withTaskMutation(target, options, operation, callback, { explicitRequired, skipWorkspaceBinding }));
|
|
35
|
+
}
|
|
30
36
|
const taskOption = options.taskId ?? options.task ?? null;
|
|
31
37
|
const taskContext = await resolveTaskContext(target, {
|
|
32
38
|
taskId: taskOption,
|
|
33
|
-
explicitRequired,
|
|
39
|
+
explicitRequired: explicitRequired || Boolean(getOperationalStore(target)),
|
|
34
40
|
packageRoot: options.packageRoot,
|
|
35
41
|
selectionMode: TASK_SELECTION_MODES.MUTATION,
|
|
36
42
|
});
|
|
37
43
|
|
|
38
44
|
if (taskContext) {
|
|
45
|
+
if (getOperationalStore(target) && ["run-action", "run-check"].includes(operation)) {
|
|
46
|
+
return withTaskLock(target, taskContext.taskId, operation, async () => {
|
|
47
|
+
await withTaskTransaction({ target, taskId: taskContext.taskId, operation: `${operation}:prepare`, packageRoot: options.packageRoot }, async () => {
|
|
48
|
+
await assertTaskMutationAllowed(target, { taskId: taskContext.taskId, packageRoot: options.packageRoot });
|
|
49
|
+
if (!skipWorkspaceBinding) await assertWorkspaceBinding(target, { taskId: taskContext.taskId, packageRoot: options.packageRoot, operation });
|
|
50
|
+
});
|
|
51
|
+
// External work runs with a durable semantic reservation and no open
|
|
52
|
+
// database transaction. Its domain services commit intent/outcome in
|
|
53
|
+
// separate transactions, so a crash cannot erase a durable start.
|
|
54
|
+
const result = await callback(taskContext);
|
|
55
|
+
await withTaskTransaction({ target, taskId: taskContext.taskId, operation, packageRoot: options.packageRoot, recordCommitEvent: true }, () => undefined);
|
|
56
|
+
return result;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
39
59
|
return withTaskTransaction({ target, taskId: taskContext.taskId, operation, packageRoot: options.packageRoot, recordCommitEvent: true }, async (transaction) => {
|
|
40
60
|
await assertTaskMutationAllowed(target, { taskId: taskContext.taskId, packageRoot: options.packageRoot });
|
|
41
61
|
if (!skipWorkspaceBinding) {
|