@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
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { resolveTaskContext } from "../core/task-context.js";
4
4
  import { inspectTaskConflictState } from "../core/task-conflict-inspection.js";
5
5
  import { appendProtocolEvent } from "../core/events.js";
6
- import { withTaskTransaction } from "../core/transaction.js";
6
+ import { getTaskTransaction, withTaskTransaction } from "../core/transaction.js";
7
7
  import { currentRepositoryFingerprint } from "../core/repository.js";
8
8
  import {
9
9
  readLockInfo,
@@ -86,6 +86,7 @@ export async function runTaskRecover({
86
86
  acknowledgeRecovery = false,
87
87
  operatorAuthorized = false,
88
88
  } = {}) {
89
+ const nested = Boolean(await getTaskTransaction(target));
89
90
  const context = await resolveTaskContext(target, { taskId, packageRoot, explicitRequired: true });
90
91
  const effectiveTaskId = context.taskId;
91
92
 
@@ -130,7 +131,7 @@ export async function runTaskRecover({
130
131
  const inspection = await inspectTaskConflictState(target, {
131
132
  taskId: effectiveTaskId,
132
133
  packageRoot,
133
- ignoredLockId: transaction.lock.lockId,
134
+ ignoredLockId: transaction.lock?.lockId ?? null,
134
135
  });
135
136
  assertRecoveryAllowed(effectiveTaskId, inspection);
136
137
  if (inspection.evidence.workStateRevision !== inspectionBeforeLock.evidence.workStateRevision
@@ -194,6 +195,13 @@ export async function runTaskRecover({
194
195
  message: `Task ${effectiveTaskId} recovered by caller acknowledgement; write claims released without completion claim`,
195
196
  };
196
197
  });
198
+ }).catch(async error => {
199
+ if (error.code === "E_STATE_REVISION_CONFLICT" && !nested) {
200
+ // The failed transaction has rolled back. Report a competing validated
201
+ // recovery through the existing domain error; never replay claim release.
202
+ await assertConsistentRecoverableOwnership(target, effectiveTaskId, packageRoot);
203
+ }
204
+ throw error;
197
205
  });
198
206
  }
199
207
 
@@ -0,0 +1,263 @@
1
+ import { canonicalFingerprint } from "../core/artifacts.js";
2
+ import { readContract } from "../core/contract.js";
3
+ import { appendProtocolEvent, validateEventLedger } from "../core/events.js";
4
+ import { readPersistedRoute } from "../core/route-artifact.js";
5
+ import { currentRepositoryFingerprint } from "../core/repository.js";
6
+ import { resolveTaskContext } from "../core/task-context.js";
7
+ import { taskArtifactPath } from "../core/task-paths.js";
8
+ import { withProjectClaimsLock, readLockInfo, classifyLockStaleness, releaseStaleTaskLockIfUnchanged } from "../core/task-lock.js";
9
+ import { withTaskTransaction } from "../core/transaction.js";
10
+ import { createWorkState, mutateWorkState, readWorkState } from "../core/work-state.js";
11
+ import { resolveTaskClaimState } from "../core/task-claim-state.js";
12
+ import {
13
+ CONTRACT_BOOTSTRAP_REPAIR_AUTHORITY,
14
+ CONTRACT_BOOTSTRAP_REPAIR_DEFECT,
15
+ CONTRACT_BOOTSTRAP_REPAIR_EVENT,
16
+ CONTRACT_BOOTSTRAP_REPAIR_VERSION,
17
+ assertContractBootstrapRepairDetails,
18
+ contractBootstrapRepairId,
19
+ isContractBootstrapRepairCandidate,
20
+ resolveEffectiveContractBootstrapRepairAnchor,
21
+ } from "../core/contract-bootstrap-recovery.js";
22
+ import {
23
+ E_CONTRACT_BOOTSTRAP_REPAIR_AUTHORIZATION_REQUIRED,
24
+ E_CONTRACT_BOOTSTRAP_REPAIR_INVALID,
25
+ E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE,
26
+ E_TASK_LOCKED,
27
+ } from "../core/error-codes.js";
28
+
29
+ function repairError(code, message, details = {}) {
30
+ const error = new Error(message);
31
+ error.code = code;
32
+ Object.assign(error, details);
33
+ return error;
34
+ }
35
+
36
+ async function readRouteIfProven(target, packageRoot, taskId, events, contractFingerprint) {
37
+ const routePath = taskArtifactPath(taskId, "route");
38
+ const hasRouteValidated = events.some((event) => event.event === "ROUTE_VALIDATED");
39
+ if (!hasRouteValidated) return null;
40
+ try {
41
+ const route = await readPersistedRoute(target, packageRoot, { taskId });
42
+ if (route.value.contractFingerprint !== contractFingerprint) {
43
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Persisted route does not bind to the canonical contract fingerprint");
44
+ }
45
+ return route;
46
+ } catch (error) {
47
+ if (error.code === "ARTIFACT_MISSING") {
48
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "ROUTE_VALIDATED history requires a persisted route artifact", { artifacts: [routePath] });
49
+ }
50
+ if (error.code === E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE) throw error;
51
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, `Persisted route cannot be proven safe: ${error.message}`, { artifacts: [routePath] });
52
+ }
53
+ }
54
+
55
+ function stateForRepair(state, { taskId, contractFingerprint, route, repository }) {
56
+ const routed = Boolean(route);
57
+ const phase = routed ? "ROUTED" : "CONTRACT_READY";
58
+ const steps = routed
59
+ ? { completedSteps: ["contract", "route"], pendingSteps: ["planning", "implementation", "verification"] }
60
+ : { completedSteps: ["contract"], pendingSteps: ["route", "planning", "implementation", "verification"] };
61
+ const base = state ? {
62
+ ...state,
63
+ taskId,
64
+ contractFingerprint,
65
+ ...(routed ? { routeFingerprint: route.fingerprint } : { routeFingerprint: undefined }),
66
+ repositoryFingerprint: repository,
67
+ phase,
68
+ selectedGuides: routed ? [...route.value.guides] : [],
69
+ completedSteps: steps.completedSteps,
70
+ pendingSteps: steps.pendingSteps,
71
+ revision: (state.revision ?? 0) + 1,
72
+ lastUpdated: new Date().toISOString(),
73
+ ...(state.phase !== phase ? { previousPhase: state.phase } : {}),
74
+ } : createWorkState({
75
+ taskId,
76
+ contractFingerprint,
77
+ ...(routed ? { routeFingerprint: route.fingerprint } : {}),
78
+ repositoryFingerprint: repository,
79
+ phase,
80
+ selectedGuides: routed ? [...route.value.guides] : [],
81
+ requiredGates: [],
82
+ satisfiedGates: [],
83
+ completedSteps: steps.completedSteps,
84
+ pendingSteps: steps.pendingSteps,
85
+ requiredArtifacts: [],
86
+ checks: [],
87
+ failures: [],
88
+ blockers: [],
89
+ verificationEvidence: [],
90
+ revision: 0,
91
+ });
92
+ if (base.routeFingerprint === undefined) delete base.routeFingerprint;
93
+ return createWorkState(base);
94
+ }
95
+
96
+ function assertStateCompatible(state, taskId, contractFingerprint, route) {
97
+ if (!state) return;
98
+ if (state.taskId !== taskId || state.contractFingerprint !== contractFingerprint) {
99
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Existing work-state is bound to a different task or contract");
100
+ }
101
+ if (!["CONTRACT_READY", "ROUTED"].includes(state.phase)) {
102
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, `Existing work-state phase ${state.phase} is beyond the repair boundary`);
103
+ }
104
+ if (route && state.routeFingerprint !== undefined && state.routeFingerprint !== route.fingerprint) {
105
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Existing work-state route fingerprint conflicts with the proven route");
106
+ }
107
+ if (!route && state.routeFingerprint !== undefined) {
108
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Existing work-state claims a route that cannot be proven from the artifacts");
109
+ }
110
+ if (state.phase === "CONTRACT_READY") {
111
+ if (state.routeFingerprint !== undefined) {
112
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "CONTRACT_READY work-state must not claim a route");
113
+ }
114
+ if (Array.isArray(state.selectedGuides) && state.selectedGuides.length > 0) {
115
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "CONTRACT_READY work-state must not have selected guides");
116
+ }
117
+ if (Array.isArray(state.requiredGates) && state.requiredGates.length > 0) {
118
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "CONTRACT_READY work-state must not have required gates");
119
+ }
120
+ if (Array.isArray(state.satisfiedGates) && state.satisfiedGates.length > 0) {
121
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "CONTRACT_READY work-state must not have satisfied gates");
122
+ }
123
+ }
124
+ }
125
+
126
+ function markerResult(taskId, marker, state, alreadyRepaired) {
127
+ return {
128
+ taskId,
129
+ repaired: alreadyRepaired ? false : true,
130
+ alreadyRepaired,
131
+ repairId: marker.details.repairId,
132
+ phase: state.phase,
133
+ reconstructedPhase: marker.details.reconstructedPhase,
134
+ markerEventSeq: marker.seq,
135
+ };
136
+ }
137
+
138
+ async function verifyExistingRepair(target, packageRoot, taskId, ledger) {
139
+ const anchor = resolveEffectiveContractBootstrapRepairAnchor(ledger.events);
140
+ if (!anchor || !ledger.valid) {
141
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_INVALID, "Existing contract bootstrap repair marker is invalid or the repaired ledger is no longer strict");
142
+ }
143
+ const contract = await readContract(target, packageRoot, { taskId });
144
+ if (contract.fingerprint !== anchor.details.contractFingerprint) {
145
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_INVALID, "Contract fingerprint no longer matches the repair marker");
146
+ }
147
+ const state = await readWorkState(target, { packageRoot, taskId });
148
+ const ownership = await resolveTaskClaimState(target, { taskId, packageRoot });
149
+ if (!ownership.ownershipValid) {
150
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_INVALID, "Current task state no longer satisfies the repaired-task invariants", {
151
+ errors: ownership.errors,
152
+ });
153
+ }
154
+ return markerResult(taskId, { ...anchor.sourceMarker, details: anchor.details }, state, true);
155
+ }
156
+
157
+ export async function runTaskRepairContractBootstrap({ target, packageRoot, taskId, acknowledgeRepair } = {}) {
158
+ if (!acknowledgeRepair) {
159
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_AUTHORIZATION_REQUIRED, "task-repair-contract-bootstrap requires fresh explicit --acknowledge-repair");
160
+ }
161
+ const context = await resolveTaskContext(target, { taskId, packageRoot, explicitRequired: true });
162
+ const effectiveTaskId = context.taskId;
163
+ const initial = await validateEventLedger(target, packageRoot, { taskId: effectiveTaskId });
164
+ if (initial.events.some((event) => event.event === CONTRACT_BOOTSTRAP_REPAIR_EVENT)) {
165
+ return verifyExistingRepair(target, packageRoot, effectiveTaskId, initial);
166
+ }
167
+ const candidate = isContractBootstrapRepairCandidate(initial.events, initial.errors, effectiveTaskId);
168
+ if (!candidate) {
169
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Ledger does not match the exact contract bootstrap repair signature", { errors: initial.errors });
170
+ }
171
+
172
+ return withProjectClaimsLock(target, "task-repair-contract-bootstrap", async () => {
173
+ const lock = await readLockInfo(target, effectiveTaskId);
174
+ const status = classifyLockStaleness(lock);
175
+ if (status.status === "LIVE") throw repairError(E_TASK_LOCKED, `Task ${effectiveTaskId} has a live mutation lock`);
176
+ if (status.status === "UNKNOWN" || status.status === "CORRUPT") {
177
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, `Task ${effectiveTaskId} lock state is ${status.status}`);
178
+ }
179
+ if (status.status === "STALE") {
180
+ const released = await releaseStaleTaskLockIfUnchanged(target, effectiveTaskId, lock);
181
+ if (!released.released && released.reason !== "LOCK_MISSING") {
182
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE,
183
+ `Task ${effectiveTaskId} stale lock could not be safely released: ${released.reason}`);
184
+ }
185
+ }
186
+ return withTaskTransaction({
187
+ target,
188
+ taskId: effectiveTaskId,
189
+ operation: "task-repair-contract-bootstrap",
190
+ packageRoot,
191
+ recordCommitEvent: true,
192
+ }, async () => {
193
+ const locked = await validateEventLedger(target, packageRoot, { taskId: effectiveTaskId });
194
+ if (locked.events.some((event) => event.event === CONTRACT_BOOTSTRAP_REPAIR_EVENT)) {
195
+ return verifyExistingRepair(target, packageRoot, effectiveTaskId, locked);
196
+ }
197
+ const lockedCandidate = isContractBootstrapRepairCandidate(locked.events, locked.errors, effectiveTaskId);
198
+ if (!lockedCandidate
199
+ || lockedCandidate.duplicateContractEvent.hash !== candidate.duplicateContractEvent.hash
200
+ || lockedCandidate.duplicateContractCommit.hash !== candidate.duplicateContractCommit.hash) {
201
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_INVALID, "Ledger changed between inspection and repair lock");
202
+ }
203
+ const contract = await readContract(target, packageRoot, { taskId: effectiveTaskId });
204
+ if (contract.fingerprint !== lockedCandidate.contractFingerprint) {
205
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Current contract does not match the canonical historical contract fingerprint");
206
+ }
207
+ const route = await readRouteIfProven(target, packageRoot, effectiveTaskId, locked.events, contract.fingerprint);
208
+ const state = await readWorkState(target, { packageRoot, taskId: effectiveTaskId });
209
+ assertStateCompatible(state, effectiveTaskId, contract.fingerprint, route);
210
+ if (!state) {
211
+ throw repairError(E_CONTRACT_BOOTSTRAP_REPAIR_UNSAFE, "Existing work-state is required to repair the contract bootstrap defect");
212
+ }
213
+ const repository = await currentRepositoryFingerprint(target);
214
+ const reconstructed = await mutateWorkState(target, {
215
+ expectedRevision: state.revision ?? 0,
216
+ packageRoot,
217
+ taskId: effectiveTaskId,
218
+ }, (current) => {
219
+ assertStateCompatible(current, effectiveTaskId, contract.fingerprint, route);
220
+ return stateForRepair(current, {
221
+ taskId: effectiveTaskId,
222
+ contractFingerprint: contract.fingerprint,
223
+ route,
224
+ repository,
225
+ });
226
+ });
227
+ const repairedAt = new Date().toISOString();
228
+ const details = {
229
+ repairVersion: CONTRACT_BOOTSTRAP_REPAIR_VERSION,
230
+ taskId: effectiveTaskId,
231
+ defect: CONTRACT_BOOTSTRAP_REPAIR_DEFECT,
232
+ canonicalContractEventSeq: lockedCandidate.canonicalContractEvent.seq,
233
+ canonicalContractEventHash: lockedCandidate.canonicalContractEvent.hash,
234
+ duplicateContractEventSeq: lockedCandidate.duplicateContractEvent.seq,
235
+ duplicateContractEventHash: lockedCandidate.duplicateContractEvent.hash,
236
+ contractCreateCommitSeq: lockedCandidate.duplicateContractCommit.seq,
237
+ contractCreateCommitHash: lockedCandidate.duplicateContractCommit.hash,
238
+ contractCreateTransactionId: lockedCandidate.duplicateContractCommit.details.transactionId,
239
+ contractFingerprint: contract.fingerprint,
240
+ reconstructedPhase: reconstructed.phase,
241
+ routeFingerprint: route?.fingerprint ?? null,
242
+ previousStateFingerprint: canonicalFingerprint(state),
243
+ reconstructedStateFingerprint: canonicalFingerprint(reconstructed),
244
+ reconstructedStateRevision: reconstructed.revision,
245
+ repairedAt,
246
+ authorityKind: CONTRACT_BOOTSTRAP_REPAIR_AUTHORITY,
247
+ };
248
+ details.repairId = contractBootstrapRepairId(details);
249
+ assertContractBootstrapRepairDetails(details);
250
+ const marker = await appendProtocolEvent(target, {
251
+ taskId: effectiveTaskId,
252
+ event: CONTRACT_BOOTSTRAP_REPAIR_EVENT,
253
+ at: repairedAt,
254
+ details,
255
+ }, packageRoot, { taskId: effectiveTaskId });
256
+ return markerResult(effectiveTaskId, marker, reconstructed, false);
257
+ });
258
+ });
259
+ }
260
+
261
+ export function formatTaskRepairContractBootstrapResult(result) {
262
+ return `taskId: ${result.taskId}\nphase: ${result.phase}\nrepairId: ${result.repairId}\n${result.alreadyRepaired ? "alreadyRepaired: true" : "repaired: true"}\n`;
263
+ }
@@ -1,3 +1,6 @@
1
+ import { withEventLedgerAudit } from "../core/events.js";
2
+ import { getOperationalStore } from "../storage/operational-context.js";
3
+ import { needsExistingProjectScope, withExistingProjectScope } from "../storage/existing-project-scope.js";
1
4
  import { resolveTaskContext } from "../core/task-context.js";
2
5
  import { readTaskDescriptor, writeTaskDescriptor } from "../core/task-descriptor.js";
3
6
  import { normalizeWriteClaims, assertScopeClean, assertScopeNotFrozen } from "../core/task-scope.js";
@@ -18,8 +21,20 @@ function taskError(code, message, artifacts = []) {
18
21
  return error;
19
22
  }
20
23
 
21
- export async function runTaskScope({ target, packageRoot, taskId, claims } = {}) {
24
+ export async function runTaskScope(options = {}) {
25
+ const { target, packageRoot, taskId, claims } = options;
26
+ const readOnly = claims === undefined || claims === null;
27
+ if (readOnly && await needsExistingProjectScope(target)) {
28
+ return withExistingProjectScope(target, () => runTaskScope(options), { readOnly: true });
29
+ }
22
30
  const context = await resolveTaskContext(target, { taskId, packageRoot, explicitRequired: true });
31
+ if (readOnly && getOperationalStore(target)) {
32
+ return withEventLedgerAudit(target, packageRoot, { taskId: context.taskId }, () => runResolvedTaskScope(options, context));
33
+ }
34
+ return runResolvedTaskScope(options, context);
35
+ }
36
+
37
+ async function runResolvedTaskScope({ target, packageRoot, claims }, context) {
23
38
  const effectiveTaskId = context.taskId;
24
39
 
25
40
  let descriptorArtifact;
@@ -38,6 +53,7 @@ export async function runTaskScope({ target, packageRoot, taskId, claims } = {})
38
53
  return withProjectClaimsLock(target, async () => {
39
54
  return withTaskLock(target, effectiveTaskId, "task-scope", async () => {
40
55
  await assertTaskNotRecovered(target, { taskId: effectiveTaskId, packageRoot });
56
+ const lockedDescriptor = (await readTaskDescriptor(target, effectiveTaskId, packageRoot)).value;
41
57
  const state = await readWorkState(target, { packageRoot, taskId: effectiveTaskId });
42
58
  if (state?.phase) {
43
59
  assertScopeNotFrozen(state.phase);
@@ -51,7 +67,7 @@ export async function runTaskScope({ target, packageRoot, taskId, claims } = {})
51
67
  }
52
68
 
53
69
  const updatedDescriptor = {
54
- ...descriptor,
70
+ ...lockedDescriptor,
55
71
  writeClaims: normalizedClaims,
56
72
  updatedAt: new Date().toISOString(),
57
73
  };
@@ -9,6 +9,9 @@ import { E_TASK_NOT_FOUND } from "../core/error-codes.js";
9
9
  import { resolveTaskClaimState } from "../core/task-claim-state.js";
10
10
  import { readPersistedRoute } from "../core/route-artifact.js";
11
11
  import { projectExecutionProfile } from "../core/execution-profile.js";
12
+ import { withEventLedgerAudit } from "../core/events.js";
13
+ import { needsExistingProjectScope, withExistingProjectScope } from "../storage/existing-project-scope.js";
14
+ import { getOperationalStore, operationalArtifactExists } from "../storage/operational-context.js";
12
15
 
13
16
  function taskError(code, message, artifacts = []) {
14
17
  const error = new Error(message);
@@ -17,8 +20,19 @@ function taskError(code, message, artifacts = []) {
17
20
  return error;
18
21
  }
19
22
 
20
- export async function runTaskShow({ target, packageRoot, taskId, compact = false } = {}) {
23
+ export async function runTaskShow(options = {}) {
24
+ const { target, packageRoot, taskId } = options;
25
+ if (await needsExistingProjectScope(target)) {
26
+ return withExistingProjectScope(target, () => runTaskShow(options), { readOnly: true });
27
+ }
21
28
  const context = await resolveTaskContext(target, { taskId, packageRoot, explicitRequired: true, selectionMode: TASK_SELECTION_MODES.READ });
29
+ if (getOperationalStore(target)) {
30
+ return withEventLedgerAudit(target, packageRoot, { taskId: context.taskId }, () => projectTaskShow(options, context));
31
+ }
32
+ return projectTaskShow(options, context);
33
+ }
34
+
35
+ async function projectTaskShow({ target, packageRoot, compact = false }, context) {
22
36
  const effectiveTaskId = context.taskId;
23
37
 
24
38
  let descriptor = null;
@@ -54,7 +68,7 @@ export async function runTaskShow({ target, packageRoot, taskId, compact = false
54
68
  const rel = taskArtifactPath(effectiveTaskId, name);
55
69
  artifacts[name] = {
56
70
  path: rel,
57
- exists: await fileExists(ensureWithin(target, rel)),
71
+ exists: operationalArtifactExists(target, rel) ?? await fileExists(ensureWithin(target, rel)),
58
72
  };
59
73
  }
60
74
 
@@ -0,0 +1,5 @@
1
+ import { runTestInventory as inventory } from "../core/test-intelligence/service.js";
2
+
3
+ export async function runTestInventory({ target = process.cwd() } = {}) { return inventory({ projectRoot: target }); }
4
+ export function formatTestInventoryResult(result) { return `${JSON.stringify(result, null, 2)}\n`; }
5
+
@@ -0,0 +1,5 @@
1
+ import { buildPrunePlan } from "../core/test-intelligence/prune.js";
2
+
3
+ export async function runTestPrunePlan({ target, packageRoot, taskId } = {}) { return buildPrunePlan({ target, packageRoot, taskId }); }
4
+ export function formatTestPrunePlanResult(result) { return `${JSON.stringify(result, null, 2)}\n`; }
5
+
@@ -0,0 +1,5 @@
1
+ import { runPruneProbe as probe } from "../core/test-intelligence/prune.js";
2
+
3
+ export async function runTestPruneProbe({ target, packageRoot, taskId, testId } = {}) { return probe({ target, packageRoot, taskId, testId }); }
4
+ export function formatTestPruneProbeResult(result) { return `${JSON.stringify(result, null, 2)}\n`; }
5
+
@@ -0,0 +1,5 @@
1
+ import { runTestUtility as analyze } from "../core/test-intelligence/service.js";
2
+
3
+ export async function runTestUtility({ target, packageRoot, taskId, semanticStatus } = {}) { return analyze({ target, packageRoot, taskId, semanticStatus }); }
4
+ export function formatTestUtilityResult(result) { return `${JSON.stringify(result, null, 2)}\n`; }
5
+
@@ -8,17 +8,20 @@ import { validateReceipt } from "../core/receipt.js";
8
8
  import { validateTaskBrief, validateDelegatedResult } from "../core/delegation.js";
9
9
  import { ARTIFACT_PATHS, readJsonArtifact } from "../core/artifacts.js";
10
10
  import { evaluatePreflight, validateReadyProtocolConsistency } from "../core/preflight.js";
11
- import { validateEventLedger, validateStateLedgerCoherence } from "../core/events.js";
11
+ import { withEventLedgerAudit, validateStateLedgerCoherence } from "../core/events.js";
12
12
  import { validateChecksExecutionProvenance } from "../core/completion-artifacts.js";
13
13
  import { assertContinuitySemantics } from "../core/continuity.js";
14
14
  import { currentChangedPaths, currentRepositoryFingerprint } from "../core/repository.js";
15
15
  import { resolveTaskClaimState } from "../core/task-claim-state.js";
16
+ import { getOperationalStore, readOperationalText } from "../storage/operational-context.js";
17
+ import { withProjectReadSnapshot } from "../storage/project-read-snapshot.js";
16
18
 
17
19
  async function readArtifact(target, relativePath, label) {
18
20
  if (!relativePath) return null;
19
21
  await assertSafePath(target, relativePath);
20
22
  const artifactPath = ensureWithin(target, relativePath);
21
- if (!(await fileExists(artifactPath))) {
23
+ const operational = readOperationalText(target, relativePath);
24
+ if (operational.selected ? operational.text === null : !(await fileExists(artifactPath))) {
22
25
  return {
23
26
  error: {
24
27
  code: "ARTIFACT_MISSING",
@@ -27,7 +30,7 @@ async function readArtifact(target, relativePath, label) {
27
30
  },
28
31
  };
29
32
  }
30
- const bytes = await readBytes(artifactPath);
33
+ const bytes = operational.selected ? Buffer.from(operational.text, "utf8") : await readBytes(artifactPath);
31
34
  try {
32
35
  assertJsonBytes(bytes, label);
33
36
  const value = JSON.parse(bytes.toString("utf8"));
@@ -44,10 +47,18 @@ async function readArtifact(target, relativePath, label) {
44
47
  }
45
48
  }
46
49
 
50
+ function isOptionalContinuityAbsence(item) {
51
+ return item.label === "continuity" && item.error?.code === "ARTIFACT_MISSING";
52
+ }
53
+
47
54
  import { taskArtifactPath } from "../core/task-paths.js";
48
55
  import { withResolvedTask } from "../core/task-command.js";
49
56
 
50
- export async function runValidateProtocol({
57
+ export async function runValidateProtocol(options) {
58
+ return withProjectReadSnapshot(options.target, () => validateSelectedProtocol(options));
59
+ }
60
+
61
+ async function validateSelectedProtocol({
51
62
  target,
52
63
  packageRoot,
53
64
  routeFile = null,
@@ -59,9 +70,17 @@ export async function runValidateProtocol({
59
70
  delegatedResultFiles = [],
60
71
  taskId = null,
61
72
  task = null,
62
- }) {
73
+ }, ownedLedger = null) {
63
74
  return withResolvedTask(target, { taskId: taskId ?? task, packageRoot }, async (ctx) => {
64
75
  const effectiveTaskId = ctx?.taskId ?? null;
76
+ if (effectiveTaskId && getOperationalStore(target) && !ownedLedger) {
77
+ // Keep the complete final proof local to this immutable projection.
78
+ // Nested preflight audits retain their own rules and share its source.
79
+ return withEventLedgerAudit(target, packageRoot, { taskId: effectiveTaskId }, ledger => validateSelectedProtocol({
80
+ target, packageRoot, routeFile, stateFile, receiptFile, contractFile, continuityFile,
81
+ taskBriefFiles, delegatedResultFiles, taskId: effectiveTaskId,
82
+ }, ledger));
83
+ }
65
84
  const effectiveRouteFile = routeFile ?? (effectiveTaskId ? taskArtifactPath(effectiveTaskId, "route") : ARTIFACT_PATHS.route);
66
85
  const effectiveStateFile = stateFile ?? (effectiveTaskId ? taskArtifactPath(effectiveTaskId, "state") : ARTIFACT_PATHS.state);
67
86
  const effectiveReceiptFile = receiptFile ?? (effectiveTaskId ? taskArtifactPath(effectiveTaskId, "receipt") : ARTIFACT_PATHS.receipt);
@@ -84,7 +103,12 @@ export async function runValidateProtocol({
84
103
  loaded.push({ label, relativePath, ...artifact });
85
104
  }
86
105
 
87
- const readErrors = loaded.filter((item) => item.error).map((item) => item.error);
106
+ // Continuity is an optional operational-context artifact. Its absence is
107
+ // represented by evaluateContinuityConformance as NOT_APPLICABLE; only a
108
+ // present but malformed continuity artifact is a validation failure.
109
+ const readErrors = loaded
110
+ .filter((item) => item.error && !isOptionalContinuityAbsence(item))
111
+ .map((item) => item.error);
88
112
  const route = loaded.find((item) => item.label === "route")?.value ?? null;
89
113
  const state = loaded.find((item) => item.label === "state")?.value ?? null;
90
114
  const receipt = loaded.find((item) => item.label === "receipt")?.value ?? null;
@@ -160,19 +184,15 @@ export async function runValidateProtocol({
160
184
  } catch {
161
185
  // A missing or invalid preflight is already outside the optional protocol set.
162
186
  }
163
- let ledgerEvents = [];
164
- let ledgerErrors = [];
165
- if (state && !stateValidationError) {
166
- const ledger = await validateEventLedger(target, packageRoot, { taskId: effectiveTaskId, eventsPath: effectiveEventsFile });
167
- ledgerEvents = ledger.events ?? [];
168
- ledgerErrors = [
187
+ const finish = async (ledger) => {
188
+ const ledgerEvents = ledger.events ?? [];
189
+ const ledgerErrors = state && !stateValidationError ? [
169
190
  ...ledger.errors.map((error) => ({ ...error, artifacts: [effectiveEventsFile] })),
170
- ...validateStateLedgerCoherence(state, ledger.events).map((error) => ({
191
+ ...validateStateLedgerCoherence(state, ledgerEvents).map((error) => ({
171
192
  ...error,
172
193
  artifacts: [effectiveStateFile, effectiveEventsFile],
173
194
  })),
174
- ];
175
- }
195
+ ] : [];
176
196
  const recoveryErrors = [];
177
197
  if (effectiveTaskId) {
178
198
  try {
@@ -216,6 +236,10 @@ export async function runValidateProtocol({
216
236
  };
217
237
  }
218
238
  return result;
239
+ };
240
+ return state && !stateValidationError
241
+ ? ownedLedger ? finish(ownedLedger) : withEventLedgerAudit(target, packageRoot, { taskId: effectiveTaskId, eventsPath: effectiveEventsFile }, finish)
242
+ : finish({ events: [], errors: [] });
219
243
  });
220
244
  }
221
245
 
@@ -4,13 +4,17 @@ import { assertJsonBytes, assertJsonLimits } from "../core/json-safety.js";
4
4
  import { ARTIFACT_PATHS } from "../core/artifacts.js";
5
5
  import { taskArtifactPath } from "../core/task-paths.js";
6
6
  import { withResolvedTask } from "../core/task-command.js";
7
+ import { readOperationalText } from "../storage/operational-context.js";
8
+ import { isOperationalArtifactPath, needsExistingProjectScope, withExistingProjectScope } from "../storage/existing-project-scope.js";
7
9
 
8
10
  async function validateReceiptFile(target, packageRoot, relativeFile) {
9
11
  await assertSafePath(target, relativeFile);
10
12
  const receiptPath = ensureWithin(target, relativeFile);
11
13
  let receipt;
12
14
  try {
13
- const bytes = await readBytes(receiptPath);
15
+ const operational = readOperationalText(target, relativeFile);
16
+ if (operational.selected && operational.text === null) throw new Error("Receipt is missing from canonical storage");
17
+ const bytes = operational.selected ? Buffer.from(operational.text, "utf8") : await readBytes(receiptPath);
14
18
  assertJsonBytes(bytes, relativeFile);
15
19
  receipt = JSON.parse(bytes.toString("utf8"));
16
20
  assertJsonLimits(receipt, relativeFile);
@@ -43,6 +47,9 @@ export async function runValidateReceipt({
43
47
  file = null,
44
48
  taskId = null,
45
49
  } = {}) {
50
+ if ((!file || isOperationalArtifactPath(file)) && await needsExistingProjectScope(target)) {
51
+ return withExistingProjectScope(target, () => runValidateReceipt({ target, packageRoot, file, taskId }), { readOnly: true });
52
+ }
46
53
  if (file) {
47
54
  return validateReceiptFile(target, packageRoot, file);
48
55
  }
@@ -86,5 +86,9 @@
86
86
  "swift": {
87
87
  "path": "ENG/swift-development-eng.md",
88
88
  "install": true
89
+ },
90
+ "python": {
91
+ "path": "ENG/python-development-eng.md",
92
+ "install": true
89
93
  }
90
94
  }
@@ -1,4 +1,4 @@
1
- import { readEvents } from "./events.js";
1
+ import { iterateEvents } from "./events.js";
2
2
  import { assertActionTransition, assertActionAuthorizationDetails } from "./action-model.js";
3
3
  import { E_ACTION_EVIDENCE_INVALID } from "./error-codes.js";
4
4
 
@@ -27,6 +27,14 @@ function hasCanonicalVerificationEvidence(details) {
27
27
  );
28
28
  }
29
29
 
30
+ async function readActionChronology(target, packageRoot, taskId, actionId) {
31
+ const chronology = [];
32
+ for await (const event of iterateEvents(target, packageRoot, { taskId })) {
33
+ if (event.details?.actionId === actionId) chronology.push(event);
34
+ }
35
+ return chronology;
36
+ }
37
+
30
38
  function issue(code, message) {
31
39
  return { code, message };
32
40
  }
@@ -49,8 +57,7 @@ export async function projectActionLedger({
49
57
  actionId,
50
58
  artifact = null,
51
59
  }) {
52
- const events = await readEvents(target, packageRoot, { taskId });
53
- const chronology = events.filter((event) => event.details?.actionId === actionId);
60
+ const chronology = await readActionChronology(target, packageRoot, taskId, actionId);
54
61
  const errors = [];
55
62
 
56
63
  const proposed = chronology.find((event) => event.event === "ACTION_PROPOSED");