@tacuchi/agent-workflow-cli 25.7.0 → 25.9.0

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 (580) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +5 -1
  3. package/dist/adapters/git-cli.js +311 -24
  4. package/dist/adapters/git-cli.js.map +1 -1
  5. package/dist/adapters/node-file-system.js +48 -0
  6. package/dist/adapters/node-file-system.js.map +1 -1
  7. package/dist/application/amend-service.js +51 -14
  8. package/dist/application/amend-service.js.map +1 -1
  9. package/dist/application/branch-resolver.js +6 -3
  10. package/dist/application/branch-resolver.js.map +1 -1
  11. package/dist/application/capability/design-handler.js +124 -43
  12. package/dist/application/capability/design-handler.js.map +1 -1
  13. package/dist/application/capability/dispatcher.js +4 -1
  14. package/dist/application/capability/dispatcher.js.map +1 -1
  15. package/dist/application/capability/durable-effect.js +3 -0
  16. package/dist/application/capability/durable-effect.js.map +1 -1
  17. package/dist/application/capability/readiness.js +26 -10
  18. package/dist/application/capability/readiness.js.map +1 -1
  19. package/dist/application/capability/wrapper.js +10 -3
  20. package/dist/application/capability/wrapper.js.map +1 -1
  21. package/dist/application/check-branch-service.js +158 -19
  22. package/dist/application/check-branch-service.js.map +1 -1
  23. package/dist/application/checkpoint/markdown.js +2 -2
  24. package/dist/application/checkpoint/markdown.js.map +1 -1
  25. package/dist/application/checkpoint/state-reader.js +12 -0
  26. package/dist/application/checkpoint/state-reader.js.map +1 -1
  27. package/dist/application/checkpoint-service.js +12 -4
  28. package/dist/application/checkpoint-service.js.map +1 -1
  29. package/dist/application/checkpoint-write-service.js +91 -17
  30. package/dist/application/checkpoint-write-service.js.map +1 -1
  31. package/dist/application/claims-ledger.js +137 -11
  32. package/dist/application/claims-ledger.js.map +1 -1
  33. package/dist/application/claims-recovery.js +85 -44
  34. package/dist/application/claims-recovery.js.map +1 -1
  35. package/dist/application/database-tool-catalog.js +33 -0
  36. package/dist/application/database-tool-catalog.js.map +1 -1
  37. package/dist/application/design/consumer-document.js +2 -2
  38. package/dist/application/design/consumer-document.js.map +1 -1
  39. package/dist/application/design/design-content-gate-service.js +20 -2
  40. package/dist/application/design/design-content-gate-service.js.map +1 -1
  41. package/dist/application/design/design-gate-service.js +2 -0
  42. package/dist/application/design/design-gate-service.js.map +1 -1
  43. package/dist/application/design/design-index-service.js +4 -0
  44. package/dist/application/design/design-index-service.js.map +1 -1
  45. package/dist/application/design/design-publish-service.js +1 -4
  46. package/dist/application/design/design-publish-service.js.map +1 -1
  47. package/dist/application/design/design-record-service.js +13 -7
  48. package/dist/application/design/design-record-service.js.map +1 -1
  49. package/dist/application/design/design-resolver-service.js +22 -3
  50. package/dist/application/design/design-resolver-service.js.map +1 -1
  51. package/dist/application/design/design-simple-service.js +24 -5
  52. package/dist/application/design/design-simple-service.js.map +1 -1
  53. package/dist/application/design/digest.js +41 -0
  54. package/dist/application/design/digest.js.map +1 -0
  55. package/dist/application/dev-only-services.js +171 -27
  56. package/dist/application/dev-only-services.js.map +1 -1
  57. package/dist/application/doc-branch-ledger.js +145 -0
  58. package/dist/application/doc-branch-ledger.js.map +1 -0
  59. package/dist/application/docs-canon-service.js +1 -1
  60. package/dist/application/docs-canon-service.js.map +1 -1
  61. package/dist/application/doctor/dist-integrity.js +113 -0
  62. package/dist/application/doctor/dist-integrity.js.map +1 -0
  63. package/dist/application/doctor/hosts.js +5 -2
  64. package/dist/application/doctor/hosts.js.map +1 -1
  65. package/dist/application/doctor/prepare.js +4 -1
  66. package/dist/application/doctor/prepare.js.map +1 -1
  67. package/dist/application/doctor/provider-installation.js +39 -19
  68. package/dist/application/doctor/provider-installation.js.map +1 -1
  69. package/dist/application/doctor/provider-mcps.js +10 -2
  70. package/dist/application/doctor/provider-mcps.js.map +1 -1
  71. package/dist/application/doctor/provider-skills.js +25 -0
  72. package/dist/application/doctor/provider-skills.js.map +1 -1
  73. package/dist/application/doctor/provider-visibility.js +76 -3
  74. package/dist/application/doctor/provider-visibility.js.map +1 -1
  75. package/dist/application/doctor/provider-workspace-block.js +156 -0
  76. package/dist/application/doctor/provider-workspace-block.js.map +1 -0
  77. package/dist/application/doctor/repair-runner.js +47 -3
  78. package/dist/application/doctor/repair-runner.js.map +1 -1
  79. package/dist/application/doctor/report.js +24 -4
  80. package/dist/application/doctor/report.js.map +1 -1
  81. package/dist/application/doctor/skills-toml-migrate.js +76 -0
  82. package/dist/application/doctor/skills-toml-migrate.js.map +1 -0
  83. package/dist/application/export-catalog-check.js +200 -0
  84. package/dist/application/export-catalog-check.js.map +1 -0
  85. package/dist/application/export-service.js +716 -79
  86. package/dist/application/export-service.js.map +1 -1
  87. package/dist/application/fix-git-service.js +285 -64
  88. package/dist/application/fix-git-service.js.map +1 -1
  89. package/dist/application/flow/advance.js +241 -30
  90. package/dist/application/flow/advance.js.map +1 -1
  91. package/dist/application/flow/annul-service.js +3 -1
  92. package/dist/application/flow/annul-service.js.map +1 -1
  93. package/dist/application/flow/batch-commit.js +189 -0
  94. package/dist/application/flow/batch-commit.js.map +1 -0
  95. package/dist/application/flow/checkout-observation.js +110 -8
  96. package/dist/application/flow/checkout-observation.js.map +1 -1
  97. package/dist/application/flow/close-artifacts.js +105 -0
  98. package/dist/application/flow/close-artifacts.js.map +1 -0
  99. package/dist/application/flow/close-at-boundary.js +155 -0
  100. package/dist/application/flow/close-at-boundary.js.map +1 -0
  101. package/dist/application/flow/close-document-guidance.js +70 -0
  102. package/dist/application/flow/close-document-guidance.js.map +1 -0
  103. package/dist/application/flow/flow-service.js +49 -5
  104. package/dist/application/flow/flow-service.js.map +1 -1
  105. package/dist/application/flow/internal-actions.js +361 -80
  106. package/dist/application/flow/internal-actions.js.map +1 -1
  107. package/dist/application/flow/internal-drive.js +47 -19
  108. package/dist/application/flow/internal-drive.js.map +1 -1
  109. package/dist/application/flow/plan-entry.js +82 -0
  110. package/dist/application/flow/plan-entry.js.map +1 -0
  111. package/dist/application/flow/prove.js +32 -1
  112. package/dist/application/flow/prove.js.map +1 -1
  113. package/dist/application/flow/quick-checkouts.js +48 -0
  114. package/dist/application/flow/quick-checkouts.js.map +1 -0
  115. package/dist/application/flow/reinfer-batch.js +177 -0
  116. package/dist/application/flow/reinfer-batch.js.map +1 -0
  117. package/dist/application/flow/reopen-run.js +159 -0
  118. package/dist/application/flow/reopen-run.js.map +1 -0
  119. package/dist/application/flow/run-journey.js +11 -8
  120. package/dist/application/flow/run-journey.js.map +1 -1
  121. package/dist/application/flow/run-projection.js +16 -5
  122. package/dist/application/flow/run-projection.js.map +1 -1
  123. package/dist/application/flow/run-state-service.js +3 -1
  124. package/dist/application/flow/run-state-service.js.map +1 -1
  125. package/dist/application/flow/submit.js +731 -154
  126. package/dist/application/flow/submit.js.map +1 -1
  127. package/dist/application/generate-launch-service.js +16 -6
  128. package/dist/application/generate-launch-service.js.map +1 -1
  129. package/dist/application/git-flow-service.js +34 -3
  130. package/dist/application/git-flow-service.js.map +1 -1
  131. package/dist/application/history-publications.js +24 -0
  132. package/dist/application/history-publications.js.map +1 -1
  133. package/dist/application/history-reconcile-service.js +45 -0
  134. package/dist/application/history-reconcile-service.js.map +1 -0
  135. package/dist/application/history-table.js +61 -12
  136. package/dist/application/history-table.js.map +1 -1
  137. package/dist/application/history-update-service.js +25 -4
  138. package/dist/application/history-update-service.js.map +1 -1
  139. package/dist/application/hook-branch-check.js +25 -3
  140. package/dist/application/hook-branch-check.js.map +1 -1
  141. package/dist/application/hook-git-commit-advisor.js +3 -4
  142. package/dist/application/hook-git-commit-advisor.js.map +1 -1
  143. package/dist/application/hook-sql-mutation-guard.js +147 -12
  144. package/dist/application/hook-sql-mutation-guard.js.map +1 -1
  145. package/dist/application/hook-turn-start.js +51 -0
  146. package/dist/application/hook-turn-start.js.map +1 -0
  147. package/dist/application/host-memory/codex.js +1 -1
  148. package/dist/application/host-memory/codex.js.map +1 -1
  149. package/dist/application/hub-registry.js +135 -0
  150. package/dist/application/hub-registry.js.map +1 -0
  151. package/dist/application/local-proposal.js +72 -19
  152. package/dist/application/local-proposal.js.map +1 -1
  153. package/dist/application/mcp-host-reader.js +1 -1
  154. package/dist/application/mcp-host-reader.js.map +1 -1
  155. package/dist/application/mcp-host-writer.js +16 -10
  156. package/dist/application/mcp-host-writer.js.map +1 -1
  157. package/dist/application/merge-state-service.js +150 -34
  158. package/dist/application/merge-state-service.js.map +1 -1
  159. package/dist/application/multiroot/claude.js +17 -10
  160. package/dist/application/multiroot/claude.js.map +1 -1
  161. package/dist/application/multiroot/codex.js +17 -11
  162. package/dist/application/multiroot/codex.js.map +1 -1
  163. package/dist/application/multiroot-service.js +52 -28
  164. package/dist/application/multiroot-service.js.map +1 -1
  165. package/dist/application/parsers/execution-batches.js +64 -0
  166. package/dist/application/parsers/execution-batches.js.map +1 -0
  167. package/dist/application/parsers/phases.js +23 -2
  168. package/dist/application/parsers/phases.js.map +1 -1
  169. package/dist/application/parsers/project-block.js +146 -17
  170. package/dist/application/parsers/project-block.js.map +1 -1
  171. package/dist/application/parsers/tasks.js +16 -2
  172. package/dist/application/parsers/tasks.js.map +1 -1
  173. package/dist/application/parsers/toml.js +19 -0
  174. package/dist/application/parsers/toml.js.map +1 -0
  175. package/dist/application/paths-service.js +13 -16
  176. package/dist/application/paths-service.js.map +1 -1
  177. package/dist/application/persist-service.js +118 -5
  178. package/dist/application/persist-service.js.map +1 -1
  179. package/dist/application/plan-exec-batch-service.js +162 -22
  180. package/dist/application/plan-exec-batch-service.js.map +1 -1
  181. package/dist/application/plan-exec-decision-service.js +61 -12
  182. package/dist/application/plan-exec-decision-service.js.map +1 -1
  183. package/dist/application/plan-exec-plan-diff.js +105 -0
  184. package/dist/application/plan-exec-plan-diff.js.map +1 -0
  185. package/dist/application/plan-lint-service.js +2 -0
  186. package/dist/application/plan-lint-service.js.map +1 -1
  187. package/dist/application/plan-passes.js +41 -0
  188. package/dist/application/plan-passes.js.map +1 -0
  189. package/dist/application/preparation-receipts.js +58 -0
  190. package/dist/application/preparation-receipts.js.map +1 -0
  191. package/dist/application/project-md-upsert-service.js +191 -52
  192. package/dist/application/project-md-upsert-service.js.map +1 -1
  193. package/dist/application/project-tab-data.js +40 -10
  194. package/dist/application/project-tab-data.js.map +1 -1
  195. package/dist/application/release-data/artifacts.js +15 -7
  196. package/dist/application/release-data/artifacts.js.map +1 -1
  197. package/dist/application/release-data/bundles.js +52 -6
  198. package/dist/application/release-data/bundles.js.map +1 -1
  199. package/dist/application/release-data/common.js +2 -2
  200. package/dist/application/release-data/common.js.map +1 -1
  201. package/dist/application/release-data/rollback.js +7 -0
  202. package/dist/application/release-data/rollback.js.map +1 -0
  203. package/dist/application/release-data/sessions.js +2 -2
  204. package/dist/application/release-data/sessions.js.map +1 -1
  205. package/dist/application/release-pass-ledger.js +1 -1
  206. package/dist/application/render/history-row.js +2 -0
  207. package/dist/application/render/history-row.js.map +1 -1
  208. package/dist/application/render/project-block.js +28 -11
  209. package/dist/application/render/project-block.js.map +1 -1
  210. package/dist/application/reseal-service.js +1 -0
  211. package/dist/application/reseal-service.js.map +1 -1
  212. package/dist/application/resume-service.js +55 -8
  213. package/dist/application/resume-service.js.map +1 -1
  214. package/dist/application/retirement/apply.js +25 -7
  215. package/dist/application/retirement/apply.js.map +1 -1
  216. package/dist/application/retirement/attribution.js +121 -48
  217. package/dist/application/retirement/attribution.js.map +1 -1
  218. package/dist/application/retirement/prepare.js +17 -11
  219. package/dist/application/retirement/prepare.js.map +1 -1
  220. package/dist/application/retirement/preview.js +2 -1
  221. package/dist/application/retirement/preview.js.map +1 -1
  222. package/dist/application/self/codex-plugin.js +1 -1
  223. package/dist/application/self/codex-plugin.js.map +1 -1
  224. package/dist/application/self/host-states.js +3 -3
  225. package/dist/application/self/host-states.js.map +1 -1
  226. package/dist/application/self/install-hooks.js +1 -1
  227. package/dist/application/self/install-hooks.js.map +1 -1
  228. package/dist/application/self/install-skill.js +35 -11
  229. package/dist/application/self/install-skill.js.map +1 -1
  230. package/dist/application/self/install-targets.js +73 -2
  231. package/dist/application/self/install-targets.js.map +1 -1
  232. package/dist/application/self/mcp-config.js +19 -11
  233. package/dist/application/self/mcp-config.js.map +1 -1
  234. package/dist/application/self/opencode-plugin.js +1 -0
  235. package/dist/application/self/opencode-plugin.js.map +1 -1
  236. package/dist/application/self/uninstall.js +22 -8
  237. package/dist/application/self/uninstall.js.map +1 -1
  238. package/dist/application/semantic-operation/protocol.js +66 -5
  239. package/dist/application/semantic-operation/protocol.js.map +1 -1
  240. package/dist/application/session-archive-service.js +113 -0
  241. package/dist/application/session-archive-service.js.map +1 -0
  242. package/dist/application/session-binding-service.js +35 -0
  243. package/dist/application/session-binding-service.js.map +1 -1
  244. package/dist/application/session-close-service.js +390 -54
  245. package/dist/application/session-close-service.js.map +1 -1
  246. package/dist/application/session-create-service.js +97 -5
  247. package/dist/application/session-create-service.js.map +1 -1
  248. package/dist/application/session-custody-recorder.js +15 -12
  249. package/dist/application/session-custody-recorder.js.map +1 -1
  250. package/dist/application/session-custody-service.js +1 -0
  251. package/dist/application/session-custody-service.js.map +1 -1
  252. package/dist/application/session-narrative.js +51 -12
  253. package/dist/application/session-narrative.js.map +1 -1
  254. package/dist/application/session-pause-service.js +46 -0
  255. package/dist/application/session-pause-service.js.map +1 -0
  256. package/dist/application/session-resolver.js +36 -11
  257. package/dist/application/session-resolver.js.map +1 -1
  258. package/dist/application/session-resume-service.js +190 -20
  259. package/dist/application/session-resume-service.js.map +1 -1
  260. package/dist/application/sessions-service.js +4 -0
  261. package/dist/application/sessions-service.js.map +1 -1
  262. package/dist/application/sessions-sweep-service.js +77 -0
  263. package/dist/application/sessions-sweep-service.js.map +1 -0
  264. package/dist/application/settle-service.js +3 -1
  265. package/dist/application/settle-service.js.map +1 -1
  266. package/dist/application/skills-resolver-service.js +1 -1
  267. package/dist/application/skills-resolver-service.js.map +1 -1
  268. package/dist/application/source-add-service.js +37 -0
  269. package/dist/application/source-add-service.js.map +1 -0
  270. package/dist/application/source-boundary-policy.js +97 -8
  271. package/dist/application/source-boundary-policy.js.map +1 -1
  272. package/dist/application/source-pipeline.js +68 -0
  273. package/dist/application/source-pipeline.js.map +1 -0
  274. package/dist/application/source-remove-service.js +15 -3
  275. package/dist/application/source-remove-service.js.map +1 -1
  276. package/dist/application/sources-service.js +71 -16
  277. package/dist/application/sources-service.js.map +1 -1
  278. package/dist/application/status-service.js +55 -5
  279. package/dist/application/status-service.js.map +1 -1
  280. package/dist/application/unit-dependencies.js +100 -0
  281. package/dist/application/unit-dependencies.js.map +1 -0
  282. package/dist/application/unit-membership.js +37 -0
  283. package/dist/application/unit-membership.js.map +1 -0
  284. package/dist/application/unit-residue.js +72 -0
  285. package/dist/application/unit-residue.js.map +1 -0
  286. package/dist/application/visibility-doctor-service.js +66 -4
  287. package/dist/application/visibility-doctor-service.js.map +1 -1
  288. package/dist/application/working-branch-service.js +6 -0
  289. package/dist/application/working-branch-service.js.map +1 -1
  290. package/dist/application/workline-graph.js +1 -1
  291. package/dist/application/workline-graph.js.map +1 -1
  292. package/dist/application/workline-index-service.js +118 -17
  293. package/dist/application/workline-index-service.js.map +1 -1
  294. package/dist/application/workspace-commit-service.js +218 -0
  295. package/dist/application/workspace-commit-service.js.map +1 -0
  296. package/dist/application/workspace-init-service.js +64 -34
  297. package/dist/application/workspace-init-service.js.map +1 -1
  298. package/dist/application/workspace-local-config.js +90 -0
  299. package/dist/application/workspace-local-config.js.map +1 -0
  300. package/dist/application/workspace-materialization-service.js +52 -3
  301. package/dist/application/workspace-materialization-service.js.map +1 -1
  302. package/dist/application/workspace-migrate/apply.js +525 -4
  303. package/dist/application/workspace-migrate/apply.js.map +1 -1
  304. package/dist/application/workspace-migrate/markers.js +9 -6
  305. package/dist/application/workspace-migrate/markers.js.map +1 -1
  306. package/dist/application/workspace-migrate/plan.js +97 -5
  307. package/dist/application/workspace-migrate/plan.js.map +1 -1
  308. package/dist/application/workspace-move-service.js +270 -0
  309. package/dist/application/workspace-move-service.js.map +1 -0
  310. package/dist/application/workspace-untrack-service.js +28 -0
  311. package/dist/application/workspace-untrack-service.js.map +1 -0
  312. package/dist/application/worktree-service.js +654 -105
  313. package/dist/application/worktree-service.js.map +1 -1
  314. package/dist/cli/ascii.js +86 -0
  315. package/dist/cli/ascii.js.map +1 -0
  316. package/dist/cli/commands/add-source.js +38 -0
  317. package/dist/cli/commands/add-source.js.map +1 -0
  318. package/dist/cli/commands/amend.js +14 -2
  319. package/dist/cli/commands/amend.js.map +1 -1
  320. package/dist/cli/commands/capability.js +26 -0
  321. package/dist/cli/commands/capability.js.map +1 -1
  322. package/dist/cli/commands/check-branch.js +1 -0
  323. package/dist/cli/commands/check-branch.js.map +1 -1
  324. package/dist/cli/commands/checkpoint-read.js +1 -0
  325. package/dist/cli/commands/checkpoint-read.js.map +1 -1
  326. package/dist/cli/commands/checkpoint-write.js +4 -1
  327. package/dist/cli/commands/checkpoint-write.js.map +1 -1
  328. package/dist/cli/commands/claims.js +1 -0
  329. package/dist/cli/commands/claims.js.map +1 -1
  330. package/dist/cli/commands/code-scan.js +1 -0
  331. package/dist/cli/commands/code-scan.js.map +1 -1
  332. package/dist/cli/commands/context-budget.js +1 -0
  333. package/dist/cli/commands/context-budget.js.map +1 -1
  334. package/dist/cli/commands/context-plan.js +1 -0
  335. package/dist/cli/commands/context-plan.js.map +1 -1
  336. package/dist/cli/commands/cut-intent.js +1 -0
  337. package/dist/cli/commands/cut-intent.js.map +1 -1
  338. package/dist/cli/commands/designs.js +15 -5
  339. package/dist/cli/commands/designs.js.map +1 -1
  340. package/dist/cli/commands/dev-only.js +22 -5
  341. package/dist/cli/commands/dev-only.js.map +1 -1
  342. package/dist/cli/commands/doc-branch.js +184 -0
  343. package/dist/cli/commands/doc-branch.js.map +1 -0
  344. package/dist/cli/commands/doctor.js +9 -0
  345. package/dist/cli/commands/doctor.js.map +1 -1
  346. package/dist/cli/commands/export.js +89 -16
  347. package/dist/cli/commands/export.js.map +1 -1
  348. package/dist/cli/commands/fix-git.js +89 -13
  349. package/dist/cli/commands/fix-git.js.map +1 -1
  350. package/dist/cli/commands/flow.js +129 -13
  351. package/dist/cli/commands/flow.js.map +1 -1
  352. package/dist/cli/commands/generate-launch.js +15 -2
  353. package/dist/cli/commands/generate-launch.js.map +1 -1
  354. package/dist/cli/commands/git-flow.js +1 -0
  355. package/dist/cli/commands/git-flow.js.map +1 -1
  356. package/dist/cli/commands/history-update.js +7 -9
  357. package/dist/cli/commands/history-update.js.map +1 -1
  358. package/dist/cli/commands/history.js +14 -0
  359. package/dist/cli/commands/history.js.map +1 -0
  360. package/dist/cli/commands/hook.js +26 -5
  361. package/dist/cli/commands/hook.js.map +1 -1
  362. package/dist/cli/commands/host-doctor.js +1 -0
  363. package/dist/cli/commands/host-doctor.js.map +1 -1
  364. package/dist/cli/commands/host-memory.js +2 -9
  365. package/dist/cli/commands/host-memory.js.map +1 -1
  366. package/dist/cli/commands/index.js +18 -1
  367. package/dist/cli/commands/index.js.map +1 -1
  368. package/dist/cli/commands/mcp.js +30 -4
  369. package/dist/cli/commands/mcp.js.map +1 -1
  370. package/dist/cli/commands/merge-state.js +3 -2
  371. package/dist/cli/commands/merge-state.js.map +1 -1
  372. package/dist/cli/commands/multiroot.js +16 -0
  373. package/dist/cli/commands/multiroot.js.map +1 -1
  374. package/dist/cli/commands/persist.js +7 -5
  375. package/dist/cli/commands/persist.js.map +1 -1
  376. package/dist/cli/commands/plan.js +1 -0
  377. package/dist/cli/commands/plan.js.map +1 -1
  378. package/dist/cli/commands/plugin-cache.js +4 -0
  379. package/dist/cli/commands/plugin-cache.js.map +1 -1
  380. package/dist/cli/commands/plugin-doctor.js +3 -0
  381. package/dist/cli/commands/plugin-doctor.js.map +1 -1
  382. package/dist/cli/commands/project-md-upsert.js +8 -3
  383. package/dist/cli/commands/project-md-upsert.js.map +1 -1
  384. package/dist/cli/commands/release-data.js +12 -0
  385. package/dist/cli/commands/release-data.js.map +1 -1
  386. package/dist/cli/commands/release-pass.js +13 -3
  387. package/dist/cli/commands/release-pass.js.map +1 -1
  388. package/dist/cli/commands/remove-source.js +1 -0
  389. package/dist/cli/commands/remove-source.js.map +1 -1
  390. package/dist/cli/commands/reseal.js +1 -0
  391. package/dist/cli/commands/reseal.js.map +1 -1
  392. package/dist/cli/commands/resume-summary.js +5 -0
  393. package/dist/cli/commands/resume-summary.js.map +1 -1
  394. package/dist/cli/commands/resume.js +13 -3
  395. package/dist/cli/commands/resume.js.map +1 -1
  396. package/dist/cli/commands/retirement.js +1 -0
  397. package/dist/cli/commands/retirement.js.map +1 -1
  398. package/dist/cli/commands/self.js +39 -1
  399. package/dist/cli/commands/self.js.map +1 -1
  400. package/dist/cli/commands/session-artifacts.js +1 -0
  401. package/dist/cli/commands/session-artifacts.js.map +1 -1
  402. package/dist/cli/commands/session-close.js +185 -31
  403. package/dist/cli/commands/session-close.js.map +1 -1
  404. package/dist/cli/commands/session-create.js +4 -1
  405. package/dist/cli/commands/session-create.js.map +1 -1
  406. package/dist/cli/commands/session-pause.js +14 -0
  407. package/dist/cli/commands/session-pause.js.map +1 -0
  408. package/dist/cli/commands/session-resume.js +1 -0
  409. package/dist/cli/commands/session-resume.js.map +1 -1
  410. package/dist/cli/commands/sessions.js +16 -2
  411. package/dist/cli/commands/sessions.js.map +1 -1
  412. package/dist/cli/commands/set-branch.js +29 -4
  413. package/dist/cli/commands/set-branch.js.map +1 -1
  414. package/dist/cli/commands/set-edit-mode.js +20 -0
  415. package/dist/cli/commands/set-edit-mode.js.map +1 -0
  416. package/dist/cli/commands/set-pipeline.js +35 -0
  417. package/dist/cli/commands/set-pipeline.js.map +1 -0
  418. package/dist/cli/commands/settle.js +1 -0
  419. package/dist/cli/commands/settle.js.map +1 -1
  420. package/dist/cli/commands/skill-index.js +1 -0
  421. package/dist/cli/commands/skill-index.js.map +1 -1
  422. package/dist/cli/commands/skills.js +1 -0
  423. package/dist/cli/commands/skills.js.map +1 -1
  424. package/dist/cli/commands/sources.js +5 -0
  425. package/dist/cli/commands/sources.js.map +1 -1
  426. package/dist/cli/commands/stack.js +1 -0
  427. package/dist/cli/commands/stack.js.map +1 -1
  428. package/dist/cli/commands/status.js +36 -2
  429. package/dist/cli/commands/status.js.map +1 -1
  430. package/dist/cli/commands/tool.js +5 -21
  431. package/dist/cli/commands/tool.js.map +1 -1
  432. package/dist/cli/commands/unknown-flags.js +68 -16
  433. package/dist/cli/commands/unknown-flags.js.map +1 -1
  434. package/dist/cli/commands/visibility.js +2 -0
  435. package/dist/cli/commands/visibility.js.map +1 -1
  436. package/dist/cli/commands/workspace-commit.js +62 -0
  437. package/dist/cli/commands/workspace-commit.js.map +1 -0
  438. package/dist/cli/commands/workspace-init.js +51 -2
  439. package/dist/cli/commands/workspace-init.js.map +1 -1
  440. package/dist/cli/commands/workspace-migrate.js +31 -14
  441. package/dist/cli/commands/workspace-migrate.js.map +1 -1
  442. package/dist/cli/commands/workspace-move.js +42 -0
  443. package/dist/cli/commands/workspace-move.js.map +1 -0
  444. package/dist/cli/commands/worktree.js +5 -4
  445. package/dist/cli/commands/worktree.js.map +1 -1
  446. package/dist/cli/context-id.js +6 -0
  447. package/dist/cli/context-id.js.map +1 -1
  448. package/dist/cli/full-cli.js +555 -0
  449. package/dist/cli/full-cli.js.map +1 -0
  450. package/dist/cli/help-groups.js +108 -14
  451. package/dist/cli/help-groups.js.map +1 -1
  452. package/dist/cli/hook-stdin-cache.js +12 -0
  453. package/dist/cli/hook-stdin-cache.js.map +1 -0
  454. package/dist/cli/main.js +47 -471
  455. package/dist/cli/main.js.map +1 -1
  456. package/dist/cli/output-mode.js +11 -2
  457. package/dist/cli/output-mode.js.map +1 -1
  458. package/dist/cli/parser.js +18 -5
  459. package/dist/cli/parser.js.map +1 -1
  460. package/dist/cli/registry.js.map +1 -1
  461. package/dist/cli/render.js +30 -1
  462. package/dist/cli/render.js.map +1 -1
  463. package/dist/cli/tui/app.js +1 -1
  464. package/dist/cli/tui/app.js.map +1 -1
  465. package/dist/cli/tui/components/workspace-init-form.js +4 -1
  466. package/dist/cli/tui/components/workspace-init-form.js.map +1 -1
  467. package/dist/cli/tui/data/recommended-skills.js +2 -2
  468. package/dist/cli/tui/data/recommended-skills.js.map +1 -1
  469. package/dist/cli/tui/data/workflow-content.js +6 -1
  470. package/dist/cli/tui/data/workflow-content.js.map +1 -1
  471. package/dist/cli/tui/tabs/mcp-tab.js +4 -3
  472. package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
  473. package/dist/cli/tui/tabs/project-tab.js +7 -2
  474. package/dist/cli/tui/tabs/project-tab.js.map +1 -1
  475. package/dist/dist-manifest.json +4117 -0
  476. package/dist/domain/capability/protocol.js.map +1 -1
  477. package/dist/domain/decision-note.js +13 -0
  478. package/dist/domain/decision-note.js.map +1 -1
  479. package/dist/domain/design/artifact.js +22 -3
  480. package/dist/domain/design/artifact.js.map +1 -1
  481. package/dist/domain/design/capability.js +1 -0
  482. package/dist/domain/design/capability.js.map +1 -1
  483. package/dist/domain/design/expansion.js +1 -1
  484. package/dist/domain/design/expansion.js.map +1 -1
  485. package/dist/domain/design/maturity.js +16 -0
  486. package/dist/domain/design/maturity.js.map +1 -1
  487. package/dist/domain/design/reference.js +5 -0
  488. package/dist/domain/design/reference.js.map +1 -1
  489. package/dist/domain/doctor/operations.js +28 -2
  490. package/dist/domain/doctor/operations.js.map +1 -1
  491. package/dist/domain/effective-contract.js +3 -1
  492. package/dist/domain/effective-contract.js.map +1 -1
  493. package/dist/domain/elicitation.js +1 -1
  494. package/dist/domain/flow/answer.js +273 -130
  495. package/dist/domain/flow/answer.js.map +1 -1
  496. package/dist/domain/flow/authority.js +330 -44
  497. package/dist/domain/flow/authority.js.map +1 -1
  498. package/dist/domain/flow/batch-review.js +65 -0
  499. package/dist/domain/flow/batch-review.js.map +1 -0
  500. package/dist/domain/flow/decision-schema.js +47 -0
  501. package/dist/domain/flow/decision-schema.js.map +1 -0
  502. package/dist/domain/flow/directive.js +16 -0
  503. package/dist/domain/flow/directive.js.map +1 -1
  504. package/dist/domain/flow/execution-result.js +169 -9
  505. package/dist/domain/flow/execution-result.js.map +1 -1
  506. package/dist/domain/flow/route.js.map +1 -1
  507. package/dist/domain/flow/rules.js +5 -6
  508. package/dist/domain/flow/rules.js.map +1 -1
  509. package/dist/domain/flow/run-state.js +531 -47
  510. package/dist/domain/flow/run-state.js.map +1 -1
  511. package/dist/domain/flow/test-run-evidence.js +285 -0
  512. package/dist/domain/flow/test-run-evidence.js.map +1 -0
  513. package/dist/domain/flow/unchanged-phase.js +15 -0
  514. package/dist/domain/flow/unchanged-phase.js.map +1 -0
  515. package/dist/domain/harnesses.js +22 -6
  516. package/dist/domain/harnesses.js.map +1 -1
  517. package/dist/domain/isolation-unit.js +2 -2
  518. package/dist/domain/isolation-unit.js.map +1 -1
  519. package/dist/domain/lineage.js +7 -2
  520. package/dist/domain/lineage.js.map +1 -1
  521. package/dist/domain/obligation-correspondence.js +4 -2
  522. package/dist/domain/obligation-correspondence.js.map +1 -1
  523. package/dist/domain/plan-handoff.js +5 -0
  524. package/dist/domain/plan-handoff.js.map +1 -0
  525. package/dist/domain/proposal.js +18 -7
  526. package/dist/domain/proposal.js.map +1 -1
  527. package/dist/domain/reservation.js +5 -3
  528. package/dist/domain/reservation.js.map +1 -1
  529. package/dist/domain/retirement/proposal.js +1 -0
  530. package/dist/domain/retirement/proposal.js.map +1 -1
  531. package/dist/domain/session/custody.js +10 -6
  532. package/dist/domain/session/custody.js.map +1 -1
  533. package/dist/domain/session/narrative.js +4 -1
  534. package/dist/domain/session/narrative.js.map +1 -1
  535. package/dist/domain/skills.js +2 -0
  536. package/dist/domain/skills.js.map +1 -1
  537. package/dist/domain/sql-lexer.js +15 -2
  538. package/dist/domain/sql-lexer.js.map +1 -1
  539. package/dist/runtime/namespace-resolver.js +4 -0
  540. package/dist/runtime/namespace-resolver.js.map +1 -1
  541. package/dist/runtime/workline-marker.js +35 -8
  542. package/dist/runtime/workline-marker.js.map +1 -1
  543. package/dist/runtime/workspace-resolution.js +123 -0
  544. package/dist/runtime/workspace-resolution.js.map +1 -0
  545. package/package.json +5 -4
  546. package/skills/w/SKILL.md +3 -1
  547. package/skills/w/artifacts/artifacts-core/CHECKPOINT.md +1 -1
  548. package/skills/w/artifacts/artifacts-core/SCRIPTS.rollback.sql +8 -0
  549. package/skills/w/artifacts/artifacts-core/SCRIPTS.sql +4 -8
  550. package/skills/w/commands/export-diagrams.md +3 -3
  551. package/skills/w/commands/export-manuals.md +6 -6
  552. package/skills/w/commands/export-reports.md +3 -3
  553. package/skills/w/commands/export-scripts.md +5 -5
  554. package/skills/w/commands/fix-git.md +12 -13
  555. package/skills/w/commands/persist.md +2 -2
  556. package/skills/w/commands/plan-exec.md +4 -2
  557. package/skills/w/commands/spec-new.md +1 -1
  558. package/skills/w/commands/workspace-init.md +2 -0
  559. package/skills/w/context/MANIFEST.json +1 -1
  560. package/skills/w/exports/export-diagrams/EXPORT.md +3 -3
  561. package/skills/w/exports/export-manuals/EXPORT.md +14 -16
  562. package/skills/w/exports/export-reports/EXPORT.md +3 -3
  563. package/skills/w/exports/export-scripts/EXPORT.md +45 -21
  564. package/skills/w/harness/HARNESS.md +5 -3
  565. package/skills/w/hooks/hooks.template.json +6 -4
  566. package/skills/w/loops/CHASSIS.md +12 -6
  567. package/skills/w/loops/CODE-POLICIES.md +7 -4
  568. package/skills/w/loops/plan-exec-loop/LOOP.md +23 -22
  569. package/skills/w/loops/plan-new-loop/LOOP.md +23 -31
  570. package/skills/w/loops/plan-refine-loop/LOOP.md +8 -2
  571. package/skills/w/loops/quick-loop/LOOP.md +6 -5
  572. package/skills/w/modules/DESIGN-REFERENCES.md +9 -11
  573. package/skills/w/modules/PLAN-EXECUTION-BATCHES.md +4 -4
  574. package/skills/w/modules/SESSION-NUMBERING.md +2 -0
  575. package/skills/w/roles/design/CONTRACT.md +16 -7
  576. package/skills/w/roles/design/ROLE.md +4 -2
  577. package/skills/w/roles/git/ROLE.md +16 -9
  578. package/skills/w/roles/research/ROLE.md +1 -1
  579. package/skills/w/roles/sql/ROLE.md +16 -14
  580. package/skills/w/schemas/design/ui-screen.v1.schema.json +9 -0
@@ -26,7 +26,8 @@ import { canonicalJson, semanticDigest } from "../../application/semantic-operat
26
26
  import { isEffectClass, touchesTheWorld } from "../capability/effects.js";
27
27
  import { AttemptLedger } from "../capability/protocol.js";
28
28
  import { normalizeObligations, validateDecisionNote } from "../decision-note.js";
29
- import { journeyOfFlow } from "./authority.js";
29
+ import { expandJourney, journeyOfFlow, } from "./authority.js";
30
+ import { isBatchReview } from "./batch-review.js";
30
31
  import { V11_JOURNEY_BASE } from "./journey-baseline.js";
31
32
  import { assuranceForRoute, isAssuranceStatus, isRouteDisposition, } from "./route.js";
32
33
  /**
@@ -40,7 +41,7 @@ import { assuranceForRoute, isAssuranceStatus, isRouteDisposition, } from "./rou
40
41
  * turning the cap off in silence while somebody alternates CLI versions over one
41
42
  * run. Failing with a cause is the requirement; failing silently is the defect.
42
43
  */
43
- export const FLOW_RUN_STATE_VERSION = 12;
44
+ export const FLOW_RUN_STATE_VERSION = 15;
44
45
  /**
45
46
  * The versions this CLI CONTINUES without adoption, newest first.
46
47
  *
@@ -50,8 +51,23 @@ export const FLOW_RUN_STATE_VERSION = 12;
50
51
  * cursor, the answers or the attempts. Every later version joins this set with its own
51
52
  * upgrade step, which is what keeps "v11 or later survives an update" true
52
53
  * without an exception per release.
54
+ *
55
+ * v13 added `reentries` and the `reentry_iteration` of attempts, observations and
56
+ * events. All three are absent on a run that never re-entered, which is every
57
+ * v12 run, so its upgrade step only re-stamps the version.
58
+ * It also added each batch's `base` and `credit`, a reseated run's `inherited_bases`
59
+ * and the `route-refused` trace kind. A v12 run has none of them either, and a
60
+ * batch without `base` is read as the one that was in flight when the CLI updated.
53
61
  */
54
- export const FLOW_RUN_STATE_CONTINUABLE = [FLOW_RUN_STATE_VERSION, 11];
62
+ // v14 adds batch reviews, signal retractions and QUICK checkout observations.
63
+ // Older observations and events remain unchanged.
64
+ export const FLOW_RUN_STATE_CONTINUABLE = [
65
+ FLOW_RUN_STATE_VERSION,
66
+ 14,
67
+ 13,
68
+ 12,
69
+ 11,
70
+ ];
55
71
  /**
56
72
  * The versions this CLI READS, newest first.
57
73
  *
@@ -75,6 +91,14 @@ export const FLOW_RUN_STATE_READABLE = [
75
91
  */
76
92
  const CONTINUABLE_UPGRADES = {
77
93
  11: (state) => ({ ...state, version: 12, journey_base: [...V11_JOURNEY_BASE[state.flow]] }),
94
+ 12: (state) => ({ ...state, version: 13 }),
95
+ // Historical reviews are never fabricated. A still-open batch must supply one.
96
+ 13: (state) => ({ ...state, version: 14 }),
97
+ 14: (state) => ({
98
+ ...state,
99
+ version: 15,
100
+ ...(state.scope ? { scope: { isolation: "unit", ...state.scope } } : {}),
101
+ }),
78
102
  };
79
103
  /** The CLI-owned run state inside the session folder. Machine-local, dotted. */
80
104
  export const FLOW_RUN_STATE_FILE = ".flow-run.json";
@@ -111,12 +135,47 @@ export function attemptsAt(state, transition) {
111
135
  }
112
136
  /** The monotone-counter key for one boundary, scoped when that boundary repeats in a batch. */
113
137
  export function attemptCounterKey(state, transition) {
114
- const iteration = currentBatchIteration(state, transition);
115
- return attemptCounterKeyForIteration(transition, iteration ?? undefined);
138
+ return attemptCounterKeyForIteration(transition, iterationOf(state, transition));
116
139
  }
117
- /** Stable counter key for a historical attempt whose batch iteration is recorded on the row. */
140
+ /** Stable counter key for a historical attempt whose iteration is recorded on the row. */
118
141
  export function attemptCounterKeyForIteration(transition, iteration) {
119
- return iteration === undefined ? transition : `${transition}@batch-${iteration}`;
142
+ const batch = iteration.batch_iteration === undefined ? "" : `@batch-${iteration.batch_iteration}`;
143
+ const reentry = iteration.reentry_iteration === undefined ? "" : `@reentry-${iteration.reentry_iteration}`;
144
+ return `${transition}${batch}${reentry}`;
145
+ }
146
+ /**
147
+ * The iteration of `transition` where the run stands: its batch copy and its
148
+ * reentry copy. Spread it into any record keyed per boundary.
149
+ */
150
+ export function iterationOf(state, transition) {
151
+ const batch = currentBatchIteration(state, transition);
152
+ const reentry = currentReentryIteration(state, transition);
153
+ return {
154
+ ...(batch === null ? {} : { batch_iteration: batch }),
155
+ ...(reentry === null ? {} : { reentry_iteration: reentry }),
156
+ };
157
+ }
158
+ /** Whether a persisted record belongs to this iteration of its boundary. */
159
+ export function sameIteration(record, iteration) {
160
+ return (record.batch_iteration === iteration.batch_iteration &&
161
+ record.reentry_iteration === iteration.reentry_iteration);
162
+ }
163
+ /**
164
+ * Which reentry inserted the row of `transition` the cursor is on, or `null` on
165
+ * the row's own place. Read at the cursor and backwards from it, so it answers
166
+ * the same before the row is applied and right after.
167
+ */
168
+ export function currentReentryIteration(state, transition) {
169
+ if ((state.reentries ?? []).length === 0)
170
+ return null;
171
+ const { rows, copies } = expandJourney(state);
172
+ for (let index = Math.min(state.applied.length, rows.length - 1); index >= 0; index -= 1) {
173
+ if (rows[index]?.id !== transition)
174
+ continue;
175
+ const copy = copies[index] ?? 0;
176
+ return copy === 0 ? null : copy;
177
+ }
178
+ return null;
120
179
  }
121
180
  /**
122
181
  * The three numbers and the difference between them, computed once.
@@ -127,15 +186,28 @@ export function attemptCounterKeyForIteration(transition, iteration) {
127
186
  * directive and the recovery guard would end up disagreeing about the same run.
128
187
  */
129
188
  function spendAt(state, transition) {
130
- const iteration = currentBatchIteration(state, transition);
131
- const rows = state.attempts.filter((attempt) => attempt.transition === transition &&
132
- (iteration === null
133
- ? attempt.batch_iteration === undefined
134
- : attempt.batch_iteration === iteration));
189
+ const iteration = iterationOf(state, transition);
190
+ const recorded = state.attempts.filter((attempt) => attempt.transition === transition && sameIteration(attempt, iteration));
191
+ const seen = new Set();
192
+ const rows = recorded.filter((attempt) => {
193
+ const key = `${attempt.invocation_id}:${attempt.attempt}:${attempt.request_digest}`;
194
+ if (seen.has(key))
195
+ return false;
196
+ seen.add(key);
197
+ return true;
198
+ });
135
199
  const key = attemptCounterKey(state, transition);
136
- const floor = state.attempt_floor?.[key] ?? 0;
200
+ // Old runs may hold a twin row and a counter raised over that twin. Removing
201
+ // both copies of the same resend from the reading preserves the anti-rollback
202
+ // excess, which is the portion the monotone floor still has to protect.
203
+ const floor = Math.max(0, (state.attempt_floor?.[key] ?? 0) - (recorded.length - rows.length));
137
204
  const granted = state.attempt_grants?.[key] ?? 0;
138
- return { rows, floor, granted, spent: Math.max(0, Math.max(rows.length, floor) - granted) };
205
+ return {
206
+ rows,
207
+ floor,
208
+ granted,
209
+ spent: Math.max(0, Math.max(rows.filter((row) => row.approval !== true).length, floor) - granted),
210
+ };
139
211
  }
140
212
  /**
141
213
  * The whole accounting of one transition, conflicts named and answerability read.
@@ -150,23 +222,24 @@ export function attemptAccountingAt(state, transition) {
150
222
  // — and a projection that disagrees with the state it describes is the very
151
223
  // thing this reading exists to stop. It cannot mask a real divergence: a
152
224
  // counter that runs AHEAD of the rows stays ahead of this maximum.
153
- const floor = Math.max(read, rows.length);
225
+ const paid = rows.filter((row) => row.approval !== true).length;
226
+ const floor = Math.max(read, paid);
154
227
  const ordinals = rows.map((attempt) => attempt.attempt);
155
228
  const conflicts = [];
156
- if (floor > rows.length) {
229
+ if (floor > paid) {
157
230
  conflicts.push({
158
231
  between: [
159
232
  { name: "attempt_floor", value: floor },
160
- { name: "attempts", value: rows.length },
233
+ { name: "attempts", value: paid },
161
234
  ],
162
235
  cause: "el contador monótono declara más intentos que las filas persistidas: o se restauró una copia anterior del ledger, o una escritura murió entre el contador y el estado",
163
236
  });
164
237
  }
165
- if (granted > Math.max(rows.length, floor)) {
238
+ if (granted > Math.max(paid, floor)) {
166
239
  conflicts.push({
167
240
  between: [
168
241
  { name: "attempt_grants", value: granted },
169
- { name: "attempts", value: Math.max(rows.length, floor) },
242
+ { name: "attempts", value: Math.max(paid, floor) },
170
243
  ],
171
244
  cause: "se perdonan más intentos de los que esta transición llegó a registrar",
172
245
  });
@@ -228,7 +301,8 @@ export function reconcileAttemptsAt(state, transition) {
228
301
  };
229
302
  }
230
303
  const { rows, floor: read, granted, spent } = spendAt(state, transition);
231
- const floor = Math.max(read, rows.length);
304
+ const paid = rows.filter((row) => row.approval !== true).length;
305
+ const floor = Math.max(read, paid);
232
306
  const accounting = attemptAccountingAt(state, transition);
233
307
  const repairs = [];
234
308
  // What is repaired is the EFFECTIVE spend, not the raw difference between the
@@ -237,7 +311,7 @@ export function reconcileAttemptsAt(state, transition) {
237
311
  // against that difference would forgive it again on every single advance and
238
312
  // quietly remove the cap. Written against the spend, the second reading finds
239
313
  // `spent === rows` and has nothing to do.
240
- const unforgiven = spent - rows.length;
314
+ const unforgiven = spent - paid;
241
315
  if (unforgiven > 0) {
242
316
  repairs.push({
243
317
  rule: "forgive-counter-excess",
@@ -247,7 +321,7 @@ export function reconcileAttemptsAt(state, transition) {
247
321
  after: granted + unforgiven,
248
322
  });
249
323
  }
250
- const recorded = Math.max(rows.length, floor);
324
+ const recorded = Math.max(paid, floor);
251
325
  if (granted > recorded) {
252
326
  repairs.push({
253
327
  rule: "clamp-grants",
@@ -287,10 +361,11 @@ function conflictCause(accounting, field) {
287
361
  function repeatedOrdinal(state) {
288
362
  const seen = new Map();
289
363
  for (const row of state.attempts) {
290
- const ordinals = seen.get(row.invocation_id) ?? new Set();
291
- if (ordinals.has(row.attempt))
364
+ const ordinals = seen.get(row.invocation_id) ?? new Map();
365
+ const previous = ordinals.get(row.attempt);
366
+ if (previous !== undefined && previous !== row.request_digest)
292
367
  return row.attempt;
293
- ordinals.add(row.attempt);
368
+ ordinals.set(row.attempt, row.request_digest);
294
369
  seen.set(row.invocation_id, ordinals);
295
370
  }
296
371
  return null;
@@ -316,11 +391,10 @@ export function applyAttemptReconciliation(state, reconciliation) {
316
391
  grants[key] = repair.after;
317
392
  next = sealRunState({ ...withoutSeal(next), attempt_grants: grants });
318
393
  }
319
- const iteration = currentBatchIteration(next, reconciliation.transition);
320
394
  return withEvent(next, {
321
395
  kind: "reconciled",
322
396
  transition: reconciliation.transition,
323
- ...(iteration === null ? {} : { batch_iteration: iteration }),
397
+ ...iterationOf(next, reconciliation.transition),
324
398
  operation: "flow.attempt-reconciliation",
325
399
  repairs: reconciliation.repairs,
326
400
  });
@@ -349,12 +423,8 @@ function unanswerableAt(state) {
349
423
  }
350
424
  return null;
351
425
  }
352
- export function recoveryBlockedAt(state, transition) {
353
- const iteration = currentBatchIteration(state, transition);
354
- const trace = state.events.filter((event) => event.transition === transition &&
355
- (iteration === null
356
- ? event.batch_iteration === undefined
357
- : event.batch_iteration === iteration));
426
+ export function recoveryBlockedAt(state, transition, iteration = iterationOf(state, transition)) {
427
+ const trace = state.events.filter((event) => event.transition === transition && sameIteration(event, iteration));
358
428
  const material = [...trace].reverse().find(declaresMaterialEffect);
359
429
  if (material !== undefined)
360
430
  return { reason: "materialized", event: material };
@@ -377,7 +447,9 @@ function declaresMaterialEffect(event) {
377
447
  // more block a recovery than reading the file could.
378
448
  if (event.kind === "reconciled" ||
379
449
  event.kind === "aligned" ||
450
+ event.kind === "route-refused" ||
380
451
  event.kind === "restarted" ||
452
+ event.kind === "retracted" ||
381
453
  event.kind === "annulled") {
382
454
  return false;
383
455
  }
@@ -417,6 +489,7 @@ export const PLAN_EXEC_BATCH_STAGES = [
417
489
  "deviation",
418
490
  "validating",
419
491
  "reviewing",
492
+ "batch-committing",
420
493
  "closed",
421
494
  "committing",
422
495
  "integrating",
@@ -634,6 +707,101 @@ export function upgradeContinuable(state) {
634
707
  }
635
708
  return sealRunState(withoutSeal(current));
636
709
  }
710
+ /** Record a reentry of the journey, after every one already recorded. */
711
+ export function withReentry(state, reentry) {
712
+ return sealRunState({
713
+ ...withoutSeal(state),
714
+ reentries: [...(state.reentries ?? []), reentry],
715
+ });
716
+ }
717
+ /**
718
+ * Take back the last reentry, for the close that recorded its intention and then
719
+ * could not happen. The field goes back to absent when it empties, so the run
720
+ * serializes the bytes it had before the intention.
721
+ */
722
+ export function withoutLastReentry(state) {
723
+ const { reentries: _all, ...rest } = withoutSeal(state);
724
+ const kept = (state.reentries ?? []).slice(0, -1);
725
+ return sealRunState(kept.length === 0 ? rest : { ...rest, reentries: kept });
726
+ }
727
+ /** Seal the base of one batch; a batch that already has one keeps it. */
728
+ export function withPlanExecBatchBase(state, batchId, base) {
729
+ const batches = state.batches ?? [];
730
+ const target = batches.find((batch) => batch.id === batchId);
731
+ // A re-run of the acquisition on the same batch must not move its base: the
732
+ // batch would then be compared against its own half-done work.
733
+ if (target === undefined || target.base !== undefined)
734
+ return state;
735
+ return sealRunState({
736
+ ...withoutSeal(state),
737
+ batches: batches.map((batch) => (batch.id === batchId ? { ...batch, base } : batch)),
738
+ });
739
+ }
740
+ /** Record the proofs that credited one batch. */
741
+ export function withPlanExecBatchCredit(state, batchId, credit) {
742
+ const batches = state.batches ?? [];
743
+ if (!batches.some((batch) => batch.id === batchId))
744
+ return state;
745
+ return sealRunState({
746
+ ...withoutSeal(state),
747
+ batches: batches.map((batch) => batch.id === batchId ? { ...batch, credit, credit_phases: [...batch.phases] } : batch),
748
+ });
749
+ }
750
+ export function withPlanExecBatchUpdate(state, id, update) {
751
+ return sealRunState({
752
+ ...withoutSeal(state),
753
+ batches: (state.batches ?? []).map((batch) => (batch.id === id ? update(batch) : batch)),
754
+ });
755
+ }
756
+ /** Re-seal the SAME unpublished batch; old validation/review cannot credit a new base. */
757
+ export function withReinferredPlanExecBatch(state, batchId, planDigest, anchor) {
758
+ const replaced = withPlanExecBatchUpdate(state, batchId, (batch) => {
759
+ const { credit: _credit, credit_phases: _phases, review: _review, commit_proposal: _proposal, ...rest } = batch;
760
+ return { ...rest, plan_digest: planDigest, stage: "inferred" };
761
+ });
762
+ const traced = withPlanExecBatchStage(replaced, batchId, "inferred", "plan-exec.batch-inference", "entered");
763
+ if (anchor === null)
764
+ return traced;
765
+ const reentered = withReentry(traced, {
766
+ kind: "reinfer",
767
+ transition: anchor,
768
+ occurrence: state.applied.filter((id) => id === anchor).length + 1,
769
+ from: "plan-exec.validation-execution",
770
+ });
771
+ return withPendingAction(withBoundary(reentered, "plan-exec.validation-execution"), null);
772
+ }
773
+ /** Old runs that closed even one batch without a commit result stay on the old tail. */
774
+ export function legacyPlanExecCommits(state) {
775
+ if (state.skipped.includes("plan-exec.batch-commit-proposal"))
776
+ return true;
777
+ const acquired = state.applied.filter((transition) => transition === "plan-exec.unit-acquisition").length;
778
+ return (state.batches ?? []).some((batch) => (batch.published_plan_digest !== undefined && batch.commit_result === undefined) ||
779
+ (batch.iteration === state.batch_loop?.iteration &&
780
+ batch.snapshot === undefined &&
781
+ acquired >= batch.iteration));
782
+ }
783
+ /** Record only the current iteration's review, never borrowing one from a prior batch. */
784
+ export function withPlanExecBatchReview(state, review) {
785
+ return sealRunState({
786
+ ...withoutSeal(state),
787
+ batches: (state.batches ?? []).map((batch) => batch.iteration === state.batch_loop?.iteration ? { ...batch, review } : batch),
788
+ });
789
+ }
790
+ /** A legacy close may have passed the old untyped review. Insert a fresh, answerable copy. */
791
+ export function withPendingBatchReview(state) {
792
+ const review = "plan-exec.review-findings";
793
+ if (state.flow !== "plan-exec" || state.boundary !== "plan-exec.batch-close")
794
+ return state;
795
+ const batch = (state.batches ?? []).find((entry) => entry.published_plan_digest === undefined);
796
+ if (batch === undefined || batch.review !== undefined)
797
+ return state;
798
+ return withBoundary(withReentry(state, {
799
+ kind: "review",
800
+ transition: "plan-exec.batch-close",
801
+ from: review,
802
+ occurrence: state.applied.filter((id) => id === "plan-exec.batch-close").length + 1,
803
+ }), review);
804
+ }
637
805
  /** Record one inferred or declared batch, refusing duplicate ids at the caller's boundary. */
638
806
  export function withPlanExecBatch(state, batch) {
639
807
  const batches = state.batches ?? [];
@@ -697,6 +865,7 @@ const PLAN_EXEC_BATCH_STAGE_BY_TRANSITION = {
697
865
  "plan-exec.deviation-recognition": "deviation",
698
866
  "plan-exec.validation-execution": "validating",
699
867
  "plan-exec.review-findings": "reviewing",
868
+ "plan-exec.batch-commit": "batch-committing",
700
869
  // These only occur after the final batch publication. They therefore extend
701
870
  // the last closed batch's trace instead of fabricating a new one for Git/done.
702
871
  "plan-exec.final-validation": "validating",
@@ -772,6 +941,9 @@ export const PLAN_EXEC_BATCH_LOOP_TRANSITIONS = new Set([
772
941
  "plan-exec.validation-execution",
773
942
  "plan-exec.deferred-check",
774
943
  "plan-exec.review-findings",
944
+ "plan-exec.batch-commit-proposal",
945
+ "plan-exec.batch-commit-authorization",
946
+ "plan-exec.batch-commit",
775
947
  "plan-exec.batch-close",
776
948
  ]);
777
949
  /** Seal the plan bytes the batch publication actually produced. */
@@ -817,6 +989,33 @@ export function withPlanExecBatchPublicationPrepared(state, batchId, publication
817
989
  export function withHandoff(state, handoff) {
818
990
  return sealRunState({ ...withoutSeal(state), handoff });
819
991
  }
992
+ export function withPlanExecEntry(state, entry) {
993
+ return sealRunState({ ...withoutSeal(state), plan_exec_entry: entry });
994
+ }
995
+ export function withDecisionDate(state, date) {
996
+ return state.decision_date === date
997
+ ? state
998
+ : sealRunState({ ...withoutSeal(state), decision_date: date });
999
+ }
1000
+ /** Both the human exit and the structural rule deliver the same recoverable destination. */
1001
+ export function planRefineHandoff(state, decisions, selection) {
1002
+ const plan = state.scope?.plan ?? state.plan_exec_entry?.plan ?? null;
1003
+ const packageBody = {
1004
+ plan,
1005
+ observations: state.observations.filter((observation) => observation.transition.startsWith("plan-exec.entry-") ||
1006
+ observation.transition.startsWith("plan-exec.deviation-")),
1007
+ decisions: plan === null
1008
+ ? { ...decisions, recovery: "nombrá el plan que debe refinar /w:plan-refine <plan>" }
1009
+ : decisions,
1010
+ selection,
1011
+ };
1012
+ return {
1013
+ destination: "plan-refine",
1014
+ command: plan === null ? "/w:plan-refine <plan>" : `/w:plan-refine ${plan}`,
1015
+ package: packageBody,
1016
+ package_digest: semanticDigest(packageBody),
1017
+ };
1018
+ }
820
1019
  /** Persist the gate's executable consequence before the run leaves that boundary. */
821
1020
  export function withSelectedChoice(state, selected) {
822
1021
  return sealRunState({ ...withoutSeal(state), selected_choice: selected });
@@ -837,6 +1036,72 @@ export function withDecisionPreparation(state, preparation) {
837
1036
  export function withFixPreview(state, preview) {
838
1037
  return sealRunState({ ...withoutSeal(state), fix_preview: preview });
839
1038
  }
1039
+ export function withQuickCheckouts(state, checkouts) {
1040
+ if (checkouts === null && state.quick_checkouts === undefined)
1041
+ return state;
1042
+ return state.flow === "quick"
1043
+ ? sealRunState({ ...withoutSeal(state), quick_checkouts: checkouts })
1044
+ : state;
1045
+ }
1046
+ /** Remove a mistaken signal only before any of its consumers has used it. */
1047
+ export function retractSignal(state, journey, signal) {
1048
+ const producers = journey.filter((row) => row.signals?.includes(signal)).map((row) => row.id);
1049
+ const consumers = journey.filter((row) => {
1050
+ const rule = row.condition?.threshold;
1051
+ return (rule !== undefined &&
1052
+ producers.includes(rule.observed) &&
1053
+ (rule.of === undefined || rule.of.includes(signal)));
1054
+ });
1055
+ if (producers.length === 0 || consumers.length === 0) {
1056
+ return {
1057
+ ok: false,
1058
+ failure: {
1059
+ code: "FLOW_RETRACT_SIGNAL_UNKNOWN",
1060
+ message: `la señal '${signal}' no tiene un consumidor retirable en este recorrido`,
1061
+ action: "usá una señal declarada por el recorrido y consumida por una condición pendiente",
1062
+ },
1063
+ };
1064
+ }
1065
+ const removed = state.observations.filter((item) => item.signals.includes(signal) && sameIteration(item, iterationOf(state, item.transition)));
1066
+ if (removed.length === 0)
1067
+ return { ok: true, state };
1068
+ const consumed = consumers.find((row) => removed.some((observation) => signalWasConsumed(state, row, observation)));
1069
+ if (consumed !== undefined) {
1070
+ return {
1071
+ ok: false,
1072
+ failure: {
1073
+ code: "FLOW_RETRACT_ALREADY_CONSUMED",
1074
+ message: `'${consumed.id}' ya aplicó o dejó una ejecución sin resolver; no se retira '${signal}'`,
1075
+ action: "conservá la señal: retirar no revierte decisiones ni efectos ya ejercidos",
1076
+ },
1077
+ };
1078
+ }
1079
+ const updated = sealRunState({
1080
+ ...withoutSeal(state),
1081
+ observations: state.observations.map((item) => removed.includes(item)
1082
+ ? { ...item, signals: item.signals.filter((value) => value !== signal) }
1083
+ : item),
1084
+ });
1085
+ return {
1086
+ ok: true,
1087
+ state: withEvent(updated, {
1088
+ kind: "retracted",
1089
+ transition: state.boundary ?? producers[0] ?? "",
1090
+ ...iterationOf(state, state.boundary ?? producers[0] ?? ""),
1091
+ operation: "flow.retract",
1092
+ signal,
1093
+ observations: removed,
1094
+ }),
1095
+ };
1096
+ }
1097
+ function signalWasConsumed(state, consumer, observation) {
1098
+ if (consumer.condition?.threshold.observed !== observation.transition)
1099
+ return false;
1100
+ // Only a consumer after THIS producer occurrence can have consumed its signal.
1101
+ const producer = state.applied.lastIndexOf(observation.transition);
1102
+ const consumed = state.applied.slice(producer + 1).includes(consumer.id);
1103
+ return consumed || recoveryBlockedAt(state, consumer.id, observation) !== null;
1104
+ }
840
1105
  /**
841
1106
  * Record what the closure owes — written once, when the batch loop ends.
842
1107
  *
@@ -954,7 +1219,7 @@ export function restatesLastEvent(state, event) {
954
1219
  if (last === undefined || last.kind !== "failed" || event.kind !== "failed")
955
1220
  return false;
956
1221
  return (last.transition === event.transition &&
957
- last.batch_iteration === event.batch_iteration &&
1222
+ sameIteration(last, event) &&
958
1223
  last.code === event.code &&
959
1224
  last.message === event.message);
960
1225
  }
@@ -975,7 +1240,7 @@ export function restatesLastEvent(state, event) {
975
1240
  */
976
1241
  export function withObservation(state, observation) {
977
1242
  const repeated = state.observations.some((past) => past.transition === observation.transition &&
978
- past.batch_iteration === observation.batch_iteration &&
1243
+ sameIteration(past, observation) &&
979
1244
  sameSignals(past.signals, observation.signals));
980
1245
  if (repeated)
981
1246
  return state;
@@ -1310,6 +1575,9 @@ function checkRecordShape(parsed, invalid) {
1310
1575
  if (version >= 12 && !isStringArray(parsed.journey_base)) {
1311
1576
  return invalid("no dice contra qué recorrido se escribió su cursor");
1312
1577
  }
1578
+ if (!isReentryArray(parsed.reentries)) {
1579
+ return invalid("declara una reentrada sin tipo, frontera, ocurrencia u origen");
1580
+ }
1313
1581
  if (parsed.exhausted_reruns !== undefined && !isStringArray(parsed.exhausted_reruns)) {
1314
1582
  return invalid("declara vueltas de fronteras agotadas que no son transiciones");
1315
1583
  }
@@ -1350,8 +1618,91 @@ function checkCommonRecordShape(parsed, invalid) {
1350
1618
  if (!isCounterMap(parsed.attempt_floor) || !isCounterMap(parsed.attempt_grants)) {
1351
1619
  return invalid("trae una contabilidad de intentos que no es un contador por transición");
1352
1620
  }
1621
+ if (!isInheritedBaseArray(parsed.inherited_bases)) {
1622
+ return invalid("hereda una base de batch sin sus fases o sin sus fuentes");
1623
+ }
1624
+ if (!isPlanExecEntry(parsed.plan_exec_entry)) {
1625
+ return invalid("declara una entrada de plan-exec sin plan o con fases inválidas");
1626
+ }
1627
+ if (parsed.decision_date !== undefined &&
1628
+ (typeof parsed.decision_date !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(parsed.decision_date))) {
1629
+ return invalid("declara una fecha de decisión inválida");
1630
+ }
1353
1631
  return null;
1354
1632
  }
1633
+ function isPlanExecEntry(value) {
1634
+ if (value === undefined)
1635
+ return true;
1636
+ if (!isRecord(value) || !(value.plan === null || isNonEmptyString(value.plan)))
1637
+ return false;
1638
+ if (value.sources !== undefined &&
1639
+ (value.plan === null || !Array.isArray(value.sources) || !value.sources.every(isNonEmptyString)))
1640
+ return false;
1641
+ if (value.grammar_failure !== undefined &&
1642
+ (!isRecord(value.grammar_failure) ||
1643
+ !isNonEmptyString(value.grammar_failure.code) ||
1644
+ !isNonEmptyString(value.grammar_failure.message) ||
1645
+ !isNonEmptyString(value.grammar_failure.action)))
1646
+ return false;
1647
+ const phases = value.phases_without_open_tasks;
1648
+ const approval = value.approved_without_changes;
1649
+ if (approval !== undefined &&
1650
+ (value.plan === null ||
1651
+ !Array.isArray(phases) ||
1652
+ !Array.isArray(approval) ||
1653
+ approval.length === 0 ||
1654
+ new Set(approval).size !== approval.length ||
1655
+ !approval.every((phase) => phases.includes(phase))))
1656
+ return false;
1657
+ return (phases === null ||
1658
+ (Array.isArray(phases) &&
1659
+ phases.every((phase) => Number.isInteger(phase) && phase > 0) &&
1660
+ new Set(phases).size === phases.length));
1661
+ }
1662
+ function isInheritedBaseArray(value) {
1663
+ if (value === undefined)
1664
+ return true;
1665
+ return (Array.isArray(value) &&
1666
+ value.every((entry) => isRecord(entry) &&
1667
+ Array.isArray(entry.phases) &&
1668
+ entry.phases.length > 0 &&
1669
+ entry.phases.every((phase) => Number.isInteger(phase) && phase > 0) &&
1670
+ isSourceMap(entry.base, true) &&
1671
+ entry.base !== undefined));
1672
+ }
1673
+ /**
1674
+ * The bases a reseated run inherits from the archived registry, read tolerantly:
1675
+ * the archive may be the very state that could not be continued, so anything
1676
+ * that is not a well-formed batch base is left behind rather than trusted.
1677
+ */
1678
+ export function inheritedBasesFrom(archived) {
1679
+ if (archived === null)
1680
+ return [];
1681
+ let parsed;
1682
+ try {
1683
+ parsed = JSON.parse(archived);
1684
+ }
1685
+ catch {
1686
+ return [];
1687
+ }
1688
+ if (!isRecord(parsed) || !Array.isArray(parsed.batches))
1689
+ return [];
1690
+ const inherited = parsed.batches.flatMap((batch) => {
1691
+ if (!isRecord(batch) || batch.base === undefined)
1692
+ return [];
1693
+ const candidate = { phases: batch.phases, base: batch.base };
1694
+ return isInheritedBaseArray([candidate]) ? [candidate] : [];
1695
+ });
1696
+ const earlier = isInheritedBaseArray(parsed.inherited_bases)
1697
+ ? (parsed.inherited_bases ?? [])
1698
+ : [];
1699
+ return [...earlier, ...inherited];
1700
+ }
1701
+ export function withInheritedBases(state, inherited) {
1702
+ if (inherited.length === 0)
1703
+ return state;
1704
+ return sealRunState({ ...withoutSeal(state), inherited_bases: [...inherited] });
1705
+ }
1355
1706
  /** Fields added by v10 that have no truthful default on a persisted run. */
1356
1707
  function checkV10RecordShape(parsed, invalid) {
1357
1708
  if (!isPlanExecBatchArray(parsed.batches)) {
@@ -1372,7 +1723,7 @@ function checkV10RecordShape(parsed, invalid) {
1372
1723
  if (!isDecisionPreparation(parsed.decision_preparation)) {
1373
1724
  return invalid("declara una vista de decisión sin nota, preview o linaje sellados");
1374
1725
  }
1375
- if (!isFixPreview(parsed.fix_preview)) {
1726
+ if (!isFixPreview(parsed.fix_preview) || !isQuickCheckouts(parsed.quick_checkouts)) {
1376
1727
  return invalid("declara un preview de arreglo sin archivos, intención o forma del diff");
1377
1728
  }
1378
1729
  if (!isSettlement(parsed.settlement)) {
@@ -1440,7 +1791,7 @@ function isRouteProposal(value) {
1440
1791
  !isRouteDisposition(control.recommendation) ||
1441
1792
  !isRecord(control.alternatives) ||
1442
1793
  !isNonEmptyString(control.alternatives.apply) ||
1443
- !isNonEmptyString(control.alternatives.omit) ||
1794
+ (control.alternatives.omit !== undefined && !isNonEmptyString(control.alternatives.omit)) ||
1444
1795
  !isNonEmptyString(control.alternatives.substitute) ||
1445
1796
  !isNonEmptyString(control.consequence) ||
1446
1797
  !isNonEmptyString(control.risk) ||
@@ -1509,6 +1860,17 @@ function isScope(value) {
1509
1860
  return false;
1510
1861
  if (!isStringArray(value.sources) || value.sources.length === 0)
1511
1862
  return false;
1863
+ if (value.isolation !== undefined && value.isolation !== "unit" && value.isolation !== "in-place")
1864
+ return false;
1865
+ if (value.final_validation !== undefined &&
1866
+ (!Array.isArray(value.final_validation) ||
1867
+ !value.final_validation.every((entry) => isRecord(entry) &&
1868
+ typeof entry.alias === "string" &&
1869
+ [entry.build, entry.test].every((item) => isRecord(item) &&
1870
+ (item.command === null || typeof item.command === "string") &&
1871
+ (item.origin === null || item.origin === "plan" || item.origin === "source") &&
1872
+ (item.action === undefined || typeof item.action === "string")))))
1873
+ return false;
1512
1874
  return value.sources.every((alias) => alias.trim().length > 0);
1513
1875
  }
1514
1876
  function isPlanExecBatchArray(value) {
@@ -1531,7 +1893,11 @@ function isPlanExecBatchArray(value) {
1531
1893
  entry.phases.length === 0 ||
1532
1894
  !entry.phases.every((phase) => typeof phase === "number" && Number.isInteger(phase) && phase > 0) ||
1533
1895
  !isStringArray(entry.tasks) ||
1534
- entry.tasks.length === 0 ||
1896
+ (entry.validation_only !== undefined && typeof entry.validation_only !== "boolean") ||
1897
+ (entry.validation_only === true && entry.tasks.length !== 0) ||
1898
+ (entry.validation_only === false && entry.kind === "validation-only") ||
1899
+ (entry.kind === "validation-only" ? entry.tasks.length !== 0 : entry.tasks.length === 0) ||
1900
+ (entry.kind !== undefined && entry.kind !== "validation-only") ||
1535
1901
  new Set(entry.tasks).size !== entry.tasks.length ||
1536
1902
  typeof entry.plan_digest !== "string" ||
1537
1903
  entry.plan_digest.length === 0 ||
@@ -1542,7 +1908,16 @@ function isPlanExecBatchArray(value) {
1542
1908
  (entry.publication !== undefined &&
1543
1909
  entry.publication.status === "applied" &&
1544
1910
  entry.published_plan_digest !== entry.publication.after_plan_digest) ||
1545
- !PLAN_EXEC_BATCH_STAGES.includes(entry.stage)) {
1911
+ !PLAN_EXEC_BATCH_STAGES.includes(entry.stage) ||
1912
+ !isSourceMap(entry.base, true) ||
1913
+ !isSourceMap(entry.credit, false) ||
1914
+ !isBatchPartition(entry.partition, entry.phases, entry.mode) ||
1915
+ !isBatchSnapshot(entry.snapshot) ||
1916
+ !isBatchCommitProposal(entry.commit_proposal) ||
1917
+ !isBatchCommitResult(entry.commit_result) ||
1918
+ (entry.credit_phases !== undefined &&
1919
+ (entry.credit === undefined || !samePhaseRange(entry.credit_phases, entry.phases))) ||
1920
+ (entry.review !== undefined && !isBatchReview(entry.review))) {
1546
1921
  return false;
1547
1922
  }
1548
1923
  ids.add(entry.id);
@@ -1550,6 +1925,75 @@ function isPlanExecBatchArray(value) {
1550
1925
  return true;
1551
1926
  });
1552
1927
  }
1928
+ function isBatchSnapshot(value) {
1929
+ if (value === undefined)
1930
+ return true;
1931
+ return (isRecord(value) &&
1932
+ Object.values(value).every((entry) => isRecord(entry) &&
1933
+ isNonEmptyString(entry.head) &&
1934
+ isNonEmptyString(entry.branch) &&
1935
+ Array.isArray(entry.dirty) &&
1936
+ entry.dirty.every((path) => isRecord(path) && isNonEmptyString(path.path) && isNonEmptyString(path.digest))));
1937
+ }
1938
+ function isBatchCommitProposal(value) {
1939
+ if (value === undefined)
1940
+ return true;
1941
+ return (isRecord(value) &&
1942
+ isNonEmptyString(value.digest) &&
1943
+ (value.approved_digest === undefined || isNonEmptyString(value.approved_digest)) &&
1944
+ Array.isArray(value.sources) &&
1945
+ value.sources.every((item) => isRecord(item) &&
1946
+ isNonEmptyString(item.alias) &&
1947
+ isNonEmptyString(item.message) &&
1948
+ isStringArray(item.paths) &&
1949
+ (item.foreign_paths === undefined || isStringArray(item.foreign_paths)) &&
1950
+ item.paths.length > 0 &&
1951
+ Array.isArray(item.dirty) &&
1952
+ item.dirty.length === item.paths.length &&
1953
+ item.dirty.every((path) => isRecord(path) && isNonEmptyString(path.path) && isNonEmptyString(path.digest))));
1954
+ }
1955
+ function isBatchCommitResult(value) {
1956
+ if (value === undefined)
1957
+ return true;
1958
+ return (isRecord(value) &&
1959
+ Object.values(value).every((receipt) => isRecord(receipt) &&
1960
+ isNonEmptyString(receipt.after) &&
1961
+ (receipt.before === null || isNonEmptyString(receipt.before)) &&
1962
+ (receipt.branch === null || isNonEmptyString(receipt.branch)) &&
1963
+ isStringArray(receipt.parents)));
1964
+ }
1965
+ function samePhaseRange(value, phases) {
1966
+ return (Array.isArray(value) &&
1967
+ value.length === phases.length &&
1968
+ value.every((phase, index) => phase === phases[index]));
1969
+ }
1970
+ function isBatchPartition(value, phases, mode) {
1971
+ if (value === undefined)
1972
+ return true;
1973
+ if (!isRecord(value) ||
1974
+ !isNonEmptyString(value.reason) ||
1975
+ !isRecord(value.effective) ||
1976
+ value.effective.mode !== mode ||
1977
+ !samePhaseRange(value.effective.phases, phases))
1978
+ return false;
1979
+ return (value.declared === null ||
1980
+ (Array.isArray(value.declared) &&
1981
+ value.declared.length > 0 &&
1982
+ value.declared.every((row) => isRecord(row) &&
1983
+ isNonEmptyString(row.id) &&
1984
+ (row.mode === "continuous" || row.mode === "isolated") &&
1985
+ Array.isArray(row.phases) &&
1986
+ row.phases.length > 0 &&
1987
+ row.phases.every((phase) => Number.isSafeInteger(phase) && phase > 0))));
1988
+ }
1989
+ /** Absent, or a non-empty alias → digest map; `nullable` admits an unobserved source. */
1990
+ function isSourceMap(value, nullable) {
1991
+ if (value === undefined)
1992
+ return true;
1993
+ if (!isRecord(value) || Object.keys(value).length === 0)
1994
+ return false;
1995
+ return Object.values(value).every((digest) => (nullable && digest === null) || (typeof digest === "string" && digest.length > 0));
1996
+ }
1553
1997
  function isPlanExecBatchPublication(value) {
1554
1998
  if (value === undefined)
1555
1999
  return true;
@@ -1587,6 +2031,7 @@ function isPlanExecBatchTraceArray(value, batches) {
1587
2031
  typeof entry.iteration === "number" &&
1588
2032
  Number.isInteger(entry.iteration) &&
1589
2033
  typeof entry.transition === "string" &&
2034
+ (entry.approval === undefined || entry.approval === true) &&
1590
2035
  entry.transition.length > 0 &&
1591
2036
  PLAN_EXEC_BATCH_STAGES.includes(entry.stage) &&
1592
2037
  (entry.kind === "entered" || entry.kind === "completed" || entry.kind === "blocked"));
@@ -1744,7 +2189,13 @@ function isFixPreview(value) {
1744
2189
  return (typeof value.intent === "string" &&
1745
2190
  value.intent.trim().length > 0 &&
1746
2191
  typeof value.diff === "string" &&
1747
- value.diff.trim().length > 0);
2192
+ value.diff.trim().length > 0 &&
2193
+ isQuickCheckouts(value.checkouts));
2194
+ }
2195
+ function isQuickCheckouts(value) {
2196
+ return (value === null ||
2197
+ value === undefined ||
2198
+ (isRecord(value) && Object.values(value).every(nonEmpty)));
1748
2199
  }
1749
2200
  function isDecisionPreview(value, baseline) {
1750
2201
  if (!isRecord(value) ||
@@ -1862,10 +2313,8 @@ function isEvent(entry) {
1862
2313
  return false;
1863
2314
  if (typeof entry.transition !== "string" || typeof entry.operation !== "string")
1864
2315
  return false;
1865
- if (entry.batch_iteration !== undefined &&
1866
- (!Number.isInteger(entry.batch_iteration) || entry.batch_iteration < 1)) {
2316
+ if (!isIterationRecord(entry))
1867
2317
  return false;
1868
- }
1869
2318
  return EVENT_BODIES.get(entry.kind)?.(entry) === true;
1870
2319
  }
1871
2320
  const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0;
@@ -1880,6 +2329,9 @@ const EVENT_BODIES = new Map(Object.entries({
1880
2329
  isEffectClassArray(entry.effects) &&
1881
2330
  isStringArray(entry.evidence),
1882
2331
  reconciled: (entry) => isRepairArray(entry.repairs),
2332
+ retracted: (entry) => nonEmpty(entry.signal) &&
2333
+ isObservationArray(entry.observations) &&
2334
+ entry.observations.length > 0,
1883
2335
  restarted: (entry) => nonEmpty(entry.archive) && nonEmpty(entry.cause),
1884
2336
  annulled: (entry) => isStringArray(entry.batches) &&
1885
2337
  entry.batches.length > 0 &&
@@ -1888,6 +2340,7 @@ const EVENT_BODIES = new Map(Object.entries({
1888
2340
  isStringArray(entry.tasks) &&
1889
2341
  nonEmpty(entry.digest),
1890
2342
  aligned: (entry) => Number.isInteger(entry.position) && entry.position >= 0 && nonEmpty(entry.reason),
2343
+ "route-refused": (entry) => isRouteDisposition(entry.disposition) && nonEmpty(entry.reason),
1891
2344
  failed: (entry) => typeof entry.code === "string" &&
1892
2345
  typeof entry.message === "string" &&
1893
2346
  typeof entry.recovery === "string" &&
@@ -1913,8 +2366,40 @@ function isObservationArray(value) {
1913
2366
  return value.every((entry) => isRecord(entry) &&
1914
2367
  typeof entry.transition === "string" &&
1915
2368
  isStringArray(entry.signals) &&
1916
- (entry.batch_iteration === undefined ||
1917
- (Number.isInteger(entry.batch_iteration) && entry.batch_iteration >= 1)));
2369
+ isIterationRecord(entry));
2370
+ }
2371
+ const REENTRY_KINDS = ["refine", "close", "reopen", "review", "reinfer"];
2372
+ /** Absent, or reentries each with its kind, its boundary, its occurrence and its origin. */
2373
+ function isReentryArray(value) {
2374
+ if (value === undefined)
2375
+ return true;
2376
+ if (!Array.isArray(value))
2377
+ return false;
2378
+ return value.every((entry) => isRecord(entry) &&
2379
+ REENTRY_KINDS.includes(entry.kind) &&
2380
+ (entry.kind !== "review" ||
2381
+ (entry.transition === "plan-exec.batch-close" &&
2382
+ entry.from === "plan-exec.review-findings")) &&
2383
+ (entry.kind !== "reinfer" ||
2384
+ (entry.from === "plan-exec.validation-execution" &&
2385
+ [
2386
+ "plan-exec.deferred-check",
2387
+ "plan-exec.review-findings",
2388
+ "plan-exec.batch-commit-proposal",
2389
+ "plan-exec.batch-close",
2390
+ ].includes(entry.transition))) &&
2391
+ nonEmpty(entry.transition) &&
2392
+ Number.isInteger(entry.occurrence) &&
2393
+ entry.occurrence >= 1 &&
2394
+ // A redraft names where it re-enters; the other kinds repeat from their row.
2395
+ (entry.kind === "refine"
2396
+ ? nonEmpty(entry.from)
2397
+ : entry.from === null || nonEmpty(entry.from)));
2398
+ }
2399
+ /** Both iteration fields, each absent or a positive integer. */
2400
+ function isIterationRecord(entry) {
2401
+ const ordinal = (value) => value === undefined || (Number.isInteger(value) && value >= 1);
2402
+ return ordinal(entry.batch_iteration) && ordinal(entry.reentry_iteration);
1918
2403
  }
1919
2404
  /**
1920
2405
  * The two optional fields are checked as ABSENT-or-well-formed, never defaulted.
@@ -1950,8 +2435,7 @@ function isAttemptArray(value) {
1950
2435
  Number.isInteger(entry.attempt) &&
1951
2436
  typeof entry.request_digest === "string" &&
1952
2437
  typeof entry.transition === "string" &&
1953
- (entry.batch_iteration === undefined ||
1954
- (Number.isInteger(entry.batch_iteration) && entry.batch_iteration >= 1)) &&
2438
+ isIterationRecord(entry) &&
1955
2439
  (entry.parent_request_digest === null || typeof entry.parent_request_digest === "string"));
1956
2440
  }
1957
2441
  //# sourceMappingURL=run-state.js.map