@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.
Files changed (395) hide show
  1. package/AGENT_COMPATIBILITY.md +8 -0
  2. package/CONTRIBUTING.md +11 -7
  3. package/DOCS_INDEX.md +37 -4
  4. package/ENG/c-development-eng.md +2 -2
  5. package/ENG/cpp-development-eng.md +2 -2
  6. package/ENG/dotnet-aspnetcore-development-eng.md +7 -1
  7. package/ENG/flutter-development-eng.md +4 -2
  8. package/ENG/go-development-eng.md +2 -2
  9. package/ENG/java-development-eng.md +3 -3
  10. package/ENG/nodejs-backend-development-eng.md +10 -6
  11. package/ENG/php-development-eng.md +3 -3
  12. package/ENG/python-development-eng.md +205 -0
  13. package/ENG/rust-development-eng.md +42 -1
  14. package/ENG/sec-code-eng.md +7 -7
  15. package/ENG/sql-development-eng.md +4 -4
  16. package/ENG/swift-development-eng.md +5 -4
  17. package/ENG/test-code-eng.md +1 -1
  18. package/ENG/typescript-development-eng.md +4 -4
  19. package/EXECUTION_STATE.md +12 -0
  20. package/GUIDE_ROUTER.md +6 -0
  21. package/LICENSE +133 -21
  22. package/LOOP_ENGINEERING.md +28 -2
  23. package/LOOP_SYSTEM_DESIGN.md +10 -10
  24. package/ORCHESTRATOR_INTEGRATION.md +9 -5
  25. package/PROTOCOL_INTEGRATION.md +55 -2
  26. package/README.md +63 -59
  27. package/TERMINOLOGY.md +2 -0
  28. package/THIRD_PARTY_NOTICES.md +3 -4
  29. package/THREAT_MODEL.md +140 -1
  30. package/completions/_forgeloop +29 -3
  31. package/completions/forgeloop.bash +55 -3
  32. package/completions/forgeloop.fish +183 -1
  33. package/docs/ADVISORY_CONTEXT.md +25 -0
  34. package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
  35. package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
  36. package/docs/AGENT_PROTOCOL_SUMMARY.md +74 -39
  37. package/docs/AGENT_SKILL.md +66 -0
  38. package/docs/ARTIFACT_REFERENCE.md +171 -35
  39. package/docs/AUDIT_UX.md +46 -0
  40. package/docs/BROWSER_VERIFICATION.md +136 -0
  41. package/docs/CLI_REFERENCE.md +512 -8
  42. package/docs/CODE_ATTESTATION.md +2 -2
  43. package/docs/DOCUMENTATION_GUIDE.md +34 -11
  44. package/docs/GETTING_STARTED.md +3 -3
  45. package/docs/JEV_BENCHMARKS.md +31 -0
  46. package/docs/MODEL_ROUTING.md +37 -0
  47. package/docs/OPENSRC_ADAPTER.md +241 -0
  48. package/docs/PACKAGE_CONTENTS.md +46 -18
  49. package/docs/PROVIDERS.md +126 -0
  50. package/docs/PROVIDER_ARCHITECTURE.md +199 -0
  51. package/docs/RECIPES.md +9 -0
  52. package/docs/RELEASE_CHECKLIST.md +116 -12
  53. package/docs/SECURITY_REVIEW.md +71 -0
  54. package/docs/SELF_HOSTED_TESTS.md +121 -0
  55. package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
  56. package/docs/TEST_INTELLIGENCE.md +29 -0
  57. package/docs/TEST_PRUNING.md +14 -0
  58. package/docs/TROUBLESHOOTING.md +198 -1
  59. package/docs/UNIVERSAL_INTEGRATION.md +31 -0
  60. package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
  61. package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
  62. package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
  63. package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
  64. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
  65. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
  66. package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
  67. package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
  68. package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
  69. package/docs/diagrams/README.md +13 -9
  70. package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
  71. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
  72. package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
  73. package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
  74. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
  75. package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
  76. package/docs/documentation-manifest.json +774 -16
  77. package/docs/protocol-requirements.json +24 -0
  78. package/package.json +43 -11
  79. package/schemas/config.schema.json +14 -0
  80. package/schemas/context-plan.schema.json +18 -0
  81. package/schemas/semantic-decision.schema.json +46 -0
  82. package/schemas/task-bundle.schema.json +7 -2
  83. package/schemas/test-utility.schema.json +44 -0
  84. package/scripts/CI_VALIDATORS.md +6 -6
  85. package/scripts/benchmark-jev.mjs +5 -0
  86. package/scripts/benchmark-test-intelligence.mjs +4 -0
  87. package/scripts/generate-agent-protocol-summary.mjs +6 -3
  88. package/scripts/generate-forgeloop-skill.mjs +133 -0
  89. package/scripts/jev-smoke.mjs +19 -0
  90. package/scripts/run-mcp-clean-tests.mjs +30 -0
  91. package/skills/forgeloop/README.md +9 -0
  92. package/skills/forgeloop/SKILL.md +77 -0
  93. package/skills/forgeloop/references/lifecycle.md +9 -0
  94. package/skills/forgeloop/references/recovery.md +7 -0
  95. package/skills/forgeloop/references/verification.md +7 -0
  96. package/src/adapters/agent-browser/assertions.js +47 -0
  97. package/src/adapters/agent-browser/commands.js +54 -0
  98. package/src/adapters/agent-browser/index.js +3 -0
  99. package/src/adapters/agent-browser/locator.js +40 -0
  100. package/src/adapters/agent-browser/process.js +215 -0
  101. package/src/adapters/agent-browser/provider.js +316 -0
  102. package/src/adapters/emulated-services/constants.js +24 -0
  103. package/src/adapters/emulated-services/index.js +7 -0
  104. package/src/adapters/emulated-services/process.js +162 -0
  105. package/src/adapters/emulated-services/provider.js +289 -0
  106. package/src/adapters/opensrc/normalize.js +90 -0
  107. package/src/adapters/opensrc/process.js +248 -0
  108. package/src/adapters/opensrc/provider.js +338 -0
  109. package/src/adapters/opensrc/search.js +264 -0
  110. package/src/adapters/temporary-paths.js +18 -0
  111. package/src/adapters/typesafe/client.js +28 -0
  112. package/src/adapters/typesafe/engine.js +63 -0
  113. package/src/adapters/typesafe/normalize.js +41 -0
  114. package/src/cli.js +218 -174
  115. package/src/commands/action-show.js +5 -2
  116. package/src/commands/advance.js +5 -1
  117. package/src/commands/baseline.js +13 -11
  118. package/src/commands/checkpoint-revalidate.js +192 -0
  119. package/src/commands/complete.js +19 -3
  120. package/src/commands/context-plan.js +38 -0
  121. package/src/commands/contract-create.js +266 -0
  122. package/src/commands/contract-revise.js +236 -0
  123. package/src/commands/decision-show.js +14 -0
  124. package/src/commands/decision-status.js +22 -0
  125. package/src/commands/discover.js +41 -0
  126. package/src/commands/doctor.js +51 -13
  127. package/src/commands/gate-record.js +194 -0
  128. package/src/commands/gate-revalidate.js +135 -0
  129. package/src/commands/handoff-list.js +6 -1
  130. package/src/commands/handoff-show.js +6 -1
  131. package/src/commands/migrate-protocol.js +2 -2
  132. package/src/commands/model-route.js +40 -0
  133. package/src/commands/next.js +7 -1
  134. package/src/commands/policy-diff.js +25 -4
  135. package/src/commands/progress.js +17 -11
  136. package/src/commands/record-diagnosis.js +3 -0
  137. package/src/commands/route.js +146 -18
  138. package/src/commands/semantic-plan.js +41 -0
  139. package/src/commands/status.js +6 -1
  140. package/src/commands/storage-backup.js +15 -0
  141. package/src/commands/storage-migrate.js +5 -0
  142. package/src/commands/storage-migration-resume.js +5 -0
  143. package/src/commands/storage-migration-status.js +44 -0
  144. package/src/commands/storage-restore-resume.js +7 -0
  145. package/src/commands/storage-restore.js +8 -0
  146. package/src/commands/task-abandon.js +224 -0
  147. package/src/commands/task-list.js +8 -43
  148. package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
  149. package/src/commands/task-migrate.js +3 -3
  150. package/src/commands/task-recover.js +10 -2
  151. package/src/commands/task-repair-contract-bootstrap.js +263 -0
  152. package/src/commands/task-scope.js +18 -2
  153. package/src/commands/task-show.js +16 -2
  154. package/src/commands/test-inventory.js +5 -0
  155. package/src/commands/test-prune-plan.js +5 -0
  156. package/src/commands/test-prune-probe.js +5 -0
  157. package/src/commands/test-utility.js +5 -0
  158. package/src/commands/validate-protocol.js +39 -15
  159. package/src/commands/validate-receipt.js +8 -1
  160. package/src/config/guides.json +4 -0
  161. package/src/core/action-ledger-projection.js +10 -3
  162. package/src/core/actions.js +38 -75
  163. package/src/core/activation.js +11 -3
  164. package/src/core/approvals.js +17 -51
  165. package/src/core/artifact-registry.js +83 -2
  166. package/src/core/artifacts.js +81 -27
  167. package/src/core/attachment-paths.js +45 -0
  168. package/src/core/attestation-coverage.js +6 -1
  169. package/src/core/attestation-verifier.js +21 -2
  170. package/src/core/attestation.js +17 -6
  171. package/src/core/audit-ux.js +514 -0
  172. package/src/core/audit.js +6 -1
  173. package/src/core/browser-verification/constants.js +149 -0
  174. package/src/core/browser-verification/normalize.js +254 -0
  175. package/src/core/browser-verification/provider.js +519 -0
  176. package/src/core/browser-verification/service.js +115 -0
  177. package/src/core/bundles.js +160 -66
  178. package/src/core/checkpoint-revalidation.js +321 -0
  179. package/src/core/cli-command-definitions.js +350 -7
  180. package/src/core/code-manifest.js +9 -3
  181. package/src/core/command-executors.js +274 -108
  182. package/src/core/command-input.js +136 -44
  183. package/src/core/completion-artifacts.js +85 -34
  184. package/src/core/completion-ownership.js +19 -8
  185. package/src/core/completion-recovery-rebind.js +11 -1
  186. package/src/core/completion.js +64 -15
  187. package/src/core/config.js +3 -0
  188. package/src/core/conformance.js +2 -1
  189. package/src/core/context-compiler/budget.js +9 -0
  190. package/src/core/context-compiler/candidates.js +39 -0
  191. package/src/core/context-compiler/compiler.js +63 -0
  192. package/src/core/context-compiler/fingerprint.js +11 -0
  193. package/src/core/context-compiler/policy.js +13 -0
  194. package/src/core/context-compiler/result.js +23 -0
  195. package/src/core/continuity-lint.js +13 -2
  196. package/src/core/continuity-reconciliation.js +16 -3
  197. package/src/core/continuity.js +16 -8
  198. package/src/core/contract-bootstrap-recovery.js +656 -0
  199. package/src/core/contract-revision.js +209 -0
  200. package/src/core/decision/artifact.js +70 -0
  201. package/src/core/decision/benchmarks.js +103 -0
  202. package/src/core/decision/cache.js +27 -0
  203. package/src/core/decision/constants.js +58 -0
  204. package/src/core/decision/cutover.js +34 -0
  205. package/src/core/decision/engine.js +22 -0
  206. package/src/core/decision/errors.js +68 -0
  207. package/src/core/decision/events.js +104 -0
  208. package/src/core/decision/freshness.js +19 -0
  209. package/src/core/decision/normalizers/index.js +115 -0
  210. package/src/core/decision/policy.js +18 -0
  211. package/src/core/decision/projection.js +16 -0
  212. package/src/core/decision/question-registry.js +201 -0
  213. package/src/core/decision/request.js +26 -0
  214. package/src/core/decision/resolver.js +138 -0
  215. package/src/core/decision/result.js +58 -0
  216. package/src/core/decision/service.js +181 -0
  217. package/src/core/decision/state-builder.js +65 -0
  218. package/src/core/decision/task-bindings.js +35 -0
  219. package/src/core/decision/test-provider.js +32 -0
  220. package/src/core/decision/thresholds.js +15 -0
  221. package/src/core/diagnosis-model.js +11 -0
  222. package/src/core/diagnosis.js +10 -1
  223. package/src/core/diagnostic-projection.js +29 -12
  224. package/src/core/diagnostic-record.js +28 -3
  225. package/src/core/efficiency.js +6 -1
  226. package/src/core/error-codes.js +278 -0
  227. package/src/core/events.js +535 -147
  228. package/src/core/evidence-readiness.js +9 -0
  229. package/src/core/execution-prerequisites.js +36 -13
  230. package/src/core/execution-profile.js +63 -38
  231. package/src/core/execution.js +26 -40
  232. package/src/core/filesystem.js +11 -0
  233. package/src/core/gate-artifact.js +105 -19
  234. package/src/core/gate-provenance.js +125 -0
  235. package/src/core/handoff.js +26 -14
  236. package/src/core/history.js +39 -35
  237. package/src/core/hypothesis-projection.js +32 -0
  238. package/src/core/information-gain-projection.js +104 -100
  239. package/src/core/inspect.js +12 -3
  240. package/src/core/integration-invocation-policy.js +37 -4
  241. package/src/core/integration-resources.js +119 -87
  242. package/src/core/ledger-event-collection.js +189 -0
  243. package/src/core/ledger-relations.js +23 -0
  244. package/src/core/model-router/constants.js +10 -0
  245. package/src/core/model-router/policy.js +103 -0
  246. package/src/core/model-router/router.js +37 -0
  247. package/src/core/native-storage.js +12 -0
  248. package/src/core/next-action-continuity.js +31 -9
  249. package/src/core/next-action-model.js +58 -0
  250. package/src/core/next-action-phases.js +131 -43
  251. package/src/core/next-action-refresh.js +43 -9
  252. package/src/core/next-action-review-phase.js +9 -4
  253. package/src/core/next-action-verification-phase.js +2 -1
  254. package/src/core/next-action.js +56 -9
  255. package/src/core/phase.js +266 -103
  256. package/src/core/policy-engine.js +12 -13
  257. package/src/core/preflight-consistency.js +89 -62
  258. package/src/core/preflight-loaders.js +48 -9
  259. package/src/core/preflight-model.js +6 -1
  260. package/src/core/preflight.js +29 -12
  261. package/src/core/progress.js +21 -10
  262. package/src/core/protocol-info.js +68 -0
  263. package/src/core/protocol-migration.js +7 -6
  264. package/src/core/protocol.js +20 -0
  265. package/src/core/reconcile-closure.js +281 -67
  266. package/src/core/recovery-history.js +67 -47
  267. package/src/core/reflection.js +72 -77
  268. package/src/core/responsibility.js +25 -13
  269. package/src/core/resumability.js +154 -44
  270. package/src/core/route-artifact.js +28 -4
  271. package/src/core/router.js +67 -1
  272. package/src/core/runtime-context.js +123 -61
  273. package/src/core/schema-validation.js +11 -3
  274. package/src/core/security-review/constants.js +64 -0
  275. package/src/core/security-review/normalize.js +245 -0
  276. package/src/core/security-review/provider.js +204 -0
  277. package/src/core/security-review/service.js +134 -0
  278. package/src/core/semantic-planning/constants.js +19 -0
  279. package/src/core/semantic-planning/projection.js +94 -0
  280. package/src/core/semantic-planning/service.js +15 -0
  281. package/src/core/settlement.js +12 -1
  282. package/src/core/signing/bundle-file.js +53 -0
  283. package/src/core/signing/bundle-reference.js +15 -0
  284. package/src/core/signing/sigstore.js +60 -33
  285. package/src/core/signing/statement-file.js +27 -0
  286. package/src/core/sources.js +37 -0
  287. package/src/core/storage-runtime-registry.js +41 -0
  288. package/src/core/structural-quality/artifacts.js +20 -14
  289. package/src/core/structural-quality/service.js +81 -56
  290. package/src/core/target-layout.js +1 -1
  291. package/src/core/task-claim-state.js +249 -15
  292. package/src/core/task-command.js +21 -1
  293. package/src/core/task-conflict-inspection.js +133 -102
  294. package/src/core/task-descriptor.js +29 -22
  295. package/src/core/task-discovery.js +288 -90
  296. package/src/core/task-lock.js +66 -306
  297. package/src/core/task-migration-validation.js +5 -5
  298. package/src/core/task-migration.js +17 -287
  299. package/src/core/task-paths.js +13 -0
  300. package/src/core/task-recovery.js +1 -0
  301. package/src/core/task-snapshot.js +51 -8
  302. package/src/core/task-storage-migration.js +18 -0
  303. package/src/core/templates.js +23 -8
  304. package/src/core/test-intelligence/benchmarks.js +68 -0
  305. package/src/core/test-intelligence/inventory.js +73 -0
  306. package/src/core/test-intelligence/prune.js +94 -0
  307. package/src/core/test-intelligence/semantic-state.js +15 -0
  308. package/src/core/test-intelligence/service.js +40 -0
  309. package/src/core/test-intelligence/utility.js +50 -0
  310. package/src/core/trace.js +164 -105
  311. package/src/core/trajectory-evaluation.js +15 -3
  312. package/src/core/trajectory-metrics.js +47 -32
  313. package/src/core/transaction.js +16 -287
  314. package/src/core/verification-scope.js +20 -12
  315. package/src/core/work-state.js +100 -59
  316. package/src/integration.d.ts +492 -0
  317. package/src/integration.js +54 -0
  318. package/src/providers/README.md +47 -0
  319. package/src/providers/capabilities.js +46 -0
  320. package/src/providers/errors.js +15 -0
  321. package/src/providers/index.js +29 -0
  322. package/src/providers/json-snapshot.js +105 -0
  323. package/src/providers/registry.js +152 -0
  324. package/src/repository-index/binary-manager.js +7 -5
  325. package/src/storage/artifact-bytes.js +22 -0
  326. package/src/storage/attachment-binding.js +11 -0
  327. package/src/storage/attachment-files.js +82 -0
  328. package/src/storage/attachment-references.js +36 -0
  329. package/src/storage/backup.js +53 -0
  330. package/src/storage/capabilities.js +31 -0
  331. package/src/storage/connection-owner.js +119 -0
  332. package/src/storage/connection.js +376 -0
  333. package/src/storage/existing-project-scope.js +45 -0
  334. package/src/storage/export-destination.js +44 -0
  335. package/src/storage/exporter.js +284 -0
  336. package/src/storage/file-durability.js +46 -0
  337. package/src/storage/importer.js +461 -0
  338. package/src/storage/index.js +74 -0
  339. package/src/storage/leases.js +63 -0
  340. package/src/storage/ledger-event-snapshot.js +150 -0
  341. package/src/storage/ledger-relations.js +220 -0
  342. package/src/storage/legacy-maintenance-boundary.js +18 -0
  343. package/src/storage/legacy-signature.js +115 -0
  344. package/src/storage/maintenance-handoff.js +129 -0
  345. package/src/storage/maintenance-owner.js +42 -0
  346. package/src/storage/maintenance.js +310 -0
  347. package/src/storage/metadata-json.js +35 -0
  348. package/src/storage/migration-activate.js +59 -0
  349. package/src/storage/migration-archive.js +57 -0
  350. package/src/storage/migration-attachment-root.js +61 -0
  351. package/src/storage/migration-candidate.js +398 -0
  352. package/src/storage/migration-publication.js +143 -0
  353. package/src/storage/migration-rollback-admission.js +54 -0
  354. package/src/storage/migration-rollback-preparation.js +132 -0
  355. package/src/storage/migration-rollback-publication.js +183 -0
  356. package/src/storage/migration-rollback-release.js +66 -0
  357. package/src/storage/migration-rollback-source-stage.js +103 -0
  358. package/src/storage/migration-rollback.js +43 -0
  359. package/src/storage/migration-source-partition.js +56 -0
  360. package/src/storage/migration-source.js +255 -0
  361. package/src/storage/migration-terminal.js +39 -0
  362. package/src/storage/migration-validation.js +75 -0
  363. package/src/storage/migration.js +43 -0
  364. package/src/storage/operational-attachments.js +49 -0
  365. package/src/storage/operational-context.js +50 -0
  366. package/src/storage/project-backup.js +98 -0
  367. package/src/storage/project-bootstrap.js +24 -0
  368. package/src/storage/project-boundary.js +79 -0
  369. package/src/storage/project-read-snapshot.js +18 -0
  370. package/src/storage/project-replacement.js +137 -0
  371. package/src/storage/project-restore.js +203 -0
  372. package/src/storage/record-definitions.js +45 -0
  373. package/src/storage/repository.js +507 -0
  374. package/src/storage/restore-journal.js +62 -0
  375. package/src/storage/restore-layout.js +30 -0
  376. package/src/storage/restore-preparation.js +84 -0
  377. package/src/storage/restore-replacement-archive.js +162 -0
  378. package/src/storage/restore-replacement-owner.js +31 -0
  379. package/src/storage/restore-replacement-preparation.js +128 -0
  380. package/src/storage/restore-replacement.js +142 -0
  381. package/src/storage/restore-terminal.js +32 -0
  382. package/src/storage/runtime.js +31 -0
  383. package/src/storage/schema.js +214 -0
  384. package/src/storage/singleton-import.js +84 -0
  385. package/src/storage/snapshot-continuity.js +16 -0
  386. package/src/storage/snapshot.js +36 -0
  387. package/src/storage/storage-marker.js +79 -0
  388. package/src/storage/task-guards.js +107 -0
  389. package/src/storage/topology.js +42 -0
  390. package/src/storage/transaction.js +179 -0
  391. package/src/storage/unit-of-work.js +663 -0
  392. package/src/storage/windows-process-incarnation.js +206 -0
  393. package/.forgeloop/forgeloop.gitignore +0 -4
  394. package/LICENSE-DOCS.md +0 -13
  395. 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
- const errors = [...validatePersistedPreflight(persisted, result)];
106
+ return withEventLedgerAudit(target, packageRoot, { taskId }, async ledger => {
107
+ const errors = [...validatePersistedPreflight(persisted, result)];
94
108
 
95
- const stateRel = taskId ? taskArtifactPath(taskId, "state") : ARTIFACT_PATHS.state;
96
- const eventsRel = taskId ? taskArtifactPath(taskId, "events") : ARTIFACT_PATHS.events;
97
- const preflightRel = taskId ? taskArtifactPath(taskId, "preflight") : ARTIFACT_PATHS.preflight;
98
- const contractRel = taskId ? taskArtifactPath(taskId, "contract") : ARTIFACT_PATHS.contract;
99
- const routeRel = taskId ? taskArtifactPath(taskId, "route") : ARTIFACT_PATHS.route;
100
- const gatesRel = taskId ? taskArtifactPath(taskId, "gates") : ARTIFACT_PATHS.gates;
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
- let state = null;
103
- try {
104
- state = await readWorkState(target, { packageRoot, taskId });
105
- } catch (error) {
106
- errors.push(issue("E_STATE_INVALID", error.message, [stateRel]));
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.contractFingerprint !== result.fingerprints.contract) {
119
- errors.push(issue("E_CONTRACT_STALE", "The resumable checkpoint does not match the READY contract fingerprint", [stateRel, contractRel]));
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
- if (state.routeFingerprint !== result.fingerprints.routing) {
122
- errors.push(issue("E_ROUTE_STALE", "The resumable checkpoint does not match the READY routing fingerprint", [stateRel, routeRel]));
146
+
147
+ if (!ledger.valid) {
148
+ errors.push(...ledger.errors.map((error) => issue(error.code ?? "E_EVENT_INVALID", error.message, [eventsRel])));
123
149
  }
124
- if (JSON.stringify(state.selectedGuides) !== JSON.stringify(result.routing.guides)) {
125
- errors.push(issue("E_ROUTE_GUIDE_MISMATCH", "The resumable checkpoint guides do not match the READY routing result", [stateRel, routeRel]));
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
- if (!sameStringSet(state.requiredGates ?? [], persisted.requiredGates)
128
- || !sameStringSet(state.satisfiedGates ?? [], persisted.satisfiedGates)) {
129
- errors.push(issue("E_PREFLIGHT_GATES_STALE", "The resumable checkpoint gate sets do not match the READY preflight", [stateRel, preflightRel, gatesRel]));
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
- const ledger = await validateEventLedger(target, packageRoot, { taskId });
134
- if (!ledger.valid) {
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
- for (const gate of persisted.satisfiedGates ?? []) {
144
- if (!events.some((event) => event.event === "GATE_SATISFIED"
145
- && event.taskId === persisted.taskId
146
- && event.details?.gate === gate)) {
147
- errors.push(issue("E_PREFLIGHT_GATE_EVENT_MISSING", `READY preflight is missing lifecycle gate event: ${gate}`, [eventsRel, `${gatesRel}/${gate}.json`]));
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
- const readyEvents = events.filter((event) => event.event === "PREFLIGHT_READY" && event.taskId === persisted.taskId);
151
- if (readyEvents.length === 0) {
152
- errors.push(issue("E_PREFLIGHT_READY_EVENT_MISSING", "Persisted READY preflight is missing the matching PREFLIGHT_READY lifecycle event", [preflightRel, eventsRel]));
153
- } else if (!readyEvents.some((event) => sameReadyPreflightEvent(event, result))) {
154
- errors.push(issue("E_PREFLIGHT_READY_EVENT_MISMATCH", "PREFLIGHT_READY lifecycle details do not match the persisted READY preflight", [preflightRel, eventsRel]));
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.some((event) => event.event === "GATE_SATISFIED"
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 { assertSourceProvenance } from "./sources.js";
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
- let registry;
67
+ const refs = contract.value.sourceRefs;
66
68
  try {
67
- registry = (await readJsonArtifact(target, ARTIFACT_PATHS.sources, "source-registry", packageRoot)).value;
69
+ assertContractPresetRefs(refs);
68
70
  } catch (error) {
69
- errors.push(issue(error.code === "ARTIFACT_MISSING" ? "E_PROFILE_SOURCE_MISSING" : "E_PROFILE_SOURCE_UNKNOWN", error.message, [ARTIFACT_PATHS.sources]));
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
- assertSourceProvenance(registry, contract.value.sourceRefs);
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
- errors.push(issue(error.code === "ARTIFACT_MISSING" ? "E_GATE_UNVERIFIED" : "E_GATE_INVALID", error.message, [defaultGateRel], { gate }));
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) {
@@ -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
- export async function evaluatePreflight({ target, packageRoot, strict = false, taskId = null, contractPath = null, routePath = null, statePath = null } = {}) {
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 ?? (taskId ? taskArtifactPath(taskId, "contract") : ARTIFACT_PATHS.contract);
63
- const routeRelPath = routePath ?? (taskId ? taskArtifactPath(taskId, "route") : ARTIFACT_PATHS.route);
64
- const stateRelPath = statePath ?? (taskId ? taskArtifactPath(taskId, "state") : ARTIFACT_PATHS.state);
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
 
@@ -1,8 +1,8 @@
1
- import { diagnosisEventsForTask } from "./diagnosis-model.js";
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
- buildInformationGainProjection,
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 = Array.isArray(events) ? events.filter((e) => !state.taskId || e.taskId === state.taskId) : [];
39
- const diagEvents = diagnosisEventsForTask(taskEvents, state.taskId);
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 ?? diagEvents.at(-1)?.details ?? null;
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 = evaluateStructuredDiagnosticStall(
53
- buildInformationGainProjection(taskEvents, state.taskId),
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,