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
@@ -0,0 +1,260 @@
1
+ """12개 작업 유형과 단계 디렉터리의 고정 대응.
2
+
3
+ 이 모듈을 import 해도 단계 실행 모듈은 적재되지 않는다. 경로는 문자열로만
4
+ 계산한다. 외부 설정에서 모듈 경로를 받아 실행하지 않는다.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+
11
+ from ..asset_roots import walk_to_asset_root
12
+
13
+
14
+ class PhaseAssetError(ValueError):
15
+ """단계 자산을 요청한 실행 루트에서 해석할 수 없다."""
16
+
17
+
18
+ class UnknownTaskType(PhaseAssetError):
19
+ """등록표에 없는 작업 유형이다."""
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class PhaseRecord:
24
+ """외부 작업 유형 하나와 그 코드 위치."""
25
+
26
+ task_type: str
27
+ package_name: str
28
+ migrated: bool
29
+ view_module: str
30
+ view_function: str
31
+
32
+
33
+ def _view(package_name: str, function: str, *, phase_package: bool) -> tuple[str, str]:
34
+ if phase_package:
35
+ return f"okstra_ctl.phases.{package_name}.report", function
36
+ return f"okstra_ctl.report_html.view_models.{package_name}", function
37
+
38
+
39
+ def _record(
40
+ task_type: str,
41
+ package_name: str,
42
+ migrated: bool,
43
+ view_function: str,
44
+ ) -> PhaseRecord:
45
+ module, function = _view(package_name, view_function, phase_package=migrated)
46
+ return PhaseRecord(task_type, package_name, migrated, module, function)
47
+
48
+
49
+ # 이전되지 않은 단계는 기존 ``prompts/profiles`` 위치를 명시적으로 쓴다.
50
+ # 이전된 단계는 okstra_ctl 패키지를 품은 루트에서 단계 디렉터리만 본다. 그
51
+ # 루트의 단계 파일이 없어도 prompts/profiles 사본으로 넘어가지 않는다. 패키지를
52
+ # 품지 않은 루트는 그 루트의 prompts/profiles 사본이 자료다 (``profile_markdown``).
53
+ PHASES: tuple[PhaseRecord, ...] = (
54
+ _record("requirements-discovery", "requirements_discovery", True, "build_requirements_discovery_view"),
55
+ _record("improvement-discovery", "improvement_discovery", True, "build_improvement_discovery_view"),
56
+ _record("project-analysis", "project_analysis", True, "build_project_analysis_view"),
57
+ _record("feature-analysis", "feature_analysis", True, "build_feature_analysis_view"),
58
+ _record("change-impact-analysis", "change_impact_analysis", True, "build_change_impact_analysis_view"),
59
+ _record("error-analysis", "error_analysis", True, "build_error_analysis_view"),
60
+ _record("technical-verification", "technical_verification", True, "build_technical_verification_view"),
61
+ _record(
62
+ "implementation-option-selection",
63
+ "implementation_option_selection",
64
+ True,
65
+ "build_implementation_option_selection_view",
66
+ ),
67
+ _record("implementation-planning", "implementation_planning", True, "build_implementation_planning_view"),
68
+ _record("implementation", "implementation", True, "build_implementation_view"),
69
+ _record("final-verification", "final_verification", True, "build_final_verification_view"),
70
+ _record("release-handoff", "release_handoff", True, "build_release_handoff_view"),
71
+ )
72
+
73
+ _BY_TASK_TYPE = {row.task_type: row for row in PHASES}
74
+
75
+ # 같은 자산 루트 안에서만 고른다. 다른 설치본으로 넘어가는 순서가 아니다.
76
+ _PACKAGE_RELATIVES = (
77
+ ("scripts", "okstra_ctl"),
78
+ ("python", "okstra_ctl"),
79
+ ("lib", "python", "okstra_ctl"),
80
+ )
81
+
82
+
83
+ def phase_record(task_type: str) -> PhaseRecord:
84
+ try:
85
+ return _BY_TASK_TYPE[task_type]
86
+ except KeyError as exc:
87
+ raise UnknownTaskType(f"unknown task type: {task_type}") from exc
88
+
89
+
90
+ def task_types() -> tuple[str, ...]:
91
+ return tuple(row.task_type for row in PHASES)
92
+
93
+
94
+ def is_migrated(task_type: str) -> bool:
95
+ """단계 패키지로 옮겨진 작업 유형인지. 등록표에 없는 이름은 False."""
96
+ record = _BY_TASK_TYPE.get(task_type)
97
+ return record is not None and record.migrated
98
+
99
+
100
+ def logical_profile_markdown(task_type: str) -> str:
101
+ """실행 자료에 기록되는 프로필 계약 경로. 물리 파일 이름과 다를 수 있다."""
102
+ phase_record(task_type)
103
+ return f"prompts/profiles/{task_type}.md"
104
+
105
+
106
+ def package_root(asset_root: Path) -> Path | None:
107
+ """``asset_root`` 안의 okstra_ctl 패키지. 없으면 None, 둘 이상이면 오류."""
108
+ found = [
109
+ asset_root.joinpath(*parts)
110
+ for parts in _PACKAGE_RELATIVES
111
+ if (asset_root.joinpath(*parts) / "__init__.py").is_file()
112
+ ]
113
+ if not found:
114
+ return None
115
+ if len(found) > 1:
116
+ joined = ", ".join(str(path) for path in found)
117
+ raise PhaseAssetError(f"ambiguous okstra_ctl package under {asset_root}: {joined}")
118
+ return found[0]
119
+
120
+
121
+ def profile_markdown(asset_root: Path, task_type: str) -> Path:
122
+ """요청한 실행 루트에서 프로필 Markdown 의 물리 경로."""
123
+ record = phase_record(task_type)
124
+ legacy = asset_root / "prompts" / "profiles" / f"{task_type}.md"
125
+ if not record.migrated:
126
+ return legacy
127
+ root = package_root(asset_root)
128
+ # 요청한 루트가 런타임 패키지를 품지 않으면 그 루트에 있는 프로필이 그 실행의
129
+ # 자료다. 패키지를 품은 루트에서 단계 파일이 없을 때는 아래 경로를 그대로
130
+ # 돌려, 같은 루트의 prompts/profiles 사본으로 넘어가지 않는다.
131
+ if root is None:
132
+ return legacy
133
+ return root / "phases" / record.package_name / "profile.md"
134
+
135
+
136
+ def profile_contract(asset_root: Path, task_type: str) -> Path:
137
+ return profile_markdown(asset_root, task_type).with_suffix(".json")
138
+
139
+
140
+ def view_builder_import(task_type: str) -> tuple[str, str]:
141
+ """표시 함수의 모듈과 이름. import 는 호출자가 선택 시점에 한다."""
142
+ record = phase_record(task_type)
143
+ return record.view_module, record.view_function
144
+
145
+
146
+ def migrated_report_template(asset_root: Path, logical_name: str) -> Path | None:
147
+ """이전된 보고서 본문의 물리 경로.
148
+
149
+ 이 논리 이름이 단계 소유가 아니면 None 이다. ``asset_root`` 가 okstra_ctl
150
+ 패키지를 품지 않을 때도 None 이며, 호출자는 그 루트의 ``templates/reports``
151
+ 사본을 읽는다 (``profile_markdown`` 과 같은 규칙).
152
+ """
153
+ for record in PHASES:
154
+ if not record.migrated:
155
+ continue
156
+ filename = _report_template_filename(record.task_type, logical_name)
157
+ if filename is None:
158
+ continue
159
+ root = package_root(asset_root)
160
+ if root is None:
161
+ return None
162
+ return root / "phases" / record.package_name / "report_assets" / filename
163
+ return None
164
+
165
+
166
+ def resolve_include(profile_path: Path, target_name: str) -> Path:
167
+ """포함 대상을 찾는다.
168
+
169
+ 이전되지 않은 프로필은 자기 부모 디렉터리 기준을 유지한다. 이전된
170
+ ``profile.md`` 는 그 파일을 품은 자산 루트의 논리 경로로 찾고, 다른
171
+ 설치본의 ``OKSTRA_HOME`` 으로 넘어가지 않는다. 공유 조각과 같은 이름의
172
+ 단계 전용 파일이 함께 있으면 어느 쪽인지 정할 수 없으므로 오류다.
173
+ """
174
+ name = target_name.strip()
175
+ if not name or name.startswith("/") or ".." in Path(name).parts:
176
+ raise PhaseAssetError(f"invalid profile include target: {target_name!r}")
177
+ if not _is_migrated_profile(profile_path):
178
+ return profile_path.parent / name
179
+ asset_root = _asset_root_containing(profile_path)
180
+ if name.startswith("prompts/"):
181
+ return asset_root / name
182
+ shared = asset_root / "prompts" / "profiles" / Path(name).name
183
+ local = profile_path.parent / name
184
+ if shared.is_file() and local.is_file():
185
+ raise PhaseAssetError(
186
+ f"profile include {name!r} exists both as a shared fragment ({shared}) "
187
+ f"and beside the phase profile ({local})"
188
+ )
189
+ if local.is_file():
190
+ return local
191
+ return shared
192
+
193
+
194
+ def _is_migrated_profile(profile_path: Path) -> bool:
195
+ if profile_path.name != "profile.md" or profile_path.parent.parent.name != "phases":
196
+ return False
197
+ package_name = profile_path.parent.name
198
+ return any(row.migrated and row.package_name == package_name for row in PHASES)
199
+
200
+
201
+ def _asset_root_containing(start: Path) -> Path:
202
+ root = walk_to_asset_root(("prompts", "profiles"), start=start, is_present=Path.is_dir)
203
+ if root is None:
204
+ raise PhaseAssetError(
205
+ f"could not locate prompts/profiles while resolving an include from {start}"
206
+ )
207
+ return root
208
+
209
+
210
+ def _report_template_filename(task_type: str, logical_name: str) -> str | None:
211
+ if task_type == "requirements-discovery" and logical_name == "fan-out-unit.template.md":
212
+ return logical_name
213
+ if logical_name == f"{task_type}-input.template.md":
214
+ return logical_name
215
+ if logical_name == f"html/tasks/{task_type}.template.html":
216
+ return f"{task_type}.template.html"
217
+ if logical_name == f"md/tasks/{task_type}.template.md":
218
+ return f"{task_type}.template.md"
219
+ return None
220
+
221
+
222
+
223
+ def host_rules(asset_root: Path, task_type: str) -> Path:
224
+ """선택된 단계의 호스트 지침을 같은 자산 루트에서 찾는다."""
225
+ record = phase_record(task_type)
226
+ root = package_root(asset_root) if record.migrated else None
227
+ if root is not None:
228
+ return root / "phases" / record.package_name / "host-rules.md"
229
+ return asset_root / "prompts" / "host-orchestration" / f"{task_type}.md"
230
+
231
+
232
+ def profile_sidecar(asset_root: Path, logical_name: str) -> Path:
233
+ """동결 프로필에 남은 구현 보조 지침 경로도 현재 정본으로 해석한다."""
234
+ path = Path(logical_name)
235
+ if logical_name in {
236
+ "prompts/lead/plan-body-verification.md",
237
+ "scripts/okstra_ctl/phases/implementation_planning/instructions/plan-body-verification.md",
238
+ }:
239
+ root = package_root(asset_root)
240
+ if root is not None:
241
+ return root / "phases" / "implementation_planning" / "instructions" / path.name
242
+ if path.parent in {
243
+ Path("prompts/profiles"),
244
+ Path("scripts/okstra_ctl/phases/implementation/instructions"),
245
+ } and path.name in {
246
+ "_implementation-executor.md", "_implementation-verifier.md",
247
+ "_implementation-deliverable.md", "_implementation-diff-review.md",
248
+ "_implementation-self-check.md",
249
+ }:
250
+ root = package_root(asset_root)
251
+ if root is not None:
252
+ return root / "phases" / "implementation" / "instructions" / path.name
253
+ return asset_root / path
254
+
255
+
256
+ def phase_boundary(asset_root: Path, task_type: str) -> Path | None:
257
+ """주어진 자산 루트 안에 있는 단계 경계 자원의 경로."""
258
+ record = phase_record(task_type)
259
+ root = package_root(asset_root)
260
+ return root / "phases" / record.package_name / "boundary.json" if root else None
@@ -0,0 +1,11 @@
1
+ {
2
+ "allowed": " - preserved behavior, impacted items, and dependency propagation\n - test and operational impact\n - constraints and open decisions passed to implementation-planning\n",
3
+ "forbidden": [
4
+ "source or configuration edits",
5
+ "tests, builds, migrations, or deployments",
6
+ "starting any other lifecycle phase inside this run",
7
+ "implementation alternatives",
8
+ "file change specifications",
9
+ "stepwise execution plans"
10
+ ]
11
+ }
@@ -0,0 +1,39 @@
1
+ """Feature-baseline input steps for change impact analysis."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Optional
5
+
6
+ from okstra_ctl.wizard.ids import S_FEATURE_EVIDENCE, S_FEATURE_EVIDENCE_PICK
7
+ from okstra_ctl.wizard.state import Prompt, WizardState
8
+ from okstra_ctl.wizard.prompts import _p
9
+ from okstra_ctl.wizard.steps_analysis import (
10
+ _accept_analysis_evidence,
11
+ _build_analysis_evidence_pick,
12
+ _submit_analysis_evidence_pick,
13
+ )
14
+
15
+
16
+ def _build_feature_evidence_pick(state: WizardState) -> Prompt:
17
+ return _build_analysis_evidence_pick(
18
+ state, step=S_FEATURE_EVIDENCE_PICK, relation="feature-baseline"
19
+ )
20
+
21
+
22
+ def _submit_feature_evidence_pick(state: WizardState, value: str) -> Optional[str]:
23
+ return _submit_analysis_evidence_pick(
24
+ state, value, step=S_FEATURE_EVIDENCE_PICK,
25
+ field_name="feature_evidence_path",
26
+ pending_name="feature_evidence_pending_text",
27
+ )
28
+
29
+
30
+ def _build_feature_evidence(state: WizardState) -> Prompt:
31
+ t = _p(state.workspace_root, S_FEATURE_EVIDENCE)
32
+ return Prompt(step=S_FEATURE_EVIDENCE, kind="text", label=t["label"],
33
+ echo_template=t["echo_template"])
34
+
35
+
36
+ def _submit_feature_evidence(state: WizardState, value: str) -> Optional[str]:
37
+ candidate = _accept_analysis_evidence(state, value, "feature_evidence_path")
38
+ state.feature_evidence_pending_text = False
39
+ return f"feature-evidence: {candidate.report_path}"
@@ -1,9 +1,9 @@
1
1
  """Human-first change-impact-analysis view model."""
2
2
  from __future__ import annotations
3
3
 
4
- from ..common import analysis_review_ids, evidence_index
5
- from ..models import HumanReportView, VisualEdge, VisualNode
6
- from ..visualizations import flow_figure
4
+ from okstra_ctl.report_html.common import analysis_review_ids, evidence_index
5
+ from okstra_ctl.report_html.models import HumanReportView, VisualEdge, VisualNode
6
+ from okstra_ctl.report_html.visualizations import flow_figure
7
7
 
8
8
  # Record fields this template anchors as `id-<row id>` (see
9
9
  # `HumanReportView.anchored_fields`); ids elsewhere land in the ledger.
@@ -0,0 +1,26 @@
1
+ # Change impact analysis phase
2
+
3
+ ## Purpose and boundaries
4
+
5
+ This phase maps a proposed change's preserved behavior, affected and unaffected boundaries, dependency propagation, tests and operational impact. It records planning constraints and open decisions without producing an execution plan. `profile.md` owns these analysis instructions and the adversarial convergence setting.
6
+
7
+ `entry.py` owns the feature-baseline selection and text-entry handlers. The common wizard registry preserves the existing question order: feature evidence before project evidence. Shared analysis-input code retains evidence ownership, review status, freshness, relation and path checks. The CLI evidence arguments and run artifacts are unchanged.
8
+
9
+ ## Result and validation
10
+
11
+ `validation.py` owns the current-code evidence collection names and the rule limiting `planningInputs` to constraints and unknowns. `validators/validate_analysis_report.py` remains the common assembly point for phase semantics, current-code evidence, frozen input snapshots, worker completion and review-resolution checks. Evidence path predicates remain in `analysis_scope.py`.
12
+
13
+ `report.py` builds the impact graph and human view from `changeImpactAnalysis`. The input, Markdown and HTML templates live in `report_assets/`. Common schemas, analysis-review controls and report routing remain shared. The common lead routing policy chooses the next phase; the profile describes facts and constraints for that decision.
14
+
15
+ ## Guarantees
16
+
17
+ | ID | Guarantee | Enforcement |
18
+ |---|---|---|
19
+ | CI-1 | Planning inputs contain constraints and unknowns only. | `scripts/okstra_ctl/phases/change_impact_analysis/validation.py::validate_change_impact_semantics` |
20
+ | CI-2 | Impact items require current-code evidence within the included scope. | `validators/validate_analysis_report.py::_validate_all_current_code_evidence`, `scripts/okstra_ctl/phases/change_impact_analysis/tests/test_change_impact_analysis_validation.py::test_change_impact_item_requires_current_code_evidence` |
21
+ | CI-3 | The wizard collects feature evidence before project evidence. | `tests/domain/wizard/test_analysis_inputs.py::test_change_impact_collects_feature_then_project_evidence` |
22
+ | CI-4 | Common validation checks the frozen analysis source, target and evidence snapshot. | `validators/validate_analysis_report.py::validate_analysis_snapshot` |
23
+
24
+ ## Tests
25
+
26
+ The phase tests retain the existing impact-evidence and forbidden-planning-field assertions through the common report validator. Shared wizard tests cover selecting, skipping, reusing and editing evidence. Shared schema, report-assembly and rendering tests cover the existing report contract and views.
@@ -0,0 +1,23 @@
1
+ """Change impact content boundaries; analysis evidence stays shared."""
2
+ from __future__ import annotations
3
+
4
+ EVIDENCE_COLLECTIONS = (
5
+ "preservedBehaviors",
6
+ "impactItems",
7
+ "dependencyBlastRadius",
8
+ "testImpact",
9
+ "operationalImpact",
10
+ )
11
+
12
+
13
+ def validate_change_impact_semantics(data: dict, errors: list[str]) -> None:
14
+ analysis = data.get("changeImpactAnalysis") or {}
15
+ allowed = {"constraint", "unknown"}
16
+ for index, row in enumerate(analysis.get("planningInputs") or []):
17
+ if not isinstance(row, dict):
18
+ continue
19
+ for field in sorted(set(row) - allowed):
20
+ errors.append(
21
+ f"changeImpactAnalysis.planningInputs[{index}] forbids `{field}`; "
22
+ "planning inputs may contain constraints and unknowns only"
23
+ )
@@ -0,0 +1 @@
1
+ """오류 분석 단계의 진단 규칙과 자원."""
@@ -0,0 +1,9 @@
1
+ {
2
+ "allowed": " - symptom and trigger evidence\n - root-cause hypotheses with supporting citations\n - reproduction gaps and missing observability\n - validation paths to confirm or refute hypotheses\n - one endStateCoverage row per brief end-state id (this phase authors no goal of its own)",
3
+ "forbidden": [
4
+ "source code edits, refactors, or fix attempts",
5
+ "implementation design or planning artifacts",
6
+ "executing builds, migrations, deployments, or any state-mutating command",
7
+ "starting `implementation-planning` or `implementation` inside this run (each must be a separate run, and `implementation` additionally requires an approved `implementation-planning` deliverable)"
8
+ ]
9
+ }
@@ -25,10 +25,10 @@
25
25
  - **Falsifiable cause candidates:** every root-cause candidate must include supporting evidence, the strongest falsifying evidence checked, confidence, and the next diagnostic action that would disprove it. A candidate that cannot be falsified is too vague for this phase.
26
26
  - **Graph-aware scope:** a graph edge can explain ordering or duplication, but it is not proof of cause by itself. Cite code/log evidence before claiming an upstream related task caused the current symptom.
27
27
  - **Sharp next diagnostic:** end with the single highest-value diagnostic command, log capture, or file inspection that should happen next, plus the expected signal that would confirm or reject the leading cause.
28
- - **Fix-design boundary:** do not design the implementation fix beyond what is necessary to validate the cause. If the cause is credible, recommend `implementation-option-selection` with the verified evidence; if the cause is still unclear, recommend another `error-analysis` run with the next diagnostic. The lead's Phase Routing settles the next phase.
28
+ - **Fix-design boundary:** do not design the implementation fix beyond what is necessary to validate the cause. Record whether the cause is credible and the next diagnostic. The common Phase Routing settles the next phase.
29
29
  - Structured diagnosis and routing contract:
30
30
  - `errorAnalysis` is the source of truth for reproduction status, `EA-NNN` cause candidates, the sharp next diagnostic, and the next route.
31
- - A route to `implementation-option-selection` requires a credible leading cause referenced by `routing.leadingCauseId` and `begin-option-selection` as the direction. A route back to `error-analysis` requires the sharp next diagnostic and `continue-investigation` as the direction.
31
+ - Record the route selected by the lead through the common Phase Routing rules, its `routing.leadingCauseId`, and the matching direction.
32
32
  - Structure is enforced by `schemas/final-report-v2.0.schema.json` `$defs.ErrorAnalysis`. `validators/validate-run.py::_validate_error_analysis_consistency` enforces the cross-field values: the routing target, a `routing.leadingCauseId` that names an actual `EA-NNN` candidate, the `verdictCard.direction` / `finalVerdict.direction` pair matching that target, and exactly one `phase-continuation` row in `followUpTasks` pointing at it. The prose of `direction` and `nextStep` is not scanned for routing wording.
33
33
  - Primary focus areas:
34
34
  - symptom and trigger clarification
@@ -1,17 +1,16 @@
1
1
  """Human-first error-analysis view model."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import re
5
6
 
6
- from ..common import evidence_index
7
- from ..models import HumanReportView, VisualEdge, VisualNode
8
- from ..visualizations import cause_graph_figure
7
+ from okstra_ctl.report_html.common import evidence_index
8
+ from okstra_ctl.report_html.models import HumanReportView, VisualEdge, VisualNode
9
+ from okstra_ctl.report_html.visualizations import cause_graph_figure
9
10
 
10
11
  # Record fields this template anchors as `id-<row id>` (see
11
12
  # `HumanReportView.anchored_fields`); ids elsewhere land in the ledger.
12
- ANCHORED_FIELDS = (
13
- "errorAnalysis.causeCandidates",
14
- )
13
+ ANCHORED_FIELDS = ("errorAnalysis.causeCandidates",)
15
14
 
16
15
 
17
16
  _LEAD_CLAUSE = re.compile(r"\s[—–-]\s|(?<=[.。!?])\s")
@@ -43,7 +42,7 @@ def _cause_node(row: dict, leading_cause_id: str) -> VisualNode:
43
42
  "candidate",
44
43
  "leading" if leading else row["confidence"],
45
44
  "",
46
- note="Leading cause" if leading else f'Confidence {row["confidence"]}',
45
+ note="Leading cause" if leading else f"Confidence {row['confidence']}",
47
46
  )
48
47
 
49
48
 
@@ -79,7 +78,9 @@ def _cause_edges(rows: list[dict], symptom_id: str) -> tuple[VisualEdge, ...]:
79
78
 
80
79
 
81
80
  def _cause_figure(error: dict):
82
- symptom = VisualNode("symptom", "Observed failure", "effect", "risk", "", note="Symptom")
81
+ symptom = VisualNode(
82
+ "symptom", "Observed failure", "effect", "risk", "", note="Symptom"
83
+ )
83
84
  rows = error.get("causeCandidates", [])
84
85
  leading_cause_id = (error.get("routing") or {}).get("leadingCauseId") or ""
85
86
  causes = tuple(_cause_node(row, leading_cause_id) for row in rows)
@@ -80,7 +80,7 @@ taskType: "{{FM_TASK_TYPE}}"
80
80
 
81
81
  > Analysers MUST NOT expand the hypothesis space or evidence collection into items listed here. If an analyser believes an excluded item is causally linked to the symptom, it is reported as a recommended follow-up analysis task in the final report — never silently merged into the current root-cause narrative. If this section is left empty, analysers treat any cause beyond what `Symptom Summary` and `Reproduction Context` describe as out of scope by default.
82
82
 
83
- **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.
83
+ **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.
84
84
 
85
85
  ## Questions for Analysers
86
86
 
@@ -1,5 +1,14 @@
1
1
  # error-analysis process
2
2
 
3
+ ## Guarantees
4
+
5
+ | ID | Guarantee | Enforcement |
6
+ |---|---|---|
7
+ | EA-1 | A blocked reproduction names its blocking reason; other statuses carry an empty reason | `scripts/okstra_ctl/phases/error_analysis/validation.py::_validate_reproduction` |
8
+ | EA-2 | Cause-chain links reference sibling candidates and reject self-links and cycles | `scripts/okstra_ctl/phases/error_analysis/tests/test_diagnosis.py::test_cause_chain_rejects_unresolvable_links` |
9
+ | EA-3 | A selected destination agrees with the cause reference, verdict directions, and continuation row | `scripts/okstra_ctl/phases/error_analysis/validation.py::_validate_error_analysis_consistency` |
10
+ | EA-4 | Common routing destinations match both supported report schemas | `scripts/okstra_ctl/phases/error_analysis/tests/test_diagnosis.py::test_error_routing_policy_matches_schema` |
11
+
3
12
  ## Index
4
13
 
5
14
  - [1. Purpose](#1-purpose)
@@ -55,7 +64,7 @@ sequenceDiagram
55
64
 
56
65
  For canonical briefs, preflight runs before worker resolution, worktree provisioning, or report creation. A brief whose `reporter-confirmations` status is `pending` stops at this point; legacy briefs keep the compatibility path.
57
66
 
58
- The final report records its next phase in `errorAnalysis.routing.nextTaskType`. A credible cause uses `implementation-option-selection`; continued investigation uses `error-analysis`. When report validation passes, Phase 7 projects `workflow.nextRecommendedPhase` from that one field (`scripts/okstra_ctl/next_phase.py::project`) — a `ready` pointer naming it. A report that leaves the field empty leaves the pointer `pending`; there is no static fallback that supplies a phase the report did not author.
67
+ The final report records its next phase in `errorAnalysis.routing.nextTaskType`. The common Phase Routing guide selects the destination from the recorded cause evidence. When report validation passes, Phase 7 projects `workflow.nextRecommendedPhase` from that one field (`scripts/okstra_ctl/next_phase.py::project`) — a `ready` pointer naming it. A report that leaves the field empty leaves the pointer `pending`; there is no static fallback that supplies a phase the report did not author.
59
68
 
60
69
  ## 4. lead execution flow
61
70
 
@@ -90,14 +99,20 @@ The expected final-report content is:
90
99
  - practical next diagnostic steps
91
100
  - if there is blocking uncertainty, `## 1. Clarification Items`, usually `Blocks=next-phase`
92
101
 
93
- For `error-analysis`, the structured `errorAnalysis` object is the source of truth for the verbatim symptom, reproduction status, `EA-NNN` cause candidates and their counter-evidence, the next diagnostic, and routing. Its shape is enforced by the final-report schema; `validators/validate-run.py::_validate_error_analysis_consistency` enforces the cross-field values — the routing target, a `leadingCauseId` naming a real cause candidate, the two `direction` fields agreeing with that target, and the single matching `phase-continuation` follow-up row. A route to `implementation-option-selection` needs a credible referenced leading cause and `begin-option-selection`. A route back to `error-analysis` needs the sharp next diagnostic and `continue-investigation`.
102
+ For `error-analysis`, the structured `errorAnalysis` object is the source of truth for the verbatim symptom, reproduction status, `EA-NNN` cause candidates and their counter-evidence, the next diagnostic, and routing. Its shape is enforced by the final-report schema; `validators/validate-run.py::_validate_error_analysis_consistency` enforces the cross-field values — the routing target, a `leadingCauseId` naming a real cause candidate, the two `direction` fields agreeing with that target, and the single matching `phase-continuation` follow-up row. The common Phase Routing guide owns the conditions for selecting the next phase.
94
103
 
95
104
  What is prohibited is source edit, refactor, fix attempt, implementation design artifact, and running build/migration/deploy. Deferring ambiguity that could be answered from code or logs to a user question is also a defect per the profile.
96
105
 
97
106
  ## 6. Code reviewed
98
107
 
99
- - [`prompts/profiles/error-analysis.md`](../../prompts/profiles/error-analysis.md)
100
- - [`templates/reports/error-analysis-input.template.md`](../../templates/reports/error-analysis-input.template.md)
101
- - [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py)
102
- - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
103
- - [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md)
108
+ - [`prompts/profiles/error-analysis.md`](profile.md)
109
+ - [`templates/reports/error-analysis-input.template.md`](report_assets/error-analysis-input.template.md)
110
+ - [`scripts/okstra_ctl/workflow.py`](../../workflow.py)
111
+ - [`scripts/okstra_ctl/wizard/`](../../wizard)
112
+ - [`prompts/lead/okstra-lead-contract.md`](../../../../prompts/lead/okstra-lead-contract.md)
113
+
114
+ ## Phase ownership
115
+
116
+ `profile.md` and `profile.json` own the diagnostic procedure and worker requirements. `validation.py` owns reproduction, cause-chain, and authored routing consistency checks. `report.py` and `report_assets/` own the diagnosis display and input template. The common lead guide `prompts/lead/phase-routing.md` owns destination selection; common evidence reading, clarification contracts, and lifecycle projection remain outside this phase. The shared 2.0 and 3.0 final-report schemas retain `$defs.ErrorAnalysis`.
117
+
118
+ `tests/test_diagnosis.py` exercises diagnosis rules. The common contract suite retains workflow projection and final-report assembly tests. No additional entry or wizard module is needed: this phase uses the common brief preflight and worker-selection flow.