okstra 0.174.0 → 0.175.1

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 (374) 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 +4 -0
  232. package/docs/architecture.md +7 -1
  233. package/docs/cli.md +26 -6
  234. package/docs/contributor-change-matrix.md +2 -2
  235. package/docs/project-structure-overview.md +16 -7
  236. package/docs/task-process/README.md +2 -0
  237. package/docs/task-process/implementation-planning.md +1 -1
  238. package/docs/task-process/implementation.md +1 -1
  239. package/package.json +11 -5
  240. package/runtime/BUILD.json +2 -2
  241. package/runtime/agents/workers/claude-worker.md +2 -1
  242. package/runtime/agents/workers/report-writer-worker.md +3 -1
  243. package/runtime/agents/workers/translator-worker.md +3 -1
  244. package/runtime/bin/lib/okstra/cli.sh +12 -0
  245. package/runtime/bin/lib/okstra/globals.sh +3 -0
  246. package/runtime/bin/lib/okstra/usage.sh +4 -4
  247. package/runtime/bin/okstra-error-log.py +27 -0
  248. package/runtime/bin/okstra-provider-exec.py +217 -5
  249. package/runtime/bin/okstra.sh +10 -0
  250. package/runtime/prompts/lead/convergence.md +27 -18
  251. package/runtime/prompts/lead/okstra-lead-contract.md +3 -1
  252. package/runtime/prompts/lead/plan-body-verification.md +10 -3
  253. package/runtime/prompts/lead/team-contract.md +1 -1
  254. package/runtime/prompts/profiles/change-impact-analysis.md +16 -0
  255. package/runtime/prompts/profiles/error-analysis.md +20 -0
  256. package/runtime/prompts/profiles/feature-analysis.md +16 -0
  257. package/runtime/prompts/profiles/final-verification.md +16 -0
  258. package/runtime/prompts/profiles/implementation-option-selection.md +16 -0
  259. package/runtime/prompts/profiles/implementation-planning.md +20 -0
  260. package/runtime/prompts/profiles/implementation.md +15 -0
  261. package/runtime/prompts/profiles/improvement-discovery.md +16 -0
  262. package/runtime/prompts/profiles/project-analysis.md +16 -0
  263. package/runtime/prompts/profiles/release-handoff.md +4 -0
  264. package/runtime/prompts/profiles/requirements-discovery.md +20 -0
  265. package/runtime/prompts/wizard/prompts.ko.json +18 -0
  266. package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +8 -0
  267. package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +8 -0
  268. package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
  269. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +2 -2
  270. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +25 -5
  271. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
  272. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +4 -1
  273. package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
  274. package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +2 -2
  275. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +79 -11
  276. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +95 -25
  277. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +59 -14
  278. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +55 -9
  279. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +51 -12
  280. package/runtime/python/okstra_ctl/agent_activity.py +5 -1
  281. package/runtime/python/okstra_ctl/agent_invocation.py +608 -14
  282. package/runtime/python/okstra_ctl/agent_prompt_cli.py +249 -50
  283. package/runtime/python/okstra_ctl/application/resolve_assignment.py +53 -12
  284. package/runtime/python/okstra_ctl/assignment_environment.py +102 -0
  285. package/runtime/python/okstra_ctl/assignment_resolver.py +790 -0
  286. package/runtime/python/okstra_ctl/attempt_evidence.py +342 -0
  287. package/runtime/python/okstra_ctl/convergence.py +409 -3
  288. package/runtime/python/okstra_ctl/convergence_engine.py +248 -15
  289. package/runtime/python/okstra_ctl/convergence_store.py +170 -1
  290. package/runtime/python/okstra_ctl/dispatch_core.py +1092 -63
  291. package/runtime/python/okstra_ctl/dispatch_state.py +696 -11
  292. package/runtime/python/okstra_ctl/doctor.py +14 -0
  293. package/runtime/python/okstra_ctl/domain/host.py +32 -1
  294. package/runtime/python/okstra_ctl/domain/provider.py +212 -6
  295. package/runtime/python/okstra_ctl/domain/role.py +125 -0
  296. package/runtime/python/okstra_ctl/domain/wizard/interaction.py +13 -0
  297. package/runtime/python/okstra_ctl/domain/worker_exec.py +34 -1
  298. package/runtime/python/okstra_ctl/domain/worker_role.py +13 -3
  299. package/runtime/python/okstra_ctl/domain/worker_stream.py +24 -0
  300. package/runtime/python/okstra_ctl/error_log_write.py +9 -0
  301. package/runtime/python/okstra_ctl/error_report.py +21 -1
  302. package/runtime/python/okstra_ctl/execution_identity.py +529 -0
  303. package/runtime/python/okstra_ctl/execution_manifest.py +1281 -0
  304. package/runtime/python/okstra_ctl/execution_mutation_audit.py +619 -0
  305. package/runtime/python/okstra_ctl/index.py +6 -2
  306. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
  307. package/runtime/python/okstra_ctl/legacy_model_selection.py +490 -0
  308. package/runtime/python/okstra_ctl/model_cli.py +278 -0
  309. package/runtime/python/okstra_ctl/model_defaults.py +46 -0
  310. package/runtime/python/okstra_ctl/model_discovery.py +26 -7
  311. package/runtime/python/okstra_ctl/model_pool.py +501 -0
  312. package/runtime/python/okstra_ctl/models.py +47 -27
  313. package/runtime/python/okstra_ctl/mutation_recovery.py +293 -0
  314. package/runtime/python/okstra_ctl/pane_title.py +151 -0
  315. package/runtime/python/okstra_ctl/ports/host_model.py +48 -17
  316. package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
  317. package/runtime/python/okstra_ctl/registry/provider_registry.py +8 -4
  318. package/runtime/python/okstra_ctl/render.py +78 -10
  319. package/runtime/python/okstra_ctl/render_final_report.py +19 -0
  320. package/runtime/python/okstra_ctl/report_contract.py +39 -0
  321. package/runtime/python/okstra_ctl/report_finalize.py +16 -0
  322. package/runtime/python/okstra_ctl/report_html/render.py +1 -0
  323. package/runtime/python/okstra_ctl/role_requirements.py +217 -0
  324. package/runtime/python/okstra_ctl/run.py +1207 -258
  325. package/runtime/python/okstra_ctl/run_index_row.py +7 -1
  326. package/runtime/python/okstra_ctl/time_report.py +38 -4
  327. package/runtime/python/okstra_ctl/usage_identity.py +86 -0
  328. package/runtime/python/okstra_ctl/usage_report.py +15 -3
  329. package/runtime/python/okstra_ctl/wizard.py +1253 -62
  330. package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
  331. package/runtime/python/okstra_ctl/worker_request.py +7 -1
  332. package/runtime/python/okstra_ctl/worker_runner.py +130 -5
  333. package/runtime/python/okstra_ctl/workers.py +7 -5
  334. package/runtime/python/okstra_ctl/write_policy.py +571 -0
  335. package/runtime/schemas/convergence-groups-v2.0.schema.json +128 -0
  336. package/runtime/schemas/execution-manifest-v2.schema.json +340 -0
  337. package/runtime/schemas/final-report-v2.0.schema.json +25 -0
  338. package/runtime/skills/okstra-run/SKILL.md +9 -9
  339. package/runtime/templates/report-writer-prompt-preamble.md +2 -0
  340. package/runtime/templates/reports/final-report-v2.template.md +7 -1
  341. package/runtime/templates/reports/html/base.template.html +21 -0
  342. package/runtime/templates/reports/html/i18n/en.json +4 -0
  343. package/runtime/templates/reports/html/i18n/ko.json +4 -0
  344. package/runtime/templates/worker-prompt-preamble.md +6 -2
  345. package/runtime/validators/lib/fixtures.sh +49 -16
  346. package/runtime/validators/validate-run.py +429 -35
  347. package/runtime/validators/validate_session_conformance.py +25 -7
  348. package/src/cli-registry.mjs +0 -539
  349. package/src/commands/execute/codex-dispatch.mjs +0 -10
  350. package/src/commands/execute/plan-items.mjs +0 -9
  351. package/src/commands/execute/plan-validate.mjs +0 -68
  352. package/src/commands/execute/run.mjs +0 -208
  353. package/src/commands/execute/wizard.mjs +0 -167
  354. package/src/commands/inspect/stage-map.mjs +0 -98
  355. package/src/commands/inspect/task-list.mjs +0 -97
  356. package/src/commands/inspect/task-show.mjs +0 -100
  357. package/src/commands/lifecycle/check-project.mjs +0 -187
  358. package/src/commands/lifecycle/config.mjs +0 -385
  359. package/src/commands/lifecycle/doctor.mjs +0 -308
  360. package/src/commands/lifecycle/install.mjs +0 -1170
  361. package/src/commands/lifecycle/paths.mjs +0 -104
  362. package/src/commands/lifecycle/preflight.mjs +0 -125
  363. package/src/commands/lifecycle/setup.mjs +0 -333
  364. package/src/commands/lifecycle/uninstall.mjs +0 -279
  365. package/src/commands/memory/memory.mjs +0 -524
  366. package/src/commands/pr/pr.mjs +0 -261
  367. package/src/lib/host-registry-client.mjs +0 -176
  368. package/src/lib/paths.mjs +0 -86
  369. package/src/lib/proc.mjs +0 -31
  370. package/src/lib/python-helper.mjs +0 -142
  371. package/src/lib/runtime-manifest.mjs +0 -70
  372. package/src/lib/skill-catalog.mjs +0 -53
  373. package/src/lib/version.mjs +0 -20
  374. /package/{src → dist}/commands/pr/default.md +0 -0
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
 
13
13
  import json
14
14
  import re
15
- from collections.abc import Mapping, Sequence
15
+ from collections.abc import Mapping
16
16
  from dataclasses import dataclass
17
17
  from pathlib import Path
18
18
 
@@ -45,25 +45,26 @@ _EVIDENCE_COMMAND_RE = re.compile(
45
45
  r"^- Evidence command:[ \t]*(?P<payload>.*)$", re.MULTILINE
46
46
  )
47
47
  _EVIDENCE_COMMAND_FIELDS = ("command", "cwd", "exitCode", "outputSummary")
48
- _EVIDENCE_COMMAND_STRING_FIELDS = ("command", "cwd", "outputSummary")
49
- _SENSITIVE_KEY_RE = re.compile(
50
- r"(?i)(authorization|auth|credential|pass(?:wd|word)?|pwd|token|secret|"
51
- r"api[_-]?key|access[_-]?key)"
52
- )
53
- _SENSITIVE_TEXT_RE = re.compile(
54
- r"(?i)(authorization\s*:\s*\S+|"
55
- r"\b(?:[A-Za-z_][A-Za-z0-9_-]*)?(?:auth|credential|pass(?:wd|word)?|pwd|"
56
- r"token|secret|api[_-]?key|access[_-]?key)[A-Za-z0-9_-]*\s*=|"
57
- r"--[\w-]*(?:auth|credential|pass(?:wd|word)?|pwd|token|secret|"
58
- r"api[-_]?key|access[-_]?key)[\w-]*(?:[ =])\S+|"
59
- r"\w+://[^\s:/@]+:[^\s@/]+@)"
60
- )
61
- _KNOWN_SECRET_RE = re.compile(
62
- r"(?:AKIA|ASIA)[0-9A-Z]{16}|gh[pousr]_[A-Za-z0-9_]{8,}|"
63
- r"github_pat_[A-Za-z0-9_]{8,}|xox[abprs]-[A-Za-z0-9-]{8,}|"
64
- r"\bsk-[A-Za-z0-9_-]{8,}\b|"
65
- r"\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b"
48
+ _EVIDENCE_COMMAND_IDENTITY_FIELDS = (
49
+ "participantRef",
50
+ "roleExecutionRef",
51
+ "invocationRef",
52
+ "attempt",
53
+ "executionLabel",
66
54
  )
55
+ _EVIDENCE_COMMAND_STRING_FIELDS = ("command", "cwd", "outputSummary")
56
+ # There is deliberately no secret detector here.
57
+ #
58
+ # One lived on this path and only ever cost runs. It matched the *name* half of
59
+ # an assignment, so `AUTH_MODE=off` and `TOKEN_TTL=60` were "sensitive material"
60
+ # and the row was refused; a worker that cannot record the command it ran has no
61
+ # way to satisfy the evidence ledger that demands it, and the run ends
62
+ # `contract-violated` over a switch. Judging the value half instead only moves
63
+ # the guesswork. What belongs in a row is the command's shape — the keys — and a
64
+ # value that must not be written down is the worker's to leave out or pass as a
65
+ # `$VAR` reference. A run does not need it: at execution time the value comes
66
+ # from the environment or from the person running it, and if it is absent the
67
+ # command fails then, where the failure is legible.
67
68
  _FILE_LINE_CITATION_RE = re.compile(
68
69
  r"`(?P<path>(?!https?://)[^`\n]+?):(?P<line>\d+(?:-\d+)?)`"
69
70
  )
@@ -116,34 +117,18 @@ class EvidenceCommand:
116
117
  cwd: str
117
118
  exit_code: int
118
119
  output_summary: str
120
+ identity: dict[str, object] | None = None
119
121
 
120
122
  def to_record(self) -> dict[str, object]:
121
- return {
123
+ record: dict[str, object] = {
122
124
  "command": self.command,
123
125
  "cwd": self.cwd,
124
126
  "exitCode": self.exit_code,
125
127
  "outputSummary": self.output_summary,
126
128
  }
127
-
128
-
129
- def _contains_sensitive_material(value: object) -> bool:
130
- if isinstance(value, Mapping):
131
- return any(
132
- (
133
- _SENSITIVE_KEY_RE.search(str(key)) is not None
134
- and nested not in (None, "", False)
135
- )
136
- or _contains_sensitive_material(nested)
137
- for key, nested in value.items()
138
- )
139
- if isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
140
- return any(_contains_sensitive_material(item) for item in value)
141
- if not isinstance(value, str):
142
- return False
143
- return (
144
- _SENSITIVE_TEXT_RE.search(value) is not None
145
- or _KNOWN_SECRET_RE.search(value) is not None
146
- )
129
+ if self.identity:
130
+ record.update(self.identity)
131
+ return record
147
132
 
148
133
 
149
134
  def _evidence_command_contract_failures(
@@ -151,7 +136,9 @@ def _evidence_command_contract_failures(
151
136
  ) -> list[str]:
152
137
  failures: list[str] = []
153
138
  missing = [key for key in _EVIDENCE_COMMAND_FIELDS if key not in payload]
154
- unexpected = sorted(set(payload) - set(_EVIDENCE_COMMAND_FIELDS))
139
+ unexpected = sorted(
140
+ set(payload) - set(_EVIDENCE_COMMAND_FIELDS) - set(_EVIDENCE_COMMAND_IDENTITY_FIELDS)
141
+ )
155
142
  if missing:
156
143
  failures.append(
157
144
  f"Evidence command row {row_number} is missing {', '.join(missing)}"
@@ -173,21 +160,15 @@ def _evidence_command_contract_failures(
173
160
  return failures
174
161
 
175
162
 
176
- def _evidence_command_from_payload(
177
- payload: Mapping[str, object], sensitive: bool
178
- ) -> EvidenceCommand:
179
- if sensitive:
180
- return EvidenceCommand(
181
- command="[redacted: potential secret]",
182
- cwd="[redacted: potential secret]",
183
- exit_code=payload["exitCode"],
184
- output_summary="omitted because potential secret material was detected",
185
- )
163
+ def _evidence_command_from_payload(payload: Mapping[str, object]) -> EvidenceCommand:
164
+ from okstra_ctl.execution_identity import stored_identity
165
+
186
166
  return EvidenceCommand(
187
167
  command=payload["command"],
188
168
  cwd=payload["cwd"],
189
169
  exit_code=payload["exitCode"],
190
170
  output_summary=payload["outputSummary"],
171
+ identity=stored_identity(payload) or None,
191
172
  )
192
173
 
193
174
 
@@ -209,16 +190,11 @@ def parse_evidence_commands(
209
190
  f"Evidence command row {row_number} must be a JSON object"
210
191
  )
211
192
  continue
212
- sensitive = _contains_sensitive_material(payload)
213
- if sensitive:
214
- failures.append(
215
- f"Evidence command row {row_number} contains sensitive material"
216
- )
217
193
  contract_failures = _evidence_command_contract_failures(payload, row_number)
218
194
  failures.extend(contract_failures)
219
195
  if contract_failures:
220
196
  continue
221
- commands.append(_evidence_command_from_payload(payload, sensitive))
197
+ commands.append(_evidence_command_from_payload(payload))
222
198
  return tuple(commands), tuple(failures)
223
199
 
224
200
 
@@ -375,7 +351,26 @@ def check_worker_results_audit(
375
351
  *,
376
352
  worker: str | None = None,
377
353
  ) -> list[str]:
378
- """Every audit-sidecar contract failure among this run's worker results.
354
+ """Every audit-sidecar contract finding among this run's worker results.
355
+
356
+ Blocking findings first, then the advisory citation-ledger ones. Mid-run
357
+ callers want both in one list: the worker session is still alive and can fix
358
+ either. Phase 7 separates them — see `worker_results_audit_findings`.
359
+ """
360
+ blocking, advisories = worker_results_audit_findings(
361
+ run_dir, task_type, seq, worker=worker
362
+ )
363
+ return blocking + advisories
364
+
365
+
366
+ def worker_results_audit_findings(
367
+ run_dir: Path,
368
+ task_type: str,
369
+ seq: str | None,
370
+ *,
371
+ worker: str | None = None,
372
+ ) -> tuple[list[str], list[str]]:
373
+ """The same checks, split into `(blocking, advisory)`.
379
374
 
380
375
  *run_dir* is `runs/<task-type>/`; `worker-results/` and `prompts/` hang off
381
376
  it. *seq* scopes the check to one run — `worker-results/` accumulates every
@@ -383,16 +378,24 @@ def check_worker_results_audit(
383
378
  did not produce. Pass ``None`` only when the seq is genuinely unknown, which
384
379
  falls back to not filtering rather than silently checking nothing.
385
380
 
386
- For each result file this checks that it carries no `## 0. Reading
387
- Confirmation` heading (that block moved to the sidecar), that the matching
388
- sidecar exists, and — for prompts carrying the required-v1 evidence-ledger
389
- marker — that every backticked `path:line` citation has an Evidence read row.
381
+ Blocking: a result file that still carries the `## 0. Reading Confirmation`
382
+ heading (that block moved to the sidecar), a missing sidecar, and a
383
+ malformed Evidence command row. Each of those means the audit trail itself
384
+ is absent or unreadable.
385
+
386
+ Advisory: a `path:line` citation with no matching Evidence read row. The
387
+ ledger exists and is readable; what the check found is a citation whose
388
+ spelling does not match a row. That is worth reporting and not worth
389
+ voiding a finished run over — one unmatched citation among hundreds used to
390
+ take the whole phase to `contract-violated`, which stops the run without
391
+ telling anyone whether the finding itself was wrong.
390
392
  """
391
393
  failures: list[str] = []
394
+ advisories: list[str] = []
392
395
  if not (run_dir / "worker-results").is_dir():
393
396
  # No worker-results directory means no analysis workers ran (e.g.
394
397
  # `release-handoff`, which is single-lead). Nothing to enforce.
395
- return failures
398
+ return failures, advisories
396
399
 
397
400
  for path, worker_role, result_seq in worker_result_files(run_dir, task_type, seq, worker):
398
401
  rel = path.name
@@ -426,7 +429,7 @@ def check_worker_results_audit(
426
429
 
427
430
  _, command_failures = read_evidence_commands(audit_path)
428
431
  failures.extend(command_failures)
429
- failures.extend(_evidence_read_ledger_failures(
432
+ advisories.extend(_evidence_read_ledger_failures(
430
433
  run_dir=run_dir,
431
434
  worker_role=worker_role,
432
435
  task_type=task_type,
@@ -435,4 +438,4 @@ def check_worker_results_audit(
435
438
  result_content=content,
436
439
  audit_path=audit_path,
437
440
  ))
438
- return failures
441
+ return failures, advisories
@@ -14,6 +14,7 @@ from pathlib import Path
14
14
 
15
15
  from .domain.worker_exec import ExecutionPolicy, WorkerExecRequest
16
16
  from .domain.worker_role import role_spec
17
+ from .write_policy import WriteEnforcement, WritePolicy
17
18
 
18
19
  # Carried over from the codex wrapper, where it was one provider's rule: cargo's
19
20
  # package-cache flock and its registry live outside every workspace, so a
@@ -36,6 +37,8 @@ def build_request(
36
37
  role: str,
37
38
  idle_timeout_seconds: int,
38
39
  session_id: str = "",
40
+ write_policy: WritePolicy | None = None,
41
+ write_enforcement: WriteEnforcement | None = None,
39
42
  ) -> WorkerExecRequest:
40
43
  """One dispatch, with every value the strategies will not re-derive.
41
44
 
@@ -53,7 +56,10 @@ def build_request(
53
56
  # Nobody is at the keyboard to answer an approval prompt, so the gate is
54
57
  # open and the boundary comes from the write scope instead.
55
58
  policy=ExecutionPolicy(
56
- auto_approve=True, write_scope=write_scope(root, worktree, role)
59
+ auto_approve=True,
60
+ write_scope=write_scope(root, worktree, role),
61
+ write_policy=write_policy,
62
+ write_enforcement=write_enforcement,
57
63
  ),
58
64
  idle_timeout_seconds=idle_timeout_seconds,
59
65
  session_id=session_id,
@@ -21,7 +21,9 @@ from functools import partial
21
21
  from pathlib import Path
22
22
  from typing import Any, Callable, Mapping
23
23
 
24
+ from .domain.provider import ServedModelAttestation, ServedModelNormalizer
24
25
  from .domain.worker_exec import (
26
+ SERVED_MODEL_MISMATCH_EXIT_CODE,
25
27
  STREAM_JSON,
26
28
  ExecCommand,
27
29
  ExecutionStrategy,
@@ -67,7 +69,11 @@ def run_worker(
67
69
  log_path: Path,
68
70
  status_path: Path,
69
71
  status_extra: Mapping[str, Any] = _NO_STATUS_EXTRA,
72
+ served_model_normalizer: ServedModelNormalizer | None = None,
73
+ served_model_verifier: Callable[[ServedModelAttestation], str] | None = None,
70
74
  ) -> int:
75
+ _validate_status_extra(status_extra)
76
+ _validate_request_write_contract(request, status_extra)
71
77
  command = strategy.build_command(request)
72
78
  started_monotonic = time.monotonic()
73
79
  status = _started_status(status_extra, log_path)
@@ -76,7 +82,7 @@ def run_worker(
76
82
 
77
83
  try:
78
84
  with guard:
79
- exit_code, timed_out, idle_seconds = _launch(
85
+ exit_code, timed_out, idle_seconds, raw_model = _launch(
80
86
  command,
81
87
  log_path,
82
88
  presentation=presentation,
@@ -94,6 +100,14 @@ def run_worker(
94
100
  raise
95
101
 
96
102
  status = _closed(status, started_monotonic)
103
+ if served_model_normalizer is not None:
104
+ attestation = served_model_normalizer(raw_model)
105
+ status["servedModelAttestation"] = _attestation_payload(attestation)
106
+ if served_model_verifier is not None:
107
+ failure = served_model_verifier(attestation)
108
+ if failure:
109
+ status["failure"] = failure
110
+ exit_code = SERVED_MODEL_MISMATCH_EXIT_CODE
97
111
  status["exit_code"] = exit_code
98
112
  if timed_out:
99
113
  status.update(
@@ -106,6 +120,57 @@ def run_worker(
106
120
  return exit_code
107
121
 
108
122
 
123
+ def _validate_status_extra(status_extra: Mapping[str, Any]) -> None:
124
+ schema = status_extra.get("schemaVersion")
125
+ identity_version = status_extra.get("executionIdentityVersion")
126
+ identity_keys = {
127
+ "participantRef",
128
+ "roleExecutionRef",
129
+ "executionLabel",
130
+ "dutyId",
131
+ "invocationRef",
132
+ }
133
+ if schema is None and identity_version is None:
134
+ if set(status_extra) & (
135
+ identity_keys | {"attempt", "servedModelAttestation"}
136
+ ):
137
+ raise ValueError("worker status mixes v1 and v2 execution identity")
138
+ return
139
+ if schema != "2.0" or identity_version != 2:
140
+ raise ValueError("worker status mixes v1 and v2 execution identity")
141
+ if any(
142
+ not isinstance(status_extra.get(key), str) or not status_extra[key]
143
+ for key in identity_keys
144
+ ):
145
+ raise ValueError("worker status v2 execution identity is incomplete")
146
+ attempt = status_extra.get("attempt")
147
+ if not isinstance(attempt, int) or isinstance(attempt, bool) or attempt < 1:
148
+ raise ValueError("worker status v2 attempt must be positive")
149
+ attestation = status_extra.get("servedModelAttestation")
150
+ if not isinstance(attestation, Mapping) or set(attestation) != {
151
+ "observedModel",
152
+ "normalizedModelRef",
153
+ "level",
154
+ "source",
155
+ }:
156
+ raise ValueError("worker status served model attestation is invalid")
157
+
158
+
159
+ def _validate_request_write_contract(
160
+ request: WorkerExecRequest, status_extra: Mapping[str, Any]
161
+ ) -> None:
162
+ if status_extra.get("executionIdentityVersion") != 2:
163
+ return
164
+ policy = request.policy.write_policy
165
+ enforcement = request.policy.write_enforcement
166
+ if policy is None or enforcement is None:
167
+ raise ValueError("v2 worker request has no write contract")
168
+ if status_extra.get("writePolicyDigest") != policy.digest:
169
+ raise ValueError("v2 worker request write policy digest changed")
170
+ if status_extra.get("writeEnforcement") != enforcement.to_payload():
171
+ raise ValueError("v2 worker request write enforcement changed")
172
+
173
+
109
174
  def _launch(
110
175
  command: ExecCommand,
111
176
  log_path: Path,
@@ -113,7 +178,7 @@ def _launch(
113
178
  presentation: str,
114
179
  idle_timeout_seconds: int,
115
180
  on_spawn: Callable[[subprocess.Popen[bytes]], None],
116
- ) -> tuple[int, bool, int]:
181
+ ) -> tuple[int, bool, int, str | None]:
117
182
  log_path.parent.mkdir(parents=True, exist_ok=True)
118
183
  with log_path.open("w", encoding="utf-8") as log_file:
119
184
  # The strategy decided where this provider runs — some CLIs work in the
@@ -128,7 +193,8 @@ def _launch(
128
193
  env=_child_env(),
129
194
  )
130
195
  on_spawn(process)
131
- return _pump(
196
+ observation = _ServedModelObservation()
197
+ exit_code, timed_out, idle_seconds = _pump(
132
198
  process,
133
199
  log_file,
134
200
  stream_format=command.stream_format,
@@ -136,7 +202,19 @@ def _launch(
136
202
  presentation=presentation,
137
203
  idle_timeout_seconds=idle_timeout_seconds,
138
204
  stdin_text=command.stdin_text,
205
+ observe_served_model=command.observe_served_model,
206
+ model_observation=observation,
139
207
  )
208
+ return exit_code, timed_out, idle_seconds, observation.raw_model
209
+
210
+
211
+ class _ServedModelObservation:
212
+ def __init__(self) -> None:
213
+ self.raw_model: str | None = None
214
+
215
+ def record(self, raw_model: str | None) -> None:
216
+ if self.raw_model is None and isinstance(raw_model, str) and raw_model.strip():
217
+ self.raw_model = raw_model
140
218
 
141
219
 
142
220
  class _AbnormalExit:
@@ -253,6 +331,8 @@ def _pump(
253
331
  presentation: str,
254
332
  idle_timeout_seconds: int,
255
333
  stdin_text: str | None = None,
334
+ observe_served_model: Callable[[Mapping[str, Any]], str | None],
335
+ model_observation: _ServedModelObservation,
256
336
  ) -> tuple[int, bool, int]:
257
337
  selector = selectors.DefaultSelector()
258
338
  readers, finalize_log = _register_output(
@@ -261,6 +341,8 @@ def _pump(
261
341
  log_file,
262
342
  stream_format=stream_format,
263
343
  normalise=normalise,
344
+ observe_served_model=observe_served_model,
345
+ model_observation=model_observation,
264
346
  presentation=presentation,
265
347
  )
266
348
  outgoing = _register_prompt(selector, process, stdin_text)
@@ -357,6 +439,8 @@ def _register_output(
357
439
  *,
358
440
  stream_format: str,
359
441
  normalise: Normalise,
442
+ observe_served_model: Callable[[Mapping[str, Any]], str | None],
443
+ model_observation: _ServedModelObservation,
360
444
  presentation: str,
361
445
  ) -> tuple[dict[int, _LineReader], Callable[[], None]]:
362
446
  """Register every stream this child speaks, each with its own destination.
@@ -367,7 +451,17 @@ def _register_output(
367
451
  assert process.stdout is not None
368
452
  if stream_format == STREAM_JSON:
369
453
  sinks = [
370
- (process.stdout, partial(_emit_event, log_file, presentation, normalise))
454
+ (
455
+ process.stdout,
456
+ partial(
457
+ _emit_event,
458
+ log_file,
459
+ presentation,
460
+ normalise,
461
+ observe_served_model,
462
+ model_observation,
463
+ ),
464
+ )
371
465
  ]
372
466
  finalize_log: Callable[[], None] = _nothing_to_finalize
373
467
  else:
@@ -519,7 +613,12 @@ class _ProgressSink:
519
613
 
520
614
 
521
615
  def _emit_event(
522
- log_file, presentation: str, normalise: Normalise, line: str
616
+ log_file,
617
+ presentation: str,
618
+ normalise: Normalise,
619
+ observe_served_model: Callable[[Mapping[str, Any]], str | None],
620
+ model_observation: _ServedModelObservation,
621
+ line: str,
523
622
  ) -> str | None:
524
623
  """Write one line of a JSON stream out; return closing text if this is it.
525
624
 
@@ -542,6 +641,7 @@ def _emit_event(
542
641
  return None
543
642
  if not isinstance(event, dict):
544
643
  return None
644
+ model_observation.record(observe_served_model(event))
545
645
 
546
646
  closing: str | None = None
547
647
  for entry in normalise(event):
@@ -560,6 +660,15 @@ def _emit_event(
560
660
  return closing
561
661
 
562
662
 
663
+ def _attestation_payload(attestation: ServedModelAttestation) -> dict[str, Any]:
664
+ return {
665
+ "observedModel": attestation.observed_model,
666
+ "normalizedModelRef": attestation.normalized_model_ref,
667
+ "level": attestation.level,
668
+ "source": attestation.source,
669
+ }
670
+
671
+
563
672
  def _write_log(log_file, lines) -> None:
564
673
  for line in lines:
565
674
  log_file.write(line + "\n")
@@ -605,6 +714,22 @@ def _child_env() -> dict[str, str]:
605
714
  return env
606
715
 
607
716
 
717
+ def write_host_event(
718
+ path: Path,
719
+ *,
720
+ invocation_ref: str,
721
+ attempt: int,
722
+ event_type: str,
723
+ payload: Mapping[str, Any],
724
+ ) -> Mapping[str, Any]:
725
+ """Append one orchestrator-owned host event from the runner boundary."""
726
+ from .attempt_evidence import HostEventStreamWriter
727
+
728
+ return HostEventStreamWriter(
729
+ path, invocation_ref=invocation_ref, attempt=attempt
730
+ ).append(event_type, payload)
731
+
732
+
608
733
  def _write_status(path: Path, status: Mapping[str, Any]) -> None:
609
734
  """Best-effort status write; a sidecar failure must not break the run.
610
735
 
@@ -1,4 +1,4 @@
1
- """Worker roster resolution.
1
+ """V1 provider-worker roster compatibility parsing.
2
2
 
3
3
  Profile 파일에서 권장 worker 목록을 뽑고(`resolve_profile_workers`), 사용자
4
4
  오버라이드와 합쳐 정규화한다(`normalize_workers`). bash workers.sh 의
@@ -28,8 +28,10 @@ class WorkersError(Exception):
28
28
  """invalid worker selection — surface to user."""
29
29
 
30
30
 
31
- def _resolve_workers_under(profile_path: Path, headers: set[str]) -> list[str]:
32
- """Generic parser: collect ` - <id> …` sub-bullets under any of `headers`
31
+ def _resolve_v1_workers_under(profile_path: Path, headers: set[str]) -> list[str]:
32
+ """Read legacy provider-worker bullets without interpreting role YAML.
33
+
34
+ Collect ` - <id> …` sub-bullets under any of `headers`
33
35
  until the next top-level bullet. Returns first token (before any
34
36
  ` — ` / ` -- ` / whitespace) of each captured line.
35
37
  """
@@ -61,7 +63,7 @@ def resolve_profile_workers(profile_path: Path) -> list[str]:
61
63
  `- Workers:` / `- Reviewers:` / `- Analysers:`) 섹션 아래 sub-bullet 들을
62
64
  worker id 리스트로 돌려준다. profile 파일이 없거나 섹션이 없으면 빈 리스트.
63
65
  """
64
- return _resolve_workers_under(profile_path, PROFILE_BULLET_HEADERS)
66
+ return _resolve_v1_workers_under(profile_path, PROFILE_BULLET_HEADERS)
65
67
 
66
68
 
67
69
  def resolve_optional_workers(profile_path: Path) -> list[str]:
@@ -69,7 +71,7 @@ def resolve_optional_workers(profile_path: Path) -> list[str]:
69
71
  들에서 worker id 만 추출한다. (` - antigravity — when added …` → `antigravity`)
70
72
  Required 와 중복되는 항목은 제거. ALLOWED_WORKERS 밖 토큰도 제거.
71
73
  """
72
- raw = _resolve_workers_under(profile_path, PROFILE_BULLET_HEADERS_OPTIONAL)
74
+ raw = _resolve_v1_workers_under(profile_path, PROFILE_BULLET_HEADERS_OPTIONAL)
73
75
  required = set(resolve_profile_workers(profile_path))
74
76
  seen: set[str] = set()
75
77
  out: list[str] = []