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
@@ -13,6 +13,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
13
13
  - When the thin core's Task worktree block resolves status to `created` or `reused`, the Executor MUST run every Edit / Write / build / test / commit command with the worktree path as cwd. Treat it as `project_root` for the duration of this run. Do NOT mutate the caller's original checkout. Do NOT `cd` out of the worktree to reach files. If a file outside the worktree is genuinely needed, treat it as a planning gap: record it in `Out-of-plan edits` and continue.
14
14
  - **How to set the working directory**: every command and native edit MUST target `{{EXECUTOR_WORKTREE_PATH}}`, never the lead session's original project directory. The selected runtime adapter owns the exact native command syntax. Provider CLI wrappers inject the worktree at the CLI layer. For tools that accept an explicit working-directory flag (`git -C <path>`, `cargo --manifest-path`, `pytest --rootdir`), prefer that form.
15
15
  - **Synced okstra state directory.** At provision time Okstra may symlink `.project-docs/` from the repo's **main worktree** into the task worktree. This is NOT an independent copy — writes through it land in the main worktree. Inside this run the executor MUST confine okstra artifact writes to its own task scope (i.e. `.okstra/tasks/<this-task-id>/...`). Other synced directories, if present due to local configuration, are not implicit okstra context; read them only when the brief explicitly cites them as source material.
16
+ - **Dependency installs stay in this worktree.** Before a package install (`yarn install`, `npm ci`, `pnpm install`, and the like), check the `node_modules` of the directory you install in. When it is a symlink that resolves outside this worktree, remove the link and install into a real `node_modules`: an install through the link rewrites the other checkout's dependencies. This is a guideline: nothing blocks the command, and the write audit only reports such a link as a `dependency tree links outside the assigned worktree` warning (`scripts/okstra_ctl/execution_mutation_audit.py`).
16
17
 
17
18
  **Enforced:** the worktree path reaches this worker as the `**Worktree:**` anchor (`scripts/okstra_ctl/worker_prompt_policy.py` `IMPLEMENTATION_HEADERS`), the CLI wrapper is started with that path as cwd by `scripts/okstra_ctl/dispatch_core.py`, and `scripts/okstra_ctl/execution_mutation_audit.py` `_source_changes` reports a mutation that landed outside the attempt's `writePolicy` roots.
18
19
 
@@ -20,8 +21,8 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
20
21
 
21
22
  - **Three BLOCKING gates bind this run, and their bodies travel with this prompt** — inlined under their own headings, or named by path under `## Required prompt resources`. Follow the delivered body verbatim; a gate re-typed from memory is a skipped gate. Each gate's own body owns its rule list, so nothing here restates it:
22
23
  - `Coding-conventions preflight` (`prompts/profiles/_coding-conventions-preflight.md`) — before the first `Edit` / `Write`. It loads the conventions and binds the TDD loop below; close it by stating in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`).
23
- - `Pre-commit diff review sweep` (`prompts/profiles/_implementation-diff-review.md`) — after the stage's last `Edit` / `Write`, before the final commit. Sweep `git diff <stage-base>..HEAD` against the conventions the preflight loaded, fix findings in place while they are inside this stage's scope, and write its `Coverage:` footer to your audit sidecar.
24
- - `Implementation self-check` (`prompts/profiles/_implementation-self-check.md`) — before you append the `status:"done"` row. Write the confirming evidence per item to your audit sidecar.
24
+ - `Pre-commit diff review sweep` (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-diff-review.md`) — after the stage's last `Edit` / `Write`, before the final commit. Sweep `git diff <stage-base>..HEAD` against the conventions the preflight loaded, fix findings in place while they are inside this stage's scope, and write its `Coverage:` footer to your audit sidecar.
25
+ - `Implementation self-check` (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-self-check.md`) — before you append the `status:"done"` row. Write the confirming evidence per item to your audit sidecar.
25
26
 
26
27
  <!--
27
28
  Gate delivery (lead / maintainer — stripped before this body reaches a worker).
@@ -88,7 +89,7 @@ template's check; that template is gone.
88
89
  ```
89
90
 
90
91
  The file MUST NOT exist before the run starts (overwrite is refused — see `--force-stage` non-goal). **Enforced:** `validators/validate-run.py` `_validate_stage_carry_sidecar_exists` fails a run that declares `stageSidecarEvidence` without the file on disk. Transcribing the JSON into the report is not the same as writing it: `consumers` treats the carry file as the source of truth for marking the stage `done`, so a missing file leaves the stage permanently incomplete and blocks every dependent stage with a `PrepareError` — while this run reports success.
91
- - **Verifier gates are not yours to run (BLOCKING).** The self-mock detector (`validators/detect_self_mock.py`) belongs to the implementation verifier and is never delegated to you (`_implementation-verifier.md` §"Self-mock detection"). The coding-conventions preflight names it as the enforcement behind the no-self-mocking principle — that names who will check your diff, not a command for you to run. You MUST NOT invoke it and MUST NOT write `<task_root>/qa/self-mock-*.json`; running it early does not pre-satisfy the gate, because the verifier runs it again under its own duty. **Enforced:** that sidecar is not among the paths your attempt's `writePolicy.artifactPolicy.allowedPaths` carries, so the write audit closes the attempt as `error` with `artifact-root change exceeds batch policy union` (`scripts/okstra_ctl/execution_mutation_audit.py`) — a stage whose every gate passed still lands as a failed run.
92
+ - **Verifier gates are not yours to run (BLOCKING).** The self-mock detector (`validators/detect_self_mock.py`) belongs to the implementation verifier and is never delegated to you (`_implementation-verifier.md` §"Self-mock detection"). The coding-conventions preflight names it as the enforcement behind the no-self-mocking principle — that names who will check your diff, not a command for you to run. You MUST NOT invoke it and MUST NOT write `<task_root>/qa/self-mock-*.json`; running it early does not pre-satisfy the gate, because the verifier runs it again under its own duty. **Enforced:** that sidecar is not among the paths your attempt's `writePolicy.artifactPolicy.allowedPaths` carries, so the write audit closes the attempt as `error` with `artifact-root change exceeds batch policy union` (`scripts/okstra_ctl/execution_mutation_audit.py`) — a stage whose every gate passed still lands as a failed run. The same holds for the conformance results `<task_root>/qa/result-*.json`: you may run a conformance script to check your work, but the verifier records every result, including an earlier stage's result that your rewrite of its script made stale. When the approved plan tells you to write one, leave it and name it in your result as a plan step the verifier owns.
92
93
  - **An external Tier 3 non-PASS does NOT withhold the carry evidence.** A Tier 3 entry whose `requires` include `http`, `external`, or `db` is advisory. Its FAIL, MISSING, no result, startup failure, or credential / network / service absence gets recorded honestly — exact command, exit code, output tail, marked `ADVISORY` in `Validation evidence` — and you emit the carry evidence anyway. Only Tier 1 and Tier 2 failures withhold it. Withholding on an external result is what actually blocks the stage: the carry file is the only thing that can mark a stage `done`, the verifier re-runs that same command from the host (where a call your sandbox could not complete often passes), and a stage the verifier then PASSes can never be closed because its evidence was never written.
93
94
  - **Reverse link (BLOCKING).** The runtime already appended a `status:"started"` row for this stage before the run began. The terminal row belongs to the lead's post-stage persistence and is verdict-gated — `status:"done"` with `carry_path` on a non-`FAIL` verdict, `status:"failed"` on `FAIL` (`_implementation-deliverable.md` §"Lead post-stage persistence").
94
95
  - **No PR / push in this phase.** This run produces local commits, carry sidecar evidence, verifier results, and the implementation final report only. Push and PR creation belong exclusively to the later `release-handoff` phase after `final-verification` returns `accepted`.
@@ -32,7 +32,7 @@ A target mismatch or changed fingerprint invalidates this check's evidence. Reco
32
32
  Verifier obtains the QA command set from exactly two declared sources, in order — there is **no fallback to guessing tools from manifest files**.
33
33
 
34
34
  1. **Tier 1 — plan validation set (task-specific):** every command listed under the approved plan's `validation` block (pre / mid / post). The plan is the file at this prompt's `**Approved plan:**` anchor, scoped to the stage its `**Stage for this implementation run:**` anchor names; both are generated headers, so a missing one is `contract-violated`, never a value to infer. Each checklist row also carries `phase`, and the phase is part of what the row asserts: `pre` runs before the stage edits, `mid` between the edits and the stage commit, `post` after the commit. A `mid` diff-scope check (`git diff --name-only` listing the touched paths) is reproduced over the stage range — `git diff --name-only <stage base>...HEAD` — once the stage has committed; its empty output on the clean post-commit tree is the plan's own step order, not a divergence. A `Discrepancy` that cites a checklist row names the row and its phase as `VC-NNN (phase: mid)`; a verifier that reads the command without the phase has read half the row. **Enforced:** `_validate_verifier_discrepancy_names_checklist_phase` in `validators/validate-run.py` fails a divergence that cites a `VC-` row without that row's phase.
35
- 2. **Tier 2 — project baseline:** the project's standing QA baseline from the `Project QA Commands` section emitted by `okstra model-io project-context --project-root <PROJECT_ROOT> --task-ref <task-ref>`.
35
+ 2. **Tier 2 — project baseline:** the project's standing QA baseline from the `Project QA Commands` section emitted by `okstra model-io project-context --project-root <PROJECT_ROOT> --task-ref <TASK_KEY>` (the full `Task key` your dispatch prompt names).
36
36
  ```json
37
37
  {
38
38
  "qaCommands": {
@@ -75,7 +75,7 @@ lock the core, gate, and accepted-report behavior respectively.
75
75
  An `io`-only non-PASS remains BLOCKING. Manifest/schema/source-mutation defects
76
76
  also remain contract violations.
77
77
 
78
- - **Source.** The conformance manifest is `<task_root>/qa/conformance-manifest.json` (the directory is the `TASK_QA_PATH` token). This run's stage conformance entry is the manifest `entries[]` item whose `stageKey` equals this run's stageKey — `<task-id>-stage-<N>`, where `<N>` is the injected Stage number. Find that one entry; ignore the others (other stages are run by their own implementation runs or by final-verification).
78
+ - **Source.** The conformance manifest is `<task_root>/qa/conformance-manifest.json` (the directory is the `TASK_QA_PATH` token). This run's stage conformance entry is the manifest `entries[]` item whose `stageKey` equals this run's stageKey — `<task-id>-stage-<N>`, where `<N>` is the injected Stage number. Find that one entry. Also run every other entry whose `script` appears in this stage's `plannedPaths`: this stage rewrote that script, so the result its own stage recorded is stale, and you write that entry's result sidecar exactly as below. Ignore the rest (other stages are run by their own implementation runs or by final-verification).
79
79
  - **Exemption / waiver → do NOT run.** If the entry carries an `exemption` (or a user `waiver`), the verifier does NOT execute the script. It records the fact and the reason (`exemption.reason` / `waiver.reason` + `waiver.acknowledgedBy`) in the Read-only command log AND writes the result sidecar reflecting the skip. An `exemption` passes outright. An external-advisory waiver is reported as `ADVISORY` with `conditional=false`; only an `io`-only blocking waiver is conditional. An empty `requires` list cannot be waived; it is declaration/contract trouble and remains BLOCKING. No script runs in either permitted waiver case.
80
80
  - **Otherwise run `runCommand` in the worktree cwd.** Execute the entry's `runCommand` verbatim from the worktree cwd. Inject env from `<PROJECT_ROOT>/.okstra/project.json`'s `qaEnv` (replica DB DSN / app base URL / env file — declared in Phase 4e). This is a **replica / test environment only** path — never run it against shared / staging / prod, identical to the DB real-execution gate principle above.
81
81
  - **Interpret the standard interface.** Parse the process exit code together with stdout: the `QA-RESULT: PASS|FAIL` marker line (if several appear, the last one wins) and the per-requirement `REQ <id>: PASS|FAIL: <reason>` lines. If no `QA-RESULT` marker is emitted, the overall result is `MISSING`; classify it according to the entry's blocking or external-advisory capability policy above.
@@ -173,7 +173,7 @@ Re-running commands proves the diff *builds and passes*; it does NOT prove the d
173
173
  - **Scope (no silent sampling).** Enumerate every changed source/test file via `git diff --name-only <base>...HEAD` and review each one. Skipping a changed file silently is a `contract-violated` outcome. If a file's language has no reference and is not covered by the agnostic checks below, record `design-review skipped: <file> (language=<x> no reference)` — never pass it silently.
174
174
  - **Load the same conventions the executor used via the routed pack.** Use this worker prompt's `**Coding preflight pack:**` anchor header as the absolute path to the installed routed pack. Read `overview.md` first, then `clean-code.md`, then apply the router's three ordered stages: language, framework, architecture. In each stage, iterate every rule, treat a rule as matched when any listed condition is true, and accumulate every matching resource — including `frameworks/node-server.md` for server-side Node work and `architectures/hexagonal.md` for ports-and-adapters / NestJS-hex layouts. Degrade to the agnostic checks below when the resolved pack is unreadable, and record either `coding-conventions: resources=<...>` or `coding-conventions: resource-unavailable → applied <project rules + agnostic principles>`. The verifier does NOT inline language rules — it loads the same situation-specific resources as the executor preflight.
175
175
  - **Load the project's review rule packs.** Run the project-context projection above and union its `Project Review Rule Packs` entries with exact `SKILL.md` paths cited by the task brief's `Source Material` / `Reporter Confirmations`. Read only those files and the `references/*.md` files they directly name. Do not search parent directories or host skill catalogs. Apply the rules as an overlay on this static review, but do NOT dispatch extra reviewer agents unless the task explicitly configured them. Record `project-review-rules: <paths read>`, `project-review-rules: declared <path> unreadable`, or `project-review-rules: none declared or cited` in the worker result — an unreadable declared pack is a recorded gap, not a skip.
176
- - **Declared architecture style promotes the placement overlay from advisory to binding.** Take `Architecture style` from that projection and record `architecture-style: <hexagonal|layered|none>` in the worker result next to the `coding-conventions:` line. A declared `hexagonal` counts the overlay as loaded even when none of the router's Stage 3 layout signals matched, so the **Hexagonal** blocking check below applies in full, and the concrete-adapter injection listed under Advisory findings is promoted to a blocking finding → verdict `FAIL`, not a `should-fix`. A declared `layered` has no pack resource; its binding invariant is direction — an upper layer may import a lower one, never the reverse — so a changed file whose import list reaches back up a layer, or around a layer boundary, is a blocking placement violation cited `path:line` from that import list. The `layered` half is worker judgement: no machine check reads layer names, so a missed reverse dependency is a missed finding, not a validator failure. A `none` or absent projected style leaves Stage 3 detection-driven and the placement items advisory. **Enforced:** `scripts/okstra_project/resolver.py` `resolve_architecture` reads the same stored field for the planning-side rule in `validators/validate-run.py` `_validate_variation_point_analysis`, and `_validate_verifier_fail_blocks_verdict` keeps the resulting `FAIL` from being dropped during synthesis.
176
+ - **Declared architecture style promotes the placement overlay from advisory to binding.** Take `Architecture style` from that projection and record `architecture-style: <hexagonal|layered|none>` in the worker result next to the `coding-conventions:` line. A declared `hexagonal` counts the overlay as loaded even when none of the router's Stage 3 layout signals matched, so the **Hexagonal** blocking check below applies in full, and the concrete-adapter injection listed under Advisory findings is promoted to a blocking finding → verdict `FAIL`, not a `should-fix`. A declared `layered` has no pack resource; its binding invariant is direction — an upper layer may import a lower one, never the reverse — so a changed file whose import list reaches back up a layer, or around a layer boundary, is a blocking placement violation cited `path:line` from that import list. The `layered` half is worker judgement: no machine check reads layer names, so a missed reverse dependency is a missed finding, not a validator failure. A `none` or absent projected style leaves Stage 3 detection-driven and the placement items advisory. **Enforced:** `scripts/okstra_project/resolver.py` `resolve_architecture` reads the same stored field for the planning-side rule in `scripts/okstra_ctl/phases/implementation_planning/plan_body.py` `_validate_variation_point_analysis`, and `_validate_verifier_fail_blocks_verdict` keeps the resulting `FAIL` from being dropped during synthesis.
177
177
  - **Blocking checks (any hit → verdict `FAIL`, cited `path:line` + rule name, recommended fix recorded — the verifier does NOT apply it):**
178
178
  - **New duplication / DRY:** two or more newly added or meaningfully modified blocks implement the same helper stack, transform, or domain rule. Literal copy-paste is always blocking; semantically equivalent transforms across services are blocking unless the approved plan explicitly justified keeping them separate. Recommend the shared module location.
179
179
  - **Self-mocking:** a test for `Foo` stubs/spies a method on the `Foo` instance under test (`jest.spyOn(sut, ...)`, `spyOn(FooService.prototype, ...)` in `foo.*.spec.*`, `vi.mocked(sut)` + stub). Mocking injected collaborators is fine.
@@ -255,7 +255,7 @@ If every verifier present in the resolved roster ends with a non-result terminal
255
255
 
256
256
  ## Executor completion self-check (not this role's gate)
257
257
 
258
- - The executor's `Implementation self-check` gate (`prompts/profiles/_implementation-self-check.md`) belongs to the worker that owns the diff, and its body is deliberately not delivered here: it asks for in-place fixes and break-then-restore mutation checks, every one of which this verifier is forbidden to perform. Do not re-derive its items or claim to have run it. What grades the same defects from this side is the blocking taxonomy above, applied to the diff you re-read yourself. When the executor's `Coverage:` / `Self-check coverage:` lines are among the inputs this prompt enumerates, a missing line or one whose file list does not reconcile with the diff is a blocking finding — the gate was skipped or partially run.
258
+ - The executor's `Implementation self-check` gate (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-self-check.md`) belongs to the worker that owns the diff, and its body is deliberately not delivered here: it asks for in-place fixes and break-then-restore mutation checks, every one of which this verifier is forbidden to perform. Do not re-derive its items or claim to have run it. What grades the same defects from this side is the blocking taxonomy above, applied to the diff you re-read yourself. When the executor's `Coverage:` / `Self-check coverage:` lines are among the inputs this prompt enumerates, a missing line or one whose file list does not reconcile with the diff is a blocking finding — the gate was skipped or partially run.
259
259
 
260
260
  ## Plan differences and completion recovery
261
261
 
@@ -25,8 +25,8 @@
25
25
  - the run brief MUST cite `--approved-plan <path>` pointing to a `final-report-implementation-planning-<seq>.data.json` report record produced by a prior `implementation-planning` run located under `runs/implementation-planning/.../reports/`
26
26
  - that plan's report record MUST carry `frontmatter.approved: true`. report-writer emits `false` by default; the user authorises this run with `--approve` or the in-session wizard. Free-form approvals such as "lgtm" / "go ahead" / paraphrased confirmations are NOT accepted; editing the full reading copy does not approve the plan (`okstra_ctl.run._apply_cli_approval`).
27
27
  - The `--approve` flag is meaningful ONLY with `--task-type implementation` and `--approved-plan <path>`; any other use raises `PrepareError`. Idempotent — re-running with `approved: true` already set does not write again.
28
- - determine the plan branch from the sibling data.json `implementationPlanning.planningContract`. For `selected-direction`, the authoritative scope is `selectedDirectionRef`, its validated snapshot, `directionRealization`, and the selected stage; the plan MUST be `plan-ready` with exact coverage, and both an `implementation-option:` frontmatter field and `--implementation-option` are forbidden. A direction change routes to `implementation-option-selection`; a detail-only plan correction routes to `implementation-planning`.
29
- - for the legacy candidate-comparison branch, the authoritative scope is the Option Candidate named by the report record `frontmatter.implementationOption` field. **If that field is empty, fall back to the plan's `Recommended Option`** (this is a soft fallback, not a hard block). The chosen option's step list becomes the authoritative scope. Any deviation MUST be justified in the final report AND routed to a new `implementation-planning` run; never silently expand scope. If the chosen option name does not match any heading under `Option Candidates`, record it as a deviation.
28
+ - determine the plan branch from the sibling data.json `implementationPlanning.planningContract`. For `selected-direction`, the authoritative scope is `selectedDirectionRef`, its validated snapshot, `directionRealization`, and the selected stage; the plan MUST be `plan-ready` with exact coverage, and both an `implementation-option:` frontmatter field and `--implementation-option` are forbidden. Record whether a deviation changes the selected direction or only plan details; the lead applies `prompts/lead/phase-routing.md`.
29
+ - for the legacy candidate-comparison branch, the authoritative scope is the Option Candidate named by the report record `frontmatter.implementationOption` field. **If that field is empty, fall back to the plan's `Recommended Option`** (this is a soft fallback, not a hard block). The chosen option's step list becomes the authoritative scope. Any deviation MUST be justified in the final report; never silently expand scope. The lead applies `prompts/lead/phase-routing.md`. If the chosen option name does not match any heading under `Option Candidates`, record it as a deviation.
30
30
  - Stage worktree (provisioned by Okstra at this implementation run's prep time):
31
31
  - Status: `{{EXECUTOR_WORKTREE_STATUS}}` (one of: `created` | `reused` | `skipped-in-worktree` | `skipped-not-git`)
32
32
  - Working tree path: `{{EXECUTOR_WORKTREE_PATH}}` — when status is `created` or `reused`, this is this run's isolated stage worktree rooted at `~/.okstra/worktrees/<project>/<task-group>/<task-id>/stage-<N>/`. When skipped, this is the caller's `project_root`.
@@ -48,9 +48,9 @@ The bulk of this profile's body is split into three sidecars so the lead's Phase
48
48
 
49
49
  | Sidecar | Read at | Purpose |
50
50
  |---------|---------|---------|
51
- | `prompts/profiles/_implementation-executor.md` | Start of Phase 5 (after Stage Map parse, before Executor's first Edit / Write) | Executor role binding, Pre-implementation context exploration, TDD loop, Stage execution contract, allowed actions, commit-message format |
52
- | `prompts/profiles/_implementation-verifier.md` | Phase 5, between Executor stage completion and the first verifier dispatch | Verifier roles, Two-tier command lookup, deny-list, discrepancy rule, Read-only command log, verifier-specific forbidden actions |
53
- | `prompts/profiles/_implementation-deliverable.md` | Start of Phase 6 (after Phase 5.5 convergence completes, before report-writer dispatch prompt construction) | Required deliverable shape, Validation / TDD evidence rules, Verifier results structure, Self-review pass, Lead post-stage persistence |
51
+ | `scripts/okstra_ctl/phases/implementation/instructions/_implementation-executor.md` | Start of Phase 5 (after Stage Map parse, before Executor's first Edit / Write) | Executor role binding, Pre-implementation context exploration, TDD loop, Stage execution contract, allowed actions, commit-message format |
52
+ | `scripts/okstra_ctl/phases/implementation/instructions/_implementation-verifier.md` | Phase 5, between Executor stage completion and the first verifier dispatch | Verifier roles, Two-tier command lookup, deny-list, discrepancy rule, Read-only command log, verifier-specific forbidden actions |
53
+ | `scripts/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md` | Start of Phase 6 (after Phase 5.5 convergence completes, before report-writer dispatch prompt construction) | Required deliverable shape, Validation / TDD evidence rules, Verifier results structure, Self-review pass, Lead post-stage persistence |
54
54
 
55
55
  **Entering Phase 5 / 6 while the relevant sidecar is not in the lead's context is BLOCKING — the phase entry is refused.** After reading a sidecar, the lead must continue into the phase's follow-up action within a single turn (i.e. the sidecar's rules take effect starting from the very turn it is read).
56
56
 
@@ -1,9 +1,9 @@
1
1
  """Human-first implementation delivery view model."""
2
2
  from __future__ import annotations
3
3
 
4
- from ..common import evidence_index
5
- from ..models import HumanReportView, VisualNode
6
- from ..visualizations import change_map_figure
4
+ from okstra_ctl.report_html.common import evidence_index
5
+ from okstra_ctl.report_html.models import HumanReportView, VisualNode
6
+ from okstra_ctl.report_html.visualizations import change_map_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.
@@ -52,7 +52,7 @@ taskType: "{{FM_TASK_TYPE}}"
52
52
 
53
53
  > The executor MUST NOT modify items listed here, even when an edit looks "trivial" or "while I'm in this file". Excluded items that block plan execution are reported back as a recommended follow-up task and the run halts for re-planning rather than silently expanding scope. This section is enforced together with `Forbidden In This Run` below.
54
54
 
55
- **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `validators/validate_improvement_report.py` checks that one.
55
+ **Enforced (delivery only):** `tests/contract/test_scope_boundary_delivery.py` pins that a filled section reaches every analysis worker through `okstra_ctl.analysis_packet` — drop it from `CANONICAL_BRIEF_SECTIONS` and every run's exclusions vanish silently. The exclusions themselves are prose and are **not** machine-checked: only the codebase-scan `out-of-scope` frontmatter is a path list, and `scripts/okstra_ctl/phases/improvement_discovery/validation.py` checks that one.
56
56
 
57
57
  **Enforced (declared edits only):** `_validate_out_of_plan_edits_are_real` in `validators/validate-run.py` fails an `Out-of-plan edits` row naming a file that is absent from `diffSummary`. The other direction — a file changed outside the approved plan and never declared — needs the plan's own file list resolved through `approvedPlanReference.planFile`, and is not built.
58
58
 
@@ -64,7 +64,7 @@ here because they were previously readable only by tracing the runtime sources.
64
64
  the automatic attachment is the fallback for an implementation run that supplies none
65
65
  (`scripts/okstra_ctl/run.py`, the `implementation` carry-in branch).
66
66
  - **Who reads it, and when.** The executor, before its first edit
67
- (`prompts/profiles/_implementation-executor.md`). A CLI executor (codex/antigravity)
67
+ (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-executor.md`). A CLI executor (codex/antigravity)
68
68
  cannot reach that path from inside its sandbox, so the lead transcribes the file's body
69
69
  into the dispatched executor prompt — a path reference alone never arrives.
70
70
  - **What happens when an answer contradicts the plan.** Each answer is an authoritative
@@ -217,10 +217,22 @@ This phase does not declare final acceptance. It says only ready for final-verif
217
217
 
218
218
  ## 8. Verified code
219
219
 
220
- - [`prompts/profiles/implementation.md`](../../prompts/profiles/implementation.md)
221
- - [`templates/reports/implementation-input.template.md`](../../templates/reports/implementation-input.template.md)
222
- - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
223
- - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
224
- - [`validators/validate-implementation-plan-stages.py`](../../validators/validate-implementation-plan-stages.py)
225
- - [`scripts/okstra_ctl/qa_commands.py`](../../scripts/okstra_ctl/qa_commands.py)
226
- - [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md)
220
+ - [`scripts/okstra_ctl/phases/implementation/profile.md`](profile.md)
221
+ - [`scripts/okstra_ctl/phases/implementation/report_assets/implementation-input.template.md`](report_assets/implementation-input.template.md)
222
+ - [`scripts/okstra_ctl/run.py`](../../run.py)
223
+ - [`scripts/okstra_ctl/wizard/`](../../wizard)
224
+ - [`validators/validate-implementation-plan-stages.py`](../../../../validators/validate-implementation-plan-stages.py)
225
+ - [`scripts/okstra_ctl/qa_commands.py`](../../qa_commands.py)
226
+ - [`prompts/lead/okstra-lead-contract.md`](../../../../prompts/lead/okstra-lead-contract.md)
227
+
228
+ ## Phase ownership
229
+
230
+ `entry.py` owns stage claim preparation, design-preparation checks and execution context publication. `wizard.py` owns implementation stage selection policy. `validation.py` enforces independent rerun and discrepancy verdicts. `tests/test_implementation_stage.py` checks claims and consumer publication; `tests/test_verifier_results.py` checks verifier verdicts. Shared plan records, stage lifecycle state and worktree registry remain common contracts. Report schema definitions remain in `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json` under `implementation`.
231
+
232
+ ## Guarantees
233
+
234
+ | ID | Guarantee | Enforcement |
235
+ |---|---|---|
236
+ | I-1 | An empty independent rerun record fails validation. | `scripts/okstra_ctl/phases/implementation/validation.py::_validate_verifier_reran_independently` |
237
+ | I-2 | A verifier cannot report a discrepancy with a PASS verdict. | `scripts/okstra_ctl/phases/implementation/validation.py::_validate_verifier_discrepancy_is_not_passed` |
238
+ | I-3 | Frozen legacy instruction pointers resolve within the selected installation without rewriting the frozen profile. | `scripts/okstra_ctl/phases/implementation/tests/test_assets.py::test_frozen_sidecar_reference_reads_the_owned_installation` |
@@ -0,0 +1,205 @@
1
+ """구현 검증자의 독립 재현과 판정 일관성 검사."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from collections.abc import Callable
6
+
7
+ _PASSING_VERDICT_TOKENS = frozenset({"accepted", "conditional-accept"})
8
+ _CHECKLIST_ID_RE = re.compile(r"\bVC-\d{3,}\b")
9
+ _CHECKLIST_PHASE_RE = re.compile(r"\bphase\W{0,3}(pre|mid|post)\b", re.IGNORECASE)
10
+
11
+
12
+ def _validate_verifier_reran_independently(data: dict, failures: list[str]) -> None:
13
+ """`independentValidationRerun` 칸이 비어 있지 않아야 한다.
14
+
15
+ 스키마는 필드 존재만 강제하고 값은 보지 않는다. 빈 칸은 재현 없이
16
+ 통과시킨 것과 구별되지 않는다.
17
+
18
+ executor 인용 표현을 잡던 정규식 갈래는 삭제했다. 표현을 세는 검사라
19
+ 같은 재현을 어떻게 서술했느냐로 통과가 갈렸다.
20
+ """
21
+ for who, row in _verifier_rows(data):
22
+ rerun = row.get("independentValidationRerun")
23
+ if not isinstance(rerun, str) or not rerun.strip():
24
+ failures.append(
25
+ f"verifier-rerun: {who} 가 independentValidationRerun 을 비워 뒀다 — "
26
+ "재현 없이 통과시킨 것과 구별되지 않는다"
27
+ )
28
+
29
+
30
+ def _validate_verifier_discrepancy_is_not_passed(
31
+ data: dict, failures: list[str]
32
+ ) -> None:
33
+ """재현 결과가 executor 보고와 갈렸는데 PASS 로 넘기지 못하게 한다.
34
+
35
+ 규칙(§"Discrepancy rule")은 Tier 1/2 와 blocking io-only Tier 3 의 divergence 에
36
+ `FAIL` 을 요구하고, Tier 3 외부 자문 divergence 만 제외한다. 리포트 구조에는
37
+ tier 필드가 없어 그 둘을 여기서 가릴 수 없다. 그래서 `PASS` 만 막는다 —
38
+ 자문 divergence 는 `CONCERNS` 로 기록할 자리가 이미 있고, `PASS` 는 "갈렸는데
39
+ 아무 일도 없었다" 는 뜻이라 어느 tier 로도 정당화되지 않는다.
40
+ """
41
+ for who, row in _verifier_rows(data):
42
+ discrepancy = row.get("discrepancy")
43
+ if not isinstance(discrepancy, str) or not discrepancy.strip():
44
+ continue
45
+ if row.get("verdict") == "PASS":
46
+ failures.append(
47
+ f"verifier-discrepancy: {who} 가 divergence 를 기록하고도 PASS 를 냈다 "
48
+ f"— FAIL(또는 자문 divergence 면 CONCERNS)이어야 한다: "
49
+ f"{discrepancy.strip()[:120]}"
50
+ )
51
+
52
+
53
+ def _verifier_rows(data: dict):
54
+ """(표시 이름, verifierResults 행) 쌍."""
55
+ implementation = data.get("implementation")
56
+ if not isinstance(implementation, dict):
57
+ return
58
+ for row in implementation.get("verifierResults") or []:
59
+ if not isinstance(row, dict):
60
+ continue
61
+ yield str(row.get("verifier") or row.get("role") or "verifier"), row
62
+
63
+
64
+ def _warn_out_of_plan_edits_not_in_diff(data: dict, warnings: list[str], changed_files: list[str]) -> None:
65
+ """소스 차이 목록은 별도 QA 산출물의 변경 여부를 증명하지 못한다."""
66
+ implementation = data.get("implementation")
67
+ if not isinstance(implementation, dict):
68
+ return
69
+ rows = implementation.get("outOfPlanEdits")
70
+ if not isinstance(rows, list) or not rows:
71
+ return
72
+ changed = set(changed_files)
73
+ if not changed:
74
+ return
75
+ for row in rows:
76
+ if not isinstance(row, dict):
77
+ continue
78
+ target = row.get("file")
79
+ if isinstance(target, str) and target and target not in changed:
80
+ warnings.append(
81
+ f"out-of-plan-edit: {row.get('id') or 'OOP-???'} 가 `{target}` 을 "
82
+ "계획 밖 편집으로 신고했지만 diffSummary 에 그 파일이 없다"
83
+ )
84
+
85
+
86
+ def _validate_verifier_discrepancy_names_checklist_phase(
87
+ data: dict,
88
+ plan: dict | None,
89
+ failures: list[str],
90
+ ) -> None:
91
+ """계획 `validationChecklist` 행을 근거로 적은 divergence 는 그 행의 `phase` 를 인용한다.
92
+
93
+ 2026-09-05 실측(fontsninja-v3-site dev-10626 stage-1): codex 검증자가 `VC-003` 의
94
+ `git diff --name-only` 가 커밋 뒤 빈 출력이라며 FAIL 을 냈다. 그 행은 계획 레코드에
95
+ `phase: mid` — 편집과 커밋 사이의 체크포인트 — 로 선언돼 있어, 커밋 뒤의 빈 출력은
96
+ 계획의 단계 순서 그 자체였다. 수렴에서 제기자 본인이 반대 읽기에 AGREE 했지만 FAIL
97
+ 행은 남아 stage 가 `failed` 로 갔고, 리드도 그 주장을 열어 보지 않고 라우팅에 옮겼다.
98
+ `pre`/`mid`/`post` 는 행이 언제 성립하는지를 정하므로, 행을 인용하는 문장이 그 값을
99
+ 함께 적어야 한다 — 읽지 않은 행을 근거로 쓰는 문장은 그러면 쓸 수 없다.
100
+
101
+ 행에 `phase` 가 없거나 계획 레코드를 못 찾으면 판정하지 않는다.
102
+ """
103
+ if plan is None:
104
+ return
105
+ planning = plan.get("implementationPlanning")
106
+ rows = planning.get("validationChecklist") if isinstance(planning, dict) else None
107
+ phases = {
108
+ str(row["id"]): str(row["phase"]).strip().lower()
109
+ for row in (rows if isinstance(rows, list) else [])
110
+ if isinstance(row, dict)
111
+ and isinstance(row.get("id"), str)
112
+ and isinstance(row.get("phase"), str)
113
+ }
114
+ if not phases:
115
+ return
116
+ for who, row in _verifier_rows(data):
117
+ discrepancy = row.get("discrepancy")
118
+ if not isinstance(discrepancy, str) or not discrepancy.strip():
119
+ continue
120
+ cited = sorted(set(_CHECKLIST_ID_RE.findall(discrepancy)) & set(phases))
121
+ if not cited:
122
+ continue
123
+ named = {
124
+ match.group(1).lower()
125
+ for match in _CHECKLIST_PHASE_RE.finditer(discrepancy)
126
+ }
127
+ missing = [
128
+ f"{row_id} (phase: {phases[row_id]})"
129
+ for row_id in cited
130
+ if phases[row_id] not in named
131
+ ]
132
+ if missing:
133
+ failures.append(
134
+ f"verifier-discrepancy: {who} 가 계획 체크리스트 행을 근거로 divergence 를 "
135
+ f"적었지만 그 행의 phase 를 인용하지 않았다 — {', '.join(missing)}. "
136
+ "`pre`/`mid`/`post` 는 행이 언제 성립하는지를 정하므로 인용 문장에 "
137
+ "`VC-NNN (phase: <값>)` 으로 적는다 (`_implementation-verifier.md` § Tier 1)."
138
+ )
139
+
140
+
141
+ def _validate_verifier_command_log_is_read_only(
142
+ data: dict,
143
+ failures: list[str],
144
+ verifier_mutation_hits: Callable[[str], list[tuple[str, str]]],
145
+ ) -> None:
146
+ """검증자의 Read-only command log 에 변조 모드가 없어야 한다.
147
+
148
+ 규칙은 prompts/profiles/_implementation-verifier.md 가 "런타임 AND 검증자가
149
+ 거부해야 한다"고 BLOCKING 으로 선언해 왔지만 런타임 검사는 없었다. 스키마는
150
+ 로그의 **존재**만 강제하고 내용은 아무도 읽지 않았다 — 검증자가
151
+ `eslint --fix` 로 자기가 검증할 소스를 고쳐 놓아도 통과한다.
152
+
153
+ 로그는 리포트에 그대로 복사되므로 여기서 읽는 것이 정본이다.
154
+ """
155
+ implementation = data.get("implementation")
156
+ if not isinstance(implementation, dict):
157
+ return
158
+ rows = [r for r in (implementation.get("verifierResults") or []) if isinstance(r, dict)]
159
+ if not rows:
160
+ return
161
+ for row in rows:
162
+ log = row.get("readOnlyCommandLog")
163
+ if not isinstance(log, str) or not log.strip():
164
+ continue
165
+ who = str(row.get("workerId") or row.get("role") or "verifier")
166
+ for label, line in verifier_mutation_hits(log):
167
+ failures.append(
168
+ f"verifier-command-log: {who} 의 read-only 로그에 변조 모드 "
169
+ f"`{label}` 이 있다: {line[:120]}"
170
+ )
171
+
172
+
173
+ def _validate_verifier_fail_blocks_verdict(data: dict, failures: list[str]) -> None:
174
+ """A verifier FAIL cannot be dropped during synthesis.
175
+
176
+ `implementation.verifierResults[]` was written, read by the stage-fix carry
177
+ helper, and by nothing else — no check compared a recorded `FAIL` against
178
+ the verdict the lead published. A FAIL lost in synthesis lets
179
+ `final-verification` reach `accepted` and `release-handoff` push work a
180
+ verifier rejected.
181
+ """
182
+ implementation = data.get("implementation")
183
+ if not isinstance(implementation, dict):
184
+ return
185
+ failed = sorted({
186
+ str(row.get("verifier") or "<unknown>")
187
+ for row in (implementation.get("verifierResults") or [])
188
+ if isinstance(row, dict) and str(row.get("verdict") or "").strip() == "FAIL"
189
+ })
190
+ if not failed:
191
+ return
192
+ token = str((data.get("finalVerdict") or {}).get("verdictToken") or "").strip()
193
+ if token in _PASSING_VERDICT_TOKENS:
194
+ failures.append(
195
+ f"final-report data.json: verifier(s) {failed} recorded "
196
+ f"`verdict: FAIL` but `finalVerdict.verdictToken` is `{token}`. A "
197
+ "verifier rejection MUST survive into the published verdict — "
198
+ "dropping it during synthesis is how rejected work reaches "
199
+ "`release-handoff`. Carry the FAIL into a blocking verdict. There "
200
+ "is no synthesis-time override: a verifier that produced no "
201
+ "verdict records `not-run` and a Tier 3 advisory divergence "
202
+ "records `CONCERNS`, and both are the verifier's to write, not "
203
+ "the lead's to substitute "
204
+ '(`_implementation-verifier.md` "All-verifier-failure policy").'
205
+ )
@@ -0,0 +1,39 @@
1
+ """구현 단계 선택의 상태 표기와 선택 가능 조건."""
2
+ from __future__ import annotations
3
+
4
+ from okstra_ctl.wizard.ids import ALL_STAGES
5
+ from okstra_ctl.wizard.state import WizardError
6
+
7
+ _STAGE_MARKER_KEYS = {
8
+ "done": "mark_done",
9
+ "active": "mark_active",
10
+ "ready": "mark_ready",
11
+ "blocked": "mark_blocked",
12
+ }
13
+
14
+
15
+ def _impl_stage_marker(t, lifecycle) -> str:
16
+ return t["options"][_STAGE_MARKER_KEYS[lifecycle.status]]
17
+
18
+
19
+ def _impl_chosen_stages(t, picks, answer, all_nums, occupied) -> set:
20
+ if ALL_STAGES in picks:
21
+ if len(picks) > 1:
22
+ raise WizardError(t["errors"]["all_exclusive"])
23
+ chosen = {n for n in all_nums if n not in occupied}
24
+ if not chosen:
25
+ raise WizardError(t["errors"]["nothing_selectable"])
26
+ return chosen
27
+ try:
28
+ nums = {int(p) for p in picks}
29
+ except ValueError:
30
+ raise WizardError(t["errors"]["bad_number"].format(answer=answer))
31
+ unknown = sorted(nums - all_nums)
32
+ if unknown:
33
+ raise WizardError(t["errors"]["unknown_stage"].format(
34
+ bad=", ".join(map(str, unknown))))
35
+ bad = sorted(nums & occupied)
36
+ if bad:
37
+ raise WizardError(t["errors"]["occupied"].format(
38
+ bad=", ".join(map(str, bad))))
39
+ return nums
@@ -0,0 +1 @@
1
+ """구현 방향 비교와 후보 검증 단계의 정본."""
@@ -0,0 +1,80 @@
1
+ """후보 평가 결과를 작성하는 보고서 계약."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Sequence
5
+
6
+ from .validation import (
7
+ EVALUATION_CRITERIA,
8
+ MAX_CRITERION_VALUE,
9
+ MAX_RANKED_OPTIONS,
10
+ MAX_RAW_CANDIDATES_PER_ANALYSER,
11
+ MIN_CRITERION_VALUE,
12
+ MIN_FEASIBLE_VOTES,
13
+ )
14
+ from okstra_ctl.exact_coverage import COVERAGE_VERDICT_PRECEDENCE
15
+
16
+
17
+ def requirement_instructions(original_requirement_ids: Sequence[str], participating_analysers: Sequence[str]) -> list[str]:
18
+ criteria = ", ".join(f"`{item}`" for item in EVALUATION_CRITERIA)
19
+ requirement_ids = ", ".join(
20
+ f"`{item}`" for item in original_requirement_ids
21
+ )
22
+ analysers = ", ".join(
23
+ f"`{item}`" for item in participating_analysers
24
+ )
25
+ return [
26
+ f"Original requirement ids, in order: {requirement_ids}.",
27
+ f"Participating analysers: {analysers}.",
28
+ f"Evaluation criteria, in exact order: {criteria}.",
29
+ "Every `rankedOptions` and `candidateAudit` row must contain one "
30
+ "`requirementCoverage` row per original requirement id and one "
31
+ "`criterionScores` row per evaluation criterion. Weights and scores "
32
+ f"are integers from {MIN_CRITERION_VALUE} through {MAX_CRITERION_VALUE}; "
33
+ "`weightedScore` is the recalculated weighted mean.",
34
+ "`proposedBy` names exactly one participating analyser id, never a "
35
+ "list. Counting `rankedOptions` and `candidateAudit` together, each "
36
+ f"analyser may propose at most {MAX_RAW_CANDIDATES_PER_ANALYSER} raw "
37
+ "candidates and the run may hold at most "
38
+ f"{MAX_RAW_CANDIDATES_PER_ANALYSER} times the analyser count.",
39
+ "`coverageSummary` is recalculated from the row's `requirementCoverage` "
40
+ "statuses and `scopeCommitments`, and every field must equal the "
41
+ "recalculation: `totalCount` = number of original requirement ids; "
42
+ "`coveredCount` = rows with status `covered`; `coveragePercent` = "
43
+ "round(coveredCount / totalCount * 100, 2); `unmappedCommitments` = "
44
+ "commitment ids whose `requirementIds` is empty or names an id outside "
45
+ "the original set; `scopePrecisionPercent` = round((commitments - "
46
+ "unmapped) / commitments * 100, 2); `contradictedRequirements` = "
47
+ "original ids with status `contradicted`, in original order; "
48
+ "`coverageVerdict` = the first that applies of "
49
+ + ", ".join(f"`{verdict}`" for verdict in COVERAGE_VERDICT_PRECEDENCE)
50
+ + " (any contradicted; coveredCount below totalCount; any unmapped; "
51
+ "otherwise).",
52
+ "A ranked option is valid only when every participating analyser "
53
+ "supplied one feasibility vote, at least "
54
+ f"{MIN_FEASIBLE_VOTES} votes are `feasible`, and both `safetyBlockers` "
55
+ "and `unresolvedFeasibilityFacts` are empty.",
56
+ ("Classify each `unresolvedFeasibilityFacts` entry with `resolutionKind`: "
57
+ "`user-decision` requires nonempty `clarificationRefs` linking that fact "
58
+ "to actual C-NNN records, including answered records; `technical-verification` "
59
+ "requires no user question. Preserve the fact, whyItMatters, and evidence. "
60
+ "Historical unclassified facts remain readable but require classification "
61
+ "before blocked report reassembly. Saving does not lift blocked routing."),
62
+ ("After a linked decision is answered, preserve its disposition and selected "
63
+ "value. Update humanSummary.actions, verdictCard.nextStep, and selection "
64
+ "guidance to name remaining technical verification separately from unanswered "
65
+ "user decisions; never reopen an answered question to permit saving."),
66
+ "Each `feasibilityVotes` row states that analyser's own verdict, "
67
+ "rationale, and strongest counterevidence as its result gives them. "
68
+ "Two non-`uncertain` votes with identical rationale and "
69
+ "counterevidence are rejected as one worker's text copied under "
70
+ "another's name.",
71
+ f"Rank at most {MAX_RANKED_OPTIONS} valid options by descending "
72
+ "`requirement-fit`, `correctness-risk`, `architecture-fit`, "
73
+ "`weightedScore`, then id.",
74
+ "In `candidate-comparison`, keep `preselectedDirection` null. In "
75
+ "`preselected-validation`, emit exactly one validated option, an empty "
76
+ "`candidateAudit`, and a cited `preselectedDirection`.",
77
+ "Record candidate validity and selection mode; the lead chooses the next "
78
+ "phase under `## implementation-option-selection` in "
79
+ "`prompts/lead/phase-routing.md`.",
80
+ ]
@@ -0,0 +1,10 @@
1
+ {
2
+ "allowed": " - candidate-comparison evidence for up to three options per worker\n - preselected-validation of exactly ONE candidate: every analyser returns its own feasibility verdict on that one direction, `candidateAudit` stays empty, and no analyser generates an alternative. It is not a re-evaluation of the merged set — `okstra_ctl.phases.implementation_option_selection.validation._validate_mode` rejects a preselected-validation report carrying more than one option or a non-empty audit\n - a ranked display of at most three options with requirement mappings\n - an audit record for every rejected candidate\n - one endStateCoverage row per brief end-state id (this phase authors no goal of its own)",
3
+ "forbidden": [
4
+ "source or configuration edits, refactors, or fix attempts",
5
+ "tests, builds, migrations, deployments, or any state-mutating command",
6
+ "detailed file lists, stage maps, execution commands, or plan approval",
7
+ "starting `implementation-planning` or `implementation` inside this run",
8
+ "displaying more than three merged candidates or omitting rejected-candidate audit records"
9
+ ]
10
+ }