okstra 0.206.0 → 0.207.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-registry.mjs +7 -1
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/install.mjs +1 -1
  5. package/dist/commands/lifecycle/install.mjs.map +1 -1
  6. package/docs/architecture/storage-model.md +1 -0
  7. package/docs/architecture.md +40 -16
  8. package/docs/cli.md +17 -15
  9. package/docs/contributor-change-matrix.md +3 -2
  10. package/docs/performance-improvement-plan-v2.md +1 -1
  11. package/docs/project-structure-overview.md +43 -20
  12. package/package.json +1 -1
  13. package/runtime/BUILD.json +2 -2
  14. package/runtime/agents/operations/code-review.json +1 -1
  15. package/runtime/bin/lib/okstra/usage.sh +3 -3
  16. package/runtime/bin/okstra-compact-reminder.sh +1 -1
  17. package/runtime/bin/okstra-spawn-followups.py +2 -2
  18. package/runtime/prompts/duties/direction-selection-worker.json +1 -1
  19. package/runtime/prompts/launch.template.md +2 -2
  20. package/runtime/prompts/lead/adapters/cmux.md +4 -3
  21. package/runtime/prompts/lead/context-loader.md +1 -1
  22. package/runtime/prompts/lead/convergence.md +44 -12
  23. package/runtime/prompts/lead/okstra-lead-contract.md +44 -73
  24. package/runtime/prompts/lead/phase-routing.md +64 -0
  25. package/runtime/prompts/lead/report-writer.md +10 -8
  26. package/runtime/prompts/lead/team-contract.md +1 -1
  27. package/runtime/prompts/profiles/_clarification-recommendation.md +4 -4
  28. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  29. package/runtime/prompts/profiles/_common-contract.md +2 -2
  30. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  31. package/runtime/prompts/profiles/forbidden-actions.json +0 -94
  32. package/runtime/prompts/wizard/prompts.ko.json +2 -1
  33. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
  34. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +5 -5
  35. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
  36. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -2
  37. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
  38. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
  39. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +17 -26
  40. package/runtime/python/okstra_ctl/agent/prompt_cli/batch.py +183 -0
  41. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +60 -10
  42. package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
  43. package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +21 -4
  44. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +10 -1
  45. package/runtime/python/okstra_ctl/analysis_inputs.py +0 -39
  46. package/runtime/python/okstra_ctl/analysis_scope.py +31 -0
  47. package/runtime/python/okstra_ctl/approval_decisions.py +32 -2
  48. package/runtime/python/okstra_ctl/asset_roots.py +19 -0
  49. package/runtime/python/okstra_ctl/assignment_resolver.py +8 -0
  50. package/runtime/python/okstra_ctl/blocking_checks.py +7 -0
  51. package/runtime/python/okstra_ctl/code_review_target.py +92 -6
  52. package/runtime/python/okstra_ctl/consumers.py +12 -0
  53. package/runtime/python/okstra_ctl/dispatch_checkpoints.py +121 -0
  54. package/runtime/python/okstra_ctl/dispatch_core.py +54 -32
  55. package/runtime/python/okstra_ctl/dispatch_state.py +34 -5
  56. package/runtime/python/okstra_ctl/doctor.py +2 -1
  57. package/runtime/python/okstra_ctl/domain/provider.py +5 -0
  58. package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -2
  59. package/runtime/python/okstra_ctl/domain/write_policy.py +2 -1
  60. package/runtime/python/okstra_ctl/execution_mutation_audit.py +46 -9
  61. package/runtime/python/okstra_ctl/handoff.py +11 -466
  62. package/runtime/python/okstra_ctl/handoff_error.py +5 -0
  63. package/runtime/python/okstra_ctl/implementation_direction.py +0 -477
  64. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +13 -1
  65. package/runtime/python/okstra_ctl/lead_progress.py +33 -1
  66. package/runtime/python/okstra_ctl/manager_view.py +26 -19
  67. package/runtime/python/okstra_ctl/model_io/lines.py +21 -4
  68. package/runtime/python/okstra_ctl/models.py +4 -1
  69. package/runtime/python/okstra_ctl/operation_invocation.py +11 -2
  70. package/runtime/python/okstra_ctl/option_comparison.py +3 -165
  71. package/runtime/python/okstra_ctl/option_votes.py +3 -191
  72. package/runtime/python/okstra_ctl/paths.py +8 -6
  73. package/runtime/python/okstra_ctl/phases/catalog.py +56 -12
  74. package/runtime/python/okstra_ctl/phases/change_impact_analysis/boundary.json +11 -0
  75. package/runtime/python/okstra_ctl/phases/change_impact_analysis/entry.py +39 -0
  76. package/runtime/python/okstra_ctl/{report_html/view_models/change_impact_analysis.py → phases/change_impact_analysis/report.py} +3 -3
  77. package/runtime/python/okstra_ctl/phases/change_impact_analysis/spec.md +26 -0
  78. package/runtime/python/okstra_ctl/phases/change_impact_analysis/validation.py +23 -0
  79. package/runtime/python/okstra_ctl/phases/error_analysis/__init__.py +1 -0
  80. package/runtime/python/okstra_ctl/phases/error_analysis/boundary.json +9 -0
  81. package/runtime/{prompts/profiles/error-analysis.md → python/okstra_ctl/phases/error_analysis/profile.md} +2 -2
  82. package/runtime/python/okstra_ctl/{report_html/view_models/error_analysis.py → phases/error_analysis/report.py} +9 -8
  83. package/runtime/{templates/reports → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis-input.template.md +1 -1
  84. package/runtime/python/okstra_ctl/phases/error_analysis/spec.md +118 -0
  85. package/runtime/python/okstra_ctl/phases/error_analysis/validation.py +241 -0
  86. package/runtime/python/okstra_ctl/phases/feature_analysis/__init__.py +1 -0
  87. package/runtime/python/okstra_ctl/phases/feature_analysis/boundary.json +8 -0
  88. package/runtime/python/okstra_ctl/phases/feature_analysis/entry.py +63 -0
  89. package/runtime/python/okstra_ctl/{report_html/view_models/feature_analysis.py → phases/feature_analysis/report.py} +12 -5
  90. package/runtime/python/okstra_ctl/phases/feature_analysis/spec.md +22 -0
  91. package/runtime/python/okstra_ctl/phases/feature_analysis/validation.py +27 -0
  92. package/runtime/python/okstra_ctl/phases/feature_analysis/wizard.py +95 -0
  93. package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
  94. package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -2
  95. package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
  96. package/runtime/python/okstra_ctl/phases/final_verification/spec.md +1 -1
  97. package/runtime/python/okstra_ctl/phases/implementation/__init__.py +1 -0
  98. package/runtime/python/okstra_ctl/phases/implementation/boundary.json +17 -0
  99. package/runtime/python/okstra_ctl/{implementation_stage.py → phases/implementation/entry.py} +22 -10
  100. package/runtime/{prompts/host-orchestration/implementation.md → python/okstra_ctl/phases/implementation/host-rules.md} +1 -1
  101. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-deliverable.md +1 -1
  102. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-executor.md +4 -3
  103. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-verifier.md +18 -7
  104. package/runtime/{prompts/profiles/implementation.md → python/okstra_ctl/phases/implementation/profile.md} +5 -5
  105. package/runtime/python/okstra_ctl/{report_html/view_models/implementation.py → phases/implementation/report.py} +3 -3
  106. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation/report_assets}/implementation-input.template.md +1 -1
  107. package/runtime/python/okstra_ctl/phases/implementation/spec.md +238 -0
  108. package/runtime/python/okstra_ctl/phases/implementation/validation.py +205 -0
  109. package/runtime/python/okstra_ctl/phases/implementation/wizard.py +39 -0
  110. package/runtime/python/okstra_ctl/phases/implementation_option_selection/__init__.py +1 -0
  111. package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +80 -0
  112. package/runtime/python/okstra_ctl/phases/implementation_option_selection/boundary.json +10 -0
  113. package/runtime/python/okstra_ctl/phases/implementation_option_selection/comparison.py +168 -0
  114. package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +27 -0
  115. package/runtime/{prompts/profiles/implementation-option-selection.md → python/okstra_ctl/phases/implementation_option_selection/profile.md} +3 -3
  116. package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
  117. package/runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md +83 -0
  118. package/runtime/python/okstra_ctl/{implementation_options.py → phases/implementation_option_selection/validation.py} +3 -3
  119. package/runtime/python/okstra_ctl/phases/implementation_option_selection/votes.py +194 -0
  120. package/runtime/python/okstra_ctl/phases/implementation_planning/__init__.py +1 -0
  121. package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +2345 -0
  122. package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +12 -0
  123. package/runtime/python/okstra_ctl/phases/implementation_planning/entry.py +161 -0
  124. package/runtime/python/okstra_ctl/phases/implementation_planning/guidance.py +178 -0
  125. package/runtime/{prompts/lead → python/okstra_ctl/phases/implementation_planning/instructions}/plan-body-verification.md +61 -51
  126. package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +3295 -0
  127. package/runtime/{prompts/profiles/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/profile.md} +74 -25
  128. package/runtime/python/okstra_ctl/phases/implementation_planning/report.py +237 -0
  129. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning-input.template.md +2 -2
  130. package/runtime/python/okstra_ctl/phases/implementation_planning/spec.md +204 -0
  131. package/runtime/python/okstra_ctl/phases/implementation_planning/validation.py +597 -0
  132. package/runtime/python/okstra_ctl/phases/implementation_planning/wizard.py +166 -0
  133. package/runtime/python/okstra_ctl/phases/improvement_discovery/boundary.json +12 -0
  134. package/runtime/python/okstra_ctl/{improvement_lenses.py → phases/improvement_discovery/lenses.py} +1 -6
  135. package/runtime/{prompts/profiles/improvement-discovery.md → python/okstra_ctl/phases/improvement_discovery/profile.md} +5 -5
  136. package/runtime/python/okstra_ctl/{report_html/view_models/improvement_discovery.py → phases/improvement_discovery/report.py} +3 -3
  137. package/runtime/{templates/reports → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery-input.template.md +1 -2
  138. package/runtime/python/okstra_ctl/phases/improvement_discovery/spec.md +29 -0
  139. package/runtime/{validators/validate_improvement_report.py → python/okstra_ctl/phases/improvement_discovery/validation.py} +5 -14
  140. package/runtime/python/okstra_ctl/phases/project_analysis/__init__.py +1 -0
  141. package/runtime/python/okstra_ctl/phases/project_analysis/boundary.json +8 -0
  142. package/runtime/python/okstra_ctl/phases/project_analysis/entry.py +11 -0
  143. package/runtime/python/okstra_ctl/{report_html/view_models/project_analysis.py → phases/project_analysis/report.py} +3 -3
  144. package/runtime/python/okstra_ctl/phases/project_analysis/spec.md +33 -0
  145. package/runtime/python/okstra_ctl/phases/project_analysis/validation.py +55 -0
  146. package/runtime/python/okstra_ctl/phases/release_handoff/__init__.py +1 -0
  147. package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +17 -0
  148. package/runtime/python/okstra_ctl/phases/release_handoff/entry.py +147 -0
  149. package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +446 -0
  150. package/runtime/{prompts/profiles/release-handoff.md → python/okstra_ctl/phases/release_handoff/profile.md} +3 -3
  151. package/runtime/python/okstra_ctl/{report_html/view_models/release_handoff.py → phases/release_handoff/report.py} +3 -3
  152. package/runtime/{templates/reports → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff-input.template.md +1 -1
  153. package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +233 -0
  154. package/runtime/python/okstra_ctl/phases/release_handoff/wizard.py +84 -0
  155. package/runtime/python/okstra_ctl/phases/requirements_discovery/__init__.py +1 -0
  156. package/runtime/python/okstra_ctl/phases/requirements_discovery/boundary.json +9 -0
  157. package/runtime/{prompts/profiles/requirements-discovery.md → python/okstra_ctl/phases/requirements_discovery/profile.md} +2 -3
  158. package/runtime/python/okstra_ctl/{report_html/view_models/requirements_discovery.py → phases/requirements_discovery/report.py} +3 -3
  159. package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +132 -0
  160. package/runtime/{validators/validate_fanout.py → python/okstra_ctl/phases/requirements_discovery/validation.py} +11 -12
  161. package/runtime/python/okstra_ctl/phases/technical_verification/__init__.py +1 -0
  162. package/runtime/python/okstra_ctl/phases/technical_verification/boundary.json +9 -0
  163. package/runtime/python/okstra_ctl/phases/technical_verification/entry.py +100 -0
  164. package/runtime/{prompts/profiles/technical-verification.md → python/okstra_ctl/phases/technical_verification/profile.md} +2 -2
  165. package/runtime/python/okstra_ctl/{report_html/view_models/technical_verification.py → phases/technical_verification/report.py} +2 -2
  166. package/runtime/python/okstra_ctl/phases/technical_verification/spec.md +37 -0
  167. package/runtime/python/okstra_ctl/phases/technical_verification/validation.py +90 -0
  168. package/runtime/python/okstra_ctl/plan_approval.py +70 -0
  169. package/runtime/python/okstra_ctl/plan_items_cli.py +2 -2130
  170. package/runtime/python/okstra_ctl/process_group.py +118 -0
  171. package/runtime/python/okstra_ctl/profile_show.py +3 -3
  172. package/runtime/python/okstra_ctl/render.py +15 -4
  173. package/runtime/python/okstra_ctl/report_assembly.py +28 -92
  174. package/runtime/python/okstra_ctl/report_finalize.py +106 -2
  175. package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
  176. package/runtime/python/okstra_ctl/report_projections.py +1 -36
  177. package/runtime/python/okstra_ctl/report_routing.py +23 -0
  178. package/runtime/python/okstra_ctl/report_synthesis_packet.py +4 -73
  179. package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
  180. package/runtime/python/okstra_ctl/report_views.py +1 -1
  181. package/runtime/python/okstra_ctl/run.py +68 -350
  182. package/runtime/python/okstra_ctl/run_artifact_prune.py +200 -0
  183. package/runtime/python/okstra_ctl/stage_map.py +13 -0
  184. package/runtime/python/okstra_ctl/team.py +108 -9
  185. package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
  186. package/runtime/python/okstra_ctl/wizard/__init__.py +31 -31
  187. package/runtime/python/okstra_ctl/wizard/api.py +18 -0
  188. package/runtime/python/okstra_ctl/wizard/outcome.py +3 -12
  189. package/runtime/python/okstra_ctl/wizard/registry.py +20 -12
  190. package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
  191. package/runtime/python/okstra_ctl/wizard/steps_options.py +8 -0
  192. package/runtime/python/okstra_ctl/wizard/steps_plan.py +10 -263
  193. package/runtime/python/okstra_ctl/wizard/steps_roles.py +2 -1
  194. package/runtime/python/okstra_ctl/work_categories.py +1 -1
  195. package/runtime/python/okstra_ctl/worker_dispatch.py +44 -3
  196. package/runtime/python/okstra_ctl/worker_prompt_contract.py +36 -0
  197. package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -0
  198. package/runtime/python/okstra_ctl/worker_runner.py +21 -3
  199. package/runtime/python/okstra_ctl/workflow.py +26 -143
  200. package/runtime/python/okstra_ctl/write_policy.py +57 -7
  201. package/runtime/python/okstra_project/dirs.py +14 -0
  202. package/runtime/python/okstra_project/resolver.py +2 -1
  203. package/runtime/schemas/execution-manifest-v2.schema.json +2 -1
  204. package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
  205. package/runtime/skills/okstra-code-review/SKILL.md +70 -32
  206. package/runtime/skills/okstra-code-review/references/review-calibration.md +26 -6
  207. package/runtime/skills/okstra-run/SKILL.md +3 -3
  208. package/runtime/templates/manager/view.template.html +18 -1
  209. package/runtime/templates/reports/quick-input.template.md +1 -1
  210. package/runtime/templates/reports/task-brief.template.md +1 -1
  211. package/runtime/validators/validate-brief.py +2 -2
  212. package/runtime/validators/validate-run.py +299 -3940
  213. package/runtime/validators/validate_analysis_report.py +14 -126
  214. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +0 -147
  215. package/runtime/python/okstra_ctl/technical_verification.py +0 -195
  216. /package/runtime/{prompts/profiles/change-impact-analysis.json → python/okstra_ctl/phases/change_impact_analysis/profile.json} +0 -0
  217. /package/runtime/{prompts/profiles/change-impact-analysis.md → python/okstra_ctl/phases/change_impact_analysis/profile.md} +0 -0
  218. /package/runtime/{templates/reports → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis-input.template.md +0 -0
  219. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.html +0 -0
  220. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.md +0 -0
  221. /package/runtime/{prompts/profiles/error-analysis.json → python/okstra_ctl/phases/error_analysis/profile.json} +0 -0
  222. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.html +0 -0
  223. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.md +0 -0
  224. /package/runtime/{prompts/profiles/feature-analysis.json → python/okstra_ctl/phases/feature_analysis/profile.json} +0 -0
  225. /package/runtime/{prompts/profiles/feature-analysis.md → python/okstra_ctl/phases/feature_analysis/profile.md} +0 -0
  226. /package/runtime/{templates/reports → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis-input.template.md +0 -0
  227. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.html +0 -0
  228. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.md +0 -0
  229. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-diff-review.md +0 -0
  230. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-self-check.md +0 -0
  231. /package/runtime/{prompts/profiles/implementation.json → python/okstra_ctl/phases/implementation/profile.json} +0 -0
  232. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.html +0 -0
  233. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.md +0 -0
  234. /package/runtime/{prompts/profiles/implementation-option-selection.json → python/okstra_ctl/phases/implementation_option_selection/profile.json} +0 -0
  235. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.html +0 -0
  236. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.md +0 -0
  237. /package/runtime/{prompts/host-orchestration/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/host-rules.md} +0 -0
  238. /package/runtime/{prompts/profiles/implementation-planning.json → python/okstra_ctl/phases/implementation_planning/profile.json} +0 -0
  239. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.html +0 -0
  240. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.md +0 -0
  241. /package/runtime/{prompts/profiles/improvement-discovery.json → python/okstra_ctl/phases/improvement_discovery/profile.json} +0 -0
  242. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.html +0 -0
  243. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.md +0 -0
  244. /package/runtime/{prompts/profiles/project-analysis.json → python/okstra_ctl/phases/project_analysis/profile.json} +0 -0
  245. /package/runtime/{prompts/profiles/project-analysis.md → python/okstra_ctl/phases/project_analysis/profile.md} +0 -0
  246. /package/runtime/{templates/reports → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis-input.template.md +0 -0
  247. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.html +0 -0
  248. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.md +0 -0
  249. /package/runtime/{prompts/profiles/release-handoff.json → python/okstra_ctl/phases/release_handoff/profile.json} +0 -0
  250. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.html +0 -0
  251. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.md +0 -0
  252. /package/runtime/python/okstra_ctl/{fanout.py → phases/requirements_discovery/fanout.py} +0 -0
  253. /package/runtime/{prompts/profiles/requirements-discovery.json → python/okstra_ctl/phases/requirements_discovery/profile.json} +0 -0
  254. /package/runtime/{templates/reports → python/okstra_ctl/phases/requirements_discovery/report_assets}/fan-out-unit.template.md +0 -0
  255. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.html +0 -0
  256. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.md +0 -0
  257. /package/runtime/{prompts/profiles/technical-verification.json → python/okstra_ctl/phases/technical_verification/profile.json} +0 -0
  258. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.html +0 -0
  259. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.md +0 -0
@@ -0,0 +1,27 @@
1
+ """기능 분석 결과의 대상 일치 정책."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ EVIDENCE_COLLECTIONS = ("flows", "domainRules", "stateChanges", "externalInteractions")
7
+
8
+
9
+ def _validate_feature_semantics(data: dict, errors: list[str]) -> None:
10
+ analysis = data.get("featureAnalysis") or {}
11
+ common_target = ((data.get("analysisCommon") or {}).get("scope") or {}).get(
12
+ "resolvedTarget"
13
+ ) or {}
14
+ feature_target = analysis.get("target") or {}
15
+ for field in ("inputMode", "requestedValue"):
16
+ if feature_target.get(field) != common_target.get(field):
17
+ errors.append(
18
+ f"featureAnalysis.target.{field} must match "
19
+ f"analysisCommon.scope.resolvedTarget.{field}"
20
+ )
21
+ resolved_feature = common_target.get("feature") or {}
22
+ if common_target.get("inputMode") == "feature-index" and (
23
+ feature_target.get("featureId") != resolved_feature.get("id")
24
+ ):
25
+ errors.append(
26
+ "featureAnalysis.target.featureId must match the resolved feature id"
27
+ )
@@ -0,0 +1,95 @@
1
+ """기능 분석 대상 선택·직접 입력 질문."""
2
+
3
+ from __future__ import annotations
4
+ from pathlib import Path
5
+ from typing import Optional
6
+ from okstra_ctl.analysis_inputs import (
7
+ AnalysisInputError,
8
+ AnalysisReportCandidate,
9
+ load_analysis_report_candidate,
10
+ )
11
+ from okstra_ctl.wizard.ids import (
12
+ PICK_TYPE_CUSTOM,
13
+ S_ANALYSIS_TARGET,
14
+ S_ANALYSIS_TARGET_PICK,
15
+ )
16
+ from okstra_ctl.wizard.state import Prompt, WizardError, WizardState
17
+ from okstra_ctl.wizard.prompts import _opt, _p
18
+ from okstra_ctl.wizard.steps_analysis import (
19
+ _analysis_evidence_paths,
20
+ _resolve_analysis_evidence,
21
+ )
22
+ from .entry import resolve_analysis_target
23
+
24
+
25
+ def _feature_description(feature: dict[object, object]) -> str:
26
+ name = str(feature.get("name") or "")
27
+ summary = str(feature.get("summary") or "")
28
+ entry_point = str(feature.get("entryPoint") or feature.get("entrypoint") or "")
29
+ return " · ".join(value for value in (name, summary, entry_point) if value)
30
+
31
+
32
+ def _build_analysis_target_pick(state: WizardState) -> Prompt:
33
+ t = _p(state.workspace_root, S_ANALYSIS_TARGET_PICK)
34
+ try:
35
+ candidate = load_analysis_report_candidate(
36
+ Path(state.project_root), Path(state.project_evidence_path)
37
+ )
38
+ except AnalysisInputError as exc:
39
+ raise WizardError(str(exc)) from exc
40
+ options = [
41
+ _opt(str(feature["id"]), str(feature["id"]), _feature_description(feature))
42
+ for feature in candidate.feature_index
43
+ if isinstance(feature, dict) and isinstance(feature.get("id"), str)
44
+ ][:3]
45
+ options.append(_opt(PICK_TYPE_CUSTOM, t["options"][PICK_TYPE_CUSTOM]))
46
+ return Prompt(
47
+ step=S_ANALYSIS_TARGET_PICK,
48
+ kind="pick",
49
+ label=t["label"],
50
+ options=options,
51
+ echo_template=t["echo_template"],
52
+ )
53
+
54
+
55
+ def _accept_analysis_target(state: WizardState, value: str) -> str:
56
+ candidates: dict[Path, AnalysisReportCandidate] = {}
57
+ for path in _analysis_evidence_paths(state):
58
+ try:
59
+ candidate = load_analysis_report_candidate(Path(state.project_root), path)
60
+ except AnalysisInputError as exc:
61
+ raise WizardError(str(exc)) from exc
62
+ candidates[candidate.report_path] = candidate
63
+ try:
64
+ target = resolve_analysis_target(
65
+ value, _resolve_analysis_evidence(state), candidates
66
+ )
67
+ except AnalysisInputError as exc:
68
+ raise WizardError(str(exc)) from exc
69
+ requested_value = target["requestedValue"]
70
+ if not isinstance(requested_value, str):
71
+ raise WizardError("analysis target resolver returned an invalid requestedValue")
72
+ state.analysis_target = requested_value
73
+ state.analysis_target_pending_text = False
74
+ return requested_value
75
+
76
+
77
+ def _submit_analysis_target_pick(state: WizardState, value: str) -> Optional[str]:
78
+ if value == PICK_TYPE_CUSTOM:
79
+ state.analysis_target_pending_text = True
80
+ return None
81
+ return f"analysis-target: {_accept_analysis_target(state, value)}"
82
+
83
+
84
+ def _build_analysis_target(state: WizardState) -> Prompt:
85
+ t = _p(state.workspace_root, S_ANALYSIS_TARGET)
86
+ return Prompt(
87
+ step=S_ANALYSIS_TARGET,
88
+ kind="text",
89
+ label=t["label"],
90
+ echo_template=t["echo_template"],
91
+ )
92
+
93
+
94
+ def _submit_analysis_target(state: WizardState, value: str) -> Optional[str]:
95
+ return f"analysis-target: {_accept_analysis_target(state, value)}"
@@ -0,0 +1,8 @@
1
+ {
2
+ "allowed": " - acceptance verdict with requirement coverage assessment\n - residual risk and regression notes\n - routing recommendation as the `routingRecommendation` object `{target, rationale}`: `target` is one of `release-handoff`, `release-handoff(stage-group)`, `error-analysis`, `implementation-option-selection`, `implementation-planning`, `implementation`, `done`, and `rationale` ties that choice to the verdict and the blocker list. Both `release-handoff` forms require a release-ready verdict — `accepted`, or `conditional-accept` with every condition declaring `blocksReleaseHandoff: false` (`okstra_ctl.release_gate.release_handoff_allowed`); either verification scope may route there, because release-handoff opens one PR per stage. Prose alone does not route the task — Phase 7 projects `workflow.nextRecommendedPhase` from `target`",
3
+ "forbidden": [
4
+ "source code edits, follow-up bug fixes, or scope expansion",
5
+ "state-mutating commands against the project or shared environments; permitted mutations are limited to the run's own `.okstra` artifacts (reports, state, `<task_root>/qa/result-*.json` sidecars, `okstra handoff record-verified` on acceptance) and Tier3 conformance scripts that mutate only their qaEnv replica datastore — everything else is read-only execution of pre-existing test or validation commands",
6
+ "starting any follow-up phase inside this run; record findings and end the run"
7
+ ]
8
+ }
@@ -36,7 +36,7 @@
36
36
  - Worker verification procedure:
37
37
  - **Target confirmation:** analyse the injected target and nothing else. Read `verification-target.md` for the stage/report mapping and the complete diff stat. Prepare fixed that target and `phases/final_verification/validation.py` `validate_verification_target_match` (called by `validators/validate-run.py`) re-checks the report against its digest, so the procedure to follow here is simply: if the worktree you can see does not match the injected target, record a `tool-failure` — never reselect a target.
38
38
  - **Evidence:** attach file:line, exact command + exit code, log excerpt, or MCP SELECT evidence to every finding. Mark a requirement as covered only when the cited artifact demonstrates it.
39
- - **Tier 1 and Tier 2 read-only validation:** Tier 1 is the originating brief/approved plan `validation` set. Tier 2 is the `Project QA Commands` section from `okstra model-io project-context --project-root <PROJECT_ROOT> --task-ref <task-ref>`. Do not auto-detect commands from package manifests. A missing tier is `qa-command not configured: <category>`. Before execution, reject commands containing source/lockfile mutation tokens such as `--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, or `npm install` without `ci`; record the exact denied token. Tier 2 is already screened by prepare, so this check catches a Tier 1 command the brief or plan named.
39
+ - **Tier 1 and Tier 2 read-only validation:** Tier 1 is the originating brief/approved plan `validation` set. Tier 2 is the `Project QA Commands` section from `okstra model-io project-context --project-root <PROJECT_ROOT> --task-ref <TASK_KEY>` (the full `Task key` your dispatch prompt names). Do not auto-detect commands from package manifests. A missing tier is `qa-command not configured: <category>`. Before execution, reject commands containing source/lockfile mutation tokens such as `--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, or `npm install` without `ci`; record the exact denied token. Tier 2 is already screened by prepare, so this check catches a Tier 1 command the brief or plan named.
40
40
  - **External QA outcome policy:** continue to attempt every in-scope Tier 3
41
41
  command. For an entry requiring `db`, `http`, or `external`, record non-PASS
42
42
  as a Tier 3 `advisory` command, add a user-owned Residual Risk and exact
@@ -66,7 +66,7 @@
66
66
  - **Read-only command log**: any pre-existing test/validation command touched during this run MUST be listed with its exact command line and one honest status — `executed` (ran; carries its exit code) / `advisory` (external Tier 3 did not PASS; carries observed/expected results and remains user-owned) / `env-unavailable` (should run but cannot in this environment — missing replica DB, container, or service; carries the reason, never a faked pass) / `not-configured` (no such qa-command tier) / `rejected` (a mutating/denied token — skipped, carries the denied token). A check that could not run locally is recorded as `env-unavailable` or `advisory` according to the external QA policy — never silently dropped and never reported as `executed` with an invented exit code. Mutating-command prohibition is the shared read-only boundary (see Non-goals); it is not restated per row.
67
67
  - **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `advisory` / `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
68
68
  - **Routing recommendation**: this phase records the verdict, the blockers, the conditions, and the repair each blocker needs. The lead chooses the next phase from the `## final-verification` section of `prompts/lead/phase-routing.md`, which lists the allowed targets and the shape of `finalVerification.routingRecommendation`. Read that section before writing the field.
69
- - **Verified-row recording** (both scopes): when the verdict is release-ready, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report data.json path> --data-json <final-report data.json path>` and quote the command + exit code in the report. Pass the record path to both: the Markdown reading copy is rendered on request and does not exist in a finished run (ADR-0014), and the helper normalizes either path to the record anyway. A `whole-task` report clears every stage in its own `stageReports`, so run it **once per those stages** — each run writes that stage's row from this one report. Without those rows the stage is never offered a pull request, and release-handoff opens one PR per stage. The helper checks the latest verification manifest, task/stage identity, report pointer, prepared target, and recorded implementation commit. It records the captured commit and original verdict, including conditional acceptance conditions. A missing target or mismatched commit requires re-verification. Recording happens before final validation; eligibility is granted only after that verification passes validation. **Enforced:** `okstra_ctl.handoff_verification` validates the evidence, and `validators/validate-run.py` `_validate_verified_row_recorded` requires a `verified` row matching this report, captured commit, and verdict.
69
+ - **Verified-row recording** (both scopes): when the verdict is release-ready, `okstra report-finalize` writes the `verified` rows itself in its `record-verified` step, right before `validate-run`: it runs `okstra handoff record-verified` once per stage in this report's `stageReports`, with the final-report data.json as both report and record. The lead does not run `handoff record-verified` by hand; it needs the data.json that `report-finalize` assembles and `validate-run` reads the rows in the same call, so no lead step fits between them. Without those rows the stage is never offered a pull request, and release-handoff opens one PR per stage. The helper checks the latest verification manifest, task/stage identity, report pointer, prepared target, and recorded implementation commit, and records the captured commit and original verdict, including conditional acceptance conditions. A missing target or mismatched commit fails the step and requires re-verification. Eligibility is granted only after the verification passes validation. **Enforced:** `okstra_ctl.report_finalize._record_verified_stages` runs the step, `okstra_ctl.handoff_verification` validates the evidence, and `validators/validate-run.py` `_validate_verified_row_recorded` fails the run (blocking, `okstra_ctl.blocking_checks`) when a cleared stage has no `verified` row matching this report, captured commit, and verdict.
70
70
  - Clarification request policy (phase-specific addendum — shared policy is in `_common-contract.md`):
71
71
  - populate `## 1. Clarification Items` only when a blocker hinges on information only the user can supply (deployment intent, intended target environment, business-rule interpretation); use `Blocks=next-phase` for items that gate continuing to release-handoff
72
72
  - Self-review pass before finalising the report (the Okstra lead runs this; do not delegate it):
@@ -85,7 +85,7 @@ taskType: "{{FM_TASK_TYPE}}"
85
85
 
86
86
  > Verifiers MUST NOT extend acceptance checks, regression scans, or sign-off recommendations into items listed here. If a verifier believes an excluded item must pass before release, it is reported as a recommended follow-up verification task in the final report — never silently included in the pass/fail decision of this run. If this section is left empty, verifiers treat any check beyond what `Acceptance Criteria` enumerates as out of scope by default.
87
87
 
88
- **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.
88
+ **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.
89
89
 
90
90
  ## Config and Deployment Verification Targets
91
91
 
@@ -193,6 +193,6 @@ The stage merge of whole-task mode is a runtime-owned integration step that prep
193
193
  - `scripts/okstra_ctl/phases/final_verification/validation.py` `_validate_added_surface_audit`
194
194
  - `prompts/lead/phase-routing.md`
195
195
  - `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json` (`finalVerification`, `finalVerdict`, `routingRecommendation.target`)
196
- - `templates/reports/final-verification-input.template.md`
196
+ - `scripts/okstra_ctl/phases/final_verification/report_assets/final-verification-input.template.md`
197
197
  - `validators/validate-run.py`
198
198
  - `scripts/okstra_ctl/release_gate.py`
@@ -0,0 +1 @@
1
+ """implementation 단계의 실행 정책과 자산."""
@@ -0,0 +1,17 @@
1
+ {
2
+ "allowed": " - approved-plan reference and quoted user-approval evidence\n - commit list with SHA, message, and the plan step each commit satisfies\n - `git diff --stat <base>..HEAD` summary plus per-file one-line change summary\n - `Out-of-plan edits` block listing every file touched outside the approved plan with rationale (empty block preferred)\n - validation evidence: actual stdout/stderr and exit code for every pre / mid / post command from the plan (no paraphrased \"tests pass\")\n - TDD evidence for TDD-applicable steps: failing-test output before implementation commit and passing-test output after, with framing SHAs\n - per-verifier sections for every verifier in the resolved roster, with an independent verdict (PASS / CONCERNS / FAIL) and cited diff snippets; dissent is preserved by the Okstra lead\n - rollback verification (advisory, never blocks — record the revert path for a human; `result` is ok / not-applicable / advisory — human-run)\n - routing recommendation as the `routingRecommendation` object `{target, rationale}`: `target` is one of `final-verification`, `error-analysis`, `implementation-planning`, `implementation`, and `rationale` is why that one and nothing else. Prose alone does not route the task — Phase 7 projects `workflow.nextRecommendedPhase` from `target`",
3
+ "forbidden": [
4
+ "any Edit/Write or state-mutating Bash before the pre-implementation gate passes (gate requires --approved-plan pointing to a final-report.md whose frontmatter has `approved: true`)",
5
+ "`git push` of any kind (including `--dry-run` against a real remote that produces side-effects), `npm publish` / `cargo publish` / `pip publish`, `gh release`, `docker push`",
6
+ "real database migrations, schema changes against shared environments, or writes to non-local datastores",
7
+ "production credentials, deploy commands, infra mutation (`terraform apply`, `kubectl apply` against non-local cluster, etc.)",
8
+ "external API write calls (POST/PUT/PATCH/DELETE) to third-party services other than localhost test fixtures",
9
+ "source edits or Bash mutations performed by any verifier role (`Antigravity verifier`, `Codex verifier`, `Claude verifier` are read-only — recommend, do not apply)",
10
+ "dispatching parallel sub-agents beyond the required worker roster",
11
+ "silent scope expansion: every file edited outside the approved plan list MUST appear in the `Out-of-plan edits` block with rationale",
12
+ "leaving placeholders such as TBD / TODO / \"implement later\" / \"handle edge cases\" in newly-added lines of this run (check via `git diff <base>..HEAD | grep -E '^\\+[^+].*\\b(TBD|TODO|FIXME|XXX|implement later|handle edge cases|similar to|placeholder)\\b'`; pre-existing strings in untouched regions are out of scope)",
13
+ "lead substituting its own verdict when every verifier present in the resolved roster returned a non-result terminal status (`timeout`/`error`/`not-run`); in that case the run MUST end as `blocked` with routing recommendation back to `error-analysis`, never with a lead-only verdict",
14
+ "declaring overall task acceptance — that is `final-verification` ownership; this phase reports only \"ready for final-verification\" or \"needs new planning loop\"",
15
+ "delegating the self-review pass — the Okstra lead must run it"
16
+ ]
17
+ }
@@ -7,17 +7,18 @@ isolated stage worktree, and record the started event.
7
7
  from __future__ import annotations
8
8
 
9
9
  import datetime as _dt
10
+ import re
10
11
  import subprocess
11
12
  import sys
12
13
  from dataclasses import dataclass, field
13
14
  from pathlib import Path
14
15
  from typing import Any
15
16
 
16
- from . import stage_targets
17
- from .design_prep import DesignPrepDecision, DesignPrepError, resolve_design_prep
18
- from .final_report_paths import final_report_data_path
19
- from .stage_reconcile import auto_reconcile_best_effort
20
- from .worker_prompt_policy import IMPLEMENTATION_STAGE_HEADER
17
+ from okstra_ctl import stage_targets
18
+ from okstra_ctl.design_prep import DesignPrepDecision, DesignPrepError, resolve_design_prep
19
+ from okstra_ctl.final_report_paths import final_report_data_path
20
+ from okstra_ctl.stage_reconcile import auto_reconcile_best_effort
21
+ from okstra_ctl.worker_prompt_policy import IMPLEMENTATION_STAGE_HEADER
21
22
 
22
23
 
23
24
  class ImplementationStageError(Exception):
@@ -87,9 +88,9 @@ def claim_implementation_stage_run(
87
88
  callers can compute stage-specific run paths after this function resolves
88
89
  the selected stage.
89
90
  """
90
- from .consumers import backfill_done_from_carry
91
- from . import worktree as _worktree
92
- from . import worktree_registry as _reg
91
+ from okstra_ctl.consumers import backfill_done_from_carry
92
+ from okstra_ctl import worktree as _worktree
93
+ from okstra_ctl import worktree_registry as _reg
93
94
 
94
95
  plan_run_root = Path(inp.approved_plan_path).resolve().parents[1]
95
96
  backfill_done_from_carry(plan_run_root)
@@ -201,7 +202,7 @@ def claim_implementation_stage_run(
201
202
  base_commit=stage_base,
202
203
  )
203
204
  except RuntimeError as exc:
204
- from .git_reconcile import guidance
205
+ from okstra_ctl.git_reconcile import guidance
205
206
 
206
207
  hint = guidance(
207
208
  plan_run_root=plan_run_root,
@@ -234,7 +235,7 @@ def _record_stage_run_claim_started(
234
235
  plan_run_root: Path,
235
236
  claim: StageRunClaim,
236
237
  ) -> None:
237
- from .consumers import append_consumer
238
+ from okstra_ctl.consumers import append_consumer
238
239
 
239
240
  now = _dt.datetime.now(_dt.timezone.utc).isoformat()
240
241
  append_consumer(
@@ -275,3 +276,14 @@ def publish_stage_run_claim(
275
276
  ctx["EXECUTOR_WORKTREE_BASE_REF"] = claim.worktree_base_ref
276
277
  ctx["EXECUTOR_WORKTREE_STATUS"] = claim.worktree_status
277
278
  ctx["EXECUTOR_WORKTREE_NOTE"] = claim.worktree_note
279
+
280
+
281
+ def resolve_instruction_paths(text: str, asset_root: Path) -> str:
282
+ """리드가 직접 여는 보조 지침은 설치 형태에 맞는 실제 경로로 기록한다."""
283
+ from okstra_ctl.phases.catalog import profile_sidecar
284
+
285
+ return re.sub(
286
+ r"(?:prompts/profiles|scripts/okstra_ctl/phases/implementation/instructions)/_implementation-[\w-]+\.md",
287
+ lambda match: str(profile_sidecar(asset_root, match.group(0))),
288
+ text,
289
+ )
@@ -54,7 +54,7 @@ If the anchor (`implementation_base_commit`) is reported unresolvable, run the s
54
54
  Because of the dependency closure, the chain queue **may include a stage that another implementation run has occupied as started/reserved.** That stage's `render-bundle` is rejected with `--stage N already in progress or reserved by another run` (StageTargetError). This is **not** an exception gate needing human judgment but a "next stage not yet ready" situation. On this rejection, **terminate the chain normally** and report the remaining queue to the user (e.g. `remaining queue: stage 4, 5 — resume with okstra-run after occupancy is released`). This is a different branch from the exception gate below (data corruption·concurrent-occupancy conflict confirmation).
55
55
 
56
56
  ### Stage ended FAIL — stop the queue and report (not an exception gate)
57
- When a stage's synthesised verdict is `FAIL`, Phase 6 writes no carry sidecar and appends a `status:"failed"` row in place of `done` (`prompts/profiles/_implementation-deliverable.md` "Lead post-stage persistence"). **Stop the queue at that stage** and report the failed stage, its report path, and the remaining queue (e.g. `stage 1 FAIL — remaining queue: stage 2, 3, 5; re-enter with okstra-run --stage 1 after the fix`). Do **not** continue to the next stage even when that stage is dependency-independent: an unattended chain that keeps building past a confirmed regression stacks later work on top of it. The `failed` row releases the stage's occupancy, so `--stage <N>` re-enters the same stage on its preserved worktree and branch — there is nothing to unblock by hand.
57
+ When a stage's synthesised verdict is `FAIL`, Phase 6 writes no carry sidecar and appends a `status:"failed"` row in place of `done` (`scripts/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md` "Lead post-stage persistence"). **Stop the queue at that stage** and report the failed stage, its report path, and the remaining queue (e.g. `stage 1 FAIL — remaining queue: stage 2, 3, 5; re-enter with okstra-run --stage 1 after the fix`). Do **not** continue to the next stage even when that stage is dependency-independent: an unattended chain that keeps building past a confirmed regression stacks later work on top of it. The `failed` row releases the stage's occupancy, so `--stage <N>` re-enters the same stage on its preserved worktree and branch — there is nothing to unblock by hand.
58
58
 
59
59
  ### Exception gate during chaining
60
60
  If `render-bundle` raises Step 5's concurrent-run conflict detection (concurrent-run branch) or git stale-SHA reconciliation (git-reconcile branch), **stop the chain at that stage** and present the gate to the user exactly as Step 5 prescribes. Once the user resolves the gate, resume the chain in place (continue with the remaining queue). Data corruption·concurrent-occupancy conflicts are confirmed by a human — this is the safety boundary of unattended chaining. (Unlike the "not ready" rejection above, these two branches do not discard the queue; they wait for user resolution.)
@@ -37,7 +37,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
37
37
  evidence and add one `recommendedNextSteps` item with environment
38
38
  prerequisites and the expected `QA-RESULT`. This is user-owned verification;
39
39
  do not route back or fail implementation solely for this advisory.
40
- - **Routing recommendation**: `implementation.routingRecommendation` is an **object** with exactly two fields — `target`, one of `final-verification`, `error-analysis`, `implementation-planning`, `implementation`, and `rationale`, one or two sentences on why that target and nothing else. It is not a prose note: Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone, so a phase named only in the prose does not route the task. Pick `final-verification` when this stage's plan items landed and validation passed; `error-analysis` when a failure's cause is not understood; `implementation-planning` when the approved plan itself no longer fits the evidence; `implementation` when work remains inside this stage and the next run is a fix run. **Enforced:** `schemas/final-report-v2.0.schema.json` rejects a `target` outside the enum, a missing `rationale`, and a string in place of the object.
40
+ - **Routing recommendation**: `implementation.routingRecommendation` is an **object** with exactly two fields — `target`, one of `final-verification`, `error-analysis`, `implementation-planning`, `implementation`, and `rationale`, one or two sentences on why that target and nothing else. It is not a prose note: Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone, so a phase named only in the prose does not route the task. Record the stage completion, validation outcome, failure-cause certainty, and plan-fit evidence; the lead chooses the destination using `prompts/lead/phase-routing.md` §implementation. **Enforced:** `schemas/final-report-v2.0.schema.json` rejects a `target` outside the enum, a missing `rationale`, and a string in place of the object.
41
41
  - **Follow-up tasks (Section 4 of the final report)**: every item discovered during this run that was *not* delivered MUST appear in the final report's `## 4. Follow-up Tasks` table with a concrete `Origin`, `New Task ID`, `Suggested task-type`, `Scope`, and `Reason / Why deferred`. Sources include: out-of-scope discoveries that the executor consciously chose not to fold into this run, verifier concerns the executor declined to fix in-place, scope-boundary items from the approved plan that turned out to need their own ticket, and any unresolved `## 1. Clarification Items` row carried over from the approved plan (`Status` ∈ `{open, answered}` at approval time). An empty section is acceptable but only when expressed as the single line `- No follow-up tasks.` — silence is treated as a contract violation. Rows with `Auto-spawn? = yes` will be materialised by `scripts/okstra-spawn-followups.py` in Phase 7; rows with `Auto-spawn? = no` MUST also appear in `Section 3. Recommended Next Steps` so the user knows to act manually.
42
42
 
43
43
  ## Self-review pass before finalising the report (the Okstra lead runs this; do not delegate it)
@@ -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 — whatever it writes (a baseline capture, build logs) goes under `<task_root>/qa/output/`, the one qa directory besides `qa/scripts/` your attempt may write — 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": {
@@ -48,7 +48,15 @@ Verifier obtains the QA command set from exactly two declared sources, in order
48
48
 
49
49
  ### Execution rule
50
50
 
51
- Tier 1 commands run verbatim first. Then every Tier 2 entry runs once. Then the Tier 3 stage conformance script (below) runs once. Then the self-mock detector (below) runs once whenever the diff changed a test file. Each command runs in the worktree cwd, and is recorded in the worker result with its exact command line, exit code, and the tail of stdout/stderr. Substituting or paraphrasing a Tier 1 command is forbidden (see Verifier-specific forbidden actions below).
51
+ Tier 1 commands run verbatim first. Then every Tier 2 entry runs once. Then the Tier 3 stage conformance script (below) runs once. Then the self-mock detector (below) runs once whenever the diff changed a test file. Those last two are run by the stage QA owner only (next section). Each command runs in the worktree cwd, and is recorded in the worker result with its exact command line, exit code, and the tail of stdout/stderr. Substituting or paraphrasing a Tier 1 command is forbidden (see Verifier-specific forbidden actions below).
52
+
53
+ ### Stage QA owner
54
+
55
+ Every verifier of this stage runs in the same worktree at the same time. Two checks change that worktree while they run: a Tier 3 conformance script may build into it (`.next/`, `dist/`) or bind fixed ports, and the self-mock detector's mutation probe rewrites production sources in place (cosmic-ray) or replaces a report file inside the worktree (Stryker). Run concurrently, they corrupt each other's result and the other verifiers' test runs (observed 2026-09-26, fontsninja-v3-site dev-11054 stage 1: `next build` + `next start -p 3000` + a proxy on 8889 from three verifiers at once).
56
+
57
+ Your prompt carries a `**Stage QA owner:**` anchor naming one worker id. If that id is yours (the `<id>` in your `**Model:** <id> worker` line), you run Tier 3 and the self-mock detector as the two sections below describe. Otherwise you run neither and write neither sidecar; each section says what to record instead. A prompt with no such anchor predates this rule: run both yourself.
58
+
59
+ **Enforced:** the anchor is generated (`scripts/okstra_ctl/worker_prompt_policy.py` `stage_qa_owner`, the first verifier in roster order). If the owner is never dispatched, no sidecar is written and the existing gates report it: a missing conformance result is BLOCKING for an `io`-only entry and ADVISORY for an external one (`scripts/okstra_ctl/conformance.py` `decide_conformance_gate`), and a missing self-mock sidecar blocks when the diff changed a test file (`validators/validate-run.py` `_validate_selfmock`). Nothing checks which verifier's log holds the commands.
52
60
 
53
61
  ### Tier 3 — stage conformance scripts
54
62
 
@@ -75,7 +83,8 @@ lock the core, gate, and accepted-report behavior respectively.
75
83
  An `io`-only non-PASS remains BLOCKING. Manifest/schema/source-mutation defects
76
84
  also remain contract violations.
77
85
 
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).
86
+ - **Owner only.** This section is the stage QA owner's (§ Stage QA owner above). A verifier that is not the owner runs no `runCommand`, writes no `result-*.json`, logs `conformance: owned by <worker-id> — not run`, and judges Tier 3 only from the diff and the manifest entry (declaration, `requires` coverage).
87
+ - **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
88
  - **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
89
  - **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
90
  - **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.
@@ -96,6 +105,7 @@ also remain contract violations.
96
105
 
97
106
  A green suite does not prove a test exercises the unit it names — a test that stubs its own SUT passes forever, including after the real implementation is deleted. The static detector is the machine half of the **Self-mocking** blocking check below, and running it is the verifier's own duty: it is never delegated to the executor and never inferred from the executor's evidence.
98
107
 
108
+ - **Owner only.** The detector is the stage QA owner's (§ Stage QA owner above). A verifier that is not the owner does not run it and writes no `self-mock-*` file; it logs `self-mock detector: owned by <worker-id> — not run` and still performs the **Self-mocking** blocking check below by reading the changed tests.
99
109
  - **Trigger.** This run's diff changed at least one **test** file. Enumerate the changed files with `git diff --name-only <base>...HEAD` from the worktree cwd — the same enumeration the static review's Scope rule uses — then keep only the paths the gate itself treats as tests: `*.spec.*`, `*.test.*`, a `test_`-prefixed basename, a `_test.` suffixed basename, or any path segment `test/` or `tests/`. Pass nothing else; non-test files are excluded. Exclude `tests/fixtures/self_mock/**` as well — those are the detector's own deliberately self-mocked fixtures, which `validate-run.py` also excludes from the trigger, so feeding them in would manufacture a `FAIL` the gate then blocks on. No changed test file → no run and no sidecar; the gate is vacuous by design.
100
110
  - **Run the detector once, in the worktree cwd**, one `--test-file` per changed test file:
101
111
  ```bash
@@ -158,7 +168,7 @@ Tier 3 external-advisory discrepancies are excluded from this promotion: preserv
158
168
 
159
169
  ### Read-only command log (per verifier)
160
170
 
161
- The worker result MUST contain a `Read-only command log` block listing every command executed during the verifier run with its exact invocation and exit code, in execution order — including the Tier 3 conformance `runCommand` (or the exemption/waiver skip note when no script ran). No source-mutating command may appear in this block; the only permitted mutations are a Tier 3 conformance script writing to its `qaEnv` replica datastore and the self-mock detector writing its own `<task_root>/qa/self-mock-*.json` sidecar — both are artifact-directory writes, both are logged like any other command, and neither touches the worktree source, so the verifier runs them without hesitation. This log is copied into the final report's verifier result section verbatim.
171
+ The worker result MUST contain a `Read-only command log` block listing every command executed during the verifier run with its exact invocation and exit code, in execution order — including the Tier 3 conformance `runCommand` (or, when no script ran, the exemption/waiver skip note or the not-the-owner note), and the self-mock detector invocation (or the not-the-owner note). No source-mutating command may appear in this block; the only permitted mutations are a Tier 3 conformance script writing to its `qaEnv` replica datastore and the self-mock detector writing its own `<task_root>/qa/self-mock-*.json` sidecar — both are artifact-directory writes, both are logged like any other command, and neither touches the worktree source, so the verifier runs them without hesitation. This log is copied into the final report's verifier result section verbatim.
162
172
 
163
173
  **Enforced:** `_validate_verifier_command_log_is_read_only` in `validators/validate-run.py` scans every `verifierResults[].readOnlyCommandLog` for mutation modes (`--fix`, `--write`, `gofmt -w`, `jest -u`, snapshot/golden updates, `cargo insta accept`, a non-`no` `INSTA_UPDATE`, and a trailing `|| true`) and fails the run. Check-only forms (`--check`, `--check-only`) pass.
164
174
 
@@ -173,7 +183,7 @@ Re-running commands proves the diff *builds and passes*; it does NOT prove the d
173
183
  - **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
184
  - **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
185
  - **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.
186
+ - **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
187
  - **Blocking checks (any hit → verdict `FAIL`, cited `path:line` + rule name, recommended fix recorded — the verifier does NOT apply it):**
178
188
  - **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
189
  - **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.
@@ -207,7 +217,8 @@ diff re-buys wall-clock without new information, so the static scope narrows —
207
217
  the command re-run does not:
208
218
 
209
219
  - **Command re-run stays full.** Every Tier 1/2/3 command from the plan's
210
- validation set runs end-to-end exactly as in a first run. QA-RESULT gating
220
+ validation set runs end-to-end exactly as in a first run (Tier 3 and the self-mock
221
+ detector by the stage QA owner only, as in a first run). QA-RESULT gating
211
222
  (`validate-run.py` Tier 3) is unchanged.
212
223
  - **Static design & test-quality sweep narrows to the fix diff.** Enumerate
213
224
  `git diff <prev-head>..HEAD` (the `Previous run HEAD` line of the Fix-Run
@@ -255,7 +266,7 @@ If every verifier present in the resolved roster ends with a non-result terminal
255
266
 
256
267
  ## Executor completion self-check (not this role's gate)
257
268
 
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.
269
+ - 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
270
 
260
271
  ## Plan differences and completion recovery
261
272
 
@@ -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