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,100 @@
1
+ """미확정 사실의 시험 입력과 관측 결과를 연결하며 도입 승인은 만들지 않는다."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import re
7
+ from pathlib import Path
8
+ from typing import TypedDict
9
+
10
+ from okstra_ctl.final_report_schema import load_schema_for_data, validate
11
+ from okstra_ctl.implementation_direction import validate_task_artifact_path
12
+ from okstra_ctl.json_boundary import load_owned_object_snapshot, serialize_owned_object
13
+ from okstra_ctl.technical_verification_facts import (
14
+ TechnicalVerificationError,
15
+ VerificationFact,
16
+ technical_verification_facts,
17
+ )
18
+
19
+
20
+ class VerificationInput(TypedDict):
21
+ sourceReport: str
22
+ sourceDataSha256: str
23
+ scope: str
24
+ facts: list[VerificationFact]
25
+
26
+
27
+ def resolve_technical_verification_input(
28
+ report: Path, project_root: Path, task_root: Path, task_key: str
29
+ ) -> VerificationInput:
30
+ """같은 작업의 후보 비교 기록을 시험 입력으로 고정한다."""
31
+ report = report if report.is_absolute() else project_root / report
32
+ validate_task_artifact_path(report, task_root, "technical verification source")
33
+ expected_parent = task_root / "runs/implementation-option-selection/reports"
34
+ if report.parent != expected_parent or not re.fullmatch(
35
+ r"final-report-implementation-option-selection-\d{3,}\.data\.json", report.name
36
+ ):
37
+ raise TechnicalVerificationError(
38
+ "source must be this task's option-selection record"
39
+ )
40
+ snapshot = load_owned_object_snapshot(
41
+ report, artifact="technical verification source"
42
+ )
43
+ data = snapshot.value
44
+ errors = validate(data, load_schema_for_data(data))
45
+ if errors:
46
+ raise TechnicalVerificationError("invalid source report: " + "; ".join(errors))
47
+ if data["header"]["taskKey"] != task_key:
48
+ raise TechnicalVerificationError(
49
+ "source taskKey does not match verification task"
50
+ )
51
+ return {
52
+ "sourceReport": report.relative_to(project_root).as_posix(),
53
+ "sourceDataSha256": hashlib.sha256(snapshot.raw_bytes).hexdigest(),
54
+ "scope": "technical-evidence-only",
55
+ "facts": technical_verification_facts(data),
56
+ }
57
+
58
+
59
+ def write_technical_verification_input(
60
+ payload: VerificationInput, run_root: Path, seq: str
61
+ ) -> Path:
62
+ """실행 순번별 입력을 저장해 후속 실행이 이전 시험 범위를 덮지 않게 한다."""
63
+ path = run_root / "state" / f"technical-verification-input-{seq}.json"
64
+ serialized = serialize_owned_object(path, payload, artifact="technical verification input")
65
+ path.parent.mkdir(parents=True, exist_ok=True)
66
+ with path.open("x", encoding="utf-8") as output:
67
+ output.write(serialized)
68
+ return path
69
+
70
+
71
+ def prepare_technical_verification_input(
72
+ source_path: str, project_root: Path, task_root: Path, task_key: str
73
+ ) -> VerificationInput:
74
+ """공통 준비가 부수효과를 시작하기 전에 필수 입력과 오류 형식을 고정한다."""
75
+ from okstra_ctl.prepare_error import PrepareError
76
+
77
+ if not source_path:
78
+ raise PrepareError("technical-verification requires --clarification-response pointing to this task's option-selection record")
79
+ try:
80
+ return resolve_technical_verification_input(
81
+ Path(source_path), project_root, task_root, task_key,
82
+ )
83
+ except ValueError as exc:
84
+ raise PrepareError(str(exc)) from exc
85
+
86
+
87
+ def materialize_technical_input_packet(payload_json: str, run_root: Path, seq: str) -> str:
88
+ """입력 저장과 패킷 안내를 함께 구성해 실행 순번별 증거 위치를 보존한다."""
89
+ import json
90
+
91
+ verification_path = write_technical_verification_input(
92
+ json.loads(payload_json), run_root, seq,
93
+ )
94
+ return (
95
+ "\n## Technical Verification Input\n\n"
96
+ f"- Frozen input: `{verification_path}`\n"
97
+ f"- Experiment copies only: `{run_root}/experiments/{seq}/<worker-id>/`\n"
98
+ "- Read the input before planning experiments; copy each fact identity verbatim into results.\n"
99
+ + "\n```json\n" + payload_json + "\n```\n"
100
+ )
@@ -12,7 +12,7 @@
12
12
  1. Read the frozen technical input linked in the analysis packet. Preserve the source hash, candidate IDs and fact identities. `resolve_technical_verification_input` enforces same-task source ownership, schema validity, eligible technical facts and unresolved user-decision gates.
13
13
  2. Before executing a probe, write its plan under `experiments/<seq>/<worker-id>/`: hypothesis, procedure, commands, confirming and rejecting signals, environment, and inconclusive criteria. Retain the plan with the evidence.
14
14
  3. Create a separate source copy in that directory. Record the source commit and any uncommitted input differences. Read the project and task worktree as inputs; perform source edits, installations and builds only in your own copy. Do not share writable dependency directories or use real credentials. Use synthetic local accounts for request-boundary experiments.
15
- 4. Preserve the baseline lockfile. When the hypothesis needs a deliberate dependency change, retain the resulting lockfile and diff, then use a frozen install against that experimental lockfile. Record command, working directory, stdout/stderr and exit code in run-local logs. Distinguish infrastructure failure from a falsified compatibility claim.
15
+ 4. Phase 7 removes every `node_modules` and `.next` directory under the run directory, so evidence must not live inside them. Preserve the baseline lockfile. When the hypothesis needs a deliberate dependency change, retain the resulting lockfile and diff, then use a frozen install against that experimental lockfile. Record command, working directory, stdout/stderr and exit code in run-local logs. Distinguish infrastructure failure from a falsified compatibility claim.
16
16
  5. Classify each fact as `supported`, `refuted`, `inconclusive` or `not-run` using the declared signals. A zero exit code alone does not establish compatibility. Record limitations and all failed or unavailable probes.
17
17
  6. During convergence, inspect plans and logs; rerun disputed probes in a separate copy when feasible. An independent report is not a substitute for command evidence.
18
18
 
@@ -22,7 +22,7 @@ Copy boundaries and pre-execution plans are worker instructions reviewed during
22
22
 
23
23
  Copy `sourceReport`, `sourceDataSha256` and `scope` from the frozen input into `technicalVerification`. Emit exactly one check per fact, preserving its `id`, `candidateId`, `factIndex` and `fact`. Each check records its hypothesis, procedure, signals, command evidence, observation, status and limitations. Use project-relative evidence paths. Mark contested results inconclusive.
24
24
 
25
- Route only to `implementation-option-selection`, with one matching phase-continuation follow-up. The next comparison consumes this report through `--clarification-response` and authors fresh feasibility votes. Do not edit the source comparison, clear unrelated uncertainties, rank candidates, approve implementation, merge code or expand the user's pilot scope.
25
+ Do not edit the source comparison, clear unrelated uncertainties, rank candidates, approve implementation, merge code or expand the user's pilot scope.
26
26
 
27
27
  `validate_technical_verification_report` checks frozen-input identity and evidence before publication and during run validation. The report schema restricts the routing target and requires `frontmatter.approved=false`.
28
28
  {{INCLUDE:_coverage-critic.md}}
@@ -2,8 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from ..common import evidence_index
6
- from ..models import HumanReportView
5
+ from okstra_ctl.report_html.common import evidence_index
6
+ from okstra_ctl.report_html.models import HumanReportView
7
7
 
8
8
 
9
9
  def build_technical_verification_view(data: dict) -> HumanReportView:
@@ -0,0 +1,37 @@
1
+ # Technical verification phase
2
+
3
+ ## Purpose and boundaries
4
+
5
+ This phase collects experimental evidence for unresolved technical facts. It does not rank candidates, select a direction, approve implementation or modify the source comparison. The lead chooses the continuation using `prompts/lead/phase-routing.md`.
6
+
7
+ ## Input and preparation
8
+
9
+ The existing `--clarification-response` argument identifies this task's option-selection data record. `entry.prepare_technical_verification_input` checks the required argument before run creation. `entry.resolve_technical_verification_input` checks ownership, the canonical record name, schema and task key, then freezes the source-byte SHA-256 and eligible fact identities. Shared `technical_verification_facts.py` retains candidate safety and unresolved user-decision rules for both producer and consumer phases.
10
+
11
+ `entry.materialize_technical_input_packet` writes `state/technical-verification-input-<seq>.json` without replacing an existing snapshot and appends the input and experiment directory to the existing analysis packet. Artifact names, CLI inputs and preparation order are unchanged.
12
+
13
+ ## Execution and output
14
+
15
+ `profile.md` owns experiment preparation, isolated source copies, command evidence, convergence and fact classification. `profile.json` owns role requirements. Worker write boundaries remain in the common invocation write contract.
16
+
17
+ The report's `technicalVerification` block preserves `sourceReport`, `sourceDataSha256`, `scope` and each fact's identity. Checks record hypothesis, procedure, confirming and rejecting signals, observations, limitations and commands. Status values are `supported`, `refuted`, `inconclusive` and `not-run`.
18
+
19
+ Report schemas remain common: `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json`, including the `technicalVerification` definition and approval/continuation constraints. `report.py` and `report_assets/` own the phase body; the common report engine owns publication and page layout.
20
+
21
+ ## Validation and failure behavior
22
+
23
+ `validation.validate_technical_verification_report` checks frozen-input metadata, exactly one check per input fact, unchanged fact identity and execution evidence. Observed checks need commands; supported checks cannot cite a nonzero exit code. Log and working-directory evidence stays inside the matching run's experiment sequence and rejects symlink escapes. `not-run` may omit commands.
24
+
25
+ Both `report_assembly.py` and `validators/validate-run.py` call this validation and the common `report_routing.technical_verification_routing_errors` check. Publication rejects invalid evidence before replacing the report. These checks do not prove that a declared command produced a log or sandbox arbitrary shell commands. Copy isolation and pre-execution plan quality remain worker instructions reviewed during convergence.
26
+
27
+ ## Tests
28
+
29
+ `tests/test_technical_verification.py` covers input ownership, unsafe/unclassified sources, source preservation, exclusive snapshot creation, fact completeness, failed or missing commands, logs, sequence and symlink boundaries, full preparation and schema-v2/v3 report rendering. `tests/report/test_report_assembly.py::test_technical_assembly_requires_evidence_before_replacing_record` checks publication preserves an existing record when evidence fails.
30
+
31
+ ## Guarantees
32
+
33
+ | ID | Guarantee | Enforcement |
34
+ |---|---|---|
35
+ | TV-1 | Report checks preserve the frozen input metadata and cover every input fact exactly once. | `scripts/okstra_ctl/phases/technical_verification/validation.py::validate_technical_verification_report` |
36
+ | TV-2 | Observed results require execution evidence within the matching experiment sequence. | `scripts/okstra_ctl/phases/technical_verification/validation.py::_check_execution_evidence` |
37
+ | TV-3 | The continuation targets implementation option selection. | `scripts/okstra_ctl/report_routing.py::technical_verification_routing_errors` |
@@ -0,0 +1,90 @@
1
+ """관측 판정과 실행별 시험 증거의 일치 검사."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from collections.abc import Mapping
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from okstra_ctl.implementation_direction import validate_task_artifact_path
10
+ from okstra_ctl.json_boundary import load_owned_object_snapshot
11
+ from okstra_ctl.technical_verification_facts import TechnicalVerificationError
12
+
13
+
14
+ def _check_execution_evidence(
15
+ check: Mapping[str, Any], project_root: Path, run_root: Path, seq: str
16
+ ) -> list[str]:
17
+ """관측 판정은 실행 기록과 실행별 시험 디렉터리를 요구한다."""
18
+ errors = []
19
+ commands = check.get("commands") or []
20
+ if check.get("status") != "not-run" and not commands:
21
+ errors.append(f"{check['id']}: an observed result requires command evidence")
22
+ for command in commands:
23
+ try:
24
+ log = project_root / command["logPath"]
25
+ experiment_root = run_root / "experiments" / seq
26
+ validate_task_artifact_path(log, experiment_root, "verification log")
27
+ if not log.read_text(encoding="utf-8").strip():
28
+ errors.append(f"{check['id']}: verification log is empty")
29
+ cwd = project_root / command["cwd"]
30
+ cwd.resolve(strict=True).relative_to(experiment_root.resolve(strict=True))
31
+ relative = cwd.relative_to(experiment_root)
32
+ current = run_root
33
+ for part in ("experiments", seq, *relative.parts):
34
+ current = current / part
35
+ if current.is_symlink():
36
+ raise TechnicalVerificationError(
37
+ "experiment cwd contains a symlink"
38
+ )
39
+ if not cwd.is_dir() or cwd.is_symlink():
40
+ errors.append(f"{check['id']}: experiment cwd must be a directory")
41
+ except (OSError, ValueError) as exc:
42
+ errors.append(f"{check['id']}: invalid execution evidence: {exc}")
43
+ if check.get("status") == "supported" and command.get("exitCode") != 0:
44
+ errors.append(f"{check['id']}: a supported result has a failed command")
45
+ return errors
46
+
47
+
48
+ def validate_technical_verification_report(
49
+ data: Mapping[str, Any], report_path: Path, project_root: Path
50
+ ) -> list[str]:
51
+ """발행·최종 검증에서 같은 사실 집합과 실제 시험 산출물을 대조한다."""
52
+ if (data.get("header") or {}).get("taskType") != "technical-verification":
53
+ return []
54
+ match = re.fullmatch(
55
+ r"final-report-technical-verification-(\d{3,})\.data\.json", report_path.name
56
+ )
57
+ if match is None:
58
+ return ["technical verification report must use its canonical record path"]
59
+ run_root = report_path.parent.parent
60
+ path = run_root / "state" / f"technical-verification-input-{match[1]}.json"
61
+ try:
62
+ validate_task_artifact_path(path, run_root, "technical verification input")
63
+ source = load_owned_object_snapshot(
64
+ path, artifact="technical verification input"
65
+ ).value
66
+ except (OSError, ValueError) as exc:
67
+ return [str(exc)]
68
+ block = data.get("technicalVerification") or {}
69
+ errors = []
70
+ for key in ("sourceReport", "sourceDataSha256", "scope"):
71
+ if block.get(key) != source.get(key):
72
+ errors.append(f"technicalVerification.{key} must match the run input")
73
+ expected = {fact["id"]: fact for fact in source["facts"]}
74
+ checks = block.get("checks") or []
75
+ ids = [check.get("id") for check in checks]
76
+ if len(ids) != len(set(ids)) or set(ids) != set(expected):
77
+ errors.append(
78
+ "technicalVerification.checks must cover each input fact exactly once"
79
+ )
80
+ for check in checks:
81
+ fact = expected.get(check.get("id"))
82
+ if fact is None:
83
+ continue
84
+ for key in ("candidateId", "factIndex", "fact"):
85
+ if check.get(key) != fact[key]:
86
+ errors.append(f"{check['id']}: {key} must preserve the input fact")
87
+ errors.extend(
88
+ _check_execution_evidence(check, project_root, run_root, match[1])
89
+ )
90
+ return errors
@@ -0,0 +1,70 @@
1
+ """계획 승인 상태를 보고서와 사용자 응답에 동일하게 제공한다."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Mapping, Any
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class PlanApprovalState:
11
+ option_names: tuple[str, ...]
12
+ recommended_option: str
13
+ disabled_reason: str
14
+ blocker_ids: tuple[str, ...]
15
+ show_option_selector: bool = True
16
+ reentry_command: str = ""
17
+
18
+
19
+ def resolve_recommended_option(rec_name: str, names: tuple[str, ...]) -> str:
20
+ if rec_name in names:
21
+ return rec_name
22
+ matches = [
23
+ name
24
+ for name in names
25
+ if rec_name and (name.startswith(rec_name) or rec_name.startswith(name))
26
+ ]
27
+ return matches[0] if len(matches) == 1 else names[0]
28
+
29
+
30
+ def plan_approval_state(data: dict) -> PlanApprovalState | None:
31
+ planning = data.get("implementationPlanning")
32
+ if not isinstance(planning, dict):
33
+ return None
34
+ blockers = tuple(
35
+ row["id"]
36
+ for row in data.get("clarificationItems", [])
37
+ if row.get("blocks") == "approval" and row.get("status") in {"open", "answered"}
38
+ )
39
+ reason = f"{len(blockers)} approval blocker(s) unresolved" if blockers else ""
40
+ if planning.get("planningContract") == "selected-direction":
41
+ if planning.get("outcome") == "direction-invalidated" and not reason:
42
+ reason = "selected direction invalidated"
43
+ task_key = (data.get("header") or {}).get("taskKey", "")
44
+ reentry_command = (
45
+ f"/okstra-run task-key={task_key} task-type=implementation-option-selection"
46
+ if planning.get("outcome") == "direction-invalidated" and task_key
47
+ else ""
48
+ )
49
+ return PlanApprovalState((), "", reason, blockers, False, reentry_command)
50
+ names = tuple(
51
+ row["name"]
52
+ for row in planning.get("optionCandidates", [])
53
+ if isinstance(row, dict) and row.get("name")
54
+ )
55
+ if not names:
56
+ return None
57
+ recommended = planning.get("recommendedOption", {}).get("name", "")
58
+ return PlanApprovalState(
59
+ names,
60
+ resolve_recommended_option(recommended, names),
61
+ reason,
62
+ blockers,
63
+ )
64
+
65
+
66
+ def plan_is_approved(report_data: Mapping[str, Any] | None) -> bool:
67
+ if not isinstance(report_data, Mapping):
68
+ return False
69
+ frontmatter = report_data.get("frontmatter")
70
+ return isinstance(frontmatter, Mapping) and frontmatter.get("approved") is True