okstra 0.206.0 → 0.207.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 (259) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-registry.mjs +7 -1
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/install.mjs +1 -1
  5. package/dist/commands/lifecycle/install.mjs.map +1 -1
  6. package/docs/architecture/storage-model.md +1 -0
  7. package/docs/architecture.md +40 -16
  8. package/docs/cli.md +17 -15
  9. package/docs/contributor-change-matrix.md +3 -2
  10. package/docs/performance-improvement-plan-v2.md +1 -1
  11. package/docs/project-structure-overview.md +43 -20
  12. package/package.json +1 -1
  13. package/runtime/BUILD.json +2 -2
  14. package/runtime/agents/operations/code-review.json +1 -1
  15. package/runtime/bin/lib/okstra/usage.sh +3 -3
  16. package/runtime/bin/okstra-compact-reminder.sh +1 -1
  17. package/runtime/bin/okstra-spawn-followups.py +2 -2
  18. package/runtime/prompts/duties/direction-selection-worker.json +1 -1
  19. package/runtime/prompts/launch.template.md +2 -2
  20. package/runtime/prompts/lead/adapters/cmux.md +4 -3
  21. package/runtime/prompts/lead/context-loader.md +1 -1
  22. package/runtime/prompts/lead/convergence.md +44 -12
  23. package/runtime/prompts/lead/okstra-lead-contract.md +44 -73
  24. package/runtime/prompts/lead/phase-routing.md +64 -0
  25. package/runtime/prompts/lead/report-writer.md +10 -8
  26. package/runtime/prompts/lead/team-contract.md +1 -1
  27. package/runtime/prompts/profiles/_clarification-recommendation.md +4 -4
  28. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  29. package/runtime/prompts/profiles/_common-contract.md +2 -2
  30. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  31. package/runtime/prompts/profiles/forbidden-actions.json +0 -94
  32. package/runtime/prompts/wizard/prompts.ko.json +2 -1
  33. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
  34. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +5 -5
  35. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
  36. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -2
  37. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
  38. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
  39. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +17 -26
  40. package/runtime/python/okstra_ctl/agent/prompt_cli/batch.py +183 -0
  41. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +60 -10
  42. package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
  43. package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +21 -4
  44. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +10 -1
  45. package/runtime/python/okstra_ctl/analysis_inputs.py +0 -39
  46. package/runtime/python/okstra_ctl/analysis_scope.py +31 -0
  47. package/runtime/python/okstra_ctl/approval_decisions.py +32 -2
  48. package/runtime/python/okstra_ctl/asset_roots.py +19 -0
  49. package/runtime/python/okstra_ctl/assignment_resolver.py +8 -0
  50. package/runtime/python/okstra_ctl/blocking_checks.py +7 -0
  51. package/runtime/python/okstra_ctl/code_review_target.py +92 -6
  52. package/runtime/python/okstra_ctl/consumers.py +12 -0
  53. package/runtime/python/okstra_ctl/dispatch_checkpoints.py +121 -0
  54. package/runtime/python/okstra_ctl/dispatch_core.py +54 -32
  55. package/runtime/python/okstra_ctl/dispatch_state.py +34 -5
  56. package/runtime/python/okstra_ctl/doctor.py +2 -1
  57. package/runtime/python/okstra_ctl/domain/provider.py +5 -0
  58. package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -2
  59. package/runtime/python/okstra_ctl/domain/write_policy.py +2 -1
  60. package/runtime/python/okstra_ctl/execution_mutation_audit.py +46 -9
  61. package/runtime/python/okstra_ctl/handoff.py +11 -466
  62. package/runtime/python/okstra_ctl/handoff_error.py +5 -0
  63. package/runtime/python/okstra_ctl/implementation_direction.py +0 -477
  64. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +13 -1
  65. package/runtime/python/okstra_ctl/lead_progress.py +33 -1
  66. package/runtime/python/okstra_ctl/manager_view.py +26 -19
  67. package/runtime/python/okstra_ctl/model_io/lines.py +21 -4
  68. package/runtime/python/okstra_ctl/models.py +4 -1
  69. package/runtime/python/okstra_ctl/operation_invocation.py +11 -2
  70. package/runtime/python/okstra_ctl/option_comparison.py +3 -165
  71. package/runtime/python/okstra_ctl/option_votes.py +3 -191
  72. package/runtime/python/okstra_ctl/paths.py +8 -6
  73. package/runtime/python/okstra_ctl/phases/catalog.py +56 -12
  74. package/runtime/python/okstra_ctl/phases/change_impact_analysis/boundary.json +11 -0
  75. package/runtime/python/okstra_ctl/phases/change_impact_analysis/entry.py +39 -0
  76. package/runtime/python/okstra_ctl/{report_html/view_models/change_impact_analysis.py → phases/change_impact_analysis/report.py} +3 -3
  77. package/runtime/python/okstra_ctl/phases/change_impact_analysis/spec.md +26 -0
  78. package/runtime/python/okstra_ctl/phases/change_impact_analysis/validation.py +23 -0
  79. package/runtime/python/okstra_ctl/phases/error_analysis/__init__.py +1 -0
  80. package/runtime/python/okstra_ctl/phases/error_analysis/boundary.json +9 -0
  81. package/runtime/{prompts/profiles/error-analysis.md → python/okstra_ctl/phases/error_analysis/profile.md} +2 -2
  82. package/runtime/python/okstra_ctl/{report_html/view_models/error_analysis.py → phases/error_analysis/report.py} +9 -8
  83. package/runtime/{templates/reports → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis-input.template.md +1 -1
  84. package/runtime/python/okstra_ctl/phases/error_analysis/spec.md +118 -0
  85. package/runtime/python/okstra_ctl/phases/error_analysis/validation.py +241 -0
  86. package/runtime/python/okstra_ctl/phases/feature_analysis/__init__.py +1 -0
  87. package/runtime/python/okstra_ctl/phases/feature_analysis/boundary.json +8 -0
  88. package/runtime/python/okstra_ctl/phases/feature_analysis/entry.py +63 -0
  89. package/runtime/python/okstra_ctl/{report_html/view_models/feature_analysis.py → phases/feature_analysis/report.py} +12 -5
  90. package/runtime/python/okstra_ctl/phases/feature_analysis/spec.md +22 -0
  91. package/runtime/python/okstra_ctl/phases/feature_analysis/validation.py +27 -0
  92. package/runtime/python/okstra_ctl/phases/feature_analysis/wizard.py +95 -0
  93. package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
  94. package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -2
  95. package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
  96. package/runtime/python/okstra_ctl/phases/final_verification/spec.md +1 -1
  97. package/runtime/python/okstra_ctl/phases/implementation/__init__.py +1 -0
  98. package/runtime/python/okstra_ctl/phases/implementation/boundary.json +17 -0
  99. package/runtime/python/okstra_ctl/{implementation_stage.py → phases/implementation/entry.py} +22 -10
  100. package/runtime/{prompts/host-orchestration/implementation.md → python/okstra_ctl/phases/implementation/host-rules.md} +1 -1
  101. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-deliverable.md +1 -1
  102. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-executor.md +4 -3
  103. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-verifier.md +18 -7
  104. package/runtime/{prompts/profiles/implementation.md → python/okstra_ctl/phases/implementation/profile.md} +5 -5
  105. package/runtime/python/okstra_ctl/{report_html/view_models/implementation.py → phases/implementation/report.py} +3 -3
  106. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation/report_assets}/implementation-input.template.md +1 -1
  107. package/runtime/python/okstra_ctl/phases/implementation/spec.md +238 -0
  108. package/runtime/python/okstra_ctl/phases/implementation/validation.py +205 -0
  109. package/runtime/python/okstra_ctl/phases/implementation/wizard.py +39 -0
  110. package/runtime/python/okstra_ctl/phases/implementation_option_selection/__init__.py +1 -0
  111. package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +80 -0
  112. package/runtime/python/okstra_ctl/phases/implementation_option_selection/boundary.json +10 -0
  113. package/runtime/python/okstra_ctl/phases/implementation_option_selection/comparison.py +168 -0
  114. package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +27 -0
  115. package/runtime/{prompts/profiles/implementation-option-selection.md → python/okstra_ctl/phases/implementation_option_selection/profile.md} +3 -3
  116. package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
  117. package/runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md +83 -0
  118. package/runtime/python/okstra_ctl/{implementation_options.py → phases/implementation_option_selection/validation.py} +3 -3
  119. package/runtime/python/okstra_ctl/phases/implementation_option_selection/votes.py +194 -0
  120. package/runtime/python/okstra_ctl/phases/implementation_planning/__init__.py +1 -0
  121. package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +2345 -0
  122. package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +12 -0
  123. package/runtime/python/okstra_ctl/phases/implementation_planning/entry.py +161 -0
  124. package/runtime/python/okstra_ctl/phases/implementation_planning/guidance.py +178 -0
  125. package/runtime/{prompts/lead → python/okstra_ctl/phases/implementation_planning/instructions}/plan-body-verification.md +61 -51
  126. package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +3295 -0
  127. package/runtime/{prompts/profiles/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/profile.md} +74 -25
  128. package/runtime/python/okstra_ctl/phases/implementation_planning/report.py +237 -0
  129. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning-input.template.md +2 -2
  130. package/runtime/python/okstra_ctl/phases/implementation_planning/spec.md +204 -0
  131. package/runtime/python/okstra_ctl/phases/implementation_planning/validation.py +597 -0
  132. package/runtime/python/okstra_ctl/phases/implementation_planning/wizard.py +166 -0
  133. package/runtime/python/okstra_ctl/phases/improvement_discovery/boundary.json +12 -0
  134. package/runtime/python/okstra_ctl/{improvement_lenses.py → phases/improvement_discovery/lenses.py} +1 -6
  135. package/runtime/{prompts/profiles/improvement-discovery.md → python/okstra_ctl/phases/improvement_discovery/profile.md} +5 -5
  136. package/runtime/python/okstra_ctl/{report_html/view_models/improvement_discovery.py → phases/improvement_discovery/report.py} +3 -3
  137. package/runtime/{templates/reports → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery-input.template.md +1 -2
  138. package/runtime/python/okstra_ctl/phases/improvement_discovery/spec.md +29 -0
  139. package/runtime/{validators/validate_improvement_report.py → python/okstra_ctl/phases/improvement_discovery/validation.py} +5 -14
  140. package/runtime/python/okstra_ctl/phases/project_analysis/__init__.py +1 -0
  141. package/runtime/python/okstra_ctl/phases/project_analysis/boundary.json +8 -0
  142. package/runtime/python/okstra_ctl/phases/project_analysis/entry.py +11 -0
  143. package/runtime/python/okstra_ctl/{report_html/view_models/project_analysis.py → phases/project_analysis/report.py} +3 -3
  144. package/runtime/python/okstra_ctl/phases/project_analysis/spec.md +33 -0
  145. package/runtime/python/okstra_ctl/phases/project_analysis/validation.py +55 -0
  146. package/runtime/python/okstra_ctl/phases/release_handoff/__init__.py +1 -0
  147. package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +17 -0
  148. package/runtime/python/okstra_ctl/phases/release_handoff/entry.py +147 -0
  149. package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +446 -0
  150. package/runtime/{prompts/profiles/release-handoff.md → python/okstra_ctl/phases/release_handoff/profile.md} +3 -3
  151. package/runtime/python/okstra_ctl/{report_html/view_models/release_handoff.py → phases/release_handoff/report.py} +3 -3
  152. package/runtime/{templates/reports → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff-input.template.md +1 -1
  153. package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +233 -0
  154. package/runtime/python/okstra_ctl/phases/release_handoff/wizard.py +84 -0
  155. package/runtime/python/okstra_ctl/phases/requirements_discovery/__init__.py +1 -0
  156. package/runtime/python/okstra_ctl/phases/requirements_discovery/boundary.json +9 -0
  157. package/runtime/{prompts/profiles/requirements-discovery.md → python/okstra_ctl/phases/requirements_discovery/profile.md} +2 -3
  158. package/runtime/python/okstra_ctl/{report_html/view_models/requirements_discovery.py → phases/requirements_discovery/report.py} +3 -3
  159. package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +132 -0
  160. package/runtime/{validators/validate_fanout.py → python/okstra_ctl/phases/requirements_discovery/validation.py} +11 -12
  161. package/runtime/python/okstra_ctl/phases/technical_verification/__init__.py +1 -0
  162. package/runtime/python/okstra_ctl/phases/technical_verification/boundary.json +9 -0
  163. package/runtime/python/okstra_ctl/phases/technical_verification/entry.py +100 -0
  164. package/runtime/{prompts/profiles/technical-verification.md → python/okstra_ctl/phases/technical_verification/profile.md} +2 -2
  165. package/runtime/python/okstra_ctl/{report_html/view_models/technical_verification.py → phases/technical_verification/report.py} +2 -2
  166. package/runtime/python/okstra_ctl/phases/technical_verification/spec.md +37 -0
  167. package/runtime/python/okstra_ctl/phases/technical_verification/validation.py +90 -0
  168. package/runtime/python/okstra_ctl/plan_approval.py +70 -0
  169. package/runtime/python/okstra_ctl/plan_items_cli.py +2 -2130
  170. package/runtime/python/okstra_ctl/process_group.py +118 -0
  171. package/runtime/python/okstra_ctl/profile_show.py +3 -3
  172. package/runtime/python/okstra_ctl/render.py +15 -4
  173. package/runtime/python/okstra_ctl/report_assembly.py +28 -92
  174. package/runtime/python/okstra_ctl/report_finalize.py +106 -2
  175. package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
  176. package/runtime/python/okstra_ctl/report_projections.py +1 -36
  177. package/runtime/python/okstra_ctl/report_routing.py +23 -0
  178. package/runtime/python/okstra_ctl/report_synthesis_packet.py +4 -73
  179. package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
  180. package/runtime/python/okstra_ctl/report_views.py +1 -1
  181. package/runtime/python/okstra_ctl/run.py +68 -350
  182. package/runtime/python/okstra_ctl/run_artifact_prune.py +200 -0
  183. package/runtime/python/okstra_ctl/stage_map.py +13 -0
  184. package/runtime/python/okstra_ctl/team.py +108 -9
  185. package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
  186. package/runtime/python/okstra_ctl/wizard/__init__.py +31 -31
  187. package/runtime/python/okstra_ctl/wizard/api.py +18 -0
  188. package/runtime/python/okstra_ctl/wizard/outcome.py +3 -12
  189. package/runtime/python/okstra_ctl/wizard/registry.py +20 -12
  190. package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
  191. package/runtime/python/okstra_ctl/wizard/steps_options.py +8 -0
  192. package/runtime/python/okstra_ctl/wizard/steps_plan.py +10 -263
  193. package/runtime/python/okstra_ctl/wizard/steps_roles.py +2 -1
  194. package/runtime/python/okstra_ctl/work_categories.py +1 -1
  195. package/runtime/python/okstra_ctl/worker_dispatch.py +44 -3
  196. package/runtime/python/okstra_ctl/worker_prompt_contract.py +36 -0
  197. package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -0
  198. package/runtime/python/okstra_ctl/worker_runner.py +21 -3
  199. package/runtime/python/okstra_ctl/workflow.py +26 -143
  200. package/runtime/python/okstra_ctl/write_policy.py +57 -7
  201. package/runtime/python/okstra_project/dirs.py +14 -0
  202. package/runtime/python/okstra_project/resolver.py +2 -1
  203. package/runtime/schemas/execution-manifest-v2.schema.json +2 -1
  204. package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
  205. package/runtime/skills/okstra-code-review/SKILL.md +70 -32
  206. package/runtime/skills/okstra-code-review/references/review-calibration.md +26 -6
  207. package/runtime/skills/okstra-run/SKILL.md +3 -3
  208. package/runtime/templates/manager/view.template.html +18 -1
  209. package/runtime/templates/reports/quick-input.template.md +1 -1
  210. package/runtime/templates/reports/task-brief.template.md +1 -1
  211. package/runtime/validators/validate-brief.py +2 -2
  212. package/runtime/validators/validate-run.py +299 -3940
  213. package/runtime/validators/validate_analysis_report.py +14 -126
  214. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +0 -147
  215. package/runtime/python/okstra_ctl/technical_verification.py +0 -195
  216. /package/runtime/{prompts/profiles/change-impact-analysis.json → python/okstra_ctl/phases/change_impact_analysis/profile.json} +0 -0
  217. /package/runtime/{prompts/profiles/change-impact-analysis.md → python/okstra_ctl/phases/change_impact_analysis/profile.md} +0 -0
  218. /package/runtime/{templates/reports → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis-input.template.md +0 -0
  219. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.html +0 -0
  220. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.md +0 -0
  221. /package/runtime/{prompts/profiles/error-analysis.json → python/okstra_ctl/phases/error_analysis/profile.json} +0 -0
  222. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.html +0 -0
  223. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.md +0 -0
  224. /package/runtime/{prompts/profiles/feature-analysis.json → python/okstra_ctl/phases/feature_analysis/profile.json} +0 -0
  225. /package/runtime/{prompts/profiles/feature-analysis.md → python/okstra_ctl/phases/feature_analysis/profile.md} +0 -0
  226. /package/runtime/{templates/reports → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis-input.template.md +0 -0
  227. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.html +0 -0
  228. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.md +0 -0
  229. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-diff-review.md +0 -0
  230. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-self-check.md +0 -0
  231. /package/runtime/{prompts/profiles/implementation.json → python/okstra_ctl/phases/implementation/profile.json} +0 -0
  232. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.html +0 -0
  233. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.md +0 -0
  234. /package/runtime/{prompts/profiles/implementation-option-selection.json → python/okstra_ctl/phases/implementation_option_selection/profile.json} +0 -0
  235. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.html +0 -0
  236. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.md +0 -0
  237. /package/runtime/{prompts/host-orchestration/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/host-rules.md} +0 -0
  238. /package/runtime/{prompts/profiles/implementation-planning.json → python/okstra_ctl/phases/implementation_planning/profile.json} +0 -0
  239. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.html +0 -0
  240. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.md +0 -0
  241. /package/runtime/{prompts/profiles/improvement-discovery.json → python/okstra_ctl/phases/improvement_discovery/profile.json} +0 -0
  242. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.html +0 -0
  243. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.md +0 -0
  244. /package/runtime/{prompts/profiles/project-analysis.json → python/okstra_ctl/phases/project_analysis/profile.json} +0 -0
  245. /package/runtime/{prompts/profiles/project-analysis.md → python/okstra_ctl/phases/project_analysis/profile.md} +0 -0
  246. /package/runtime/{templates/reports → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis-input.template.md +0 -0
  247. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.html +0 -0
  248. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.md +0 -0
  249. /package/runtime/{prompts/profiles/release-handoff.json → python/okstra_ctl/phases/release_handoff/profile.json} +0 -0
  250. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.html +0 -0
  251. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.md +0 -0
  252. /package/runtime/python/okstra_ctl/{fanout.py → phases/requirements_discovery/fanout.py} +0 -0
  253. /package/runtime/{prompts/profiles/requirements-discovery.json → python/okstra_ctl/phases/requirements_discovery/profile.json} +0 -0
  254. /package/runtime/{templates/reports → python/okstra_ctl/phases/requirements_discovery/report_assets}/fan-out-unit.template.md +0 -0
  255. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.html +0 -0
  256. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.md +0 -0
  257. /package/runtime/{prompts/profiles/technical-verification.json → python/okstra_ctl/phases/technical_verification/profile.json} +0 -0
  258. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.html +0 -0
  259. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.md +0 -0
@@ -6,9 +6,10 @@ description: >-
6
6
  unrelated to an okstra run. The tell is a review request over a diff:
7
7
  "review this stage", "review my branch", "code review", "leave the review
8
8
  in a file". The orchestrator censuses the diff into an explicit worklist,
9
- four parallel reviewers return a verdict for every cell against this
10
- project's coding-preflight rules, and a coverage audit re-dispatches any
11
- gap. NOT for writing a PR body (okstra-pr-gen), starting a run
9
+ one or two reviewers (the user picks) each return a verdict for every cell
10
+ against this project's coding-preflight rules, a coverage audit
11
+ re-dispatches any gap, and the orchestrator settles what the reviewers
12
+ disagree on. NOT for writing a PR body (okstra-pr-gen), starting a run
12
13
  (okstra-run), or inspecting a finished task (okstra-inspect).
13
14
  ---
14
15
 
@@ -79,7 +80,7 @@ okstra code-review target --task-key <taskKey> --stage <N> --project-root <proje
79
80
  okstra code-review target --branch <name> [--base <ref>] --project-root <projectRoot> --text
80
81
  ```
81
82
 
82
- `Status: ready` carries `Project root`, `Mode`, `Worktree path`, `Branch`, `Base commit`, `Head commit`, `Review path`, and `Round`; stage mode adds `Task key`, `Task root`, and `Stage`. Carry every field verbatim into the later steps — none of them is recomputed anywhere below.
83
+ `Status: ready` carries `Project root`, `Mode`, `Worktree path`, `Branch`, `Base commit`, `Head commit`, `Review path`, `Round`, and `Report language`; stage mode adds `Task key`, `Task root`, and `Stage`. Carry every field verbatim into the later steps — none of them is recomputed anywhere below.
83
84
 
84
85
  `Status: error` carries `Failure stage` and `Failure reason`. Report both and stop, unless the Exceptions table names that case.
85
86
 
@@ -95,7 +96,7 @@ pass task manifests, target-CLI JSON, or arbitrary JSON fields to a reviewer.
95
96
 
96
97
  **You never derive the base.** Pass `--base <ref>` only when the user named one; otherwise the CLI resolves it. `baseCommit` is a **ref, not necessarily a commit id** — a caller-supplied `--base` passes through verbatim — so use it as given in `git diff <baseCommit>..<headCommit>` and never present it as "commit `<sha>`".
97
98
 
98
- **Where to run git.** Use `worktreePath` when it is non-empty; otherwise run git in `projectRoot` and read the stage's `branch` ref. An empty `worktreePath` does **not** mean the stage is gone: a completed stage's registry row is `released`, so the field is empty even when the directory is still on disk. Either way the commits are on the branch.
99
+ **Where to run git.** Use `worktreePath` when it is non-empty; otherwise run git in `projectRoot` and read the stage's `branch` ref. An empty `worktreePath` does **not** mean the stage is gone: a completed stage's registry row is `released`, so the field is empty even when the directory is still on disk. Either way the commits are on the branch. With no worktree there is no checked-out tree to read whole files from, so every brief tells the reviewer to read a file at the reviewed commit with `git -C <projectRoot> show <headCommit>:<path>` — never from the project root's working tree, which holds a different commit.
99
100
 
100
101
  **Then show the base and confirm it — branch mode and stage mode alike.** The CLI's answer is a recommendation the user has not seen yet, and a base nobody looked at is how unrelated commits slip into a review unnoticed. Print `baseCommit` verbatim next to `git -C <workdir> log -1 --oneline <baseCommit>` so the commit it names is legible, then ask with a 3-option picker:
101
102
 
@@ -117,43 +118,49 @@ pass task manifests, target-CLI JSON, or arbitrary JSON fields to a reviewer.
117
118
 
118
119
  A large census is never truncated. Report the cell count and confirm before dispatching — a silent cut is a false "I looked at everything" signal.
119
120
 
120
- ## Step 3 — Materialize and dispatch four reviewers in parallel
121
+ ## Step 3 — Materialize and dispatch the reviewers in parallel
121
122
 
122
- Ask the runtime what this operation runs — do not choose the role, the providers, or the reviewer count
123
- here:
123
+ **Ask how many reviewers** with a 3-option picker:
124
+
125
+ 1. `2 reviewers` — **the recommendation**: two different models each review the whole census, and you settle only where they disagree.
126
+ 2. `1 reviewer` — cheaper; you adjudicate every finding it returns.
127
+ 3. `Enter directly` — always last; accept only `1` or `2`.
128
+
129
+ Then ask the runtime what those reviewers run — do not choose the role or the providers here:
124
130
 
125
131
  ```
126
- okstra agent-prompt resolve-operation --operation code-review
132
+ okstra agent-prompt resolve-operation --operation code-review --count <1|2>
127
133
  ```
128
134
 
129
135
  It prints the duty, the role, the reviewer count, and one `slot` line per reviewer carrying that slot's
130
- provider and model. The contract owns those values (`agents/operations/code-review.json`), so a machine
131
- with too few distinct models fails here rather than quietly running fewer reviewers. Dispatch exactly the
132
- slots it prints.
136
+ provider and model. The contract owns those values (`agents/operations/code-review.json`, whose `count` is
137
+ the ceiling), so a machine with too few distinct models fails here rather than quietly running fewer
138
+ reviewers. Dispatch exactly the slots it prints.
133
139
 
134
140
  Every reviewer and later gap-fill is a separate auditable standalone invocation. For each slot, create
135
141
  `.okstra/agent-invocations/code-review/<invocation-id>.instructions.md` from that reviewer's brief, then run
136
- `okstra agent-prompt materialize` with `--purpose code-review`, `--audience <dutyId>`, that slot's
137
- `--provider` and `--model <modelRef>`, and the canonical `.prompt.md` path beside it; the returned
138
- assignment is authoritative. Run `okstra agent-prompt verify` against the returned `metadataPath` before
142
+ `okstra agent-prompt materialize --project-root <projectRoot> --invocation-id <invocation-id> --host-runtime <runtime> --provider <slot provider> --model <slot model> --model-role <role> --audience <duty> --purpose code-review --instruction <instructions-path> --prompt <prompt-path>`,
143
+ copying `role`, `duty`, and the slot's `provider` and `model` verbatim from `resolve-operation` (`--model`
144
+ takes the `provider/model` value the slot line prints). The prompt path is the canonical `.prompt.md` beside
145
+ the instructions file; the returned assignment is authoritative. Run `okstra agent-prompt verify` against the returned `metadataPath` before
139
146
  invoking any model.
140
147
 
141
148
  For a native host call, pass the verified prompt body and `hostModelValue`. For a deterministic provider
142
149
  process, run the provider wrapper `~/.okstra/bin/okstra-<provider>-exec.sh <projectRoot> <modelExecutionValue> <prompt-path>`
143
150
  with the verified prompt path (`okstra worker-dispatch` dispatches only a run manifest's assignments, not a
144
151
  standalone prompt). The wrapper records the provider's output in the prompt path with `.md` replaced by
145
- `.log`. Never substitute one model value for the other. Dispatch the four verified calls in parallel when the host supports
146
- it. Every brief carries:
152
+ `.log`. Never substitute one model value for the other. Dispatch the verified calls in parallel when the host supports
153
+ it. **Every reviewer receives the same brief** — two reviewers are worth their cost only when both look at every cell. Every brief carries:
147
154
 
148
- - the diff, plus the work directory path so the reviewer can read whole files for context
155
+ - the diff, plus how to read whole files at the reviewed commit: the `worktreePath` when it is non-empty, otherwise `git -C <projectRoot> show <headCommit>:<path>`
149
156
  - the project layout in one or two lines (where source, tests, and — if the routing found one — domain / ports / adapters live)
150
- - **its own axis's cell list**, verbatim from the census
151
- - the absolute paths of the packs its axis reads (from step 2's routing)
157
+ - **the whole census** — every cell of all four axes, verbatim
158
+ - the absolute paths of every applied pack (from step 2's routing)
152
159
  - the calibration path, written out in full as Step 2 fixed it — `~/.agents/skills/okstra-code-review/references/review-calibration.md`. The verdict format, the severity points, and the rules for a legitimate `clean` are defined there, not in the brief; a reviewer that cannot open this file cannot return a usable verdict, so never hand it a relative path or a "next to the skill" hint
153
160
 
154
161
  Each axis is **one rule group**, so a cell is `target × <axis>` — never `target × <individual rule>`. The reviewer names the specific rule it found violated inside the verdict's `rule` field, and one cell may carry findings from several rules of its group.
155
162
 
156
- Axis scope — the `Reads` column names that group's rules, and a brief never restates them; the bodies are in the packs:
163
+ Axis scope — each reviewer works all four axes; the `Reads` column names each group's rules, and a brief never restates them; the bodies are in the packs:
157
164
 
158
165
  | Axis | Cell | Reads |
159
166
  |---|---|---|
@@ -172,18 +179,47 @@ review result and cannot contribute a verdict.
172
179
 
173
180
  ## Step 3.5 — Audit the coverage
174
181
 
175
- Diff each reviewer's verified `returnedBody` cells against the slice you handed it. Any cell without a verdict
176
- → dispatch **one gap-fill invocation per axis**, carrying only the missing cells and the same brief. Each
182
+ Diff each reviewer's verified `returnedBody` cells against the census. Any cell without a verdict
183
+ → dispatch **one gap-fill invocation per reviewer**, on that reviewer's slot, carrying only its missing cells and the same brief. Each
177
184
  gap-fill uses a new invocation ID and repeats the full materialize → verify → dispatch → materialize-result →
178
- complete → verify-completion boundary from Step 3. Repeat until every cell of every axis has a verdict.
185
+ complete → verify-completion boundary from Step 3. Repeat until every reviewer has a verdict for every cell.
186
+
187
+ A missing verdict is unfinished work, never an implicit `clean`. Do not start Step 3.6 while a single cell is unaccounted for.
188
+
189
+ ## Step 3.6 — Check every citation
190
+
191
+ Reviewers miscount lines. Pass every finding's `path:line` to one call:
192
+
193
+ ```bash
194
+ okstra code-review check-lines --project-root <projectRoot> --base <baseCommit> --head <headCommit> --cite <path:line> [--cite <path:line> ...]
195
+ ```
196
+
197
+ `ok` keeps the citation. For `not-changed` or `not-in-diff`, find the finding's `snippet` in `git -C <projectRoot> show <headCommit>:<path>`; if it sits on one of the changed lines the output lists, replace the line number with that line and say so in the finding. A finding whose snippet is on no changed line goes to `Rejected` as "cites no changed line". Re-run `check-lines` until every kept citation is `ok`.
198
+
199
+ ## Step 3.7 — Settle the findings
200
+
201
+ Reviewers are wrong in a way a census cannot catch: a claim about code they did not open. What you settle depends on the reviewer count. A `must-fix` or `should-fix` with no `failure` or no `evidence` is rejected as "no failure scenario" in either case — the calibration requires both.
202
+
203
+ **Two reviewers.** Pair the findings first: two findings are the same finding when they cite the same `path:line` and describe the same defect. Then:
204
+
205
+ - **Agreed** — both reviewers report it with the same severity and timing. It stands as reported; you do not adjudicate it.
206
+ - **Graded differently** — both report it, with a different severity or timing. Pick one of the two values after reading the code, and record both values and your reason in the finding. Never pick a third value.
207
+ - **One-sided** — one reviewer reports it and the other returned `clean` for that cell or reported something else. Adjudicate it as below.
208
+
209
+ **One reviewer.** Adjudicate every finding it returns.
210
+
211
+ **Adjudicating** a finding: open each `evidence` location at `headCommit`, plus the definition of every symbol its `failure` depends on, and check the `failure` against that code.
212
+
213
+ - **Confirmed** — the code produces the stated failure. The finding keeps its severity and timing.
214
+ - **Rejected** — the code contradicts the claim (the called function never reads `this`, the value cannot be null there, the branch is unreachable). Move it to `Rejected` with the contradicting `path:line` and one sentence on what it shows.
179
215
 
180
- A missing verdict is unfinished work, never an implicit `clean`. Do not start Step 4 while a single cell is unaccounted for.
216
+ Rejecting is a statement about the code, so it always carries a `path:line`. Never reject for being unconvinced. Apart from choosing between two reviewers' values, never promote, demote, or re-time a finding. Confirmed and agreed `park` findings go to `Parked`, unscored.
181
217
 
182
218
  ## Step 4 — Merge and write
183
219
 
184
220
  1. **Read `references/review-calibration.md`** (next to this file) and follow its report section — you are the one writing the file, and it fixes the Coverage sentence, the per-finding line format, the Score table columns, and the total row. The reviewers were given it for their verdicts; the report obeys it too.
185
- 2. **Dedupe across axes.** The same defect surfaced by two axes stays once, under the rule that explains it best.
186
- 3. **Severity is the reviewer's.** The merge concatenates and dedupes; it never re-grades. If a verdict looks wrong, the brief was wrong — improve the brief for next run and ship this one as returned.
221
+ 2. **Dedupe across axes and reviewers.** The same defect surfaced by two axes or two reviewers stays once, under the rule that explains it best, and each finding says how it was settled: `agreed`, `graded by orchestrator`, or `confirmed by orchestrator`.
222
+ 3. **Severity is the reviewers'; truth is yours.** The merge never re-grades or re-times a finding except by choosing between two reviewers' values in Step 3.7.
187
223
  4. **Write the report to `reviewPath`** with the Write tool (it creates the parent directories). Frontmatter fields, in this order:
188
224
 
189
225
  ```yaml
@@ -192,14 +228,15 @@ taskKey: <task-key> # stage mode
192
228
  branch: <branch> # branch mode
193
229
  stage: <N> # stage mode only
194
230
  round: <round>
231
+ reviewers: [<provider/model>, ...] # the slots Step 3 dispatched
195
232
  baseCommit: <exactly as the CLI returned it>
196
233
  headCommit: <headCommit>
197
234
  packs: [<applied coding-preflight pack paths>]
198
235
  generatedAt: <YYYY-MM-DD HH:MM>
199
236
  ```
200
237
 
201
- Body sections, in this order: `## Coverage`, `## Must-fix`, `## Should-fix`, `## Nits`, `## Score`. Empty severity sections are omitted; `Coverage` and `Score` are always present, and a review with no findings still emits the Score table with a total of 0.
202
- 5. **In the session, print only** the `reviewPath`, the count per severity, and the score total. The file is the deliverable — do not replay the findings in chat.
238
+ Body sections, in this order: `## Coverage`, `## Must-fix`, `## Should-fix`, `## Nits`, `## Parked`, `## Rejected`, `## Score`. Empty sections are omitted; `Coverage` and `Score` are always present, and a review with no confirmed `now` findings still emits the Score table with a total of 0. The score counts confirmed `now` findings only. Write the prose in the `Report language` from Step 1.
239
+ 5. **In the session, print only** the `reviewPath`, the count per severity, the parked and rejected counts, and the score total. The file is the deliverable — do not replay the findings in chat.
203
240
 
204
241
  ## Exceptions
205
242
 
@@ -207,7 +244,7 @@ generatedAt: <YYYY-MM-DD HH:MM>
207
244
  |---|---|
208
245
  | `preflight` reports `Okstra preflight: failed` | retry with `--cwd <dir>`; if that also fails, tell the user to run `/okstra-setup` first and stop |
209
246
  | `unknown command: code-review` | the `okstra` binary predates this skill — tell the user to update it (`npm i -g okstra@latest`) and stop |
210
- | `worktreePath` is empty | not a hard stop and not a missing stage: run git in `projectRoot` against the stage's `branch` ref and continue |
247
+ | `worktreePath` is empty | not a hard stop and not a missing stage: run git in `projectRoot` against the stage's `branch` ref, and have reviewers read whole files with `git -C <projectRoot> show <headCommit>:<path>` |
211
248
  | `baseCommit` is not an ancestor of `headCommit` — `git -C <workdir> rev-list --count <headCommit>..<baseCommit>` returns a **non-zero** count, meaning a rebase or squash rewrote the history the stage was recorded against, and `<baseCommit>..<headCommit>` would drag predecessor work in backwards | code-review is read-only, so do not force a reconcile. Offer two options: review against the branch's current tip, or run `okstra git-reconcile` first and retry |
212
249
  | the diff is empty | dispatch no reviewers; write the "no changes" report to `reviewPath` and stop. It is a normal report, not a free-form note: the same frontmatter, `## Coverage` reading "0 changed files → 0 cells on every axis, 0 files excluded" plus the applied packs, every severity section omitted, and `## Score` carrying the table with its single total row reading 0 |
213
250
  | the census is large | never truncate — report the cell count and confirm before dispatching |
@@ -215,9 +252,10 @@ generatedAt: <YYYY-MM-DD HH:MM>
215
252
 
216
253
  ## Principles
217
254
 
218
- - **Stay in the diff.** Every finding cites a line this diff changed. A cell whose only wart sits on untouched lines verdicts `clean` — pre-existing issues are not this change's problem.
255
+ - **Stay in the diff.** Every finding cites a line this diff changed, and Step 3.6 checks it. A cell whose only wart sits on untouched lines verdicts `clean` — pre-existing issues are not this change's problem.
219
256
  - **Don't manufacture findings.** A census fully verdicted `clean` is a valid, useful result.
220
257
  - **No finding without a fix.** Readability findings carry a pseudocode sketch; naming findings carry a concrete alternative name.
221
258
  - **The census is law.** A reviewer that rebuilds its own worklist reintroduces exactly the run-to-run variance this skill exists to kill.
222
259
  - **Every cell gets a verdict.** `clean` is a result, not an omission; the audit treats a gap as unfinished work.
223
- - **The report prose is Korean.** Paths, identifiers, rule names, and quoted code stay verbatim.
260
+ - **Only a checked claim scores.** A finding reaches the score after its citation is on a changed line and its failure holds against the code; everything else is `Parked` or `Rejected`, with its reason.
261
+ - **The report prose follows `Report language`.** Paths, identifiers, rule names, and quoted code stay verbatim.
@@ -18,11 +18,16 @@ A cell covers its whole rule group, so it can carry several findings from severa
18
18
  rule: DRY
19
19
  line: 42
20
20
  severity: must-fix
21
+ timing: now
21
22
  snippet: `discount = subtotal * 0.15 if tier == "gold" else 0`
23
+ failure: when the gold rate changes in `domain/tiers.py`, this line keeps charging 15% and the two prices disagree.
24
+ evidence: `domain/tiers.py:18`
22
25
  note: The same tier→rate table is already in `domain/tiers.py:18`; a rate change now has two homes. Call the existing lookup instead of re-expressing it here.
23
26
  ```
24
27
 
25
- Fields: `cell` (`target × axis`, exactly as the census wrote it — the axis is the rule group, and there is never one cell per individual rule), `verdict` (`clean` | `finding`), `rule` (the specific rule this finding violates, spelled as its pack spells it; omitted on `clean`), `line` (a line **this diff changed**), `severity`, `snippet` (the quoted changed line), `note` (1–2 sentences: what is wrong plus a concrete fix).
28
+ Fields: `cell` (`target × axis`, exactly as the census wrote it — the axis is the rule group, and there is never one cell per individual rule), `verdict` (`clean` | `finding`), `rule` (the specific rule this finding violates, spelled as its pack spells it; omitted on `clean`), `line` (a line **this diff changed**, numbered at the head commit), `severity`, `timing` (`now` | `park`, below), `snippet` (the quoted changed line, verbatim — the orchestrator locates the finding by it), `failure` (required at `must-fix` and `should-fix`: the input or state that produces the wrong result, and what goes wrong), `evidence` (required at `must-fix` and `should-fix`: every `path:line` you opened to establish the failure — the definitions of the symbols the claim depends on, not only the cited line), `note` (1–2 sentences: what is wrong plus a concrete fix).
29
+
30
+ **Open the definition before you claim its behaviour.** A claim about what a called function, method, or value does — that it reads `this`, throws, mutates its argument, returns `null` — cites that definition in `evidence`. A claim you could not check against its definition is not a finding; it is `clean`. The orchestrator opens every `evidence` location and rejects a finding the code contradicts.
26
31
 
27
32
  There is no length budget. Dropping a real finding to stay brief is the failure this review exists to prevent, and a missing cell is re-dispatched as unfinished work, never read as a clean.
28
33
 
@@ -36,6 +41,15 @@ There is no length budget. Dropping a real finding to stay brief is the failure
36
41
 
37
42
  Grade the defect, not your confidence. If you are not confident, the verdict is `clean` — see the hedge test below.
38
43
 
44
+ **Name the failure.** A `must-fix` or `should-fix` states the input or state that produces the wrong result (`if the header is absent, line 42 throws before the 401 is returned`). Code that works as written is not a defect, however you would have written it differently: alternative structures, defensive guards for states no caller reaches, and "consider extracting / renaming / memoizing" are improvements. An improvement is either `park` or `clean`, never a `now` finding.
45
+
46
+ ## Timing — `now` or `park`
47
+
48
+ - `now` — this change should fix it before it merges: a defect on a changed line, or a rule violation the change introduced.
49
+ - `park` — real, but not this change's to fix: the fix lies outside the diff, or the code is correct and the finding asks for more (a regression test for behaviour that already works, a follow-up refactor). Parked findings are listed in the report and **do not score**.
50
+
51
+ Every finding carries `timing`. When unsure, ask whether merging without the fix leaves this change wrong; if not, it is `park`.
52
+
39
53
  ## When `clean` is the right verdict
40
54
 
41
55
  `clean` is a result, not a concession. Return it when:
@@ -62,19 +76,25 @@ Loose typing in test files (`any`, dynamic casts, untyped fixtures) is a **typin
62
76
 
63
77
  ## The report
64
78
 
65
- Merged by the orchestrator, written to `reviewPath`. Sections, in this order, empty ones omitted except `Coverage` and `Score`:
79
+ Merged and adjudicated by the orchestrator, written to `reviewPath`. Sections, in this order, empty ones omitted except `Coverage` and `Score`:
66
80
 
67
81
  ```
68
82
  ## Coverage
69
83
  ## Must-fix
70
84
  ## Should-fix
71
85
  ## Nits
86
+ ## Parked
87
+ ## Rejected
72
88
  ## Score
73
89
  ```
74
90
 
75
- - **Coverage** — one or two lines: N changed files → S `structural` / F `semantic` / T `state-and-tests` / G `general` cells, all verdicted; M files excluded with reasons; the applied packs, and any pack that was unavailable. The four counts are cell counts at the census's granularity — one cell per target per axis.
76
- - **Findings** — each one opens with `` `path/to/file.py:42` `` + the verdict's `rule` name + severity + points, then the snippet as a blockquote, then the 1–2 sentence note with its fix.
77
- - **Score** — every finding gets a row, and the table is emitted even when there are none, with a single total row reading 0:
91
+ - **Must-fix / Should-fix / Nits** — confirmed `now` findings only.
92
+ - **Parked** — `park` findings, with their severity, not scored.
93
+ - **Rejected** — findings the orchestrator's adjudication disproved or that cite no changed line: the reviewer's claim in one line, then the contradicting `path:line` and what it shows. Not scored.
94
+
95
+ - **Coverage** — two or three lines: the reviewers (`provider/model`, one or two); N changed files → S `structural` / F `semantic` / T `state-and-tests` / G `general` cells, all verdicted by every reviewer; M files excluded with reasons; the applied packs, and any pack that was unavailable; and how the findings were settled — agreed, graded by the orchestrator, confirmed by the orchestrator, rejected. The four cell counts are at the census's granularity — one cell per target per axis.
96
+ - **Findings** — each one opens with `` `path/to/file.py:42` `` + the verdict's `rule` name + severity + points, then the snippet as a blockquote, then the 1–2 sentence note with its fix. Its note then says how it was settled: `agreed`, `graded by orchestrator` (with both reviewers' values), or `confirmed by orchestrator`.
97
+ - **Score** — every confirmed `now` finding gets a row, and the table is emitted even when there are none, with a single total row reading 0:
78
98
 
79
99
  ```
80
100
  | # | Location | Rule | Severity | Points |
@@ -83,4 +103,4 @@ Merged by the orchestrator, written to `reviewPath`. Sections, in this order, em
83
103
  | | | | **Total** | **3** |
84
104
  ```
85
105
 
86
- The report's prose is written in Korean. Paths, identifiers, rule names, and quoted code stay verbatim.
106
+ The report's prose is written in the `Report language` the target CLI returned (the project's `reportLanguage`). Paths, identifiers, rule names, and quoted code stay verbatim.
@@ -261,9 +261,9 @@ okstra config set pr-template-path "<value>" --scope global
261
261
 
262
262
  If an action has an unknown `command`, `key`, or `scope`, stop and report the wizard output instead of inventing a command.
263
263
 
264
- Before rendering the next phase's bundle — and between worker rounds within a phase (reverify/critic/gapverify batches), after you have collected that round's results and token usage and before you dispatch the next round — close the panes of the dispatches that finished in the prior round so they do not accumulate, in two passes. First count: `okstra team reclaim --project-root <projectRoot> --run-manifest <RUN_MANIFEST_PATH> --dry-run` closes nothing and prints one `<paneId>\t<kind>` line per pane it would close — count those lines as `<n>`. Then run the same command **without** `--dry-run` to close them, and emit `PROGRESS: phase-batch-cleanup panes=<n>` with that count at the batch boundary. The command reads each dispatch's recorded status, so an in-progress worker keeps its pane whichever moment you call it. It closes only the panes okstra opened and recorded — a pane the harness opened for its own teammate carries no recorded id and is not okstra's to close. `shutdown_request` alone only idles the agent and frees no pane, so it stays part of the run-end sequence for roster/token hygiene. A `cli-wrapper` run holds no pane at all, so `<n>` is `0` — still emit the checkpoint.
264
+ Before rendering the next phase's bundle — and between worker rounds within a phase (reverify/critic/gapverify batches), after you have collected that round's results and token usage and before you dispatch the next round — close the panes of the dispatches that finished in the prior round so they do not accumulate: `okstra team reclaim --project-root <projectRoot> --run-manifest <RUN_MANIFEST_PATH>` closes them, records `phase-batch-cleanup panes=<n>` with the number it closed, and prints that `PROGRESS:` line last — emit it as printed and do not call `okstra lead-progress append` for it. The command reads each dispatch's recorded status, so an in-progress worker keeps its pane whichever moment you call it. It closes only the panes okstra opened and recorded — a pane the harness opened for its own teammate carries no recorded id and is not okstra's to close. `shutdown_request` alone only idles the agent and frees no pane, so it stays part of the run-end sequence for roster/token hygiene. A `cli-wrapper` run holds no pane at all and `team reclaim` refuses it, so record the checkpoint there with `okstra lead-progress append … --phase phase-batch-cleanup --field panes=0`.
265
265
 
266
- Before you ask the user for any approval, clarification, or decision after workers have been dispatched, run the same two passes first: `okstra team reclaim … --dry-run` to count the panes, then the same command without `--dry-run` to close them, emit `PROGRESS: phase-gate-cleanup panes=<n>`, and `TaskStop` each completed worker. A `TaskStop` by itself idles the task but leaves the pane open — the `team reclaim` call is what closes it. This keeps a user gate from being shown while finished worker panes remain; in-progress dispatches keep their panes. Then follow `prompts/lead/okstra-lead-contract.md` "User confirmation before an approval blocker": read cited plan items, worker findings, and files before asking, and ask in the user's language with each option's outcome.
266
+ Before you ask the user for any approval, clarification, or decision after workers have been dispatched, run `okstra team reclaim … --gate` first: it closes the finished panes and prints `PROGRESS: phase-gate-cleanup panes=<n>` for you to emit, without recording a batch cleanup. Then `TaskStop` each completed worker. A `TaskStop` by itself idles the task but leaves the pane open — the `team reclaim` call is what closes it. This keeps a user gate from being shown while finished worker panes remain; in-progress dispatches keep their panes. Then follow `prompts/lead/okstra-lead-contract.md` "User confirmation before an approval blocker": read cited plan items, worker findings, and files before asking, and ask in the user's language with each option's outcome.
267
267
 
268
268
  Build the `okstra render-bundle` invocation from `outcome.renderArgv`, passing every token verbatim and in order (including empty strings — they are intentional `use phase default` markers).
269
269
 
@@ -428,7 +428,7 @@ If the anchor (`implementation_base_commit`) is reported unresolvable, run the s
428
428
  Because of the dependency closure, the chain queue **may include a stage that another implementation run has occupied as started/reserved.** That stage's `render-bundle` is rejected with `--stage N already in progress or reserved by another run` (StageTargetError). This is **not** an exception gate needing human judgment but a "next stage not yet ready" situation. On this rejection, **terminate the chain normally** and report the remaining queue to the user (e.g. `remaining queue: stage 4, 5 — resume with okstra-run after occupancy is released`). This is a different branch from the exception gate below (data corruption·concurrent-occupancy conflict confirmation).
429
429
 
430
430
  ### Stage ended FAIL — stop the queue and report (not an exception gate)
431
- When a stage's synthesised verdict is `FAIL`, Phase 6 writes no carry sidecar and appends a `status:"failed"` row in place of `done` (`prompts/profiles/_implementation-deliverable.md` "Lead post-stage persistence"). **Stop the queue at that stage** and report the failed stage, its report path, and the remaining queue (e.g. `stage 1 FAIL — remaining queue: stage 2, 3, 5; re-enter with okstra-run --stage 1 after the fix`). Do **not** continue to the next stage even when that stage is dependency-independent: an unattended chain that keeps building past a confirmed regression stacks later work on top of it. The `failed` row releases the stage's occupancy, so `--stage <N>` re-enters the same stage on its preserved worktree and branch — there is nothing to unblock by hand.
431
+ When a stage's synthesised verdict is `FAIL`, Phase 6 writes no carry sidecar and appends a `status:"failed"` row in place of `done` (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md` "Lead post-stage persistence"). **Stop the queue at that stage** and report the failed stage, its report path, and the remaining queue (e.g. `stage 1 FAIL — remaining queue: stage 2, 3, 5; re-enter with okstra-run --stage 1 after the fix`). Do **not** continue to the next stage even when that stage is dependency-independent: an unattended chain that keeps building past a confirmed regression stacks later work on top of it. The `failed` row releases the stage's occupancy, so `--stage <N>` re-enters the same stage on its preserved worktree and branch — there is nothing to unblock by hand.
432
432
 
433
433
  ### Exception gate during chaining
434
434
  If `render-bundle` raises Step 5's concurrent-run conflict detection (concurrent-run branch) or git stale-SHA reconciliation (git-reconcile branch), **stop the chain at that stage** and present the gate to the user exactly as Step 5 prescribes. Once the user resolves the gate, resume the chain in place (continue with the remaining queue). Data corruption·concurrent-occupancy conflicts are confirmed by a human — this is the safety boundary of unattended chaining. (Unlike the "not ready" rejection above, these two branches do not discard the queue; they wait for user resolution.)
@@ -59,9 +59,26 @@ h3 { font-size: 15px; margin: 0; }
59
59
  table { width: 100%; border-collapse: collapse; }
60
60
  th, td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
61
61
  th { color: var(--muted); font-weight: 600; font-size: 12px; white-space: nowrap; }
62
- .wrap { display: inline-block; min-width: 220px; }
63
62
  code.id { white-space: nowrap; word-break: normal; }
64
63
  code { font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-all; }
64
+ .children table { table-layout: fixed; }
65
+ .children th:nth-child(1) { width: 23%; }
66
+ .children th:nth-child(2) { width: 22%; }
67
+ .children td { padding-top: 14px; padding-bottom: 14px; overflow-wrap: anywhere; }
68
+ .child-ticket { display: block; margin-bottom: 4px; }
69
+ code.child-key { word-break: normal; }
70
+ .child-status { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 10px; margin: 8px 0 0; font-size: 12px; }
71
+ .child-status dt { color: var(--muted); }
72
+ .child-status dd { margin: 0; }
73
+ .child-assignment { line-height: 1.65; }
74
+ .child-links { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 10px; font-size: 12px; }
75
+ .child-error { color: var(--blocked); margin: 8px 0 0; font-size: 12px; }
76
+ @media (max-width: 700px) {
77
+ .children table, .children tbody, .children tr, .children td { display: block; width: 100%; }
78
+ .children thead { display: none; }
79
+ .children tr { padding: 12px 0; border-bottom: 1px solid var(--line); }
80
+ .children td { padding: 6px 0; border: 0; }
81
+ }
65
82
  .chip {
66
83
  display: inline-block;
67
84
  padding: 1px 8px;
@@ -52,7 +52,7 @@ taskType: "{{FM_TASK_TYPE}}"
52
52
  > If left blank, any changes beyond the explicit requirements of the input will be treated as out of scope by default.
53
53
  > Any exclusions that appear necessary will be recorded only as follow-up recommendations in the final report, and no further action will be taken.
54
54
 
55
- **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `validators/validate_improvement_report.py` checks that one.
55
+ **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `scripts/okstra_ctl/phases/improvement_discovery/validation.py` checks that one.
56
56
 
57
57
  ## Config and Deployment References
58
58
 
@@ -95,7 +95,7 @@ taskType: "{{FM_TASK_TYPE}}"
95
95
 
96
96
  > Workers MUST NOT expand into items listed here. If a worker believes an excluded item must be addressed to satisfy the requirement, the worker records it as a recommended follow-up task in the final report and stops — it does not silently include the work. If this section is left empty, workers treat any change beyond what `Request Summary` and `Current Context` explicitly demand as out of scope by default.
97
97
 
98
- **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `validators/validate_improvement_report.py` checks that one.
98
+ **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `scripts/okstra_ctl/phases/improvement_discovery/validation.py` checks that one.
99
99
 
100
100
  ## Configuration References and Expected Values
101
101
 
@@ -32,7 +32,7 @@ Checks performed per brief file:
32
32
  10. `scope` is one of {reporter-input, codebase} (absent ⇒ reporter-input).
33
33
  11. codebase-scan variant (`scope: codebase`): the Scan Scope section is
34
34
  non-empty and Priority Lenses lists 1–4 values from the lens whitelist
35
- (`scripts/okstra_ctl/improvement_lenses.py` SSOT).
35
+ (`scripts/okstra_ctl/phases/improvement_discovery/lenses.py` SSOT).
36
36
  12. When present, `Related Task Graph` is a markdown table with the canonical
37
37
  columns and relation/direction values from the okstra-brief-gen contract.
38
38
  13. The requirement/objective section `## Desired Outcome` (required in every
@@ -70,7 +70,7 @@ for _ssot_dir in (_VALIDATORS_DIR.parent / "scripts", _VALIDATORS_DIR.parent / "
70
70
  if _ssot_dir.is_dir() and str(_ssot_dir) not in sys.path:
71
71
  sys.path.insert(0, str(_ssot_dir))
72
72
 
73
- from okstra_ctl.improvement_lenses import (
73
+ from okstra_ctl.phases.improvement_discovery.lenses import (
74
74
  LENSES,
75
75
  MAX_PRIORITY_LENSES,
76
76
  MIN_PRIORITY_LENSES,