okstra 0.174.0 → 0.176.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 (419) hide show
  1. package/README.md +18 -9
  2. package/bin/okstra +8 -4
  3. package/dist/cli-registry.d.mts +16 -0
  4. package/dist/cli-registry.mjs +560 -0
  5. package/dist/cli-registry.mjs.map +1 -0
  6. package/dist/commands/execute/agent-prompt.d.mts +1 -0
  7. package/{src → dist}/commands/execute/agent-prompt.mjs +10 -11
  8. package/dist/commands/execute/agent-prompt.mjs.map +1 -0
  9. package/dist/commands/execute/codex-dispatch.d.mts +3 -0
  10. package/dist/commands/execute/codex-dispatch.mjs +6 -0
  11. package/dist/commands/execute/codex-dispatch.mjs.map +1 -0
  12. package/dist/commands/execute/codex-run.d.mts +3 -0
  13. package/{src → dist}/commands/execute/codex-run.mjs +30 -37
  14. package/dist/commands/execute/codex-run.mjs.map +1 -0
  15. package/dist/commands/execute/convergence.d.mts +1 -0
  16. package/{src → dist}/commands/execute/convergence.mjs +15 -16
  17. package/dist/commands/execute/convergence.mjs.map +1 -0
  18. package/dist/commands/execute/error-log.d.mts +1 -0
  19. package/{src → dist}/commands/execute/error-log.mjs +2 -3
  20. package/dist/commands/execute/error-log.mjs.map +1 -0
  21. package/dist/commands/execute/git-reconcile.d.mts +1 -0
  22. package/{src → dist}/commands/execute/git-reconcile.mjs +10 -11
  23. package/dist/commands/execute/git-reconcile.mjs.map +1 -0
  24. package/dist/commands/execute/handoff.d.mts +1 -0
  25. package/{src → dist}/commands/execute/handoff.mjs +10 -11
  26. package/dist/commands/execute/handoff.mjs.map +1 -0
  27. package/dist/commands/execute/incremental-carry.d.mts +1 -0
  28. package/{src → dist}/commands/execute/incremental-carry.mjs +2 -3
  29. package/dist/commands/execute/incremental-carry.mjs.map +1 -0
  30. package/dist/commands/execute/incremental-scope.d.mts +1 -0
  31. package/{src → dist}/commands/execute/incremental-scope.mjs +2 -3
  32. package/dist/commands/execute/incremental-scope.mjs.map +1 -0
  33. package/dist/commands/execute/integrate-stages.d.mts +1 -0
  34. package/{src → dist}/commands/execute/integrate-stages.mjs +10 -11
  35. package/dist/commands/execute/integrate-stages.mjs.map +1 -0
  36. package/dist/commands/execute/pane-title.d.mts +1 -0
  37. package/dist/commands/execute/pane-title.mjs +20 -0
  38. package/dist/commands/execute/pane-title.mjs.map +1 -0
  39. package/dist/commands/execute/plan-items.d.mts +1 -0
  40. package/dist/commands/execute/plan-items.mjs +9 -0
  41. package/dist/commands/execute/plan-items.mjs.map +1 -0
  42. package/dist/commands/execute/plan-validate.d.mts +1 -0
  43. package/dist/commands/execute/plan-validate.mjs +68 -0
  44. package/dist/commands/execute/plan-validate.mjs.map +1 -0
  45. package/dist/commands/execute/plan-verify.d.mts +1 -0
  46. package/{src → dist}/commands/execute/plan-verify.mjs +13 -16
  47. package/dist/commands/execute/plan-verify.mjs.map +1 -0
  48. package/dist/commands/execute/render-bundle.d.mts +3 -0
  49. package/{src → dist}/commands/execute/render-bundle.mjs +65 -61
  50. package/dist/commands/execute/render-bundle.mjs.map +1 -0
  51. package/dist/commands/execute/run.d.mts +24 -0
  52. package/dist/commands/execute/run.mjs +196 -0
  53. package/dist/commands/execute/run.mjs.map +1 -0
  54. package/dist/commands/execute/spawn-followups.d.mts +1 -0
  55. package/{src → dist}/commands/execute/spawn-followups.mjs +6 -7
  56. package/dist/commands/execute/spawn-followups.mjs.map +1 -0
  57. package/dist/commands/execute/team.d.mts +3 -0
  58. package/{src → dist}/commands/execute/team.mjs +29 -36
  59. package/dist/commands/execute/team.mjs.map +1 -0
  60. package/dist/commands/execute/token-usage.d.mts +1 -0
  61. package/{src → dist}/commands/execute/token-usage.mjs +2 -3
  62. package/dist/commands/execute/token-usage.mjs.map +1 -0
  63. package/dist/commands/execute/wizard.d.mts +8 -0
  64. package/dist/commands/execute/wizard.mjs +191 -0
  65. package/dist/commands/execute/wizard.mjs.map +1 -0
  66. package/dist/commands/execute/worker-audit-check.d.mts +1 -0
  67. package/{src → dist}/commands/execute/worker-audit-check.mjs +11 -12
  68. package/dist/commands/execute/worker-audit-check.mjs.map +1 -0
  69. package/dist/commands/execute/worker-dispatch.d.mts +7 -0
  70. package/{src → dist}/commands/execute/worker-dispatch.mjs +34 -46
  71. package/dist/commands/execute/worker-dispatch.mjs.map +1 -0
  72. package/dist/commands/execute/worker-state.d.mts +1 -0
  73. package/{src → dist}/commands/execute/worker-state.mjs +15 -16
  74. package/dist/commands/execute/worker-state.mjs.map +1 -0
  75. package/dist/commands/execute/worktree-lookup.d.mts +1 -0
  76. package/{src → dist}/commands/execute/worktree-lookup.mjs +38 -37
  77. package/dist/commands/execute/worktree-lookup.mjs.map +1 -0
  78. package/dist/commands/execute/worktree-status.d.mts +1 -0
  79. package/{src → dist}/commands/execute/worktree-status.mjs +52 -46
  80. package/dist/commands/execute/worktree-status.mjs.map +1 -0
  81. package/dist/commands/inspect/code-review.d.mts +1 -0
  82. package/{src → dist}/commands/inspect/code-review.mjs +16 -19
  83. package/dist/commands/inspect/code-review.mjs.map +1 -0
  84. package/dist/commands/inspect/container.d.mts +1 -0
  85. package/{src → dist}/commands/inspect/container.mjs +11 -13
  86. package/dist/commands/inspect/container.mjs.map +1 -0
  87. package/dist/commands/inspect/context-cost.d.mts +1 -0
  88. package/{src → dist}/commands/inspect/context-cost.mjs +11 -13
  89. package/dist/commands/inspect/context-cost.mjs.map +1 -0
  90. package/dist/commands/inspect/design-prep.d.mts +1 -0
  91. package/{src → dist}/commands/inspect/design-prep.mjs +10 -11
  92. package/dist/commands/inspect/design-prep.mjs.map +1 -0
  93. package/dist/commands/inspect/error-report.d.mts +1 -0
  94. package/{src → dist}/commands/inspect/error-report.mjs +11 -13
  95. package/dist/commands/inspect/error-report.mjs.map +1 -0
  96. package/dist/commands/inspect/error-zip.d.mts +1 -0
  97. package/{src → dist}/commands/inspect/error-zip.mjs +11 -12
  98. package/dist/commands/inspect/error-zip.mjs.map +1 -0
  99. package/dist/commands/inspect/log-report.d.mts +1 -0
  100. package/{src → dist}/commands/inspect/log-report.mjs +11 -13
  101. package/dist/commands/inspect/log-report.mjs.map +1 -0
  102. package/dist/commands/inspect/profile-show.d.mts +1 -0
  103. package/{src → dist}/commands/inspect/profile-show.mjs +10 -11
  104. package/dist/commands/inspect/profile-show.mjs.map +1 -0
  105. package/dist/commands/inspect/recap.d.mts +1 -0
  106. package/{src → dist}/commands/inspect/recap.mjs +11 -13
  107. package/dist/commands/inspect/recap.mjs.map +1 -0
  108. package/dist/commands/inspect/resolve-task-key.d.mts +1 -0
  109. package/{src → dist}/commands/inspect/resolve-task-key.mjs +11 -13
  110. package/dist/commands/inspect/resolve-task-key.mjs.map +1 -0
  111. package/dist/commands/inspect/rollup.d.mts +1 -0
  112. package/{src → dist}/commands/inspect/rollup.mjs +11 -13
  113. package/dist/commands/inspect/rollup.mjs.map +1 -0
  114. package/dist/commands/inspect/run-audit.d.mts +1 -0
  115. package/{src → dist}/commands/inspect/run-audit.mjs +11 -12
  116. package/dist/commands/inspect/run-audit.mjs.map +1 -0
  117. package/dist/commands/inspect/set-work-status.d.mts +1 -0
  118. package/{src → dist}/commands/inspect/set-work-status.mjs +11 -13
  119. package/dist/commands/inspect/set-work-status.mjs.map +1 -0
  120. package/dist/commands/inspect/stage-map.d.mts +1 -0
  121. package/dist/commands/inspect/stage-map.mjs +110 -0
  122. package/dist/commands/inspect/stage-map.mjs.map +1 -0
  123. package/dist/commands/inspect/task-list.d.mts +1 -0
  124. package/dist/commands/inspect/task-list.mjs +103 -0
  125. package/dist/commands/inspect/task-list.mjs.map +1 -0
  126. package/dist/commands/inspect/task-show.d.mts +1 -0
  127. package/dist/commands/inspect/task-show.mjs +108 -0
  128. package/dist/commands/inspect/task-show.mjs.map +1 -0
  129. package/dist/commands/inspect/time-report.d.mts +1 -0
  130. package/{src → dist}/commands/inspect/time-report.mjs +11 -13
  131. package/dist/commands/inspect/time-report.mjs.map +1 -0
  132. package/dist/commands/inspect/usage-report.d.mts +1 -0
  133. package/{src → dist}/commands/inspect/usage-report.mjs +11 -13
  134. package/dist/commands/inspect/usage-report.mjs.map +1 -0
  135. package/dist/commands/inspect/user-response.d.mts +1 -0
  136. package/{src → dist}/commands/inspect/user-response.mjs +10 -11
  137. package/dist/commands/inspect/user-response.mjs.map +1 -0
  138. package/dist/commands/inspect/worker-liveness.d.mts +1 -0
  139. package/{src → dist}/commands/inspect/worker-liveness.mjs +11 -13
  140. package/dist/commands/inspect/worker-liveness.mjs.map +1 -0
  141. package/dist/commands/lifecycle/check-project.d.mts +21 -0
  142. package/dist/commands/lifecycle/check-project.mjs +175 -0
  143. package/dist/commands/lifecycle/check-project.mjs.map +1 -0
  144. package/dist/commands/lifecycle/config.d.mts +1 -0
  145. package/dist/commands/lifecycle/config.mjs +369 -0
  146. package/dist/commands/lifecycle/config.mjs.map +1 -0
  147. package/dist/commands/lifecycle/doctor.d.mts +10 -0
  148. package/dist/commands/lifecycle/doctor.mjs +317 -0
  149. package/dist/commands/lifecycle/doctor.mjs.map +1 -0
  150. package/dist/commands/lifecycle/install.d.mts +17 -0
  151. package/dist/commands/lifecycle/install.mjs +1077 -0
  152. package/dist/commands/lifecycle/install.mjs.map +1 -0
  153. package/dist/commands/lifecycle/migrate.d.mts +1 -0
  154. package/{src → dist}/commands/lifecycle/migrate.mjs +10 -11
  155. package/dist/commands/lifecycle/migrate.mjs.map +1 -0
  156. package/dist/commands/lifecycle/model.d.mts +1 -0
  157. package/dist/commands/lifecycle/model.mjs +22 -0
  158. package/dist/commands/lifecycle/model.mjs.map +1 -0
  159. package/dist/commands/lifecycle/paths.d.mts +1 -0
  160. package/dist/commands/lifecycle/paths.mjs +102 -0
  161. package/dist/commands/lifecycle/paths.mjs.map +1 -0
  162. package/dist/commands/lifecycle/preflight.d.mts +1 -0
  163. package/dist/commands/lifecycle/preflight.mjs +124 -0
  164. package/dist/commands/lifecycle/preflight.mjs.map +1 -0
  165. package/dist/commands/lifecycle/setup.d.mts +1 -0
  166. package/dist/commands/lifecycle/setup.mjs +297 -0
  167. package/dist/commands/lifecycle/setup.mjs.map +1 -0
  168. package/dist/commands/lifecycle/uninstall.d.mts +4 -0
  169. package/dist/commands/lifecycle/uninstall.mjs +262 -0
  170. package/dist/commands/lifecycle/uninstall.mjs.map +1 -0
  171. package/dist/commands/manager.d.mts +3 -0
  172. package/{src → dist}/commands/manager.mjs +25 -32
  173. package/dist/commands/manager.mjs.map +1 -0
  174. package/dist/commands/memory/memory.d.mts +1 -0
  175. package/dist/commands/memory/memory.mjs +569 -0
  176. package/dist/commands/memory/memory.mjs.map +1 -0
  177. package/dist/commands/pr/pr.d.mts +33 -0
  178. package/dist/commands/pr/pr.mjs +296 -0
  179. package/dist/commands/pr/pr.mjs.map +1 -0
  180. package/dist/commands/report/agent-activity.d.mts +1 -0
  181. package/{src → dist}/commands/report/agent-activity.mjs +11 -12
  182. package/dist/commands/report/agent-activity.mjs.map +1 -0
  183. package/dist/commands/report/finalize.d.mts +4 -0
  184. package/{src → dist}/commands/report/finalize.mjs +25 -32
  185. package/dist/commands/report/finalize.mjs.map +1 -0
  186. package/dist/commands/report/inject-report-index.d.mts +1 -0
  187. package/{src → dist}/commands/report/inject-report-index.mjs +6 -7
  188. package/dist/commands/report/inject-report-index.mjs.map +1 -0
  189. package/dist/commands/report/render-final-report.d.mts +1 -0
  190. package/{src → dist}/commands/report/render-final-report.mjs +6 -7
  191. package/dist/commands/report/render-final-report.mjs.map +1 -0
  192. package/dist/commands/report/render-views.d.mts +1 -0
  193. package/{src → dist}/commands/report/render-views.mjs +6 -7
  194. package/dist/commands/report/render-views.mjs.map +1 -0
  195. package/dist/commands/report/translate.d.mts +1 -0
  196. package/{src → dist}/commands/report/translate.mjs +6 -7
  197. package/dist/commands/report/translate.mjs.map +1 -0
  198. package/dist/lib/helper-scripts.d.mts +3 -0
  199. package/{src → dist}/lib/helper-scripts.mjs +11 -14
  200. package/dist/lib/helper-scripts.mjs.map +1 -0
  201. package/dist/lib/host-registry-client.d.mts +25 -0
  202. package/dist/lib/host-registry-client.mjs +152 -0
  203. package/dist/lib/host-registry-client.mjs.map +1 -0
  204. package/dist/lib/install-assets.d.mts +8 -0
  205. package/{src → dist}/lib/install-assets.mjs +17 -20
  206. package/dist/lib/install-assets.mjs.map +1 -0
  207. package/dist/lib/okstra-dirs.d.mts +4 -0
  208. package/{src → dist}/lib/okstra-dirs.mjs +3 -6
  209. package/dist/lib/okstra-dirs.mjs.map +1 -0
  210. package/dist/lib/paths.d.mts +4 -0
  211. package/dist/lib/paths.mjs +78 -0
  212. package/dist/lib/paths.mjs.map +1 -0
  213. package/dist/lib/proc.d.mts +3 -0
  214. package/dist/lib/proc.mjs +31 -0
  215. package/dist/lib/proc.mjs.map +1 -0
  216. package/dist/lib/python-helper.d.mts +8 -0
  217. package/dist/lib/python-helper.mjs +123 -0
  218. package/dist/lib/python-helper.mjs.map +1 -0
  219. package/dist/lib/runtime-manifest.d.mts +7 -0
  220. package/dist/lib/runtime-manifest.mjs +73 -0
  221. package/dist/lib/runtime-manifest.mjs.map +1 -0
  222. package/dist/lib/skill-catalog.d.mts +4 -0
  223. package/dist/lib/skill-catalog.mjs +50 -0
  224. package/dist/lib/skill-catalog.mjs.map +1 -0
  225. package/dist/lib/types.d.mts +129 -0
  226. package/dist/lib/types.mjs +2 -0
  227. package/dist/lib/types.mjs.map +1 -0
  228. package/dist/lib/version.d.mts +2 -0
  229. package/dist/lib/version.mjs +27 -0
  230. package/dist/lib/version.mjs.map +1 -0
  231. package/docs/architecture/storage-model.md +6 -2
  232. package/docs/architecture.md +29 -20
  233. package/docs/cli.md +40 -16
  234. package/docs/contributor-change-matrix.md +2 -2
  235. package/docs/for-ai/skills/okstra-inspect.md +2 -3
  236. package/docs/for-ai/skills/okstra-rollup.md +1 -0
  237. package/docs/project-structure-overview.md +72 -62
  238. package/docs/task-process/README.md +12 -8
  239. package/docs/task-process/common-flow.md +13 -16
  240. package/docs/task-process/error-analysis.md +9 -10
  241. package/docs/task-process/final-verification.md +7 -7
  242. package/docs/task-process/implementation-planning.md +9 -9
  243. package/docs/task-process/implementation.md +6 -6
  244. package/docs/task-process/release-handoff.md +8 -7
  245. package/docs/task-process/requirements-discovery.md +8 -8
  246. package/package.json +11 -5
  247. package/runtime/BUILD.json +2 -2
  248. package/runtime/agents/workers/claude-worker.md +2 -1
  249. package/runtime/agents/workers/report-writer-worker.md +3 -1
  250. package/runtime/agents/workers/translator-worker.md +3 -1
  251. package/runtime/bin/lib/okstra/cli.sh +12 -0
  252. package/runtime/bin/lib/okstra/globals.sh +3 -0
  253. package/runtime/bin/lib/okstra/interactive.sh +12 -6
  254. package/runtime/bin/lib/okstra/usage.sh +7 -6
  255. package/runtime/bin/okstra-error-log.py +27 -0
  256. package/runtime/bin/okstra-provider-exec.py +217 -5
  257. package/runtime/bin/okstra-spawn-followups.py +4 -2
  258. package/runtime/bin/okstra.sh +10 -0
  259. package/runtime/prompts/launch.template.md +2 -2
  260. package/runtime/prompts/lead/context-loader.md +1 -2
  261. package/runtime/prompts/lead/convergence.md +27 -18
  262. package/runtime/prompts/lead/okstra-lead-contract.md +6 -5
  263. package/runtime/prompts/lead/plan-body-verification.md +10 -3
  264. package/runtime/prompts/lead/report-writer.md +15 -1
  265. package/runtime/prompts/lead/team-contract.md +17 -13
  266. package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
  267. package/runtime/prompts/profiles/_implementation-executor.md +0 -3
  268. package/runtime/prompts/profiles/_implementation-verifier.md +3 -7
  269. package/runtime/prompts/profiles/change-impact-analysis.md +20 -0
  270. package/runtime/prompts/profiles/error-analysis.md +27 -1
  271. package/runtime/prompts/profiles/feature-analysis.md +20 -0
  272. package/runtime/prompts/profiles/final-verification.md +20 -1
  273. package/runtime/prompts/profiles/implementation-option-selection.md +20 -0
  274. package/runtime/prompts/profiles/implementation-planning.md +26 -0
  275. package/runtime/prompts/profiles/implementation.md +19 -0
  276. package/runtime/prompts/profiles/improvement-discovery.md +21 -1
  277. package/runtime/prompts/profiles/project-analysis.md +20 -0
  278. package/runtime/prompts/profiles/release-handoff.md +4 -0
  279. package/runtime/prompts/profiles/requirements-discovery.md +27 -1
  280. package/runtime/prompts/wizard/prompts.ko.json +35 -0
  281. package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +8 -0
  282. package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +8 -0
  283. package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
  284. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +2 -2
  285. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +25 -5
  286. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
  287. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +4 -1
  288. package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
  289. package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +2 -2
  290. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +79 -11
  291. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +95 -25
  292. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +59 -14
  293. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +55 -9
  294. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +51 -12
  295. package/runtime/python/okstra_ctl/adapters/runtime/__init__.py +1 -0
  296. package/runtime/python/okstra_ctl/adapters/runtime/assembly.py +27 -0
  297. package/runtime/python/okstra_ctl/adapters/runtime/cli_wrapper.py +49 -0
  298. package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +74 -0
  299. package/runtime/python/okstra_ctl/agent_activity.py +5 -1
  300. package/runtime/python/okstra_ctl/agent_invocation.py +608 -14
  301. package/runtime/python/okstra_ctl/agent_prompt_cli.py +249 -50
  302. package/runtime/python/okstra_ctl/application/open_worker.py +29 -0
  303. package/runtime/python/okstra_ctl/application/resolve_assignment.py +53 -12
  304. package/runtime/python/okstra_ctl/assignment_environment.py +102 -0
  305. package/runtime/python/okstra_ctl/assignment_resolver.py +790 -0
  306. package/runtime/python/okstra_ctl/attempt_evidence.py +342 -0
  307. package/runtime/python/okstra_ctl/convergence.py +409 -3
  308. package/runtime/python/okstra_ctl/convergence_engine.py +248 -15
  309. package/runtime/python/okstra_ctl/convergence_store.py +170 -1
  310. package/runtime/python/okstra_ctl/dispatch_core.py +1204 -155
  311. package/runtime/python/okstra_ctl/dispatch_state.py +696 -11
  312. package/runtime/python/okstra_ctl/doctor.py +14 -0
  313. package/runtime/python/okstra_ctl/domain/host.py +34 -1
  314. package/runtime/python/okstra_ctl/domain/provider.py +212 -6
  315. package/runtime/python/okstra_ctl/domain/role.py +125 -0
  316. package/runtime/python/okstra_ctl/domain/wizard/interaction.py +18 -0
  317. package/runtime/python/okstra_ctl/domain/worker_exec.py +34 -1
  318. package/runtime/python/okstra_ctl/domain/worker_role.py +13 -3
  319. package/runtime/python/okstra_ctl/domain/worker_runtime.py +44 -0
  320. package/runtime/python/okstra_ctl/domain/worker_stream.py +24 -0
  321. package/runtime/python/okstra_ctl/error_log_write.py +9 -0
  322. package/runtime/python/okstra_ctl/error_report.py +21 -1
  323. package/runtime/python/okstra_ctl/execution_identity.py +529 -0
  324. package/runtime/python/okstra_ctl/execution_manifest.py +1281 -0
  325. package/runtime/python/okstra_ctl/execution_mutation_audit.py +619 -0
  326. package/runtime/python/okstra_ctl/implementation_outcome.py +21 -5
  327. package/runtime/python/okstra_ctl/index.py +6 -2
  328. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
  329. package/runtime/python/okstra_ctl/legacy_model_selection.py +578 -0
  330. package/runtime/python/okstra_ctl/manager_sync.py +4 -1
  331. package/runtime/python/okstra_ctl/model_cli.py +278 -0
  332. package/runtime/python/okstra_ctl/model_defaults.py +46 -0
  333. package/runtime/python/okstra_ctl/model_discovery.py +26 -7
  334. package/runtime/python/okstra_ctl/model_pool.py +501 -0
  335. package/runtime/python/okstra_ctl/models.py +47 -27
  336. package/runtime/python/okstra_ctl/mutation_recovery.py +293 -0
  337. package/runtime/python/okstra_ctl/next_phase.py +236 -0
  338. package/runtime/python/okstra_ctl/pane_title.py +151 -0
  339. package/runtime/python/okstra_ctl/ports/host_model.py +48 -17
  340. package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
  341. package/runtime/python/okstra_ctl/ports/worker_runtime.py +26 -0
  342. package/runtime/python/okstra_ctl/recap.py +4 -1
  343. package/runtime/python/okstra_ctl/registry/provider_registry.py +8 -4
  344. package/runtime/python/okstra_ctl/render.py +124 -57
  345. package/runtime/python/okstra_ctl/render_final_report.py +19 -0
  346. package/runtime/python/okstra_ctl/report_contract.py +39 -0
  347. package/runtime/python/okstra_ctl/report_finalize.py +16 -0
  348. package/runtime/python/okstra_ctl/report_html/render.py +1 -0
  349. package/runtime/python/okstra_ctl/role_requirements.py +210 -0
  350. package/runtime/python/okstra_ctl/rollup.py +4 -1
  351. package/runtime/python/okstra_ctl/run.py +1210 -258
  352. package/runtime/python/okstra_ctl/run_index_row.py +7 -1
  353. package/runtime/python/okstra_ctl/stage_fix_carry.py +17 -1
  354. package/runtime/python/okstra_ctl/team.py +14 -18
  355. package/runtime/python/okstra_ctl/time_report.py +38 -4
  356. package/runtime/python/okstra_ctl/usage_identity.py +86 -0
  357. package/runtime/python/okstra_ctl/usage_report.py +15 -3
  358. package/runtime/python/okstra_ctl/wizard.py +1449 -66
  359. package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
  360. package/runtime/python/okstra_ctl/worker_prompt_body.py +18 -2
  361. package/runtime/python/okstra_ctl/worker_prompt_contract.py +40 -9
  362. package/runtime/python/okstra_ctl/worker_prompt_headers.py +16 -1
  363. package/runtime/python/okstra_ctl/worker_request.py +7 -1
  364. package/runtime/python/okstra_ctl/worker_runner.py +130 -5
  365. package/runtime/python/okstra_ctl/workers.py +7 -5
  366. package/runtime/python/okstra_ctl/workflow.py +18 -32
  367. package/runtime/python/okstra_ctl/worktree.py +3 -3
  368. package/runtime/python/okstra_ctl/worktree_registry.py +5 -4
  369. package/runtime/python/okstra_ctl/write_policy.py +571 -0
  370. package/runtime/python/okstra_project/state.py +54 -6
  371. package/runtime/schemas/convergence-groups-v2.0.schema.json +128 -0
  372. package/runtime/schemas/execution-manifest-v2.schema.json +340 -0
  373. package/runtime/schemas/final-report-v2.0.schema.json +68 -5
  374. package/runtime/skills/okstra-inspect/facets/recap.md +2 -0
  375. package/runtime/skills/okstra-inspect/facets/report.md +1 -1
  376. package/runtime/skills/okstra-inspect/facets/status.md +15 -13
  377. package/runtime/skills/okstra-rollup/SKILL.md +1 -0
  378. package/runtime/skills/okstra-run/SKILL.md +14 -14
  379. package/runtime/templates/implementation-worker-preamble.md +3 -18
  380. package/runtime/templates/project-docs/task-index.template.md +0 -1
  381. package/runtime/templates/report-writer-prompt-preamble.md +2 -0
  382. package/runtime/templates/reports/final-report-v2.template.md +7 -1
  383. package/runtime/templates/reports/html/base.template.html +21 -0
  384. package/runtime/templates/reports/html/i18n/en.json +4 -0
  385. package/runtime/templates/reports/html/i18n/ko.json +4 -0
  386. package/runtime/templates/reports/html/macros/forms.html +5 -4
  387. package/runtime/templates/reports/html/tasks/final-verification.template.html +1 -1
  388. package/runtime/templates/reports/html/tasks/implementation.template.html +1 -1
  389. package/runtime/templates/worker-prompt-preamble.md +6 -35
  390. package/runtime/validators/lib/fixtures.sh +49 -16
  391. package/runtime/validators/validate-run.py +486 -134
  392. package/runtime/validators/validate_session_conformance.py +25 -7
  393. package/src/cli-registry.mjs +0 -539
  394. package/src/commands/execute/codex-dispatch.mjs +0 -10
  395. package/src/commands/execute/plan-items.mjs +0 -9
  396. package/src/commands/execute/plan-validate.mjs +0 -68
  397. package/src/commands/execute/run.mjs +0 -208
  398. package/src/commands/execute/wizard.mjs +0 -167
  399. package/src/commands/inspect/stage-map.mjs +0 -98
  400. package/src/commands/inspect/task-list.mjs +0 -97
  401. package/src/commands/inspect/task-show.mjs +0 -100
  402. package/src/commands/lifecycle/check-project.mjs +0 -187
  403. package/src/commands/lifecycle/config.mjs +0 -385
  404. package/src/commands/lifecycle/doctor.mjs +0 -308
  405. package/src/commands/lifecycle/install.mjs +0 -1170
  406. package/src/commands/lifecycle/paths.mjs +0 -104
  407. package/src/commands/lifecycle/preflight.mjs +0 -125
  408. package/src/commands/lifecycle/setup.mjs +0 -333
  409. package/src/commands/lifecycle/uninstall.mjs +0 -279
  410. package/src/commands/memory/memory.mjs +0 -524
  411. package/src/commands/pr/pr.mjs +0 -261
  412. package/src/lib/host-registry-client.mjs +0 -176
  413. package/src/lib/paths.mjs +0 -86
  414. package/src/lib/proc.mjs +0 -31
  415. package/src/lib/python-helper.mjs +0 -142
  416. package/src/lib/runtime-manifest.mjs +0 -70
  417. package/src/lib/skill-catalog.mjs +0 -53
  418. package/src/lib/version.mjs +0 -20
  419. /package/{src → dist}/commands/pr/default.md +0 -0
@@ -2,8 +2,9 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import argparse
5
+ from collections.abc import Mapping
5
6
  import json
6
- from pathlib import Path
7
+ from pathlib import Path, PurePosixPath
7
8
  import sys
8
9
  from typing import Any
9
10
 
@@ -32,6 +33,9 @@ from .convergence_store import (
32
33
  write_final_state_atomic,
33
34
  write_json_atomic,
34
35
  )
36
+ from .execution_identity import ExecutionManifest
37
+ from .execution_manifest import read_execution_manifest_view
38
+ from .paths import RunRef
35
39
  from .verdict_blocks import FindingVote, VerdictBlockError, parse_finding_votes
36
40
 
37
41
 
@@ -154,7 +158,7 @@ def _parser() -> argparse.ArgumentParser:
154
158
  prog="okstra convergence",
155
159
  description="Advance and validate deterministic re-verification state.",
156
160
  epilog=(
157
- "Working lifecycle: groups v1.0 → work v1.0 → "
161
+ "Working lifecycle: groups v1.0/v2.0 → work v1.0/v2.0 → "
158
162
  "round-plan/results v1.0 → final v1.3\n"
159
163
  "historical final readers: v1.0, v1.1, v1.2"
160
164
  ),
@@ -188,6 +192,7 @@ def _parser() -> argparse.ArgumentParser:
188
192
 
189
193
  seed = subparsers.add_parser("seed", help="create, resume, or recover working state")
190
194
  seed.add_argument("--groups", type=Path, required=True)
195
+ seed.add_argument("--run-manifest", type=Path)
191
196
  seed.add_argument("--work-state", type=Path, required=True)
192
197
  seed.add_argument("--final-state", type=Path, required=True)
193
198
  seed.add_argument("--migration-dir", type=Path, required=True)
@@ -314,13 +319,402 @@ def _seeded_groups_provenance_errors(groups_path: Path, document: dict) -> list[
314
319
  )
315
320
 
316
321
 
322
+ def _seed_execution_manifest(
323
+ groups_path: Path,
324
+ grouped_input: dict[str, Any],
325
+ manifest_path: Path | None,
326
+ work_state_path: Path,
327
+ final_state_path: Path,
328
+ ) -> ExecutionManifest | None:
329
+ if manifest_path is None:
330
+ return None
331
+ manifest, authority = read_execution_manifest_view(manifest_path)
332
+ if grouped_input.get("schemaVersion") == "2.0":
333
+ _validate_v2_seed_authority(
334
+ groups_path,
335
+ grouped_input,
336
+ manifest_path,
337
+ authority,
338
+ work_state_path,
339
+ final_state_path,
340
+ execution_manifest=manifest,
341
+ )
342
+ return manifest
343
+
344
+
345
+ def _validate_v2_seed_authority(
346
+ groups_path: Path,
347
+ grouped_input: dict[str, Any],
348
+ manifest_path: Path,
349
+ authority: Mapping[str, Any],
350
+ work_state_path: Path,
351
+ final_state_path: Path,
352
+ *,
353
+ execution_manifest: ExecutionManifest,
354
+ ) -> None:
355
+ validated = _validated_v2_work_authority(
356
+ work_state_path,
357
+ grouped_input,
358
+ manifest_snapshot=(manifest_path, execution_manifest, authority),
359
+ path_label="state output",
360
+ )
361
+ if validated is None:
362
+ raise ConvergenceContractError("v2 convergence groups require v2 work authority")
363
+ _manifest, run_dir, task_type, state_sequence = validated
364
+ expected_groups_name = _canonical_run_artifact_name(
365
+ "convergence-groups",
366
+ task_type,
367
+ state_sequence,
368
+ )
369
+ if groups_path.name != expected_groups_name:
370
+ raise ConvergenceContractError(
371
+ "convergence groups filename does not match run authority"
372
+ )
373
+ expected_state_dir = run_dir / "state"
374
+ if groups_path.absolute() != groups_path.resolve():
375
+ raise ConvergenceContractError("groups artifact path must be canonical")
376
+ if groups_path.resolve().parent != expected_state_dir:
377
+ raise ConvergenceContractError(
378
+ "groups artifact is outside the current run state directory"
379
+ )
380
+ _validate_v2_state_artifact_path(
381
+ final_state_path,
382
+ state_dir=expected_state_dir,
383
+ task_type=task_type,
384
+ state_sequence=state_sequence,
385
+ prefix="convergence",
386
+ label="state output",
387
+ )
388
+
389
+
390
+ def _validated_v2_work_authority(
391
+ work_state_path: Path,
392
+ state: Mapping[str, Any],
393
+ *,
394
+ manifest_snapshot: tuple[
395
+ Path,
396
+ ExecutionManifest,
397
+ Mapping[str, Any],
398
+ ] | None = None,
399
+ path_label: str = "working state",
400
+ ) -> tuple[ExecutionManifest, Path, str, str] | None:
401
+ if state.get("schemaVersion") != "2.0":
402
+ return None
403
+ if state.get("executionIdentityVersion") != 2:
404
+ raise ConvergenceContractError(
405
+ "v2 working state requires executionIdentityVersion 2"
406
+ )
407
+ task_key = _manifest_authority_string(state, "taskKey")
408
+ run_ref = _manifest_authority_string(state, "runManifestPath")
409
+ project_root = _project_root_for_v2_work_state(work_state_path, path_label)
410
+ expected_manifest_path = _canonical_project_artifact_path(
411
+ project_root,
412
+ run_ref,
413
+ "working runManifestPath",
414
+ )
415
+ if manifest_snapshot is None:
416
+ execution_manifest, authority = read_execution_manifest_view(
417
+ expected_manifest_path
418
+ )
419
+ manifest_path = expected_manifest_path
420
+ else:
421
+ supplied_manifest_path, execution_manifest, authority = manifest_snapshot
422
+ manifest_path = supplied_manifest_path.resolve()
423
+ if (
424
+ supplied_manifest_path.absolute() != manifest_path
425
+ or manifest_path != expected_manifest_path
426
+ ):
427
+ raise ConvergenceContractError(
428
+ "--run-manifest must use the canonical run manifest path; "
429
+ "runManifestPath does not match supplied path"
430
+ )
431
+ manifest_project_root = _manifest_project_root(authority)
432
+ if project_root != manifest_project_root:
433
+ raise ConvergenceContractError(
434
+ "working state path does not match run manifest projectRoot"
435
+ )
436
+ canonical_run_ref = _manifest_run_ref(
437
+ authority,
438
+ project_root,
439
+ manifest_path,
440
+ )
441
+ if task_key != authority.get("taskKey"):
442
+ raise ConvergenceContractError(
443
+ "working state taskKey does not match run manifest"
444
+ )
445
+ if run_ref != canonical_run_ref:
446
+ raise ConvergenceContractError(
447
+ "working state runManifestPath does not match run manifest"
448
+ )
449
+ run_dir, task_type, state_sequence = _validated_run_artifact_authority(
450
+ authority,
451
+ project_root,
452
+ manifest_path,
453
+ canonical_run_ref,
454
+ )
455
+ _validate_v2_state_artifact_path(
456
+ work_state_path,
457
+ state_dir=run_dir / "state",
458
+ task_type=task_type,
459
+ state_sequence=state_sequence,
460
+ prefix="convergence-work",
461
+ label=path_label,
462
+ )
463
+ return execution_manifest, run_dir, task_type, state_sequence
464
+
465
+
466
+ def _project_root_for_v2_work_state(
467
+ work_state_path: Path,
468
+ path_label: str,
469
+ ) -> Path:
470
+ supplied_path = work_state_path.absolute()
471
+ resolved_path = work_state_path.resolve()
472
+ if supplied_path != resolved_path:
473
+ raise ConvergenceContractError(
474
+ f"{path_label} path does not match run authority"
475
+ )
476
+ for parent in supplied_path.parents:
477
+ if parent.name == ".okstra":
478
+ return parent.parent
479
+ raise ConvergenceContractError(
480
+ f"{path_label} path does not match run authority"
481
+ )
482
+
483
+
484
+ def _validated_run_artifact_authority(
485
+ authority: Mapping[str, Any],
486
+ project_root: Path,
487
+ manifest_path: Path,
488
+ run_ref: str,
489
+ ) -> tuple[Path, str, str]:
490
+ run_dir = _manifest_run_directory(authority, project_root, manifest_path)
491
+ task_type = _manifest_authority_string(authority, "taskType")
492
+ manifest_sequence = _manifest_sequence(authority, "manifests")
493
+ expected_name = _canonical_run_artifact_name(
494
+ "run-manifest",
495
+ task_type,
496
+ manifest_sequence,
497
+ )
498
+ try:
499
+ recovered = RunRef.from_run_dir(
500
+ run_dir,
501
+ seq=int(manifest_sequence),
502
+ )
503
+ except ValueError as exc:
504
+ raise ConvergenceContractError(
505
+ "run manifest runDirectoryPath is not a canonical run directory"
506
+ ) from exc
507
+ if recovered.project_root != project_root:
508
+ raise ConvergenceContractError(
509
+ "run manifest projectRoot does not match recovered run directory"
510
+ )
511
+ if recovered.task_type != task_type:
512
+ raise ConvergenceContractError(
513
+ "run manifest taskType does not match run directory"
514
+ )
515
+ stage = recovered.stage
516
+ invalid_stage = (
517
+ (task_type == "implementation" and (stage is None or stage < 1))
518
+ or (task_type == "final-verification" and stage is not None and stage < 1)
519
+ or (
520
+ task_type not in ("implementation", "final-verification")
521
+ and stage is not None
522
+ )
523
+ )
524
+ if invalid_stage:
525
+ raise ConvergenceContractError(
526
+ "run manifest stage semantics do not match taskType"
527
+ )
528
+ if recovered.run_dir != run_dir:
529
+ raise ConvergenceContractError(
530
+ "run manifest stage does not match runDirectoryPath"
531
+ )
532
+ if manifest_path.name != expected_name:
533
+ raise ConvergenceContractError(
534
+ "run manifest filename does not match run authority"
535
+ )
536
+ if manifest_path != recovered.manifest:
537
+ raise ConvergenceContractError(
538
+ "run manifest path does not match runDirectoryPath authority"
539
+ )
540
+ expected_ref = recovered.manifest.relative_to(project_root).as_posix()
541
+ if run_ref != expected_ref:
542
+ raise ConvergenceContractError(
543
+ "runManifestPath does not match canonical run authority"
544
+ )
545
+ return run_dir, task_type, _manifest_sequence(authority, "state")
546
+
547
+
548
+ def _manifest_authority_string(
549
+ authority: Mapping[str, Any],
550
+ key: str,
551
+ ) -> str:
552
+ value = authority.get(key)
553
+ if not isinstance(value, str) or not value.strip():
554
+ raise ConvergenceContractError(f"run manifest has no {key}")
555
+ return value
556
+
557
+
558
+ def _manifest_sequence(authority: Mapping[str, Any], category: str) -> str:
559
+ sequences = authority.get("runSequencesByCategory")
560
+ if not isinstance(sequences, Mapping):
561
+ raise ConvergenceContractError(
562
+ "run manifest has no runSequencesByCategory object"
563
+ )
564
+ return _manifest_authority_string(sequences, category)
565
+
566
+
567
+ def _canonical_run_artifact_name(
568
+ prefix: str,
569
+ task_type: str,
570
+ sequence: str,
571
+ ) -> str:
572
+ try:
573
+ sequence_number = int(sequence)
574
+ except ValueError as exc:
575
+ raise ConvergenceContractError(
576
+ "run manifest sequence is not canonical"
577
+ ) from exc
578
+ if sequence_number < 1:
579
+ raise ConvergenceContractError(
580
+ "run manifest sequence is not canonical"
581
+ )
582
+ probe = RunRef(
583
+ project_root=Path("/"),
584
+ task_group="group",
585
+ task_id="task",
586
+ task_type=task_type,
587
+ seq=sequence_number,
588
+ ).manifest.name
589
+ if not probe.endswith(f"-{sequence}.json"):
590
+ raise ConvergenceContractError(
591
+ "run manifest sequence is not canonical"
592
+ )
593
+ suffix = probe.removeprefix("run-manifest").removesuffix(".json")
594
+ return f"{prefix}{suffix}.json"
595
+
596
+
597
+ def _manifest_run_directory(
598
+ authority: Mapping[str, Any],
599
+ project_root: Path,
600
+ manifest_path: Path,
601
+ ) -> Path:
602
+ value = _manifest_authority_string(authority, "runDirectoryPath")
603
+ posix = PurePosixPath(value)
604
+ if (
605
+ posix.is_absolute()
606
+ or posix.as_posix() != value
607
+ or not posix.parts
608
+ or posix.parts[0] != ".okstra"
609
+ or ".." in posix.parts
610
+ ):
611
+ raise ConvergenceContractError(
612
+ "run manifest runDirectoryPath is not canonical"
613
+ )
614
+ resolved = (project_root / value).resolve()
615
+ if not resolved.is_relative_to(project_root):
616
+ raise ConvergenceContractError(
617
+ "run manifest runDirectoryPath escapes projectRoot"
618
+ )
619
+ if resolved != manifest_path.parent.parent:
620
+ raise ConvergenceContractError(
621
+ "run manifest runDirectoryPath does not identify the supplied run"
622
+ )
623
+ return resolved
624
+
625
+
626
+ def _validate_v2_state_artifact_path(
627
+ supplied_path: Path,
628
+ *,
629
+ state_dir: Path,
630
+ task_type: str,
631
+ state_sequence: str,
632
+ prefix: str,
633
+ label: str,
634
+ ) -> None:
635
+ expected_path = state_dir / _canonical_run_artifact_name(
636
+ prefix,
637
+ task_type,
638
+ state_sequence,
639
+ )
640
+ if (
641
+ supplied_path.absolute() != supplied_path.resolve()
642
+ or supplied_path.resolve() != expected_path
643
+ ):
644
+ raise ConvergenceContractError(
645
+ f"{label} path does not match run authority"
646
+ )
647
+
648
+
649
+ def _manifest_project_root(authority: dict[str, Any]) -> Path:
650
+ value = authority.get("projectRoot")
651
+ if not isinstance(value, str) or not value.strip():
652
+ raise ConvergenceContractError("run manifest has no projectRoot")
653
+ project_root = Path(value)
654
+ if not project_root.is_absolute() or project_root.absolute() != project_root.resolve():
655
+ raise ConvergenceContractError("run manifest projectRoot must be canonical")
656
+ return project_root
657
+
658
+
659
+ def _manifest_run_ref(
660
+ authority: dict[str, Any],
661
+ project_root: Path,
662
+ manifest_path: Path,
663
+ ) -> str:
664
+ value = _manifest_authority_string(authority, "runManifestPath")
665
+ resolved = _canonical_project_artifact_path(
666
+ project_root,
667
+ value,
668
+ "run manifest runManifestPath",
669
+ )
670
+ if resolved != manifest_path:
671
+ raise ConvergenceContractError(
672
+ "run manifest runManifestPath does not identify the supplied manifest"
673
+ )
674
+ return value
675
+
676
+
677
+ def _canonical_project_artifact_path(
678
+ project_root: Path,
679
+ value: str,
680
+ label: str,
681
+ ) -> Path:
682
+ posix = PurePosixPath(value)
683
+ supplied = project_root.joinpath(*posix.parts)
684
+ resolved = supplied.resolve()
685
+ if not resolved.is_relative_to(project_root):
686
+ raise ConvergenceContractError(f"{label} escapes projectRoot")
687
+ if (
688
+ posix.is_absolute()
689
+ or posix.as_posix() != value
690
+ or not posix.parts
691
+ or posix.parts[0] != ".okstra"
692
+ or ".." in posix.parts
693
+ ):
694
+ raise ConvergenceContractError(f"{label} is not canonical")
695
+ if supplied.absolute() != resolved:
696
+ raise ConvergenceContractError(f"{label} escapes projectRoot")
697
+ return resolved
698
+
699
+
317
700
  def _seed(args: argparse.Namespace) -> tuple[str, Path]:
318
701
  grouped_input = load_json_object(args.groups)
702
+ execution_manifest = _seed_execution_manifest(
703
+ args.groups,
704
+ grouped_input,
705
+ args.run_manifest,
706
+ args.work_state,
707
+ args.final_state,
708
+ )
319
709
  provenance = _seeded_groups_provenance_errors(args.groups, grouped_input)
320
710
  if provenance:
321
711
  raise ConvergenceContractError(
322
712
  "grouping cites source items no worker reported: " + "; ".join(provenance)
323
713
  )
714
+ state = seed_working_state(
715
+ grouped_input,
716
+ execution_manifest=execution_manifest,
717
+ )
324
718
  decision = decide_seed_action(
325
719
  grouped_input=grouped_input,
326
720
  work_state_path=args.work_state,
@@ -338,7 +732,6 @@ def _seed(args: argparse.Namespace) -> tuple[str, Path]:
338
732
  )
339
733
  return decision.action, args.work_state
340
734
 
341
- state = seed_working_state(grouped_input)
342
735
  if decision.action == "restart-round0":
343
736
  migration = _archive_existing_states(
344
737
  work_state_path=args.work_state,
@@ -364,6 +757,7 @@ def _plan_round(args: argparse.Namespace) -> tuple[str, Path]:
364
757
 
365
758
  def _apply_round(args: argparse.Namespace) -> tuple[str, Path]:
366
759
  state = load_json_object(args.work_state)
760
+ _validated_v2_work_authority(args.work_state, state)
367
761
  plan = load_json_object(args.plan)
368
762
  results = load_json_object(args.results)
369
763
  updated = apply_round_results(state, plan, results)
@@ -376,6 +770,7 @@ def _apply_round(args: argparse.Namespace) -> tuple[str, Path]:
376
770
 
377
771
  def _apply_critic_gaps(args: argparse.Namespace) -> tuple[str, Path]:
378
772
  state = load_json_object(args.work_state)
773
+ _validated_v2_work_authority(args.work_state, state)
379
774
  results = load_json_object(args.results)
380
775
  updated = apply_critic_gap_results(state, results)
381
776
  write_json_atomic(args.work_state, updated)
@@ -384,6 +779,17 @@ def _apply_critic_gaps(args: argparse.Namespace) -> tuple[str, Path]:
384
779
 
385
780
  def _finalize(args: argparse.Namespace) -> tuple[str, Path]:
386
781
  state = load_json_object(args.work_state)
782
+ authority = _validated_v2_work_authority(args.work_state, state)
783
+ if authority is not None:
784
+ _manifest, run_dir, task_type, state_sequence = authority
785
+ _validate_v2_state_artifact_path(
786
+ args.output,
787
+ state_dir=run_dir / "state",
788
+ task_type=task_type,
789
+ state_sequence=state_sequence,
790
+ prefix="convergence",
791
+ label="final state",
792
+ )
387
793
  final = finalize_working_state(state)
388
794
  migration = state.get("migration")
389
795
  write_final_state_atomic(args.output, final, migration=migration)