@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,7 +1,7 @@
|
|
|
1
1
|
import { ARTIFACT_PATHS } from "./artifacts.js";
|
|
2
2
|
import { readContract } from "./contract.js";
|
|
3
3
|
import { readPersistedRoute } from "./route-artifact.js";
|
|
4
|
-
import { appendProtocolEvent, validateEventLedger } from "./events.js";
|
|
4
|
+
import { appendProtocolEvent, validateEventLedger, withEventLedgerAudit } from "./events.js";
|
|
5
5
|
import { readWorkState } from "./work-state.js";
|
|
6
6
|
import { assertStateIdentity } from "./completion-relationships.js";
|
|
7
7
|
import { ensureResumableState, synchronizePreflightState } from "./resumability.js";
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
validatePersistedPreflight,
|
|
15
15
|
} from "./preflight-model.js";
|
|
16
16
|
|
|
17
|
+
import { ledgerEventsOfTypes, ledgerTypeSummary } from "./ledger-event-collection.js";
|
|
17
18
|
import { taskArtifactPath } from "./task-paths.js";
|
|
18
19
|
|
|
19
20
|
async function readOptionalIdentityArtifact(readArtifact, invalidCode, artifactPath) {
|
|
@@ -80,6 +81,18 @@ function sameReadyPreflightEvent(event, result) {
|
|
|
80
81
|
&& sameStringSet(event.details?.satisfiedGates, result.satisfiedGates);
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
function latestContractRevisionSeq(events) {
|
|
85
|
+
return ledgerTypeSummary(events, "CONTRACT_REVISED").latest?.seq ?? 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function hasCurrentRevisionGate(events, taskId, gate) {
|
|
89
|
+
const revisionSeq = latestContractRevisionSeq(events);
|
|
90
|
+
for (const event of ledgerEventsOfTypes(events, ["GATE_SATISFIED"])) {
|
|
91
|
+
if (event.taskId === taskId && event.details?.gate === gate && event.seq > revisionSeq) return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
export async function validateReadyProtocolConsistency({
|
|
84
97
|
target,
|
|
85
98
|
packageRoot,
|
|
@@ -90,70 +103,80 @@ export async function validateReadyProtocolConsistency({
|
|
|
90
103
|
} = {}) {
|
|
91
104
|
if (persisted?.status !== "READY") return [];
|
|
92
105
|
const result = current ?? await evaluateCurrentPreflight({ target, packageRoot, taskId });
|
|
93
|
-
|
|
106
|
+
return withEventLedgerAudit(target, packageRoot, { taskId }, async ledger => {
|
|
107
|
+
const errors = [...validatePersistedPreflight(persisted, result)];
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
const stateRel = taskId ? taskArtifactPath(taskId, "state") : ARTIFACT_PATHS.state;
|
|
110
|
+
const eventsRel = taskId ? taskArtifactPath(taskId, "events") : ARTIFACT_PATHS.events;
|
|
111
|
+
const preflightRel = taskId ? taskArtifactPath(taskId, "preflight") : ARTIFACT_PATHS.preflight;
|
|
112
|
+
const contractRel = taskId ? taskArtifactPath(taskId, "contract") : ARTIFACT_PATHS.contract;
|
|
113
|
+
const routeRel = taskId ? taskArtifactPath(taskId, "route") : ARTIFACT_PATHS.route;
|
|
114
|
+
const gatesRel = taskId ? taskArtifactPath(taskId, "gates") : ARTIFACT_PATHS.gates;
|
|
101
115
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
if (!state) {
|
|
109
|
-
errors.push(issue(
|
|
110
|
-
"E_STATE_MISSING_AFTER_PREFLIGHT_READY",
|
|
111
|
-
"A persisted READY preflight must have a resumable work-state checkpoint",
|
|
112
|
-
[preflightRel, stateRel],
|
|
113
|
-
));
|
|
114
|
-
} else {
|
|
115
|
-
if (state.taskId !== persisted.taskId) {
|
|
116
|
-
errors.push(issue("E_STATE_TASK_MISMATCH", "The resumable checkpoint does not belong to the READY preflight task", [stateRel, preflightRel]));
|
|
116
|
+
let state = null;
|
|
117
|
+
try {
|
|
118
|
+
state = await readWorkState(target, { packageRoot, taskId });
|
|
119
|
+
} catch (error) {
|
|
120
|
+
errors.push(issue("E_STATE_INVALID", error.message, [stateRel]));
|
|
117
121
|
}
|
|
118
|
-
if (state
|
|
119
|
-
errors.push(issue(
|
|
122
|
+
if (!state) {
|
|
123
|
+
errors.push(issue(
|
|
124
|
+
"E_STATE_MISSING_AFTER_PREFLIGHT_READY",
|
|
125
|
+
"A persisted READY preflight must have a resumable work-state checkpoint",
|
|
126
|
+
[preflightRel, stateRel],
|
|
127
|
+
));
|
|
128
|
+
} else {
|
|
129
|
+
if (state.taskId !== persisted.taskId) {
|
|
130
|
+
errors.push(issue("E_STATE_TASK_MISMATCH", "The resumable checkpoint does not belong to the READY preflight task", [stateRel, preflightRel]));
|
|
131
|
+
}
|
|
132
|
+
if (state.contractFingerprint !== result.fingerprints.contract) {
|
|
133
|
+
errors.push(issue("E_CONTRACT_STALE", "The resumable checkpoint does not match the READY contract fingerprint", [stateRel, contractRel]));
|
|
134
|
+
}
|
|
135
|
+
if (state.routeFingerprint !== result.fingerprints.routing) {
|
|
136
|
+
errors.push(issue("E_ROUTE_STALE", "The resumable checkpoint does not match the READY routing fingerprint", [stateRel, routeRel]));
|
|
137
|
+
}
|
|
138
|
+
if (JSON.stringify(state.selectedGuides) !== JSON.stringify(result.routing.guides)) {
|
|
139
|
+
errors.push(issue("E_ROUTE_GUIDE_MISMATCH", "The resumable checkpoint guides do not match the READY routing result", [stateRel, routeRel]));
|
|
140
|
+
}
|
|
141
|
+
if (!sameStringSet(state.requiredGates ?? [], persisted.requiredGates)
|
|
142
|
+
|| !sameStringSet(state.satisfiedGates ?? [], persisted.satisfiedGates)) {
|
|
143
|
+
errors.push(issue("E_PREFLIGHT_GATES_STALE", "The resumable checkpoint gate sets do not match the READY preflight", [stateRel, preflightRel, gatesRel]));
|
|
144
|
+
}
|
|
120
145
|
}
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
|
|
147
|
+
if (!ledger.valid) {
|
|
148
|
+
errors.push(...ledger.errors.map((error) => issue(error.code ?? "E_EVENT_INVALID", error.message, [eventsRel])));
|
|
123
149
|
}
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
const events = ledger.events ?? [];
|
|
151
|
+
const requiredEvents = ["CONTRACT_VALIDATED", "ROUTE_VALIDATED"];
|
|
152
|
+
const observedEvents = new Set();
|
|
153
|
+
for (const event of ledgerEventsOfTypes(events, requiredEvents)) {
|
|
154
|
+
if (event.taskId === persisted.taskId) observedEvents.add(event.event);
|
|
126
155
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
156
|
+
for (const requiredEvent of requiredEvents) {
|
|
157
|
+
if (!observedEvents.has(requiredEvent)) {
|
|
158
|
+
errors.push(issue("E_PREFLIGHT_EVENT_MISSING", `READY preflight is missing lifecycle event: ${requiredEvent}`, [eventsRel, preflightRel]));
|
|
159
|
+
}
|
|
130
160
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
errors.push(...ledger.errors.map((error) => issue(error.code ?? "E_EVENT_INVALID", error.message, [eventsRel])));
|
|
136
|
-
}
|
|
137
|
-
const events = ledger.events ?? [];
|
|
138
|
-
for (const requiredEvent of ["CONTRACT_VALIDATED", "ROUTE_VALIDATED"]) {
|
|
139
|
-
if (!events.some((event) => event.event === requiredEvent && event.taskId === persisted.taskId)) {
|
|
140
|
-
errors.push(issue("E_PREFLIGHT_EVENT_MISSING", `READY preflight is missing lifecycle event: ${requiredEvent}`, [eventsRel, preflightRel]));
|
|
161
|
+
for (const gate of persisted.satisfiedGates ?? []) {
|
|
162
|
+
if (!hasCurrentRevisionGate(events, persisted.taskId, gate)) {
|
|
163
|
+
errors.push(issue("E_PREFLIGHT_GATE_EVENT_MISSING", `READY preflight is missing lifecycle gate event: ${gate}`, [eventsRel, `${gatesRel}/${gate}.json`]));
|
|
164
|
+
}
|
|
141
165
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
166
|
+
let readyCount = 0;
|
|
167
|
+
let readyMatches = false;
|
|
168
|
+
for (const event of ledgerEventsOfTypes(events, ["PREFLIGHT_READY"])) {
|
|
169
|
+
if (event.taskId !== persisted.taskId) continue;
|
|
170
|
+
readyCount++;
|
|
171
|
+
if (sameReadyPreflightEvent(event, result)) readyMatches = true;
|
|
148
172
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
errors
|
|
155
|
-
}
|
|
156
|
-
return sortIssues(errors);
|
|
173
|
+
if (readyCount === 0) {
|
|
174
|
+
errors.push(issue("E_PREFLIGHT_READY_EVENT_MISSING", "Persisted READY preflight is missing the matching PREFLIGHT_READY lifecycle event", [preflightRel, eventsRel]));
|
|
175
|
+
} else if (!readyMatches) {
|
|
176
|
+
errors.push(issue("E_PREFLIGHT_READY_EVENT_MISMATCH", "PREFLIGHT_READY lifecycle details do not match the persisted READY preflight", [preflightRel, eventsRel]));
|
|
177
|
+
}
|
|
178
|
+
return sortIssues(errors);
|
|
179
|
+
});
|
|
157
180
|
}
|
|
158
181
|
|
|
159
182
|
function sameBlockedPreflightEvent(event, result) {
|
|
@@ -189,9 +212,12 @@ export function assertExistingReadyLifecycleCompatibility(ledger, result) {
|
|
|
189
212
|
const existingReady = events.findLast((event) => event.event === "PREFLIGHT_READY" && event.taskId === result.taskId);
|
|
190
213
|
if (!existingReady) return;
|
|
191
214
|
const latestOutcome = latestPreflightOutcomeEvent(events, result.taskId);
|
|
215
|
+
const revisedAfterReady = events.some((event) => event.event === "CONTRACT_REVISED"
|
|
216
|
+
&& event.taskId === result.taskId
|
|
217
|
+
&& event.seq > existingReady.seq);
|
|
192
218
|
// A READY outcome superseded by a later BLOCKED outcome may be replaced by a
|
|
193
219
|
// fresh READY with different details once the blocked preflight is resolved.
|
|
194
|
-
if (latestOutcome?.event === "PREFLIGHT_BLOCKED") return;
|
|
220
|
+
if (latestOutcome?.event === "PREFLIGHT_BLOCKED" || revisedAfterReady) return;
|
|
195
221
|
if (!sameReadyPreflightEvent(existingReady, result)) {
|
|
196
222
|
throw preflightError(
|
|
197
223
|
"E_PHASE_CHRONOLOGY_INVALID",
|
|
@@ -217,9 +243,7 @@ export async function appendActivationEvents(target, packageRoot, ledger, result
|
|
|
217
243
|
await append({ taskId: result.taskId, event: "ROUTE_VALIDATED", fingerprint: result.fingerprints.routing });
|
|
218
244
|
}
|
|
219
245
|
for (const gate of result.satisfiedGates) {
|
|
220
|
-
if (!events
|
|
221
|
-
&& event.taskId === result.taskId
|
|
222
|
-
&& event.details?.gate === gate)) {
|
|
246
|
+
if (!hasCurrentRevisionGate(events, result.taskId, gate)) {
|
|
223
247
|
await append({ taskId: result.taskId, event: "GATE_SATISFIED", details: { gate } });
|
|
224
248
|
}
|
|
225
249
|
}
|
|
@@ -227,15 +251,18 @@ export async function appendActivationEvents(target, packageRoot, ledger, result
|
|
|
227
251
|
const existingReady = events.findLast((event) => event.event === "PREFLIGHT_READY" && event.taskId === result.taskId);
|
|
228
252
|
const latestOutcome = latestPreflightOutcomeEvent(events, result.taskId);
|
|
229
253
|
const readySupersededByBlocked = existingReady && latestOutcome?.event === "PREFLIGHT_BLOCKED";
|
|
254
|
+
const readySupersededByContractRevision = existingReady && events.some((event) => event.event === "CONTRACT_REVISED"
|
|
255
|
+
&& event.taskId === result.taskId
|
|
256
|
+
&& event.seq > existingReady.seq);
|
|
230
257
|
if (result.status === "READY") {
|
|
231
|
-
if (existingReady && !readySupersededByBlocked && !sameReadyPreflightEvent(existingReady, result)) {
|
|
258
|
+
if (existingReady && !readySupersededByBlocked && !readySupersededByContractRevision && !sameReadyPreflightEvent(existingReady, result)) {
|
|
232
259
|
throw preflightError(
|
|
233
260
|
"E_PHASE_CHRONOLOGY_INVALID",
|
|
234
261
|
"PREFLIGHT_READY already exists with different READY preflight details; repair the contract, route, or gate lifecycle before refreshing preflight",
|
|
235
262
|
[ARTIFACT_PATHS.preflight, ARTIFACT_PATHS.events, ARTIFACT_PATHS.contract, ARTIFACT_PATHS.route, ARTIFACT_PATHS.gates],
|
|
236
263
|
);
|
|
237
264
|
}
|
|
238
|
-
if (!existingReady || readySupersededByBlocked) {
|
|
265
|
+
if (!existingReady || readySupersededByBlocked || readySupersededByContractRevision) {
|
|
239
266
|
await append({
|
|
240
267
|
taskId: result.taskId,
|
|
241
268
|
event: "PREFLIGHT_READY",
|
|
@@ -2,13 +2,15 @@ import { ARTIFACT_PATHS, readJsonArtifact } from "./artifacts.js";
|
|
|
2
2
|
import { readContract } from "./contract.js";
|
|
3
3
|
import { readGateIfPresent, validateGateArtifacts } from "./gate-artifact.js";
|
|
4
4
|
import { requiredGatesForGuides } from "./guide-metadata.js";
|
|
5
|
-
import {
|
|
5
|
+
import { assertContractPresetRefs, assertContractSourceProvenance, externalContractSourceRefs } from "./sources.js";
|
|
6
6
|
import { readPersistedRoute } from "./route-artifact.js";
|
|
7
7
|
import { ensureWithin, readBytes } from "./filesystem.js";
|
|
8
8
|
import { sha256 } from "./manifest.js";
|
|
9
9
|
import { findProfilePath } from "./profile.js";
|
|
10
10
|
import { issue } from "./preflight-model.js";
|
|
11
11
|
import { taskGatePath, taskArtifactPath } from "./task-paths.js";
|
|
12
|
+
import { readEvents } from "./events.js";
|
|
13
|
+
import { hasCurrentGateEvidence } from "./gate-provenance.js";
|
|
12
14
|
|
|
13
15
|
export async function readProfile(target) {
|
|
14
16
|
const relativePath = await findProfilePath(target);
|
|
@@ -39,7 +41,7 @@ export async function optionalConfig(target, packageRoot, errors) {
|
|
|
39
41
|
|
|
40
42
|
export async function loadContract(target, packageRoot, errors, options = {}) {
|
|
41
43
|
try {
|
|
42
|
-
return await readContract(target, packageRoot, options);
|
|
44
|
+
return await (options.readers?.readContract ?? readContract)(target, packageRoot, options);
|
|
43
45
|
} catch (error) {
|
|
44
46
|
const path = options.contractPath ?? (options.taskId ? taskArtifactPath(options.taskId, "contract") : ARTIFACT_PATHS.contract);
|
|
45
47
|
errors.push(issue(error.code === "ARTIFACT_MISSING" ? "E_CONTRACT_MISSING" : "E_CONTRACT_INVALID", error.message, [path]));
|
|
@@ -49,7 +51,7 @@ export async function loadContract(target, packageRoot, errors, options = {}) {
|
|
|
49
51
|
|
|
50
52
|
export async function loadRoute(target, packageRoot, errors, options = {}) {
|
|
51
53
|
try {
|
|
52
|
-
return await readPersistedRoute(target, packageRoot, options);
|
|
54
|
+
return await (options.readers?.readRoute ?? readPersistedRoute)(target, packageRoot, options);
|
|
53
55
|
} catch (error) {
|
|
54
56
|
const path = options.routePath ?? (options.taskId ? taskArtifactPath(options.taskId, "route") : ARTIFACT_PATHS.route);
|
|
55
57
|
const code = error.code === "ARTIFACT_MISSING"
|
|
@@ -62,21 +64,43 @@ export async function loadRoute(target, packageRoot, errors, options = {}) {
|
|
|
62
64
|
|
|
63
65
|
export async function loadSources(target, contract, packageRoot, errors) {
|
|
64
66
|
if (!contract?.value?.sourceRefs?.length) return null;
|
|
65
|
-
|
|
67
|
+
const refs = contract.value.sourceRefs;
|
|
66
68
|
try {
|
|
67
|
-
|
|
69
|
+
assertContractPresetRefs(refs);
|
|
68
70
|
} catch (error) {
|
|
69
|
-
errors.push(issue(error.code
|
|
71
|
+
errors.push(issue(error.code ?? "E_PROFILE_SOURCE_UNKNOWN", error.message, [ARTIFACT_PATHS.sources]));
|
|
70
72
|
return null;
|
|
71
73
|
}
|
|
74
|
+
const externalRefs = externalContractSourceRefs(refs);
|
|
75
|
+
let registry;
|
|
76
|
+
if (externalRefs.length > 0) {
|
|
77
|
+
try {
|
|
78
|
+
registry = (await readJsonArtifact(target, ARTIFACT_PATHS.sources, "source-registry", packageRoot)).value;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
errors.push(issue(error.code === "ARTIFACT_MISSING" ? "E_PROFILE_SOURCE_MISSING" : "E_PROFILE_SOURCE_UNKNOWN", error.message, [ARTIFACT_PATHS.sources]));
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
72
84
|
try {
|
|
73
|
-
|
|
85
|
+
assertContractSourceProvenance(registry, refs);
|
|
74
86
|
} catch (error) {
|
|
75
87
|
errors.push(issue(error.code ?? "E_PROFILE_SOURCE_UNKNOWN", error.message, [ARTIFACT_PATHS.sources]));
|
|
76
88
|
}
|
|
77
89
|
return registry;
|
|
78
90
|
}
|
|
79
91
|
|
|
92
|
+
async function readGateEvents(target, packageRoot, taskId, options) {
|
|
93
|
+
let events = [];
|
|
94
|
+
if (taskId) {
|
|
95
|
+
try {
|
|
96
|
+
events = await (options.readers?.readEvents ?? readEvents)(target, packageRoot, { taskId });
|
|
97
|
+
} catch {
|
|
98
|
+
events = [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return events;
|
|
102
|
+
}
|
|
103
|
+
|
|
80
104
|
export async function inspectGates(target, contract, route, packageRoot, errors, config = {}, options = {}) {
|
|
81
105
|
if (!route) return { required: [], satisfied: [], records: {} };
|
|
82
106
|
const guideGates = await requiredGatesForGuides(route.value.guides, packageRoot);
|
|
@@ -84,13 +108,17 @@ export async function inspectGates(target, contract, route, packageRoot, errors,
|
|
|
84
108
|
const satisfied = [];
|
|
85
109
|
const records = {};
|
|
86
110
|
const taskId = options.taskId ?? null;
|
|
111
|
+
const events = await readGateEvents(target, packageRoot, taskId, options);
|
|
112
|
+
const latestContractRevisionSeq = events.findLast((event) => event.event === "CONTRACT_REVISED")?.seq ?? 0;
|
|
87
113
|
for (const gate of required) {
|
|
88
114
|
let artifact;
|
|
89
115
|
const defaultGateRel = taskId ? taskGatePath(taskId, gate) : `${ARTIFACT_PATHS.gates}/${gate}.json`;
|
|
90
116
|
try {
|
|
91
|
-
artifact = await readGateIfPresent(target, gate, packageRoot, { ...options, taskId });
|
|
117
|
+
artifact = await (options.readers?.readGate ?? readGateIfPresent)(target, gate, packageRoot, { ...options, taskId });
|
|
92
118
|
} catch (error) {
|
|
93
|
-
|
|
119
|
+
const code = error.code === "E_STORAGE_PAYLOAD_MISMATCH" && error.taskIdentityMismatch ? "E_GATE_TASK_MISMATCH"
|
|
120
|
+
: error.code === "ARTIFACT_MISSING" ? "E_GATE_UNVERIFIED" : "E_GATE_INVALID";
|
|
121
|
+
errors.push(issue(code, error.message, [defaultGateRel], { gate }));
|
|
94
122
|
continue;
|
|
95
123
|
}
|
|
96
124
|
if (!artifact) {
|
|
@@ -111,6 +139,17 @@ export async function inspectGates(target, contract, route, packageRoot, errors,
|
|
|
111
139
|
errors.push(issue("E_GATE_STALE", `Gate ${gate} references stale artifacts`, [artifact.path], { gate, stale }));
|
|
112
140
|
continue;
|
|
113
141
|
}
|
|
142
|
+
const currentEpochSatisfied = latestContractRevisionSeq === 0
|
|
143
|
+
|| hasCurrentGateEvidence(events, taskId, gate, latestContractRevisionSeq);
|
|
144
|
+
if (!currentEpochSatisfied) {
|
|
145
|
+
errors.push(issue(
|
|
146
|
+
"E_GATE_UNVERIFIED",
|
|
147
|
+
`Required gate ${gate} was satisfied before the current contract revision`,
|
|
148
|
+
[defaultGateRel],
|
|
149
|
+
{ gate },
|
|
150
|
+
));
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
114
153
|
satisfied.push(gate);
|
|
115
154
|
}
|
|
116
155
|
return { required, satisfied: satisfied.sort(), records };
|
|
@@ -31,7 +31,12 @@ export function sameStringSet(left, right) {
|
|
|
31
31
|
&& [...leftSet].every((value) => rightSet.has(value));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function validatePersistedPreflight(persisted, current) {
|
|
34
|
+
export function validatePersistedPreflight(persisted, current, readError = null) {
|
|
35
|
+
if (readError?.taskIdentityMismatch) return [issue("E_PREFLIGHT_TASK_MISMATCH", "Persisted preflight does not belong to the current task", [ARTIFACT_PATHS.preflight, ARTIFACT_PATHS.contract])];
|
|
36
|
+
return validatePersistedPreflightPayload(persisted, current);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function validatePersistedPreflightPayload(persisted, current) {
|
|
35
40
|
const errors = [];
|
|
36
41
|
if (persisted?.status !== "READY") {
|
|
37
42
|
if (Array.isArray(persisted?.errors) && persisted.errors.length > 0) {
|
package/src/core/preflight.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ARTIFACT_PATHS, writeJsonArtifact } from "./artifacts.js";
|
|
2
|
+
import { withTaskTransaction } from "./transaction.js";
|
|
2
3
|
import { readContract } from "./contract.js";
|
|
3
4
|
import { assertRouteInvariants } from "./router.js";
|
|
4
5
|
import { validateProfileSources } from "./profile.js";
|
|
@@ -35,13 +36,17 @@ const PREVIEW_DECISION_MAX_LENGTH = 240;
|
|
|
35
36
|
|
|
36
37
|
export { validatePersistedPreflight } from "./preflight-model.js";
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
function preflightArtifactPath(explicitPath, taskId, kind) {
|
|
40
|
+
return explicitPath ?? (taskId ? taskArtifactPath(taskId, kind) : ARTIFACT_PATHS[kind]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function evaluatePreflight({ target, packageRoot, strict = false, taskId = null, contractPath = null, routePath = null, statePath = null, readers = null } = {}) {
|
|
39
44
|
const errors = [];
|
|
40
45
|
const profile = await readProfile(target);
|
|
41
46
|
const profileProvenance = await validateProfileSources(target, packageRoot);
|
|
42
47
|
errors.push(...(profileProvenance.errors ?? []));
|
|
43
|
-
const contract = await loadContract(target, packageRoot, errors, { taskId, contractPath });
|
|
44
|
-
const route = await loadRoute(target, packageRoot, errors, { taskId, routePath });
|
|
48
|
+
const contract = await loadContract(target, packageRoot, errors, { taskId, contractPath, readers });
|
|
49
|
+
const route = await loadRoute(target, packageRoot, errors, { taskId, routePath, readers });
|
|
45
50
|
const config = await optionalConfig(target, packageRoot, errors);
|
|
46
51
|
if (config.structuralQuality !== undefined) {
|
|
47
52
|
try {
|
|
@@ -59,9 +64,9 @@ export async function evaluatePreflight({ target, packageRoot, strict = false, t
|
|
|
59
64
|
errors.push(issue("E_PROFILE_UNVERIFIED", "Strict preflight requires a verified project profile", [PROFILE_PATH]));
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
const contractRelPath = contractPath
|
|
63
|
-
const routeRelPath = routePath
|
|
64
|
-
const stateRelPath = statePath
|
|
67
|
+
const contractRelPath = preflightArtifactPath(contractPath, taskId, "contract");
|
|
68
|
+
const routeRelPath = preflightArtifactPath(routePath, taskId, "route");
|
|
69
|
+
const stateRelPath = preflightArtifactPath(statePath, taskId, "state");
|
|
65
70
|
|
|
66
71
|
const unresolvedDecisions = contract?.value?.unresolvedDecisions ?? [];
|
|
67
72
|
if (unresolvedDecisions.length > 0) {
|
|
@@ -88,11 +93,11 @@ export async function evaluatePreflight({ target, packageRoot, strict = false, t
|
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
const sources = await loadSources(target, contract, packageRoot, errors);
|
|
91
|
-
const gates = await inspectGates(target, contract, route, packageRoot, errors, config, { taskId });
|
|
96
|
+
const gates = await inspectGates(target, contract, route, packageRoot, errors, config, { taskId, readers });
|
|
92
97
|
|
|
93
98
|
let state = null;
|
|
94
99
|
try {
|
|
95
|
-
state = await readWorkState(target, { packageRoot, taskId, statePath });
|
|
100
|
+
state = await (readers?.readState ?? readWorkState)(target, { packageRoot, taskId, statePath });
|
|
96
101
|
} catch (error) {
|
|
97
102
|
errors.push(issue("E_STATE_INVALID", error.message, [stateRelPath]));
|
|
98
103
|
}
|
|
@@ -135,7 +140,7 @@ export async function evaluatePreflight({ target, packageRoot, strict = false, t
|
|
|
135
140
|
reasonCodes: [],
|
|
136
141
|
next: config.structuralQuality?.mode === "gate" ? "CAPTURE_STRUCTURAL_QUALITY_BASELINE" : null,
|
|
137
142
|
};
|
|
138
|
-
if (effectiveTaskId !== "unknown") {
|
|
143
|
+
if (effectiveTaskId !== "unknown" && (!readers || structuralQuality.mode !== "off")) {
|
|
139
144
|
try {
|
|
140
145
|
const { projectStructuralQualityStatus } = await import("./structural-quality/service.js");
|
|
141
146
|
structuralQuality = await projectStructuralQualityStatus({ target, packageRoot, taskId: effectiveTaskId });
|
|
@@ -183,7 +188,19 @@ export async function validateReadyProtocolConsistency(options = {}) {
|
|
|
183
188
|
});
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
export async function runPreflight({
|
|
191
|
+
export async function runPreflight(options = {}) {
|
|
192
|
+
if (options.persist === false) return runPreflightInTransaction(options);
|
|
193
|
+
let taskId = options.taskId;
|
|
194
|
+
if (!taskId) {
|
|
195
|
+
const { target, packageRoot, strict, contractPath, routePath, statePath } = options;
|
|
196
|
+
const result = await evaluatePreflight({ target, packageRoot, strict, contractPath, routePath, statePath });
|
|
197
|
+
if (result.taskId !== "unknown") taskId = result.taskId;
|
|
198
|
+
}
|
|
199
|
+
if (!taskId) return runPreflightInTransaction(options);
|
|
200
|
+
return withTaskTransaction({ target: options.target, taskId, packageRoot: options.packageRoot, operation: "preflight" }, () => runPreflightInTransaction({ ...options, taskId }));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function runPreflightInTransaction({
|
|
187
204
|
target,
|
|
188
205
|
packageRoot,
|
|
189
206
|
strict = false,
|
|
@@ -198,7 +215,7 @@ export async function runPreflight({
|
|
|
198
215
|
let result = await evaluatePreflight({ target, packageRoot, strict, taskId, contractPath, routePath, statePath });
|
|
199
216
|
if (!persist) return result;
|
|
200
217
|
|
|
201
|
-
let ledger = await assertPreflightPersistenceSafety(target, packageRoot, { taskId, eventsPath });
|
|
218
|
+
let ledger = await assertPreflightPersistenceSafety(target, packageRoot, { taskId, contractPath, routePath, statePath, eventsPath });
|
|
202
219
|
assertPreflightResultPersistenceSafety(result);
|
|
203
220
|
assertExistingReadyLifecycleCompatibility(ledger, result);
|
|
204
221
|
|
|
@@ -224,7 +241,7 @@ export async function runPreflight({
|
|
|
224
241
|
result = await evaluatePreflight({ target, packageRoot, strict, taskId, contractPath, routePath, statePath });
|
|
225
242
|
assertPreflightResultPersistenceSafety(result);
|
|
226
243
|
assertExistingReadyLifecycleCompatibility(ledger, result);
|
|
227
|
-
ledger = await assertPreflightPersistenceSafety(target, packageRoot, { taskId, eventsPath });
|
|
244
|
+
ledger = await assertPreflightPersistenceSafety(target, packageRoot, { taskId, contractPath, routePath, statePath, eventsPath });
|
|
228
245
|
}
|
|
229
246
|
}
|
|
230
247
|
|
package/src/core/progress.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isLedgerEventCollection, ledgerEventsOfTypes } from "./ledger-event-collection.js";
|
|
2
|
+
import { latestDiagnosisForTask } from "./diagnosis-model.js";
|
|
2
3
|
import { resolveCurrentCycleDiagnostic } from "./diagnostic-projection.js";
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
-
evaluateStructuredDiagnosticStall,
|
|
5
|
+
summarizeInformationGain,
|
|
6
6
|
} from "./information-gain-projection.js";
|
|
7
7
|
|
|
8
8
|
export const PROGRESS_STATUS = Object.freeze({
|
|
@@ -27,6 +27,17 @@ export function diagnosisRequirements(diagnosis, checksById) {
|
|
|
27
27
|
)].sort();
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function progressTaskEvents(events, taskId) {
|
|
31
|
+
if (Array.isArray(events)) return events.filter(event => !taskId || event.taskId === taskId);
|
|
32
|
+
return isLedgerEventCollection(events) ? events : [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function* progressVerificationEvents(events, taskId) {
|
|
36
|
+
for (const event of ledgerEventsOfTypes(events, ["VERIFICATION_RECORDED"])) {
|
|
37
|
+
if (!taskId || event.taskId === taskId) yield event;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
export function evaluateProgress({ state, events = [] } = {}) {
|
|
31
42
|
const signals = [];
|
|
32
43
|
let status = PROGRESS_STATUS.ADVANCING;
|
|
@@ -35,10 +46,10 @@ export function evaluateProgress({ state, events = [] } = {}) {
|
|
|
35
46
|
return { status, signals };
|
|
36
47
|
}
|
|
37
48
|
|
|
38
|
-
const taskEvents =
|
|
39
|
-
const
|
|
49
|
+
const taskEvents = progressTaskEvents(events, state.taskId);
|
|
50
|
+
const latestLegacy = latestDiagnosisForTask(taskEvents, state.taskId);
|
|
40
51
|
const resolvedDiagnostic = resolveCurrentCycleDiagnostic(taskEvents, state.taskId, state.verificationCycle ?? null);
|
|
41
|
-
const latestDiag = resolvedDiagnostic?.details ??
|
|
52
|
+
const latestDiag = resolvedDiagnostic?.details ?? latestLegacy?.details ?? null;
|
|
42
53
|
|
|
43
54
|
let latestGainClassification = latestDiag?.informationGain ?? null;
|
|
44
55
|
let structuredStall = null;
|
|
@@ -49,8 +60,8 @@ export function evaluateProgress({ state, events = [] } = {}) {
|
|
|
49
60
|
)];
|
|
50
61
|
}
|
|
51
62
|
// Canonical structured-stall truth; compatibility classification is presentation only.
|
|
52
|
-
structuredStall =
|
|
53
|
-
|
|
63
|
+
structuredStall = summarizeInformationGain(
|
|
64
|
+
taskEvents, state.taskId,
|
|
54
65
|
{ verificationCycle: state.verificationCycle ?? null },
|
|
55
66
|
);
|
|
56
67
|
latestDiag.effectiveInformationGain = !(structuredStall.stalled);
|
|
@@ -63,7 +74,7 @@ export function evaluateProgress({ state, events = [] } = {}) {
|
|
|
63
74
|
if (check.id) checksById.set(check.id, check);
|
|
64
75
|
if (check.checkId) checksById.set(check.checkId, check);
|
|
65
76
|
}
|
|
66
|
-
for (const event of taskEvents) {
|
|
77
|
+
for (const event of progressVerificationEvents(taskEvents, state.taskId)) {
|
|
67
78
|
if (event.event === "VERIFICATION_RECORDED" && event.details) {
|
|
68
79
|
if (event.details.id) checksById.set(event.details.id, event.details);
|
|
69
80
|
if (event.details.checkId) checksById.set(event.details.checkId, event.details);
|
|
@@ -108,7 +119,7 @@ export function evaluateProgress({ state, events = [] } = {}) {
|
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
// Also extract from VERIFICATION_RECORDED events
|
|
111
|
-
for (const event of taskEvents) {
|
|
122
|
+
for (const event of progressVerificationEvents(taskEvents, state.taskId)) {
|
|
112
123
|
if (event.event === "VERIFICATION_RECORDED") {
|
|
113
124
|
const details = event.details ?? {};
|
|
114
125
|
if (details.status === "failed" || details.status === "blocked") {
|
|
@@ -4,6 +4,10 @@ import { PUBLIC_ERROR_REGISTRY } from "./error-codes.js";
|
|
|
4
4
|
import { GUIDE_REGISTRY } from "./guide-registry.js";
|
|
5
5
|
import { PROTOCOL_VERSION, WORK_PHASES, WORK_TRANSITIONS } from "./protocol.js";
|
|
6
6
|
import { VERIFICATION_ISOLATION_MODES } from "./verification-execution.js";
|
|
7
|
+
import { PROVIDER_KINDS } from "../providers/capabilities.js";
|
|
8
|
+
import { DECISION_DEFAULT_POLICY, DECISION_ENGINE_ID, PINNED_JEV_MODEL } from "./decision/constants.js";
|
|
9
|
+
|
|
10
|
+
import { getStorageCapabilities } from "../storage/capabilities.js";
|
|
7
11
|
|
|
8
12
|
export const SCHEMA_COMPATIBILITY_POLICY = Object.freeze({
|
|
9
13
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -36,6 +40,43 @@ export function protocolInfo({ packageVersion = null } = {}) {
|
|
|
36
40
|
writesSchemaVersions: schemaVersions,
|
|
37
41
|
compatibility: SCHEMA_COMPATIBILITY_POLICY,
|
|
38
42
|
features: {
|
|
43
|
+
operationalStorage: getStorageCapabilities(),
|
|
44
|
+
semanticDecisionPlane: {
|
|
45
|
+
version: 1,
|
|
46
|
+
supported: true,
|
|
47
|
+
requiredForNewSemanticDecisions: true,
|
|
48
|
+
engine: DECISION_ENGINE_ID,
|
|
49
|
+
model: PINNED_JEV_MODEL,
|
|
50
|
+
policyVersion: DECISION_DEFAULT_POLICY.policyVersion,
|
|
51
|
+
authority: "SEMANTIC_DECISION",
|
|
52
|
+
evidenceAuthority: "NONE",
|
|
53
|
+
lifecycleAuthority: false,
|
|
54
|
+
completionAuthority: false,
|
|
55
|
+
ownershipAuthority: false,
|
|
56
|
+
installationAuthority: false,
|
|
57
|
+
commands: ["decision-status", "decision-show", "context-plan", "model-route", "semantic-plan", "test-inventory", "test-utility", "test-prune-plan", "test-prune-probe"],
|
|
58
|
+
resource: "task/decisions",
|
|
59
|
+
contextPlanResource: "task/context-plan",
|
|
60
|
+
modelRouteResource: "task/model-route",
|
|
61
|
+
testUtilityResource: "task/test-utility",
|
|
62
|
+
testPruneResource: "task/test-utility",
|
|
63
|
+
offlineInspection: true,
|
|
64
|
+
completePerformsLiveRequest: false,
|
|
65
|
+
modelRouting: {
|
|
66
|
+
version: 1,
|
|
67
|
+
tiers: ["NONE", "FAST", "STANDARD", "PRIMARY"],
|
|
68
|
+
deterministicFloor: true,
|
|
69
|
+
advisoryEscalationOnly: true,
|
|
70
|
+
vendorSelection: false,
|
|
71
|
+
},
|
|
72
|
+
semanticPlanning: {
|
|
73
|
+
version: 1,
|
|
74
|
+
questionSets: ["intake-v1", "contract-v1", "route-v1", "context-v1", "model-route-v1", "failure-v1", "diagnosis-v1", "review-v1", "task-overlap-v1", "test-utility-v1", "test-prune-v1"],
|
|
75
|
+
authority: "SEMANTIC_DECISION",
|
|
76
|
+
evidenceAuthority: "NONE",
|
|
77
|
+
lifecycleAuthority: false,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
39
80
|
taskClaimRecovery: {
|
|
40
81
|
version: 1,
|
|
41
82
|
durableRecoveryState: true,
|
|
@@ -153,6 +194,18 @@ export function protocolInfo({ packageVersion = null } = {}) {
|
|
|
153
194
|
commands: ["next", "task-show"],
|
|
154
195
|
preservesDefaultOutput: true,
|
|
155
196
|
},
|
|
197
|
+
auditUx: {
|
|
198
|
+
version: 1,
|
|
199
|
+
supported: true,
|
|
200
|
+
readOnly: true,
|
|
201
|
+
resource: "task/audit-view",
|
|
202
|
+
timeline: true,
|
|
203
|
+
lifecycleAuthority: false,
|
|
204
|
+
evidenceAuthority: false,
|
|
205
|
+
completionAuthority: false,
|
|
206
|
+
mutationAuthority: false,
|
|
207
|
+
externalExecution: false,
|
|
208
|
+
},
|
|
156
209
|
usageTelemetry: {
|
|
157
210
|
version: 1,
|
|
158
211
|
supported: true,
|
|
@@ -205,6 +258,21 @@ export function protocolInfo({ packageVersion = null } = {}) {
|
|
|
205
258
|
evidenceAuthority: false,
|
|
206
259
|
executable: false,
|
|
207
260
|
},
|
|
261
|
+
providerExtensions: {
|
|
262
|
+
version: 1,
|
|
263
|
+
supported: true,
|
|
264
|
+
providerNeutral: true,
|
|
265
|
+
maturity: "experimental",
|
|
266
|
+
publicRegistryApi: false,
|
|
267
|
+
packageSubpathExported: false,
|
|
268
|
+
autoInstall: false,
|
|
269
|
+
lifecycleAuthority: false,
|
|
270
|
+
completionAuthority: false,
|
|
271
|
+
evidenceAuthority: false,
|
|
272
|
+
providerKinds: [...PROVIDER_KINDS],
|
|
273
|
+
resultBoundary: "STRICT_JSON_SNAPSHOT",
|
|
274
|
+
cancellation: "COOPERATIVE_ABORT_SIGNAL",
|
|
275
|
+
},
|
|
208
276
|
responsibilityConstraints: {
|
|
209
277
|
version: 1,
|
|
210
278
|
supported: true,
|