okstra 0.205.1 → 0.206.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +2 -2
  2. package/dist/commands/lifecycle/install.mjs +2 -1
  3. package/dist/commands/lifecycle/install.mjs.map +1 -1
  4. package/docs/architecture.md +16 -16
  5. package/docs/cli.md +4 -4
  6. package/docs/contributor-change-matrix.md +3 -2
  7. package/docs/performance-improvement-plan-v2.md +1 -1
  8. package/docs/project-structure-overview.md +45 -21
  9. package/package.json +2 -3
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/bin/okstra-spawn-followups.py +2 -2
  12. package/runtime/prompts/launch.template.md +1 -1
  13. package/runtime/prompts/lead/context-loader.md +1 -1
  14. package/runtime/prompts/lead/convergence.md +3 -3
  15. package/runtime/prompts/lead/okstra-lead-contract.md +14 -55
  16. package/runtime/prompts/lead/phase-routing.md +82 -0
  17. package/runtime/prompts/lead/report-writer.md +2 -2
  18. package/runtime/prompts/lead/team-contract.md +1 -1
  19. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  20. package/runtime/prompts/profiles/_common-contract.md +1 -1
  21. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  22. package/runtime/prompts/profiles/forbidden-actions.json +0 -94
  23. package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
  24. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +10 -1
  25. package/runtime/python/okstra_ctl/analysis_inputs.py +0 -39
  26. package/runtime/python/okstra_ctl/analysis_scope.py +31 -0
  27. package/runtime/python/okstra_ctl/asset_roots.py +19 -0
  28. package/runtime/python/okstra_ctl/consumers.py +12 -0
  29. package/runtime/python/okstra_ctl/contract_graph.py +75 -10
  30. package/runtime/python/okstra_ctl/dispatch_state.py +22 -0
  31. package/runtime/python/okstra_ctl/doctor.py +15 -4
  32. package/runtime/python/okstra_ctl/execution_mutation_audit.py +27 -1
  33. package/runtime/python/okstra_ctl/handoff.py +11 -466
  34. package/runtime/python/okstra_ctl/handoff_error.py +5 -0
  35. package/runtime/python/okstra_ctl/implementation_direction.py +9 -485
  36. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +8 -1
  37. package/runtime/python/okstra_ctl/next_phase.py +2 -2
  38. package/runtime/python/okstra_ctl/option_comparison.py +3 -165
  39. package/runtime/python/okstra_ctl/option_votes.py +3 -191
  40. package/runtime/python/okstra_ctl/paths.py +22 -6
  41. package/runtime/python/okstra_ctl/phases/__init__.py +4 -0
  42. package/runtime/python/okstra_ctl/phases/catalog.py +260 -0
  43. package/runtime/python/okstra_ctl/phases/change_impact_analysis/boundary.json +11 -0
  44. package/runtime/python/okstra_ctl/phases/change_impact_analysis/entry.py +39 -0
  45. package/runtime/python/okstra_ctl/{report_html/view_models/change_impact_analysis.py → phases/change_impact_analysis/report.py} +3 -3
  46. package/runtime/python/okstra_ctl/phases/change_impact_analysis/spec.md +26 -0
  47. package/runtime/python/okstra_ctl/phases/change_impact_analysis/validation.py +23 -0
  48. package/runtime/python/okstra_ctl/phases/error_analysis/__init__.py +1 -0
  49. package/runtime/python/okstra_ctl/phases/error_analysis/boundary.json +9 -0
  50. package/runtime/{prompts/profiles/error-analysis.md → python/okstra_ctl/phases/error_analysis/profile.md} +2 -2
  51. package/runtime/python/okstra_ctl/{report_html/view_models/error_analysis.py → phases/error_analysis/report.py} +9 -8
  52. package/runtime/{templates/reports → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis-input.template.md +1 -1
  53. package/{docs/task-process/error-analysis.md → runtime/python/okstra_ctl/phases/error_analysis/spec.md} +22 -7
  54. package/runtime/python/okstra_ctl/phases/error_analysis/validation.py +241 -0
  55. package/runtime/python/okstra_ctl/phases/feature_analysis/__init__.py +1 -0
  56. package/runtime/python/okstra_ctl/phases/feature_analysis/boundary.json +8 -0
  57. package/runtime/python/okstra_ctl/phases/feature_analysis/entry.py +63 -0
  58. package/runtime/python/okstra_ctl/{report_html/view_models/feature_analysis.py → phases/feature_analysis/report.py} +12 -5
  59. package/runtime/python/okstra_ctl/phases/feature_analysis/spec.md +22 -0
  60. package/runtime/python/okstra_ctl/phases/feature_analysis/validation.py +27 -0
  61. package/runtime/python/okstra_ctl/phases/feature_analysis/wizard.py +95 -0
  62. package/runtime/python/okstra_ctl/phases/final_verification/__init__.py +4 -0
  63. package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
  64. package/runtime/python/okstra_ctl/phases/final_verification/entry.py +166 -0
  65. package/runtime/{prompts/profiles/final-verification.md → python/okstra_ctl/phases/final_verification/profile.md} +5 -5
  66. package/runtime/python/okstra_ctl/{report_html/view_models/final_verification.py → phases/final_verification/report.py} +12 -3
  67. package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
  68. package/{docs/task-process/final-verification.md → runtime/python/okstra_ctl/phases/final_verification/spec.md} +42 -25
  69. package/runtime/python/okstra_ctl/phases/final_verification/target.py +296 -0
  70. package/runtime/python/okstra_ctl/phases/final_verification/validation.py +190 -0
  71. package/runtime/python/okstra_ctl/phases/final_verification/wizard.py +38 -0
  72. package/runtime/python/okstra_ctl/phases/implementation/__init__.py +1 -0
  73. package/runtime/python/okstra_ctl/phases/implementation/boundary.json +17 -0
  74. package/runtime/python/okstra_ctl/{implementation_stage.py → phases/implementation/entry.py} +22 -10
  75. package/runtime/{prompts/host-orchestration/implementation.md → python/okstra_ctl/phases/implementation/host-rules.md} +1 -1
  76. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-deliverable.md +1 -1
  77. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-executor.md +4 -3
  78. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-verifier.md +4 -4
  79. package/runtime/{prompts/profiles/implementation.md → python/okstra_ctl/phases/implementation/profile.md} +5 -5
  80. package/runtime/python/okstra_ctl/{report_html/view_models/implementation.py → phases/implementation/report.py} +3 -3
  81. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation/report_assets}/implementation-input.template.md +1 -1
  82. package/{docs/task-process/implementation.md → runtime/python/okstra_ctl/phases/implementation/spec.md} +20 -8
  83. package/runtime/python/okstra_ctl/phases/implementation/validation.py +205 -0
  84. package/runtime/python/okstra_ctl/phases/implementation/wizard.py +39 -0
  85. package/runtime/python/okstra_ctl/phases/implementation_option_selection/__init__.py +1 -0
  86. package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +80 -0
  87. package/runtime/python/okstra_ctl/phases/implementation_option_selection/boundary.json +10 -0
  88. package/runtime/python/okstra_ctl/phases/implementation_option_selection/comparison.py +168 -0
  89. package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +27 -0
  90. package/runtime/{prompts/profiles/implementation-option-selection.md → python/okstra_ctl/phases/implementation_option_selection/profile.md} +2 -2
  91. package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
  92. package/{docs/task-process/implementation-option-selection.md → runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md} +20 -7
  93. package/runtime/python/okstra_ctl/{implementation_options.py → phases/implementation_option_selection/validation.py} +3 -3
  94. package/runtime/python/okstra_ctl/phases/implementation_option_selection/votes.py +194 -0
  95. package/runtime/python/okstra_ctl/phases/implementation_planning/__init__.py +1 -0
  96. package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +2345 -0
  97. package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +12 -0
  98. package/runtime/python/okstra_ctl/phases/implementation_planning/entry.py +161 -0
  99. package/runtime/python/okstra_ctl/phases/implementation_planning/guidance.py +178 -0
  100. package/runtime/{prompts/lead → python/okstra_ctl/phases/implementation_planning/instructions}/plan-body-verification.md +61 -51
  101. package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +3295 -0
  102. package/runtime/{prompts/profiles/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/profile.md} +74 -25
  103. package/runtime/python/okstra_ctl/phases/implementation_planning/report.py +237 -0
  104. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning-input.template.md +2 -2
  105. package/{docs/task-process/implementation-planning.md → runtime/python/okstra_ctl/phases/implementation_planning/spec.md} +30 -6
  106. package/runtime/python/okstra_ctl/phases/implementation_planning/validation.py +597 -0
  107. package/runtime/python/okstra_ctl/phases/implementation_planning/wizard.py +166 -0
  108. package/runtime/python/okstra_ctl/phases/improvement_discovery/boundary.json +12 -0
  109. package/runtime/python/okstra_ctl/{improvement_lenses.py → phases/improvement_discovery/lenses.py} +1 -6
  110. package/runtime/{prompts/profiles/improvement-discovery.md → python/okstra_ctl/phases/improvement_discovery/profile.md} +5 -5
  111. package/runtime/python/okstra_ctl/{report_html/view_models/improvement_discovery.py → phases/improvement_discovery/report.py} +3 -3
  112. package/runtime/{templates/reports → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery-input.template.md +1 -2
  113. package/runtime/python/okstra_ctl/phases/improvement_discovery/spec.md +29 -0
  114. package/runtime/{validators/validate_improvement_report.py → python/okstra_ctl/phases/improvement_discovery/validation.py} +5 -14
  115. package/runtime/python/okstra_ctl/phases/project_analysis/__init__.py +1 -0
  116. package/runtime/python/okstra_ctl/phases/project_analysis/boundary.json +8 -0
  117. package/runtime/python/okstra_ctl/phases/project_analysis/entry.py +11 -0
  118. package/runtime/python/okstra_ctl/{report_html/view_models/project_analysis.py → phases/project_analysis/report.py} +3 -3
  119. package/runtime/python/okstra_ctl/phases/project_analysis/spec.md +33 -0
  120. package/runtime/python/okstra_ctl/phases/project_analysis/validation.py +55 -0
  121. package/runtime/python/okstra_ctl/phases/release_handoff/__init__.py +1 -0
  122. package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +17 -0
  123. package/runtime/python/okstra_ctl/phases/release_handoff/entry.py +147 -0
  124. package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +446 -0
  125. package/runtime/{prompts/profiles/release-handoff.md → python/okstra_ctl/phases/release_handoff/profile.md} +3 -3
  126. package/runtime/python/okstra_ctl/{report_html/view_models/release_handoff.py → phases/release_handoff/report.py} +3 -3
  127. package/runtime/{templates/reports → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff-input.template.md +1 -1
  128. package/{docs/task-process/release-handoff.md → runtime/python/okstra_ctl/phases/release_handoff/spec.md} +22 -9
  129. package/runtime/python/okstra_ctl/phases/release_handoff/wizard.py +84 -0
  130. package/runtime/python/okstra_ctl/phases/requirements_discovery/__init__.py +1 -0
  131. package/runtime/python/okstra_ctl/phases/requirements_discovery/boundary.json +9 -0
  132. package/runtime/{prompts/profiles/requirements-discovery.md → python/okstra_ctl/phases/requirements_discovery/profile.md} +2 -3
  133. package/runtime/python/okstra_ctl/{report_html/view_models/requirements_discovery.py → phases/requirements_discovery/report.py} +3 -3
  134. package/{docs/task-process/requirements-discovery.md → runtime/python/okstra_ctl/phases/requirements_discovery/spec.md} +25 -6
  135. package/runtime/{validators/validate_fanout.py → python/okstra_ctl/phases/requirements_discovery/validation.py} +11 -12
  136. package/runtime/python/okstra_ctl/phases/technical_verification/__init__.py +1 -0
  137. package/runtime/python/okstra_ctl/phases/technical_verification/boundary.json +9 -0
  138. package/runtime/python/okstra_ctl/phases/technical_verification/entry.py +100 -0
  139. package/runtime/{prompts/profiles/technical-verification.md → python/okstra_ctl/phases/technical_verification/profile.md} +1 -1
  140. package/runtime/python/okstra_ctl/{report_html/view_models/technical_verification.py → phases/technical_verification/report.py} +2 -2
  141. package/runtime/python/okstra_ctl/phases/technical_verification/spec.md +37 -0
  142. package/runtime/python/okstra_ctl/phases/technical_verification/validation.py +90 -0
  143. package/runtime/python/okstra_ctl/plan_approval.py +70 -0
  144. package/runtime/python/okstra_ctl/plan_items_cli.py +2 -2130
  145. package/runtime/python/okstra_ctl/profile_show.py +9 -3
  146. package/runtime/python/okstra_ctl/render.py +9 -2
  147. package/runtime/python/okstra_ctl/render_final_report.py +3 -2
  148. package/runtime/python/okstra_ctl/report_assembly.py +14 -93
  149. package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
  150. package/runtime/python/okstra_ctl/report_html/render.py +3 -2
  151. package/runtime/python/okstra_ctl/report_html/router.py +9 -33
  152. package/runtime/python/okstra_ctl/report_projections.py +1 -36
  153. package/runtime/python/okstra_ctl/report_routing.py +23 -0
  154. package/runtime/python/okstra_ctl/report_synthesis_packet.py +4 -73
  155. package/runtime/python/okstra_ctl/report_template_loader.py +35 -0
  156. package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
  157. package/runtime/python/okstra_ctl/report_views.py +18 -2
  158. package/runtime/python/okstra_ctl/run.py +113 -503
  159. package/runtime/python/okstra_ctl/stage_map.py +13 -0
  160. package/runtime/python/okstra_ctl/stage_targets.py +9 -286
  161. package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
  162. package/runtime/python/okstra_ctl/user_response.py +199 -4
  163. package/runtime/python/okstra_ctl/verification_target.py +1 -1
  164. package/runtime/python/okstra_ctl/wizard/__init__.py +31 -31
  165. package/runtime/python/okstra_ctl/wizard/api.py +18 -0
  166. package/runtime/python/okstra_ctl/wizard/outcome.py +3 -12
  167. package/runtime/python/okstra_ctl/wizard/registry.py +20 -12
  168. package/runtime/python/okstra_ctl/wizard/state.py +6 -2
  169. package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
  170. package/runtime/python/okstra_ctl/wizard/steps_plan.py +27 -278
  171. package/runtime/python/okstra_ctl/wizard/steps_roles.py +2 -1
  172. package/runtime/python/okstra_ctl/work_categories.py +1 -1
  173. package/runtime/python/okstra_ctl/worker_prompt_contract.py +36 -0
  174. package/runtime/python/okstra_ctl/workflow.py +26 -143
  175. package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
  176. package/runtime/skills/okstra-run/SKILL.md +1 -1
  177. package/runtime/skills/okstra-user-response/SKILL.md +23 -4
  178. package/runtime/templates/reports/quick-input.template.md +1 -1
  179. package/runtime/templates/reports/task-brief.template.md +1 -1
  180. package/runtime/validators/validate-brief.py +2 -2
  181. package/runtime/validators/validate-run.py +287 -4091
  182. package/runtime/validators/validate_analysis_report.py +14 -126
  183. package/docs/task-process/README.md +0 -82
  184. package/docs/task-process/common-flow.md +0 -173
  185. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +0 -147
  186. package/runtime/python/okstra_ctl/technical_verification.py +0 -195
  187. /package/runtime/{prompts/profiles/change-impact-analysis.json → python/okstra_ctl/phases/change_impact_analysis/profile.json} +0 -0
  188. /package/runtime/{prompts/profiles/change-impact-analysis.md → python/okstra_ctl/phases/change_impact_analysis/profile.md} +0 -0
  189. /package/runtime/{templates/reports → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis-input.template.md +0 -0
  190. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.html +0 -0
  191. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.md +0 -0
  192. /package/runtime/{prompts/profiles/error-analysis.json → python/okstra_ctl/phases/error_analysis/profile.json} +0 -0
  193. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.html +0 -0
  194. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.md +0 -0
  195. /package/runtime/{prompts/profiles/feature-analysis.json → python/okstra_ctl/phases/feature_analysis/profile.json} +0 -0
  196. /package/runtime/{prompts/profiles/feature-analysis.md → python/okstra_ctl/phases/feature_analysis/profile.md} +0 -0
  197. /package/runtime/{templates/reports → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis-input.template.md +0 -0
  198. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.html +0 -0
  199. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.md +0 -0
  200. /package/runtime/{prompts/profiles/final-verification.json → python/okstra_ctl/phases/final_verification/profile.json} +0 -0
  201. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/final_verification/report_assets}/final-verification.template.html +0 -0
  202. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/final_verification/report_assets}/final-verification.template.md +0 -0
  203. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-diff-review.md +0 -0
  204. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-self-check.md +0 -0
  205. /package/runtime/{prompts/profiles/implementation.json → python/okstra_ctl/phases/implementation/profile.json} +0 -0
  206. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.html +0 -0
  207. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.md +0 -0
  208. /package/runtime/{prompts/profiles/implementation-option-selection.json → python/okstra_ctl/phases/implementation_option_selection/profile.json} +0 -0
  209. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.html +0 -0
  210. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.md +0 -0
  211. /package/runtime/{prompts/host-orchestration/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/host-rules.md} +0 -0
  212. /package/runtime/{prompts/profiles/implementation-planning.json → python/okstra_ctl/phases/implementation_planning/profile.json} +0 -0
  213. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.html +0 -0
  214. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.md +0 -0
  215. /package/runtime/{prompts/profiles/improvement-discovery.json → python/okstra_ctl/phases/improvement_discovery/profile.json} +0 -0
  216. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.html +0 -0
  217. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.md +0 -0
  218. /package/runtime/{prompts/profiles/project-analysis.json → python/okstra_ctl/phases/project_analysis/profile.json} +0 -0
  219. /package/runtime/{prompts/profiles/project-analysis.md → python/okstra_ctl/phases/project_analysis/profile.md} +0 -0
  220. /package/runtime/{templates/reports → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis-input.template.md +0 -0
  221. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.html +0 -0
  222. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.md +0 -0
  223. /package/runtime/{prompts/profiles/release-handoff.json → python/okstra_ctl/phases/release_handoff/profile.json} +0 -0
  224. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.html +0 -0
  225. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.md +0 -0
  226. /package/runtime/python/okstra_ctl/{fanout.py → phases/requirements_discovery/fanout.py} +0 -0
  227. /package/runtime/{prompts/profiles/requirements-discovery.json → python/okstra_ctl/phases/requirements_discovery/profile.json} +0 -0
  228. /package/runtime/{templates/reports → python/okstra_ctl/phases/requirements_discovery/report_assets}/fan-out-unit.template.md +0 -0
  229. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.html +0 -0
  230. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.md +0 -0
  231. /package/runtime/{prompts/profiles/technical-verification.json → python/okstra_ctl/phases/technical_verification/profile.json} +0 -0
  232. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.html +0 -0
  233. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.md +0 -0
@@ -15,6 +15,16 @@ for _ssot_dir in (_VALIDATORS_DIR.parent / "scripts", _VALIDATORS_DIR.parent / "
15
15
  sys.path.insert(0, str(_ssot_dir))
16
16
 
17
17
  from okstra_ctl.analysis_inputs import ANALYSIS_TASK_TYPES
18
+ from okstra_ctl.phases.change_impact_analysis.validation import (
19
+ EVIDENCE_COLLECTIONS as CHANGE_IMPACT_EVIDENCE_COLLECTIONS,
20
+ validate_change_impact_semantics,
21
+ )
22
+ from okstra_ctl.phases.feature_analysis.validation import (
23
+ EVIDENCE_COLLECTIONS as FEATURE_EVIDENCE_COLLECTIONS,
24
+ _validate_feature_semantics,
25
+ )
26
+ from okstra_ctl.analysis_scope import _normalized_project_path, _path_is_included
27
+ from okstra_ctl.phases.project_analysis.validation import validate_project_semantics
18
28
  from okstra_ctl.final_report_paths import final_report_data_path
19
29
  from okstra_ctl.paths import RunRef
20
30
  from okstra_ctl.report_views import analysis_review_context
@@ -35,19 +45,8 @@ _EVIDENCE_COLLECTIONS = {
35
45
  "externalSystems",
36
46
  "featureIndex",
37
47
  ),
38
- "feature-analysis": (
39
- "flows",
40
- "domainRules",
41
- "stateChanges",
42
- "externalInteractions",
43
- ),
44
- "change-impact-analysis": (
45
- "preservedBehaviors",
46
- "impactItems",
47
- "dependencyBlastRadius",
48
- "testImpact",
49
- "operationalImpact",
50
- ),
48
+ "feature-analysis": FEATURE_EVIDENCE_COLLECTIONS,
49
+ "change-impact-analysis": CHANGE_IMPACT_EVIDENCE_COLLECTIONS,
51
50
  }
52
51
  _ANALYSIS_PARENT_KEYS = {
53
52
  "project-analysis": "projectAnalysis",
@@ -111,33 +110,6 @@ def validate_analysis_snapshot(
111
110
  )
112
111
 
113
112
 
114
- def _normalized_project_path(path: object) -> PurePosixPath | None:
115
- if not isinstance(path, str):
116
- return None
117
- raw = path.strip().rstrip("/")
118
- if not raw or raw == "." or raw.startswith("/"):
119
- return None
120
- if any(part in {"", ".", ".."} for part in raw.split("/")):
121
- return None
122
- normalized = PurePosixPath(raw)
123
- if normalized.is_absolute():
124
- return None
125
- return normalized
126
-
127
-
128
- def _path_is_included(path: object, included_paths: list[object]) -> bool:
129
- candidate = _normalized_project_path(path)
130
- if candidate is None:
131
- return False
132
- for raw in included_paths:
133
- included = _normalized_project_path(raw)
134
- if included is not None and (
135
- candidate == included or included in candidate.parents
136
- ):
137
- return True
138
- return False
139
-
140
-
141
113
  def _validate_included_paths(included_paths: list[object], errors: list[str]) -> None:
142
114
  for index, path in enumerate(included_paths):
143
115
  if _normalized_project_path(path) is None:
@@ -201,90 +173,6 @@ def _validate_all_current_code_evidence(
201
173
  )
202
174
 
203
175
 
204
- def _validate_project_semantics(data: dict, errors: list[str]) -> None:
205
- common = data.get("analysisCommon") or {}
206
- included = ((common.get("scope") or {}).get("includedPaths") or [])
207
- analysis = data.get("projectAnalysis") or {}
208
- for row in analysis.get("featureIndex") or []:
209
- if not isinstance(row, dict):
210
- continue
211
- entry = row.get("representativeEntryPoint") or {}
212
- if not _path_is_included(entry.get("path"), included):
213
- errors.append(
214
- f"projectAnalysis.featureIndex `{row.get('id') or '?'}` representative "
215
- "entry point must be inside analysisCommon.scope.includedPaths"
216
- )
217
- _validate_component_references(analysis, errors)
218
-
219
-
220
- def _validate_component_references(analysis: dict, errors: list[str]) -> None:
221
- """Every componentId a row names has to be a component this report declares.
222
-
223
- The reader clicks these — they render as links to the component's row — so
224
- a reference to a component that was never listed is a dead anchor, and one
225
- to a component that exists under a different id is worse: it reads as a
226
- relationship the analysis never found.
227
- """
228
- declared = {
229
- row.get("id")
230
- for row in analysis.get("components") or []
231
- if isinstance(row, dict) and row.get("id")
232
- }
233
- if not declared:
234
- return
235
-
236
- def check(component_id: object, where: str) -> None:
237
- if isinstance(component_id, str) and component_id and component_id not in declared:
238
- errors.append(f"{where} names component `{component_id}`, which is not declared")
239
-
240
- for row in analysis.get("internalInterfaces") or []:
241
- if not isinstance(row, dict):
242
- continue
243
- where = f"projectAnalysis.internalInterfaces `{row.get('id') or '?'}`"
244
- check(row.get("ownerComponentId"), where)
245
- for consumer in row.get("consumers") or []:
246
- check(consumer, where)
247
- for row in analysis.get("workflows") or []:
248
- if not isinstance(row, dict):
249
- continue
250
- for step in row.get("steps") or []:
251
- if isinstance(step, dict):
252
- check(step.get("componentId"), f"projectAnalysis.workflows `{row.get('id') or '?'}`")
253
-
254
-
255
- def _validate_feature_semantics(data: dict, errors: list[str]) -> None:
256
- analysis = data.get("featureAnalysis") or {}
257
- common_target = (((data.get("analysisCommon") or {}).get("scope") or {}).get(
258
- "resolvedTarget"
259
- ) or {})
260
- feature_target = analysis.get("target") or {}
261
- for field in ("inputMode", "requestedValue"):
262
- if feature_target.get(field) != common_target.get(field):
263
- errors.append(
264
- f"featureAnalysis.target.{field} must match "
265
- f"analysisCommon.scope.resolvedTarget.{field}"
266
- )
267
- resolved_feature = common_target.get("feature") or {}
268
- if common_target.get("inputMode") == "feature-index" and (
269
- feature_target.get("featureId") != resolved_feature.get("id")
270
- ):
271
- errors.append(
272
- "featureAnalysis.target.featureId must match the resolved feature id"
273
- )
274
-
275
-
276
- def _validate_change_impact_semantics(data: dict, errors: list[str]) -> None:
277
- analysis = data.get("changeImpactAnalysis") or {}
278
- allowed = {"constraint", "unknown"}
279
- for index, row in enumerate(analysis.get("planningInputs") or []):
280
- if not isinstance(row, dict):
281
- continue
282
- for field in sorted(set(row) - allowed):
283
- errors.append(
284
- f"changeImpactAnalysis.planningInputs[{index}] forbids `{field}`; "
285
- "planning inputs may contain constraints and unknowns only"
286
- )
287
-
288
176
 
289
177
  def _required_worker_roles(
290
178
  run_manifest: dict, errors: list[str]
@@ -475,11 +363,11 @@ def validate_analysis_semantics(
475
363
  )
476
364
  _validate_all_current_code_evidence(task_type, data, errors)
477
365
  if task_type == "project-analysis":
478
- _validate_project_semantics(data, errors)
366
+ validate_project_semantics(data, errors)
479
367
  elif task_type == "feature-analysis":
480
368
  _validate_feature_semantics(data, errors)
481
369
  elif task_type == "change-impact-analysis":
482
- _validate_change_impact_semantics(data, errors)
370
+ validate_change_impact_semantics(data, errors)
483
371
  _validate_scope_before_dispatch(
484
372
  data, analysis_worker_roles, reporter_confirmation, errors
485
373
  )
@@ -1,82 +0,0 @@
1
- # okstra-run task process
2
-
3
- ## Index
4
-
5
- - [1. Reading order](#1-reading-order)
6
- - [2. Big picture](#2-big-picture)
7
- - [3. task-type documents](#3-task-type-documents)
8
- - [4. Key code locations](#4-key-code-locations)
9
- - [5. Quick comparison table](#5-quick-comparison-table)
10
-
11
- ## 1. Reading order
12
-
13
- `okstra-run` is the path that starts a task inside a supported Claude Code, Codex, or Antigravity host session. This folder organizes that execution flow into two layers.
14
-
15
- 1. First read [common-flow.md](common-flow.md). It is the wizard, render-bundle, lead phase, and artifact flow shared by every task-type.
16
- 2. Then read the document for the task-type you want to run.
17
- 3. Check the per-task-type differences across three places: "what the wizard additionally asks", "what `prepare_task_bundle()` blocks in the runtime", and "what the lead profile enforces within the phase".
18
-
19
- ## 2. Big picture
20
-
21
- ```mermaid
22
- flowchart TD
23
- U[User in supported host] --> S[okstra-run skill]
24
- S --> R[Step 1<br/>ensure-installed / paths / check-project]
25
- R --> W[okstra wizard<br/>state machine]
26
- W --> A[render-args]
27
- A --> B[okstra render-bundle<br/>--render-only]
28
- B --> P[prepare_task_bundle()]
29
- P --> I["runs/task-type/prompts<br/>lead-execution-prompt-*.md"]
30
- I --> L[Current host session<br/>takes over as Okstra lead]
31
- L --> F[Phase 1-7 lead workflow]
32
- F --> O[final-report + manifests + status]
33
- ```
34
-
35
- `okstra-run` does not call `scripts/okstra.sh`. Instead it goes through `okstra wizard` and `okstra render-bundle` and converges on the same single Python entrypoint, `prepare_task_bundle()`.
36
-
37
- Launch selection is role slots and model refs, not a provider roster. The wizard asks one screen per static role: a checkbox of candidate models for a role that runs several instances (the number checked is the instance count, rendered as `--role-count <role>=<N>` plus one `--role-model <role>=<provider>/<model>` per checked model; the label states the profile range and recommended count), a single pick for a fixed single-instance role. current-session lead is this session and is listed on the confirmation summary. Roles with `min = 0` stay closed unless the user adds them. There is no provider multi-pick and no `Use defaults / Customize` fork for worker selection. `--workers` is compatibility-only. `lead` is a compatibility alias for `leader`. `executor` is a compatibility alias for `implementer`. New records write `leader` and `implementer`.
38
-
39
- ## 3. task-type documents
40
-
41
- | task-type | Document | One-line purpose |
42
- |---|---|---|
43
- | `requirements-discovery` | [requirements-discovery.md](requirements-discovery.md) | Classify the request and choose the next safe phase. |
44
- | `error-analysis` | [error-analysis.md](error-analysis.md) | Find cause candidates and validation paths from symptoms and evidence. |
45
- | `implementation-option-selection` | [implementation-option-selection.md](implementation-option-selection.md) | Compare or validate exact-coverage directions before detailed planning. |
46
- | `implementation-planning` | [implementation-planning.md](implementation-planning.md) | Realize one selected direction as an exact-coverage plan with a separate approval gate. |
47
- | `implementation` | [implementation.md](implementation.md) | The executor implements the approved plan and the verifier verifies it independently. |
48
- | `final-verification` | [final-verification.md](final-verification.md) | Judge whole-task or single-stage acceptance of the implementation result. |
49
- | `release-handoff` | [release-handoff.md](release-handoff.md) | Perform the push/PR handoff lead-only after an accepted verdict. |
50
-
51
- ## 4. Key code locations
52
-
53
- | Concern | Source of truth |
54
- |---|---|
55
- | okstra-run skill procedure | [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) |
56
- | wizard state machine | [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/) |
57
- | wizard prompt text | [`prompts/wizard/prompts.ko.json`](../../prompts/wizard/prompts.ko.json) |
58
- | render-bundle Node shim | [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts) |
59
- | single entrypoint for bundle creation | [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py) |
60
- | implementation stage selection/provisioning | [`scripts/okstra_ctl/implementation_stage.py`](../../scripts/okstra_ctl/implementation_stage.py) |
61
- | Stage Lifecycle Snapshot + stage target/base/verification policy | [`scripts/okstra_ctl/stage_targets.py`](../../scripts/okstra_ctl/stage_targets.py) |
62
- | phase boundary | [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py) |
63
- | task worktree | [`scripts/okstra_ctl/worktree/`](../../scripts/okstra_ctl/worktree/) |
64
- | stage-group handoff | [`scripts/okstra_ctl/handoff.py`](../../scripts/okstra_ctl/handoff.py) |
65
- | worker roster parser | [`scripts/okstra_ctl/workers.py`](../../scripts/okstra_ctl/workers.py) |
66
- | lead operating contract | [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md) |
67
- | phase profiles | [`prompts/profiles/`](../../prompts/profiles/) |
68
- | final report shape / HTML view | [`templates/reports/final-report-v2.template.md`](../../templates/reports/final-report-v2.template.md), [`scripts/okstra_ctl/report_views.py`](../../scripts/okstra_ctl/report_views.py) |
69
-
70
- ## 5. Quick comparison table
71
-
72
- The last column is the `workflow.nextRecommendedPhase` pointer Phase 7 leaves behind — an object `{phase, status, rationale}`, projected from the report's own routing field. There is no static default: a run that settles no route ends `pending` with no phase. The routing field's `rationale` is carried into the pointer, and the lead's closeout quotes it. The rule for authoring that field is stated once, in the Phase 6 checklist of [`prompts/lead/report-writer.md`](../../prompts/lead/report-writer.md).
73
-
74
- | task-type | wizard special question | runtime prepare gate | lead/worker mode | next-phase pointer |
75
- |---|---|---|---|---|
76
- | `requirements-discovery` | common questions only | profile/brief/base-ref exist | multi-worker analysis, convergence 1 round default | `ready` at `error-analysis` or `implementation-option-selection`; `pending` when neither is settled |
77
- | `error-analysis` | common questions only | profile/brief/base-ref exist | multi-worker analysis, convergence 2 rounds default | `ready` at `implementation-option-selection`, or at `error-analysis` while the investigation continues |
78
- | `implementation-option-selection` | comparison or preselected-validation context | stable brief IDs and at least three analysers | read-only candidate validation, exact coverage, separate direction confirmation | `ready` at `implementation-planning` (a confirmed direction, or ranked candidates the planning wizard lets the user pick from), `pending` when no candidate was ranked, or `blocked` |
79
- | `implementation-planning` | selected-direction report for a new plan | selection report/sidecar/digest or same-task planning rerun | one-direction realization + Phase 6 plan-body verification | `ready` at `implementation` on approvable `plan-ready` (`awaitingApproval` until the user flips `approved`); `blocked` when the gate is blocking or a `Blocks=approval` row is open; `ready` at `implementation-option-selection` on `direction-invalidated` |
80
- | `implementation` | approved plan, stage multi-pick, executor | approved marker, Stage Lifecycle Snapshot, stage-key reservation, QA command deny-list | one run = one stage; executor writes in isolated stage worktree, verifiers read-only | `ready` at the stage report's `routingRecommendation.target` — `final-verification` on a clean stage |
81
- | `final-verification` | approved plan, stage pick (whole-task or single-stage) | `VERIFICATION_TARGET` resolved; whole-task auto integration/teardown or single-stage worktree reuse | whole-task may integrate stages first; analyser verification itself is read-only | `ready` at `release-handoff` on an `accepted` verdict, otherwise at the phase owning the defect; `terminal` on `done` |
82
- | `release-handoff` | handoff scope (stage-group or whole-task), PR template override/scope | Stage Lifecycle Snapshot eligibility, generated `release-handoff-input.md`, empty worker roster | single-lead; whole-task PR or stage-group collector branch/PR | always `terminal` |
@@ -1,173 +0,0 @@
1
- # okstra-run common flow
2
-
3
- ## Index
4
-
5
- - [1. One-line summary](#1-one-line-summary)
6
- - [2. Where the two entrypoints meet](#2-where-the-two-entrypoints-meet)
7
- - [3. wizard input collection flow](#3-wizard-input-collection-flow)
8
- - [4. render-bundle and prepare_task_bundle](#4-render-bundle-and-prepare_task_bundle)
9
- - [5. Okstra lead phase 1-7](#5-okstra-lead-phase-1-7)
10
- - [6. artifact layout](#6-artifact-layout)
11
- - [7. Common branching rules](#7-common-branching-rules)
12
- - [8. Inconsistencies to watch for](#8-inconsistencies-to-watch-for)
13
-
14
- ## 1. One-line summary
15
-
16
- `okstra-run` is not a "skill that decides questions on its own" but a thin loop that relays the `okstra wizard` JSON state machine to the user. Once input collection finishes, it calls `okstra render-bundle`, and that command builds the task bundle through `python3 -m okstra_ctl.run --render-only`. After that, the current Claude Code, Codex, or Antigravity session switches over to the host-native `Okstra lead`.
17
-
18
- ## 2. Where the two entrypoints meet
19
-
20
- ```mermaid
21
- flowchart LR
22
- subgraph InSession["supported host session"]
23
- A[okstra-run skill] --> B[okstra wizard]
24
- B --> C[okstra render-bundle<br/>forces --render-only]
25
- end
26
-
27
- subgraph Terminal["terminal path"]
28
- D[scripts/okstra.sh] --> E[CLI parse / prompt / confirm]
29
- end
30
-
31
- C --> P[prepare_task_bundle()]
32
- E --> P
33
- P --> G[task bundle artifacts]
34
- G --> H{launch mode}
35
- H -->|render-only| I[current host reads lead prompt]
36
- H -->|non-render-only| J[exec claude --session-id ...]
37
- ```
38
-
39
- The common principle is that `prepare_task_bundle()` is the single authority for task bundle creation. Neither the wizard nor the shell wrapper duplicates the path computation, manifest creation, or worktree creation logic.
40
-
41
- ## 3. wizard input collection flow
42
-
43
- ```mermaid
44
- stateDiagram-v2
45
- [*] --> VerifyRuntime: okstra ensure-installed / paths / check-project
46
- VerifyRuntime --> NewState: okstra wizard new-state-file
47
- NewState --> TaskPick: wizard init
48
- TaskPick --> BriefPath: brand-new task
49
- TaskPick --> TaskType: existing task
50
- BriefPath --> TaskGroup: new task, brief accepted
51
- TaskGroup --> TaskId
52
- TaskId --> TaskType
53
- TaskType --> BriefKeep: existing task with existing brief
54
- BriefKeep --> BriefPath: change
55
- BriefKeep --> BaseRef: keep
56
- TaskType --> BaseRef: no active worktree
57
- TaskType --> ImplementationExtras: implementation only
58
- BaseRef --> ImplementationExtras: implementation only
59
- BaseRef --> LeaderSession: non-implementation
60
- ImplementationExtras --> LeaderSession
61
- LeaderSession --> RoleSlots: one model screen per role
62
- RoleSlots --> OptionalInputs: directive / related / clarification
63
- OptionalInputs --> Confirm
64
- Confirm --> EditTarget: Edit
65
- EditTarget --> TaskType: rewind selected step
66
- Confirm --> Done: Proceed
67
- ```
68
-
69
- A new task receives its brief first. If the brief frontmatter has `task-group:` and `brief-id:`, the wizard shows the task group/id as recommended picks. An existing task shows the manifest's `workflow.nextRecommendedPhase.phase` as the recommended task-type, but only while that pointer's `status` is `ready`. Under any other status the recommended slot stays empty and the list falls back to rerunning `workflow.currentPhase` plus the full task-type choices. If an existing brief path exists it asks whether to keep or change it.
70
-
71
- ## 4. render-bundle and prepare_task_bundle
72
-
73
- ```mermaid
74
- sequenceDiagram
75
- participant Skill as okstra-run skill
76
- participant Node as okstra CLI
77
- participant Py as okstra_ctl.run
78
- participant FS as .okstra
79
- participant Home as ~/.okstra
80
-
81
- Skill->>Node: okstra wizard outcome
82
- Node-->>Skill: { renderArgs: ..., persistActions: ... }
83
- opt persistActions present
84
- Skill->>Node: okstra config set ...
85
- end
86
- Skill->>Node: okstra render-bundle --... --render-only
87
- Node->>Py: python3 -m okstra_ctl.run --render-only --...
88
- Py->>Py: validate profile, brief, task-type gates
89
- Py->>Home: reserve/reuse task worktree registry
90
- Py->>FS: write run-context and instruction-set
91
- Py->>FS: write task/run manifests, team-state, timeline, discovery
92
- Py->>Home: record_start status=prepared
93
- Py-->>Node: task root, instruction-set, rendered lead prompt
94
- Node-->>Skill: stdout
95
- Skill->>FS: read lead-execution-prompt.md
96
- ```
97
-
98
- The Node shim for `render-bundle` is [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts). This shim attaches the `--workspace-root`, `--render-only`, and runtime resolution arguments directly. As a result, on the okstra-run path the initial run status starts at `prepared` and the task status starts at `ready-for-lead`.
99
-
100
- ## 5. Okstra lead phase 1-7
101
-
102
- ```mermaid
103
- flowchart TD
104
- P1[Phase 1<br/>task bundle intake] --> P2[Phase 2<br/>worker prompt preparation]
105
- P2 --> P3[Phase 3<br/>resolve persisted runners]
106
- P3 -->|native session| P4[Phase 4<br/>host-native dispatch]
107
- P3 -->|CLI wrapper| P5[Phase 4<br/>provider CLI dispatch]
108
- P4 --> C[Phase 5.5<br/>convergence]
109
- P5 --> C
110
- C --> P6[Phase 6<br/>report-writer synthesis]
111
- P6 --> PV{implementation-planning?}
112
- PV -->|yes| PBV[Plan-body verification]
113
- PV -->|no| P7[Phase 7<br/>persist + validate]
114
- PBV --> P7
115
- P7 --> Done[final report + manifests updated]
116
- ```
117
-
118
- The roles of the analysis workers and the report-writer are separated. `report-writer` is not a Phase 4/5 analysis worker but the Phase 6 final report author. Note, however, that `release-handoff` is a single-lead phase, so it deliberately does not follow this phase graph.
119
-
120
- ## 6. artifact layout
121
-
122
- ```mermaid
123
- flowchart TD
124
- Root["<PROJECT_ROOT>/.okstra/tasks/<group>/<task>/"] --> IS[instruction-set/]
125
- Root --> Runs[runs/<task-type>/]
126
- Root --> Hist[history/timeline.json]
127
- IS --> Profile[analysis-profile.md]
128
- IS --> Brief[task-brief.md]
129
- Runs --> Lead["prompts/lead-execution-prompt-*.md"]
130
- Runs --> Man[manifests/run-manifest-*.json]
131
- Runs --> Prompts[prompts/*-worker-prompt-*.md]
132
- Runs --> Results[worker-results/*.md]
133
- Runs --> Reports[reports/final-report-*.md<br/>reports/*.data.json<br/>reports/final-report-*.html]
134
- Runs --> State[state/*.json]
135
- Runs --> Status[status/final-status-*.json]
136
- Runs --> ImplStage[implementation/stage-N/...]
137
- Runs --> FvStage[final-verification/stage-N/...]
138
- Runs --> Carry[implementation/carry/stage-N.json]
139
- Runs --> Consumers[implementation-planning/consumers.jsonl]
140
- Root --> Handoff[release-handoff-input.md]
141
- ```
142
-
143
- `implementation` and single-stage `final-verification` isolate their run deliverables under `stage-<N>/`. The `implementation` carry sidecar and `consumers.jsonl` are cross-stage coordination ledgers, so they remain at the phase root. The runtime reads this ledger and the registry reservations as a Stage Lifecycle Snapshot to compute stage selection and handoff eligibility. `release-handoff` does not receive a brief; prepare generates `release-handoff-input.md`.
144
-
145
- `runtime/` is build output, so when you fix this flow you edit the sources `scripts/`, `skills/`, `agents/`, `prompts/`, `templates/`, `validators/` and refresh with `npm run build`.
146
-
147
- ## 7. Common branching rules
148
-
149
- ```mermaid
150
- flowchart TD
151
- T[task-type selected] --> W{active worktree in registry?}
152
- W -->|yes| Reuse[reuse existing worktree<br/>base-ref prompt skipped]
153
- W -->|no| Base[ask base-ref<br/>validate with git rev-parse]
154
- Base --> M[one screen per static role<br/>checkbox: models checked = instances<br/>single pick: fixed single role]
155
- Reuse --> M
156
- M --> O[directive / related / clarification]
157
- O --> Special{release-handoff?}
158
- Special -->|yes| PR[PR template override/scope]
159
- Special -->|no| Confirm
160
- PR --> Confirm
161
- ```
162
-
163
- Launch selection is role slots and model refs. The wizard does not show a provider roster multi-pick and does not fork on `Use defaults / Customize` for workers. A multi-instance role is one checkbox screen whose checked models become the instances (the wizard renders `--role-count` from that number); on the CLI, omitting `--role-count` keeps each static role at its profile **recommended** count within `min..max`. Duplicate model refs in the same role are rejected. `--workers` remains a CLI compatibility input only.
164
-
165
- Worktree rules differ per phase. From `requirements-discovery` through `implementation-planning`, the task-key worktree is reused. `implementation` uses the task-key worktree as an anchor but does the actual execution isolated one stage at a time in a stage-key (`stage-<N>`) worktree and the `runs/implementation/stage-<N>/` deliverables. `final-verification --stage N` reuses that implementation stage worktree as a read target, and whole-task mode auto-integrates the stage commits into the task-key worktree and then builds the verification target. The Stage Lifecycle Snapshot is a read-side view that does not change this storage structure.
166
-
167
- ## 8. Inconsistencies to watch for
168
-
169
- - The `okstra-run` wizard path passes only if the implementation approved plan already has an approval marker. `scripts/okstra.sh` has `--approve`, which can flip the checkbox with a CLI ack, but the current wizard `render_args()` has no `approve` flag.
170
- - `release-handoff` has no brief. Prepare cites the accepted final-verification report to build `release-handoff-input.md`, and the wizard's `handoff_stage_pick` or the CLI `--stages` fixes the whole-task/stage-group scope.
171
- - `release-handoff` is also a target for task worktree provisioning. A healthy handoff is safest when it reuses the implementation/final-verification results of the same task-key. Starting a new task creates a new worktree, which may be blocked at the profile's "an implementation commit must exist" entry gate.
172
- - `release-handoff` has no `Required workers:` block in its profile. The runtime also forces the worker roster to be empty.
173
- - No task-type starts the next lifecycle phase within a single run. "Proceed to the next step" is interpreted only as wrapping up the current phase's output.
@@ -1,147 +0,0 @@
1
- """Human-first implementation-planning view and approval state."""
2
- from __future__ import annotations
3
-
4
- import re
5
- from dataclasses import dataclass
6
-
7
- from ..common import evidence_index
8
- from ..models import HumanReportView, VisualEdge, VisualNode
9
- from ..visualizations import stage_map_figure
10
-
11
-
12
- @dataclass(frozen=True)
13
- class PlanApprovalState:
14
- option_names: tuple[str, ...]
15
- recommended_option: str
16
- disabled_reason: str
17
- blocker_ids: tuple[str, ...]
18
- show_option_selector: bool = True
19
- reentry_command: str = ""
20
-
21
-
22
- def resolve_recommended_option(rec_name: str, names: tuple[str, ...]) -> str:
23
- if rec_name in names:
24
- return rec_name
25
- matches = [
26
- name
27
- for name in names
28
- if rec_name and (name.startswith(rec_name) or rec_name.startswith(name))
29
- ]
30
- return matches[0] if len(matches) == 1 else names[0]
31
-
32
-
33
- def plan_approval_state(data: dict) -> PlanApprovalState | None:
34
- planning = data.get("implementationPlanning")
35
- if not isinstance(planning, dict):
36
- return None
37
- blockers = tuple(
38
- row["id"]
39
- for row in data.get("clarificationItems", [])
40
- if row.get("blocks") == "approval"
41
- and row.get("status") in {"open", "answered"}
42
- )
43
- reason = f"{len(blockers)} approval blocker(s) unresolved" if blockers else ""
44
- if planning.get("planningContract") == "selected-direction":
45
- if planning.get("outcome") == "direction-invalidated" and not reason:
46
- reason = "selected direction invalidated"
47
- task_key = (data.get("header") or {}).get("taskKey", "")
48
- reentry_command = (
49
- f"/okstra-run task-key={task_key} "
50
- "task-type=implementation-option-selection"
51
- if planning.get("outcome") == "direction-invalidated" and task_key
52
- else ""
53
- )
54
- return PlanApprovalState(
55
- (), "", reason, blockers, False, reentry_command
56
- )
57
- names = tuple(
58
- row["name"]
59
- for row in planning.get("optionCandidates", [])
60
- if isinstance(row, dict) and row.get("name")
61
- )
62
- if not names:
63
- return None
64
- recommended = planning.get("recommendedOption", {}).get("name", "")
65
- return PlanApprovalState(
66
- names,
67
- resolve_recommended_option(recommended, names),
68
- reason,
69
- blockers,
70
- )
71
-
72
-
73
- def _stage_figure(planning: dict):
74
- nodes = tuple(
75
- VisualNode(
76
- f"stage-{row['stage']}",
77
- f"Stage {row['stage']} · {row['title']}",
78
- "stage",
79
- "planned",
80
- row["exitContractSummary"],
81
- )
82
- for row in planning["stageMap"]
83
- )
84
- edges = tuple(
85
- VisualEdge(f"stage-{dependency}", f"stage-{row['stage']}", "precedes", "dependency")
86
- for row in planning["stageMap"]
87
- for dependency in re.findall(r"\d+", row["dependsOn"])
88
- )
89
- return stage_map_figure(nodes=nodes, edges=edges, title="Implementation stage dependencies")
90
-
91
-
92
- # Record fields this template anchors as `id-<row id>` (see
93
- # `HumanReportView.anchored_fields`). The implementer-facing tables the
94
- # approver does not read — validation checklist, cross-project dependencies,
95
- # migration risk, rollback — are not drawn, so their rows land in the ledger.
96
- ANCHORED_FIELDS = (
97
- "implementationPlanning.directionRealization.fileStructure",
98
- "implementationPlanning.directionRealization.planningInvariants",
99
- "implementationPlanning.optionCandidates.fileStructure",
100
- "implementationPlanning.designPreparation.items",
101
- "implementationPlanning.requirementCoverage",
102
- "implementationPlanning.planBodyVerification.planItems",
103
- "implementationPlanning.supersessionLedger",
104
- )
105
-
106
-
107
- def build_implementation_planning_view(data: dict) -> HumanReportView:
108
- planning = data["implementationPlanning"]
109
- figure = _stage_figure(planning) if planning.get("stageMap") else None
110
- approval = plan_approval_state(data)
111
- activities = tuple(
112
- row for row in data.get("agentActivity", []) if isinstance(row, dict)
113
- )
114
- decision_cards = tuple(
115
- row
116
- for row in data.get("clarificationItems", [])
117
- if isinstance(row, dict)
118
- and row.get("blocks") == "approval"
119
- and isinstance(row.get("approvalContext"), dict)
120
- )
121
- context = {
122
- "humanSummary": data["humanSummary"],
123
- "planning": planning,
124
- "narrative": planning.get("userNarrative", {}),
125
- "stageFigure": figure,
126
- "approval": approval,
127
- "openDecisions": [
128
- row
129
- for row in data.get("clarificationItems", [])
130
- if isinstance(row, dict)
131
- and row.get("blocks") == "approval"
132
- and row.get("status") in {"open", "answered"}
133
- ],
134
- "agentActivities": activities,
135
- "activityById": {
136
- row["activityId"]: row for row in activities if row.get("activityId")
137
- },
138
- "decisionCards": decision_cards,
139
- "evidenceIndex": evidence_index(data, ANCHORED_FIELDS),
140
- }
141
- return HumanReportView(
142
- "implementation-planning",
143
- "html/tasks/implementation-planning.template.html",
144
- context,
145
- (figure,) if figure is not None else (),
146
- anchored_fields=ANCHORED_FIELDS,
147
- )