okstra 0.186.7 → 0.187.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 (541) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-registry.d.mts +88 -1
  3. package/dist/cli-registry.mjs +68 -111
  4. package/dist/cli-registry.mjs.map +1 -1
  5. package/dist/commands/execute/render-bundle.mjs +0 -1
  6. package/dist/commands/execute/render-bundle.mjs.map +1 -1
  7. package/dist/commands/execute/run.mjs +8 -3
  8. package/dist/commands/execute/run.mjs.map +1 -1
  9. package/dist/commands/lifecycle/check-project.mjs +1 -14
  10. package/dist/commands/lifecycle/check-project.mjs.map +1 -1
  11. package/dist/commands/lifecycle/config.mjs +38 -40
  12. package/dist/commands/lifecycle/config.mjs.map +1 -1
  13. package/dist/commands/lifecycle/doctor.d.mts +22 -7
  14. package/dist/commands/lifecycle/doctor.mjs +77 -49
  15. package/dist/commands/lifecycle/doctor.mjs.map +1 -1
  16. package/dist/commands/lifecycle/install.d.mts +12 -10
  17. package/dist/commands/lifecycle/install.mjs +104 -39
  18. package/dist/commands/lifecycle/install.mjs.map +1 -1
  19. package/dist/commands/lifecycle/paths.mjs +8 -3
  20. package/dist/commands/lifecycle/paths.mjs.map +1 -1
  21. package/dist/commands/lifecycle/preflight.mjs +2 -1
  22. package/dist/commands/lifecycle/preflight.mjs.map +1 -1
  23. package/dist/commands/lifecycle/setup.mjs +22 -36
  24. package/dist/commands/lifecycle/setup.mjs.map +1 -1
  25. package/dist/commands/lifecycle/uninstall.d.mts +4 -2
  26. package/dist/commands/lifecycle/uninstall.mjs +59 -15
  27. package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
  28. package/dist/commands/memory/memory.mjs +7 -1
  29. package/dist/commands/memory/memory.mjs.map +1 -1
  30. package/dist/lib/helper-scripts.d.mts +1 -1
  31. package/dist/lib/helper-scripts.mjs +10 -18
  32. package/dist/lib/helper-scripts.mjs.map +1 -1
  33. package/dist/lib/host-config.d.mts +72 -0
  34. package/dist/lib/host-config.mjs +404 -0
  35. package/dist/lib/host-config.mjs.map +1 -0
  36. package/dist/lib/host-registry-client.d.mts +2 -2
  37. package/dist/lib/host-registry-client.mjs +0 -3
  38. package/dist/lib/host-registry-client.mjs.map +1 -1
  39. package/dist/lib/install-assets.d.mts +1 -0
  40. package/dist/lib/install-assets.mjs +4 -0
  41. package/dist/lib/install-assets.mjs.map +1 -1
  42. package/dist/lib/proc.d.mts +2 -0
  43. package/dist/lib/proc.mjs +12 -0
  44. package/dist/lib/proc.mjs.map +1 -1
  45. package/dist/lib/python-command.d.mts +2 -0
  46. package/dist/lib/python-command.mjs +52 -0
  47. package/dist/lib/python-command.mjs.map +1 -0
  48. package/dist/lib/python-helper.d.mts +2 -5
  49. package/dist/lib/python-helper.mjs +3 -52
  50. package/dist/lib/python-helper.mjs.map +1 -1
  51. package/dist/lib/runtime-payload.d.mts +23 -0
  52. package/dist/lib/runtime-payload.mjs +57 -0
  53. package/dist/lib/runtime-payload.mjs.map +1 -0
  54. package/dist/lib/types.d.mts +24 -13
  55. package/docs/architecture/storage-model.md +21 -5
  56. package/docs/architecture.md +37 -36
  57. package/docs/cli.md +55 -76
  58. package/docs/coding-rules.md +295 -0
  59. package/docs/container.md +10 -36
  60. package/docs/contributor-change-matrix.md +1 -1
  61. package/docs/for-ai/skills/okstra-code-review.md +0 -1
  62. package/docs/for-ai/skills/okstra-container-build.md +8 -41
  63. package/docs/for-ai/skills/okstra-inspect.md +4 -4
  64. package/docs/for-ai/skills/okstra-manager.md +2 -2
  65. package/docs/for-ai/skills/okstra-rollup.md +0 -1
  66. package/docs/for-ai/skills/okstra-run.md +3 -3
  67. package/docs/for-ai/skills/okstra-user-response.md +0 -1
  68. package/docs/performance-improvement-plan-v2.md +1 -1
  69. package/docs/project-structure-overview.md +62 -62
  70. package/docs/task-process/README.md +3 -3
  71. package/docs/task-process/common-flow.md +1 -1
  72. package/docs/task-process/error-analysis.md +3 -3
  73. package/docs/task-process/implementation-planning.md +3 -1
  74. package/docs/task-process/release-handoff.md +1 -1
  75. package/package.json +3 -2
  76. package/runtime/BUILD.json +2 -2
  77. package/runtime/agents/workers/claude-worker.md +6 -11
  78. package/runtime/agents/workers/report-writer-worker.md +1 -1
  79. package/runtime/bin/lib/okstra/cli.sh +4 -0
  80. package/runtime/bin/lib/okstra/globals.sh +2 -0
  81. package/runtime/bin/lib/okstra/interactive.sh +26 -173
  82. package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
  83. package/runtime/bin/lib/okstra/usage.sh +3 -3
  84. package/runtime/bin/okstra-compact-reminder.sh +1 -5
  85. package/runtime/bin/okstra-error-log.py +19 -2
  86. package/runtime/bin/okstra-import-check.py +26 -0
  87. package/runtime/bin/okstra-inject-report-index.py +5 -4
  88. package/runtime/bin/okstra-provider-exec.py +22 -17
  89. package/runtime/bin/okstra-render-final-report.py +16 -6
  90. package/runtime/bin/okstra-render-report-views.py +25 -18
  91. package/runtime/bin/okstra-report-translate.py +30 -18
  92. package/runtime/bin/okstra-spawn-followups.py +4 -0
  93. package/runtime/bin/okstra-token-usage.py +3 -0
  94. package/runtime/bin/okstra.sh +4 -2
  95. package/runtime/bin/okstra_bootstrap.py +58 -0
  96. package/runtime/prompts/coding-preflight/overview.md +1 -1
  97. package/runtime/prompts/duties/planning-worker.md +1 -1
  98. package/runtime/prompts/launch.template.md +35 -9
  99. package/runtime/prompts/lead/convergence.md +96 -87
  100. package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
  101. package/runtime/prompts/lead/plan-body-verification.md +65 -46
  102. package/runtime/prompts/lead/report-writer.md +34 -4
  103. package/runtime/prompts/lead/team-contract.md +4 -1
  104. package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
  105. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  106. package/runtime/prompts/profiles/_common-contract.md +3 -3
  107. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  108. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
  109. package/runtime/prompts/profiles/_implementation-executor.md +3 -1
  110. package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
  111. package/runtime/prompts/profiles/error-analysis.md +4 -3
  112. package/runtime/prompts/profiles/final-verification.md +2 -2
  113. package/runtime/prompts/profiles/implementation-planning.md +22 -17
  114. package/runtime/prompts/profiles/implementation.md +3 -2
  115. package/runtime/prompts/profiles/requirements-discovery.md +2 -1
  116. package/runtime/prompts/wizard/prompts.ko.json +29 -8
  117. package/runtime/python/okstra_ctl/__init__.py +6 -27
  118. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
  119. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
  120. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
  121. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +40 -22
  122. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -21
  123. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
  124. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
  125. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
  126. package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
  127. package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
  128. package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +12 -1
  129. package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
  130. package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
  131. package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
  132. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +215 -0
  133. package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
  134. package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
  135. package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
  136. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +408 -0
  137. package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
  138. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
  139. package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
  140. package/runtime/python/okstra_ctl/approval_decisions.py +260 -8
  141. package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
  142. package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
  143. package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
  144. package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
  145. package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
  146. package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
  147. package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
  148. package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
  149. package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
  150. package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
  151. package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
  152. package/runtime/python/okstra_ctl/cmux.py +38 -31
  153. package/runtime/python/okstra_ctl/code_review_target.py +163 -1
  154. package/runtime/python/okstra_ctl/conformance.py +23 -0
  155. package/runtime/python/okstra_ctl/container.py +38 -421
  156. package/runtime/python/okstra_ctl/context_cost.py +16 -2
  157. package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
  158. package/runtime/python/okstra_ctl/convergence.py +101 -15
  159. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
  160. package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
  161. package/runtime/python/okstra_ctl/convergence_store.py +5 -29
  162. package/runtime/python/okstra_ctl/design_prep.py +108 -12
  163. package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
  164. package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
  165. package/runtime/python/okstra_ctl/dispatch_core.py +102 -25
  166. package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
  167. package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
  168. package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
  169. package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -1
  170. package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
  171. package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
  172. package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
  173. package/runtime/python/okstra_ctl/error_log_core.py +1 -1
  174. package/runtime/python/okstra_ctl/error_report.py +14 -0
  175. package/runtime/python/okstra_ctl/error_zip.py +18 -2
  176. package/runtime/python/okstra_ctl/execution_identity.py +100 -7
  177. package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
  178. package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
  179. package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
  180. package/runtime/python/okstra_ctl/final_report_schema.py +90 -16
  181. package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
  182. package/runtime/python/okstra_ctl/handoff.py +24 -1
  183. package/runtime/python/okstra_ctl/ids.py +6 -16
  184. package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
  185. package/runtime/python/okstra_ctl/implementation_options.py +25 -11
  186. package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
  187. package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
  188. package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
  189. package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
  190. package/runtime/python/okstra_ctl/index.py +2 -2
  191. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
  192. package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
  193. package/runtime/python/okstra_ctl/json_boundary.py +10 -0
  194. package/runtime/python/okstra_ctl/listing.py +0 -91
  195. package/runtime/python/okstra_ctl/locks.py +5 -19
  196. package/runtime/python/okstra_ctl/log_report.py +14 -0
  197. package/runtime/python/okstra_ctl/manager_cli.py +22 -3
  198. package/runtime/python/okstra_ctl/manager_launch.py +4 -8
  199. package/runtime/python/okstra_ctl/material.py +2 -2
  200. package/runtime/python/okstra_ctl/migrate.py +23 -1
  201. package/runtime/python/okstra_ctl/model_cli.py +19 -5
  202. package/runtime/python/okstra_ctl/model_discovery.py +46 -47
  203. package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
  204. package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
  205. package/runtime/python/okstra_ctl/model_io/references.py +370 -0
  206. package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
  207. package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
  208. package/runtime/python/okstra_ctl/model_pool.py +10 -6
  209. package/runtime/python/okstra_ctl/models.py +8 -8
  210. package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
  211. package/runtime/python/okstra_ctl/next_phase.py +121 -69
  212. package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
  213. package/runtime/python/okstra_ctl/pane_title.py +11 -8
  214. package/runtime/python/okstra_ctl/path_hints.py +36 -11
  215. package/runtime/python/okstra_ctl/paths.py +76 -8
  216. package/runtime/python/okstra_ctl/plan_items.py +132 -16
  217. package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
  218. package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
  219. package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
  220. package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
  221. package/runtime/python/okstra_ctl/prepare_error.py +20 -0
  222. package/runtime/python/okstra_ctl/prior_planning.py +157 -0
  223. package/runtime/python/okstra_ctl/profile_show.py +18 -1
  224. package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
  225. package/runtime/python/okstra_ctl/recap.py +22 -1
  226. package/runtime/python/okstra_ctl/reconcile.py +84 -0
  227. package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
  228. package/runtime/python/okstra_ctl/render.py +98 -32
  229. package/runtime/python/okstra_ctl/render_final_report.py +3 -7
  230. package/runtime/python/okstra_ctl/report_assembly.py +297 -7
  231. package/runtime/python/okstra_ctl/report_contract.py +30 -7
  232. package/runtime/python/okstra_ctl/report_finalize.py +206 -15
  233. package/runtime/python/okstra_ctl/report_html/common.py +2 -2
  234. package/runtime/python/okstra_ctl/report_html/render.py +8 -12
  235. package/runtime/python/okstra_ctl/report_language.py +8 -4
  236. package/runtime/python/okstra_ctl/report_narrative.py +90 -3
  237. package/runtime/python/okstra_ctl/report_projections.py +8 -2
  238. package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
  239. package/runtime/python/okstra_ctl/report_translation.py +2 -35
  240. package/runtime/python/okstra_ctl/report_views.py +4 -22
  241. package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
  242. package/runtime/python/okstra_ctl/rollup.py +13 -0
  243. package/runtime/python/okstra_ctl/run.py +639 -138
  244. package/runtime/python/okstra_ctl/run_audit.py +13 -0
  245. package/runtime/python/okstra_ctl/run_index_row.py +0 -12
  246. package/runtime/python/okstra_ctl/seeding.py +21 -11
  247. package/runtime/python/okstra_ctl/sequence.py +1 -1
  248. package/runtime/python/okstra_ctl/session.py +64 -14
  249. package/runtime/python/okstra_ctl/set_work_status.py +18 -0
  250. package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
  251. package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
  252. package/runtime/python/okstra_ctl/stage_map.py +57 -11
  253. package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
  254. package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
  255. package/runtime/python/okstra_ctl/stage_targets.py +3 -12
  256. package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
  257. package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
  258. package/runtime/python/okstra_ctl/task_target.py +4 -16
  259. package/runtime/python/okstra_ctl/team.py +49 -2
  260. package/runtime/python/okstra_ctl/time_report.py +17 -2
  261. package/runtime/python/okstra_ctl/usage_report.py +11 -0
  262. package/runtime/python/okstra_ctl/user_response.py +55 -218
  263. package/runtime/python/okstra_ctl/user_response_values.py +242 -0
  264. package/runtime/python/okstra_ctl/validation_contract.py +3 -0
  265. package/runtime/python/okstra_ctl/verification_target.py +68 -0
  266. package/runtime/python/okstra_ctl/wizard.py +457 -92
  267. package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
  268. package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
  269. package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
  270. package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
  271. package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
  272. package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
  273. package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
  274. package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
  275. package/runtime/python/okstra_ctl/worker_request.py +2 -1
  276. package/runtime/python/okstra_ctl/worker_runner.py +16 -9
  277. package/runtime/python/okstra_ctl/worker_state.py +16 -1
  278. package/runtime/python/okstra_ctl/workflow.py +18 -1
  279. package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
  280. package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
  281. package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
  282. package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
  283. package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
  284. package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
  285. package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
  286. package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
  287. package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
  288. package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
  289. package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
  290. package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
  291. package/runtime/python/okstra_ctl/write_policy.py +90 -213
  292. package/runtime/python/okstra_project/__init__.py +0 -4
  293. package/runtime/python/okstra_project/dirs.py +2 -2
  294. package/runtime/python/okstra_project/phase_pointer.py +84 -0
  295. package/runtime/python/okstra_project/slug.py +24 -0
  296. package/runtime/python/okstra_project/state.py +22 -230
  297. package/runtime/python/okstra_token_usage/claude.py +9 -1
  298. package/runtime/python/okstra_token_usage/cli.py +3 -1
  299. package/runtime/python/okstra_token_usage/collect.py +71 -10
  300. package/runtime/python/okstra_token_usage/cursor.py +2 -0
  301. package/runtime/python/okstra_token_usage/grok.py +1 -5
  302. package/runtime/python/okstra_token_usage/paths.py +26 -0
  303. package/runtime/python/okstra_token_usage/pricing.py +19 -7
  304. package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
  305. package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
  306. package/runtime/schemas/final-report-v2.0.schema.json +9 -26
  307. package/runtime/schemas/final-report-v3.0.schema.json +173 -41
  308. package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
  309. package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
  310. package/runtime/skills/okstra-container-build/SKILL.md +16 -47
  311. package/runtime/skills/okstra-inspect/facets/history.md +1 -1
  312. package/runtime/skills/okstra-inspect/facets/status.md +7 -6
  313. package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
  314. package/runtime/skills/okstra-run/SKILL.md +7 -5
  315. package/runtime/templates/report-writer-prompt-preamble.md +1 -1
  316. package/runtime/templates/reports/brief.template.md +6 -2
  317. package/runtime/templates/reports/error-analysis-input.template.md +2 -0
  318. package/runtime/templates/reports/final-verification-input.template.md +2 -0
  319. package/runtime/templates/reports/implementation-input.template.md +7 -1
  320. package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
  321. package/runtime/templates/reports/quick-input.template.md +2 -0
  322. package/runtime/templates/reports/release-handoff-input.template.md +6 -1
  323. package/runtime/templates/reports/report.js +20 -3
  324. package/runtime/templates/reports/schedule.template.md +2 -0
  325. package/runtime/templates/reports/settings.template.json +0 -10
  326. package/runtime/templates/reports/task-brief.template.md +3 -0
  327. package/runtime/templates/reports/user-response.template.md +7 -3
  328. package/runtime/validators/checks/fixtures-01.py +57 -0
  329. package/runtime/validators/checks/fixtures-02.py +565 -0
  330. package/runtime/validators/checks/runners-01.py +108 -0
  331. package/runtime/validators/checks/validate-assets-01.py +60 -0
  332. package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
  333. package/runtime/validators/checks/validate-tasks-01.py +46 -0
  334. package/runtime/validators/checks/validate-tasks-02.py +85 -0
  335. package/runtime/validators/checks/validate-tasks-03.py +61 -0
  336. package/runtime/validators/checks/validate-tasks-04.py +118 -0
  337. package/runtime/validators/forbidden_actions.py +73 -3
  338. package/runtime/validators/lib/common.sh +5 -0
  339. package/runtime/validators/lib/fixtures.sh +7 -591
  340. package/runtime/validators/lib/paths.sh +13 -0
  341. package/runtime/validators/lib/runners.sh +6 -104
  342. package/runtime/validators/lib/summary.sh +1 -1
  343. package/runtime/validators/lib/validate-assets.sh +6 -56
  344. package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
  345. package/runtime/validators/lib/validate-tasks.sh +9 -294
  346. package/runtime/validators/validate-implementation-plan-stages.py +4 -4
  347. package/runtime/validators/validate-run.py +1369 -2654
  348. package/runtime/validators/validate-workflow.sh +56 -16
  349. package/runtime/validators/validate_improvement_report.py +2 -1
  350. package/runtime/validators/validate_session_conformance.py +295 -49
  351. package/dist/commands/execute/agent-prompt.d.mts +0 -1
  352. package/dist/commands/execute/agent-prompt.mjs +0 -24
  353. package/dist/commands/execute/agent-prompt.mjs.map +0 -1
  354. package/dist/commands/execute/codex-dispatch.d.mts +0 -3
  355. package/dist/commands/execute/codex-dispatch.mjs +0 -6
  356. package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
  357. package/dist/commands/execute/codex-run.d.mts +0 -3
  358. package/dist/commands/execute/codex-run.mjs +0 -62
  359. package/dist/commands/execute/codex-run.mjs.map +0 -1
  360. package/dist/commands/execute/convergence.d.mts +0 -1
  361. package/dist/commands/execute/convergence.mjs +0 -38
  362. package/dist/commands/execute/convergence.mjs.map +0 -1
  363. package/dist/commands/execute/error-log.d.mts +0 -1
  364. package/dist/commands/execute/error-log.mjs +0 -18
  365. package/dist/commands/execute/error-log.mjs.map +0 -1
  366. package/dist/commands/execute/git-reconcile.d.mts +0 -1
  367. package/dist/commands/execute/git-reconcile.mjs +0 -30
  368. package/dist/commands/execute/git-reconcile.mjs.map +0 -1
  369. package/dist/commands/execute/handoff.d.mts +0 -1
  370. package/dist/commands/execute/handoff.mjs +0 -31
  371. package/dist/commands/execute/handoff.mjs.map +0 -1
  372. package/dist/commands/execute/incremental-carry.d.mts +0 -1
  373. package/dist/commands/execute/incremental-carry.mjs +0 -20
  374. package/dist/commands/execute/incremental-carry.mjs.map +0 -1
  375. package/dist/commands/execute/incremental-scope.d.mts +0 -1
  376. package/dist/commands/execute/incremental-scope.mjs +0 -29
  377. package/dist/commands/execute/incremental-scope.mjs.map +0 -1
  378. package/dist/commands/execute/integrate-stages.d.mts +0 -1
  379. package/dist/commands/execute/integrate-stages.mjs +0 -24
  380. package/dist/commands/execute/integrate-stages.mjs.map +0 -1
  381. package/dist/commands/execute/pane-title.d.mts +0 -1
  382. package/dist/commands/execute/pane-title.mjs +0 -20
  383. package/dist/commands/execute/pane-title.mjs.map +0 -1
  384. package/dist/commands/execute/plan-items.d.mts +0 -1
  385. package/dist/commands/execute/plan-items.mjs +0 -9
  386. package/dist/commands/execute/plan-items.mjs.map +0 -1
  387. package/dist/commands/execute/plan-validate.d.mts +0 -1
  388. package/dist/commands/execute/plan-validate.mjs +0 -68
  389. package/dist/commands/execute/plan-validate.mjs.map +0 -1
  390. package/dist/commands/execute/plan-verify.d.mts +0 -1
  391. package/dist/commands/execute/plan-verify.mjs +0 -43
  392. package/dist/commands/execute/plan-verify.mjs.map +0 -1
  393. package/dist/commands/execute/spawn-followups.d.mts +0 -1
  394. package/dist/commands/execute/spawn-followups.mjs +0 -22
  395. package/dist/commands/execute/spawn-followups.mjs.map +0 -1
  396. package/dist/commands/execute/team.d.mts +0 -3
  397. package/dist/commands/execute/team.mjs +0 -66
  398. package/dist/commands/execute/team.mjs.map +0 -1
  399. package/dist/commands/execute/token-usage.d.mts +0 -1
  400. package/dist/commands/execute/token-usage.mjs +0 -19
  401. package/dist/commands/execute/token-usage.mjs.map +0 -1
  402. package/dist/commands/execute/worker-audit-check.d.mts +0 -1
  403. package/dist/commands/execute/worker-audit-check.mjs +0 -34
  404. package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
  405. package/dist/commands/execute/worker-dispatch.d.mts +0 -7
  406. package/dist/commands/execute/worker-dispatch.mjs +0 -64
  407. package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
  408. package/dist/commands/execute/worker-state.d.mts +0 -1
  409. package/dist/commands/execute/worker-state.mjs +0 -28
  410. package/dist/commands/execute/worker-state.mjs.map +0 -1
  411. package/dist/commands/execute/worktree-lookup.d.mts +0 -1
  412. package/dist/commands/execute/worktree-lookup.mjs +0 -92
  413. package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
  414. package/dist/commands/execute/worktree-status.d.mts +0 -1
  415. package/dist/commands/execute/worktree-status.mjs +0 -121
  416. package/dist/commands/execute/worktree-status.mjs.map +0 -1
  417. package/dist/commands/inspect/code-review.d.mts +0 -1
  418. package/dist/commands/inspect/code-review.mjs +0 -32
  419. package/dist/commands/inspect/code-review.mjs.map +0 -1
  420. package/dist/commands/inspect/container.d.mts +0 -1
  421. package/dist/commands/inspect/container.mjs +0 -25
  422. package/dist/commands/inspect/container.mjs.map +0 -1
  423. package/dist/commands/inspect/context-cost.d.mts +0 -1
  424. package/dist/commands/inspect/context-cost.mjs +0 -25
  425. package/dist/commands/inspect/context-cost.mjs.map +0 -1
  426. package/dist/commands/inspect/design-prep.d.mts +0 -1
  427. package/dist/commands/inspect/design-prep.mjs +0 -22
  428. package/dist/commands/inspect/design-prep.mjs.map +0 -1
  429. package/dist/commands/inspect/error-report.d.mts +0 -1
  430. package/dist/commands/inspect/error-report.mjs +0 -25
  431. package/dist/commands/inspect/error-report.mjs.map +0 -1
  432. package/dist/commands/inspect/error-zip.d.mts +0 -1
  433. package/dist/commands/inspect/error-zip.mjs +0 -24
  434. package/dist/commands/inspect/error-zip.mjs.map +0 -1
  435. package/dist/commands/inspect/log-report.d.mts +0 -1
  436. package/dist/commands/inspect/log-report.mjs +0 -26
  437. package/dist/commands/inspect/log-report.mjs.map +0 -1
  438. package/dist/commands/inspect/model-io.d.mts +0 -1
  439. package/dist/commands/inspect/model-io.mjs +0 -25
  440. package/dist/commands/inspect/model-io.mjs.map +0 -1
  441. package/dist/commands/inspect/profile-show.d.mts +0 -1
  442. package/dist/commands/inspect/profile-show.mjs +0 -28
  443. package/dist/commands/inspect/profile-show.mjs.map +0 -1
  444. package/dist/commands/inspect/recap.d.mts +0 -1
  445. package/dist/commands/inspect/recap.mjs +0 -30
  446. package/dist/commands/inspect/recap.mjs.map +0 -1
  447. package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
  448. package/dist/commands/inspect/resolve-task-key.mjs +0 -24
  449. package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
  450. package/dist/commands/inspect/rollup.d.mts +0 -1
  451. package/dist/commands/inspect/rollup.mjs +0 -25
  452. package/dist/commands/inspect/rollup.mjs.map +0 -1
  453. package/dist/commands/inspect/run-audit.d.mts +0 -1
  454. package/dist/commands/inspect/run-audit.mjs +0 -25
  455. package/dist/commands/inspect/run-audit.mjs.map +0 -1
  456. package/dist/commands/inspect/set-work-status.d.mts +0 -1
  457. package/dist/commands/inspect/set-work-status.mjs +0 -29
  458. package/dist/commands/inspect/set-work-status.mjs.map +0 -1
  459. package/dist/commands/inspect/stage-map.d.mts +0 -1
  460. package/dist/commands/inspect/stage-map.mjs +0 -131
  461. package/dist/commands/inspect/stage-map.mjs.map +0 -1
  462. package/dist/commands/inspect/task-list.d.mts +0 -1
  463. package/dist/commands/inspect/task-list.mjs +0 -149
  464. package/dist/commands/inspect/task-list.mjs.map +0 -1
  465. package/dist/commands/inspect/task-show.d.mts +0 -1
  466. package/dist/commands/inspect/task-show.mjs +0 -108
  467. package/dist/commands/inspect/task-show.mjs.map +0 -1
  468. package/dist/commands/inspect/time-report.d.mts +0 -1
  469. package/dist/commands/inspect/time-report.mjs +0 -24
  470. package/dist/commands/inspect/time-report.mjs.map +0 -1
  471. package/dist/commands/inspect/usage-report.d.mts +0 -1
  472. package/dist/commands/inspect/usage-report.mjs +0 -23
  473. package/dist/commands/inspect/usage-report.mjs.map +0 -1
  474. package/dist/commands/inspect/user-response.d.mts +0 -1
  475. package/dist/commands/inspect/user-response.mjs +0 -35
  476. package/dist/commands/inspect/user-response.mjs.map +0 -1
  477. package/dist/commands/inspect/worker-liveness.d.mts +0 -1
  478. package/dist/commands/inspect/worker-liveness.mjs +0 -45
  479. package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
  480. package/dist/commands/lifecycle/contract-check.d.mts +0 -1
  481. package/dist/commands/lifecycle/contract-check.mjs +0 -18
  482. package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
  483. package/dist/commands/lifecycle/migrate.d.mts +0 -1
  484. package/dist/commands/lifecycle/migrate.mjs +0 -30
  485. package/dist/commands/lifecycle/migrate.mjs.map +0 -1
  486. package/dist/commands/lifecycle/model.d.mts +0 -1
  487. package/dist/commands/lifecycle/model.mjs +0 -22
  488. package/dist/commands/lifecycle/model.mjs.map +0 -1
  489. package/dist/commands/manager.d.mts +0 -3
  490. package/dist/commands/manager.mjs +0 -50
  491. package/dist/commands/manager.mjs.map +0 -1
  492. package/dist/commands/report/agent-activity.d.mts +0 -1
  493. package/dist/commands/report/agent-activity.mjs +0 -20
  494. package/dist/commands/report/agent-activity.mjs.map +0 -1
  495. package/dist/commands/report/approval-decision.d.mts +0 -1
  496. package/dist/commands/report/approval-decision.mjs +0 -21
  497. package/dist/commands/report/approval-decision.mjs.map +0 -1
  498. package/dist/commands/report/design-snapshot.d.mts +0 -1
  499. package/dist/commands/report/design-snapshot.mjs +0 -19
  500. package/dist/commands/report/design-snapshot.mjs.map +0 -1
  501. package/dist/commands/report/finalize.d.mts +0 -4
  502. package/dist/commands/report/finalize.mjs +0 -64
  503. package/dist/commands/report/finalize.mjs.map +0 -1
  504. package/dist/commands/report/inject-report-index.d.mts +0 -1
  505. package/dist/commands/report/inject-report-index.mjs +0 -21
  506. package/dist/commands/report/inject-report-index.mjs.map +0 -1
  507. package/dist/commands/report/render-final-report.d.mts +0 -1
  508. package/dist/commands/report/render-final-report.mjs +0 -23
  509. package/dist/commands/report/render-final-report.mjs.map +0 -1
  510. package/dist/commands/report/render-views.d.mts +0 -1
  511. package/dist/commands/report/render-views.mjs +0 -27
  512. package/dist/commands/report/render-views.mjs.map +0 -1
  513. package/dist/commands/report/translate.d.mts +0 -1
  514. package/dist/commands/report/translate.mjs +0 -33
  515. package/dist/commands/report/translate.mjs.map +0 -1
  516. package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
  517. package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
  518. package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
  519. package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
  520. package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
  521. package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
  522. package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
  523. package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
  524. package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
  525. package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
  526. package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
  527. package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
  528. package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
  529. package/runtime/bin/okstra-central.sh +0 -152
  530. package/runtime/bin/okstra-incremental-carry.py +0 -10
  531. package/runtime/bin/okstra-incremental-scope.py +0 -10
  532. package/runtime/bin/okstra-team-reconcile.sh +0 -36
  533. package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
  534. package/runtime/python/okstra_ctl/batch.py +0 -60
  535. package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
  536. package/runtime/python/okstra_ctl/container_registry.py +0 -72
  537. package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
  538. package/runtime/python/okstra_ctl/resolver.py +0 -54
  539. package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
  540. package/runtime/python/okstra_ctl/tmux.py +0 -134
  541. package/runtime/python/okstra_ctl/worktree.py +0 -1099
@@ -27,7 +27,7 @@ from okstra_project.dirs import (
27
27
  TASKS_RELATIVE,
28
28
  okstra_home,
29
29
  )
30
- from okstra_project.state import slugify
30
+ from okstra_project.slug import slugify
31
31
 
32
32
  __all__ = [
33
33
  "OKSTRA_RELATIVE",
@@ -43,8 +43,22 @@ __all__ = [
43
43
  "container_paths",
44
44
  "okstra_home",
45
45
  "find_asset_root",
46
+ "RUN_VALIDATOR_RELATIVE",
47
+ "BRIEF_VALIDATOR_RELATIVE",
48
+ "STAGE_VALIDATOR_RELATIVE",
46
49
  ]
47
50
 
51
+ # validators 트리 안의 자산들. `find_asset_root` 에 그대로 넘겨 쓰라고 튜플로
52
+ # 둔다 — 이 이름들을 문자열로 조립하던 호출부들이 저마다 다른 루트를 가정해
53
+ # 어긋나 있었다(설치본에서는 `~/.okstra/lib/validators`, 체크아웃에서는
54
+ # `<repo>/validators`).
55
+ RUN_VALIDATOR_RELATIVE = ("validators", "validate-run.py")
56
+ BRIEF_VALIDATOR_RELATIVE = ("validators", "validate-brief.py")
57
+ STAGE_VALIDATOR_RELATIVE = (
58
+ "validators",
59
+ "validate-implementation-plan-stages.py",
60
+ )
61
+
48
62
 
49
63
  def find_asset_root(
50
64
  relative: Sequence[str],
@@ -191,6 +205,18 @@ class RunRef:
191
205
  def manifest(self) -> Path:
192
206
  return self.run_dir / "manifests" / f"run-manifest{self._suffix}.json"
193
207
 
208
+ @property
209
+ def convergence_state(self) -> Path:
210
+ """이 run 의 finding convergence 상태 파일.
211
+
212
+ 이름은 다른 산출물과 같은 seq 규칙을 쓴다. `compute_run_paths` 는
213
+ 디렉터리마다 seq 를 따로 세므로(`reports: 004` 와 `state: 005` 가 실제로
214
+ 갈린 적이 있다), 리포트 경로에서 만든 ref 로 이 값을 계산하면 그 갈린
215
+ run 에서는 존재하지 않는 파일을 가리킨다. 호출자는 파일이 없는 경우를
216
+ 정상 분기로 다뤄야 한다.
217
+ """
218
+ return self.run_dir / "state" / f"convergence{self._suffix}.json"
219
+
194
220
  def carry(self, stage: int) -> Path:
195
221
  """stage 의 carry 사이드카. implementation 은 stage-SHARED(flat)다."""
196
222
  return self.carry_dir / f"stage-{int(stage)}.json"
@@ -354,6 +380,20 @@ def task_manifest_file(task_root: Path) -> Path:
354
380
  return Path(task_root) / TASK_MANIFEST_FILENAME
355
381
 
356
382
 
383
+ def task_qa_dir(task_root: Path) -> Path:
384
+ """task 의 qa 산출물 디렉터리.
385
+
386
+ Tier 3 conformance manifest 와 그 스크립트, self-mock 사이드카, 워커가 실행한
387
+ result-*.json 이 모두 여기 산다. 쓰기 계약이 이 경로를 역할별로 허용해야 하므로
388
+ (`dispatch_core._task_qa_paths`) 디렉터리 이름을 리터럴로 흩어 두지 않는다."""
389
+ return Path(task_root) / "qa"
390
+
391
+
392
+ def task_conformance_manifest_file(task_root: Path) -> Path:
393
+ """task 의 Tier 3 conformance manifest 경로."""
394
+ return task_qa_dir(task_root) / "conformance-manifest.json"
395
+
396
+
357
397
  def task_timeline_file(task_root: Path) -> Path:
358
398
  """task 의 history timeline 경로."""
359
399
  return Path(task_root) / "history" / "timeline.json"
@@ -369,10 +409,7 @@ def container_paths(project_root: Path, task_group: str, task_id: str) -> dict:
369
409
  return {
370
410
  "container_dir": base,
371
411
  "env_override": base / "env.override",
372
- "registry": base / "registry.json",
373
- "registry_lock": base / "registry.json.lock",
374
412
  "deploy_state": base / "deploy-state.json",
375
- "watchers_dir": base / "watchers",
376
413
  }
377
414
 
378
415
 
@@ -445,8 +482,8 @@ def compute_run_paths(
445
482
  """주어진 identity 와 task-type 에 대해 모든 path/segment 값을 계산해
446
483
  dict 로 돌려준다. 부수효과 없음.
447
484
 
448
- run_seq_override: 정수가 주어지면 7개 seq 모두 그 값으로 강제. okstra-ctl
449
- rerun 처럼 외부에서 seq 를 미리 reserve 한 경로용. 미지정 시 디스크 스캔
485
+ run_seq_override: 정수가 주어지면 7개 seq 모두 그 값으로 강제. 외부에서
486
+ seq 를 미리 reserve 한 경로용(현재는 테스트 hook). 미지정 시 디스크 스캔
450
487
  결과로 결정.
451
488
  """
452
489
  project_root = Path(project_root)
@@ -471,7 +508,7 @@ def compute_run_paths(
471
508
  task_index = task_root / "task-index.md"
472
509
  instruction_set = task_root / "instruction-set"
473
510
  analysis_packet = instruction_set / "analysis-packet.md"
474
- task_qa = task_root / "qa"
511
+ task_qa = task_qa_dir(task_root)
475
512
  runs_dir = runs_dir_of(task_root)
476
513
  history_dir = task_root / "history"
477
514
  timeline_file = task_timeline_file(task_root)
@@ -569,6 +606,7 @@ def compute_run_paths(
569
606
  approval_decisions = run_state / f"approval-decisions-{task_type_segment}-{seqs['state']}.json"
570
607
  design_preparation = run_state / f"design-preparation-{task_type_segment}-{seqs['state']}.json"
571
608
  plan_body_verification = run_state / f"plan-body-verification-{task_type_segment}-{seqs['state']}.json"
609
+ incremental_decision = run_state / f"incremental-decision-{task_type_segment}-{seqs['state']}.json"
572
610
 
573
611
  run_errors_log = run_logs / f"errors-{task_type_segment}-{seqs['state']}.jsonl"
574
612
  runtime_home = okstra_home()
@@ -578,7 +616,14 @@ def compute_run_paths(
578
616
  antigravity_worker_errors_sidecar = worker_results / f"antigravity-worker-errors{suffixes['worker_results']}.json"
579
617
  report_writer_worker_errors_sidecar = worker_results / f"report-writer-worker-errors{suffixes['worker_results']}.json"
580
618
 
581
- run_validator_script = workspace_root / "validators" / "validate-run.py"
619
+ # validators 트리는 설치본에서 `~/.okstra/lib/validators` 에, 체크아웃에서는
620
+ # `<repo>/validators` 에 있다. workspace_root 로 계산하면 셸 진입점이 넘기는
621
+ # `~/.okstra` 아래에서 빗나가므로(그 아래엔 `validators/` 가 없다) 자산을
622
+ # 실제로 가진 루트를 탐색해서 해소한다. 탐색이 실패하면 workspace_root 를
623
+ # 그대로 써서 소비자 쪽 존재 검사가 원래 경로를 그대로 보고하게 둔다.
624
+ run_validator_script = (
625
+ find_asset_root(RUN_VALIDATOR_RELATIVE) or workspace_root
626
+ ).joinpath(*RUN_VALIDATOR_RELATIVE)
582
627
 
583
628
  abs_paths = {
584
629
  "PROJECT_ID": project_id,
@@ -679,6 +724,7 @@ def compute_run_paths(
679
724
  "DESIGN_PREPARATION_PATH": str(design_preparation),
680
725
  "CONVERGENCE_STATE_PATH": str(convergence_state),
681
726
  "PLAN_BODY_VERIFICATION_STATE_PATH": str(plan_body_verification),
727
+ "INCREMENTAL_DECISION_STATE_PATH": str(incremental_decision),
682
728
  "RUN_ERRORS_LOG_PATH": str(run_errors_log),
683
729
  "CLAUDE_WORKER_ERRORS_SIDECAR_PATH": str(claude_worker_errors_sidecar),
684
730
  "CODEX_WORKER_ERRORS_SIDECAR_PATH": str(codex_worker_errors_sidecar),
@@ -758,6 +804,7 @@ def compute_run_paths(
758
804
  ("APPROVAL_DECISIONS_RELATIVE_PATH", approval_decisions),
759
805
  ("DESIGN_PREPARATION_RELATIVE_PATH", design_preparation),
760
806
  ("PLAN_BODY_VERIFICATION_STATE_RELATIVE_PATH", plan_body_verification),
807
+ ("INCREMENTAL_DECISION_STATE_RELATIVE_PATH", incremental_decision),
761
808
  ("RUN_ERRORS_LOG_RELATIVE_PATH", run_errors_log),
762
809
  ("CLAUDE_WORKER_ERRORS_SIDECAR_RELATIVE_PATH", claude_worker_errors_sidecar),
763
810
  ("CODEX_WORKER_ERRORS_SIDECAR_RELATIVE_PATH", codex_worker_errors_sidecar),
@@ -767,3 +814,24 @@ def compute_run_paths(
767
814
  ]
768
815
  rel_paths = {key: _rel(project_root, target) for key, target in rel_pairs}
769
816
  return {**abs_paths, **rel_paths}
817
+
818
+
819
+ # ---- task-root 에서 역산하는 순수 경로 계산 ----------------------------
820
+ # task_target 에 있었다. 그 모듈은 okstra_project 를 끌어오므로, 이 두 함수만
821
+ # 필요한 stage_map·stage_ledger 가 okstra_project 를 통째로 딸려오게 했다.
822
+
823
+ def infer_project_root(task_root: Path) -> Path:
824
+ parts = task_root.parts
825
+ if ".okstra" not in parts:
826
+ return task_root
827
+ # The okstra subtree (.okstra/tasks/...) introduces the deepest ".okstra"
828
+ # segment; a project checked out under a path that itself contains
829
+ # ".okstra" must not resolve to that outer segment.
830
+ idx = len(parts) - 1 - parts[::-1].index(".okstra")
831
+ return Path(*parts[:idx]).resolve()
832
+
833
+ def project_rel(path: Path, project_root: Path) -> str:
834
+ try:
835
+ return str(path.resolve().relative_to(project_root.resolve()))
836
+ except ValueError:
837
+ return str(path)
@@ -294,21 +294,11 @@ def _extract_prep_items(
294
294
  ) -> None:
295
295
  if not planning.get("stages"):
296
296
  return
297
- detection_input = planning
298
- if planning.get("planningContract") == _SELECTED_DIRECTION_CONTRACT:
299
- realization = planning.get("directionRealization")
300
- if not isinstance(realization, Mapping):
301
- raise PlanItemContractError("directionRealization must be an object")
302
- detection_input = dict(planning)
303
- detection_input["optionCandidates"] = [
304
- {
305
- "name": "Selected Direction",
306
- "fileStructure": realization.get("fileStructure") or [],
307
- }
308
- ]
309
- detection_input["recommendedOption"] = {"name": "Selected Direction"}
297
+ # 계약 분기는 탐지기가 안다(`design_surfaces._planned_file_structure`).
298
+ # 여기서 레거시 모양을 흉내 내 넘기던 동안 그 지식은 이 호출부에만 있었고,
299
+ # 같은 탐지기를 부르는 나머지 세 곳은 선택 방향 계획에서 실패했다.
310
300
  try:
311
- triggers = detect_design_surfaces(detection_input)
301
+ triggers = detect_design_surfaces(planning)
312
302
  except (DesignSurfaceError, TypeError, AttributeError) as exc:
313
303
  raise PlanItemContractError(f"design-surface detection failed: {exc}") from exc
314
304
  for trigger in triggers:
@@ -658,6 +648,55 @@ def is_critic_worker(worker: str) -> bool:
658
648
  return name == CRITIC_WORKER_ID or name.endswith("-critic-worker")
659
649
 
660
650
 
651
+ def analyser_key(worker: str) -> str:
652
+ """`codex` 와 `codex-worker` 는 같은 분석자다."""
653
+ name = str(worker or "").strip()
654
+ return name[: -len("-worker")] if name.endswith("-worker") else name
655
+
656
+
657
+ def voting_analyser_keys(items: Sequence[Mapping[str, Any]]) -> set[str]:
658
+ """`participatingAnalysers.voting` 의 유일한 계산.
659
+
660
+ 게이트 산술의 분모다 — 두 표의 과반과 세 표의 과반은 다른 주장이므로,
661
+ 이 run 에서 판정을 남긴 서로 다른 분석자를 항목·라운드를 가리지 않고
662
+ 센다. 빠지는 둘: 결과를 못 낸 워커(`verification-error`)는 게이트 산술에
663
+ 들어가지 않고, critic 은 다수결에 참여하지 않고 짝수 분할만 가르며
664
+ 로스터(`workerAssignments`)에도 없어 `rostered` 에 잡히지 않는다.
665
+
666
+ 생산자(`okstra plan-items complete-round`)와 검증기
667
+ (`validators/validate-run.py` `_validate_participating_analysers`)가 같은
668
+ 함수를 부른다. 종전에는 생산자가 이번 라운드 디스패치 큐의 표만 세고
669
+ 검증기가 전 항목·전 라운드를 다시 세서, critic 이 동수만 가른 라운드에서
670
+ 기록값과 재계산값이 갈렸다.
671
+ """
672
+ keys: set[str] = set()
673
+ for item in items:
674
+ if not isinstance(item, Mapping):
675
+ continue
676
+ for worker, token in _item_votes(item):
677
+ if token == "verification-error" or is_critic_worker(worker):
678
+ continue
679
+ key = analyser_key(worker)
680
+ if key and key != analyser_key(CRITIC_WORKER_ID):
681
+ keys.add(key)
682
+ return keys
683
+
684
+
685
+ def critic_is_rostered(run_manifest: Mapping[str, Any]) -> bool:
686
+ """이 run 이 critic 슬롯을 실제로 배정했는가.
687
+
688
+ 정본은 `invocationAssignments` 다 — run 이 해소한 critic 을 적는 곳이고
689
+ (`okstra_ctl.render._optional_worker_roles`), `critic/*` 항목이 없으면
690
+ critic 이 없다. `workerAssignments` 로는 판정할 수 없다: critic 은 분석
691
+ 워커 로스터에서 제외되므로(`okstra_ctl.run._analysis_worker_rows`)
692
+ rostered 여부와 무관하게 그 배열에 나타나지 않는다.
693
+ """
694
+ assignments = run_manifest.get("invocationAssignments")
695
+ if not isinstance(assignments, Mapping):
696
+ return False
697
+ return any(str(ref).startswith("critic/") for ref in assignments)
698
+
699
+
661
700
  def tie_vote_item_ids(
662
701
  items: Sequence[Mapping[str, Any]],
663
702
  ledger: Mapping[str, str] | None,
@@ -702,6 +741,58 @@ CRITIC_TIE_PREAMBLE = (
702
741
  "settles the split. Do not re-open items that are not listed.\n"
703
742
  )
704
743
 
744
+ # 라운드 2+ 는 직전 라운드의 반대 의견을 해결하려고 존재한다. 그 의견을 프롬프트가
745
+ # 싣지 않으면 반대한 워커는 자기 판정을 그대로 다시 적고 동료는 근거 없이 다시
746
+ # 판단하므로, 루프가 예산을 같은 분할을 재도출하는 데 쓴다.
747
+ REVERIFY_PREAMBLE = (
748
+ "This is a re-verification round. Each item below carries a "
749
+ "**Prior round dissent** block: what the previous round's verifiers said "
750
+ "about that item, and what the planner changed in response. Read that "
751
+ "block before judging the CURRENT text. If you raised the prior objection "
752
+ "and still DISAGREE, state what you re-opened after the rewrite and why "
753
+ "the correction is insufficient — restating your previous explanation "
754
+ "without engaging the correction is not a valid verdict. If the correction "
755
+ "resolves your objection, say so and AGREE. Add one line per item to your "
756
+ "response, directly under **Verdict**:\n"
757
+ "**Prior dissent**: resolved | unresolved | none — <which prior objection, "
758
+ "and what the current text does about it>\n"
759
+ )
760
+
761
+
762
+ # 파서(`verdict_blocks._ITEM_RE` / `_FIELD_RE`)가 읽을 수 있는 응답 형식.
763
+ # 정본 서술은 plan-body-verification.md §"Response format" 이지만 전달 채널은
764
+ # 이 출력이다 — 큐는 모든 검증자 프롬프트에 verbatim 으로 실리는 유일한
765
+ # 조각이라, 여기 실린 블록은 리드가 프롬프트를 어떻게 손 조립하든 도달한다.
766
+ # 두 실측 실패 모양(`## <id>` 2해시 헤딩, `**Verdict:** AGREE` 굵게 안 콜론)을
767
+ # 본문이 직접 금지한다.
768
+ PLAN_VERIFY_RESPONSE_FORMAT = (
769
+ "\n## Response format\n"
770
+ "\n"
771
+ "Answer with one block per plan item in the queue above, headed by the "
772
+ "item's own id at exactly three hashes (`### P-...`). The collector parses "
773
+ "`^### ` and nothing else — a block at any other depth is not an unparsed "
774
+ "block; it is a verdict that was never recorded, and the round is scored "
775
+ "on the items that remain. Field labels keep the colon outside the bold: "
776
+ "`**Verdict**: AGREE`, never `**Verdict:** AGREE`.\n"
777
+ "\n"
778
+ "### <item-id>\n"
779
+ "**Verdict**: AGREE | DISAGREE(<a|b|c|d|e|f>) | SUPPLEMENT | UNVERIFIABLE\n"
780
+ "**Fixability** (only when DISAGREE): planner-fixable | needs-user-input\n"
781
+ "**Claim** (only on DISAGREE(a), or DISAGREE(f) on a P-Req item): "
782
+ "fact | judgement\n"
783
+ "**Probe** (only when Claim is fact): <one line of JSON, e.g. "
784
+ '{"kind": "path-absent", "path": "src/missing.ts"}>\n'
785
+ "**Note**: <the falsification candidate considered and why it is "
786
+ "excluded; required even for AGREE>\n"
787
+ "**Explanation**: <2-3 sentences>\n"
788
+ )
789
+
790
+
791
+ def with_response_format(queue_markdown: str) -> str:
792
+ """큐 본문 뒤에 응답 형식 블록을 덧붙인다. run 003 실측: 리드가 손 조립
793
+ 중 이 블록을 빼먹어 검증자 2명의 판정 32건 전부가 형식 불일치로 버려졌다."""
794
+ return queue_markdown.rstrip("\n") + "\n" + PLAN_VERIFY_RESPONSE_FORMAT
795
+
705
796
 
706
797
  def item_cites_build_command(item: Mapping[str, Any]) -> bool:
707
798
  """이 항목이 계획 워크트리에서 실행 불가한 빌드/테스트 명령을 인용하는가."""
@@ -826,8 +917,18 @@ class NextDispatch:
826
917
  def next_dispatch(
827
918
  items: Sequence[Mapping[str, Any]],
828
919
  payloads: Mapping[str, Mapping[str, Any]] | None = None,
920
+ *,
921
+ critic_rostered: bool = True,
829
922
  ) -> NextDispatch:
830
- """환경 전용 UNVERIFIABLE 은 전체 라운드를 만들지 않는다. 일괄 오류만 그 워커."""
923
+ """환경 전용 UNVERIFIABLE 은 전체 라운드를 만들지 않는다. 일괄 오류만 그 워커.
924
+
925
+ ``critic_rostered`` 가 거짓이면 미해결 1대1 은 `user-decision` 이다 —
926
+ critic 이 없는 로스터에는 라운드 안에서 동수를 가를 표가 존재하지 않고,
927
+ 또 한 라운드를 도는 것은 같은 두 분석자에게 같은 분할을 다시 시키는
928
+ 일이다. 호출자가 로스터를 모를 때(run manifest 없이 부를 때)는 종전대로
929
+ `critic-tie` 다: critic 이 있는 run 을 사용자 결정으로 보내는 쪽이 더
930
+ 나쁜 오답이다.
931
+ """
831
932
  assigned = tuple(
832
933
  str(item["id"]) for item in items
833
934
  if isinstance(item.get("id"), str) and item["id"]
@@ -847,13 +948,23 @@ def next_dispatch(
847
948
  str(item["id"]) for item in items
848
949
  if isinstance(item.get("id"), str) and _is_tie(item)
849
950
  )
850
- if ties:
951
+ if ties and critic_rostered:
851
952
  return NextDispatch(
852
953
  kind="critic-tie",
853
954
  workers=(CRITIC_WORKER_ID,),
854
955
  item_ids=ties,
855
956
  reason="unsettled analyser tie; critic settles",
856
957
  )
958
+ if ties:
959
+ return NextDispatch(
960
+ kind="user-decision",
961
+ workers=(),
962
+ item_ids=ties,
963
+ reason=(
964
+ "unsettled analyser tie and no rostered critic; open one "
965
+ "approval decision per item"
966
+ ),
967
+ )
857
968
  return NextDispatch(
858
969
  kind="none", workers=(), item_ids=(),
859
970
  reason="no worker batch",
@@ -869,3 +980,8 @@ def critic_tie_prompt_text(queue_markdown: str) -> str:
869
980
  """동수 critic 프롬프트. 가르는 지시가 큐보다 앞이다."""
870
981
  return f"{CRITIC_TIE_PREAMBLE.rstrip()}\n\n{queue_markdown.lstrip()}"
871
982
 
983
+
984
+ def reverify_prompt_text(queue_markdown: str) -> str:
985
+ """라운드 2+ 프롬프트. 직전 반대 의견을 읽으라는 지시가 큐보다 앞이다."""
986
+ return f"{REVERIFY_PREAMBLE.rstrip()}\n\n{queue_markdown.lstrip()}"
987
+