okstra 0.206.0 → 0.206.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +2 -2
  2. package/dist/commands/lifecycle/install.mjs +1 -1
  3. package/dist/commands/lifecycle/install.mjs.map +1 -1
  4. package/docs/architecture.md +12 -12
  5. package/docs/cli.md +4 -4
  6. package/docs/contributor-change-matrix.md +3 -2
  7. package/docs/performance-improvement-plan-v2.md +1 -1
  8. package/docs/project-structure-overview.md +39 -18
  9. package/package.json +1 -1
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/bin/okstra-spawn-followups.py +2 -2
  12. package/runtime/prompts/launch.template.md +1 -1
  13. package/runtime/prompts/lead/context-loader.md +1 -1
  14. package/runtime/prompts/lead/convergence.md +3 -3
  15. package/runtime/prompts/lead/okstra-lead-contract.md +13 -54
  16. package/runtime/prompts/lead/phase-routing.md +64 -0
  17. package/runtime/prompts/lead/report-writer.md +2 -2
  18. package/runtime/prompts/lead/team-contract.md +1 -1
  19. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  20. package/runtime/prompts/profiles/_common-contract.md +1 -1
  21. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  22. package/runtime/prompts/profiles/forbidden-actions.json +0 -94
  23. package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
  24. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +10 -1
  25. package/runtime/python/okstra_ctl/analysis_inputs.py +0 -39
  26. package/runtime/python/okstra_ctl/analysis_scope.py +31 -0
  27. package/runtime/python/okstra_ctl/asset_roots.py +19 -0
  28. package/runtime/python/okstra_ctl/consumers.py +12 -0
  29. package/runtime/python/okstra_ctl/dispatch_state.py +22 -0
  30. package/runtime/python/okstra_ctl/doctor.py +2 -1
  31. package/runtime/python/okstra_ctl/execution_mutation_audit.py +27 -1
  32. package/runtime/python/okstra_ctl/handoff.py +11 -466
  33. package/runtime/python/okstra_ctl/handoff_error.py +5 -0
  34. package/runtime/python/okstra_ctl/implementation_direction.py +0 -477
  35. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +8 -1
  36. package/runtime/python/okstra_ctl/option_comparison.py +3 -165
  37. package/runtime/python/okstra_ctl/option_votes.py +3 -191
  38. package/runtime/python/okstra_ctl/paths.py +8 -6
  39. package/runtime/python/okstra_ctl/phases/catalog.py +56 -12
  40. package/runtime/python/okstra_ctl/phases/change_impact_analysis/boundary.json +11 -0
  41. package/runtime/python/okstra_ctl/phases/change_impact_analysis/entry.py +39 -0
  42. package/runtime/python/okstra_ctl/{report_html/view_models/change_impact_analysis.py → phases/change_impact_analysis/report.py} +3 -3
  43. package/runtime/python/okstra_ctl/phases/change_impact_analysis/spec.md +26 -0
  44. package/runtime/python/okstra_ctl/phases/change_impact_analysis/validation.py +23 -0
  45. package/runtime/python/okstra_ctl/phases/error_analysis/__init__.py +1 -0
  46. package/runtime/python/okstra_ctl/phases/error_analysis/boundary.json +9 -0
  47. package/runtime/{prompts/profiles/error-analysis.md → python/okstra_ctl/phases/error_analysis/profile.md} +2 -2
  48. package/runtime/python/okstra_ctl/{report_html/view_models/error_analysis.py → phases/error_analysis/report.py} +9 -8
  49. package/runtime/{templates/reports → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis-input.template.md +1 -1
  50. package/runtime/python/okstra_ctl/phases/error_analysis/spec.md +118 -0
  51. package/runtime/python/okstra_ctl/phases/error_analysis/validation.py +241 -0
  52. package/runtime/python/okstra_ctl/phases/feature_analysis/__init__.py +1 -0
  53. package/runtime/python/okstra_ctl/phases/feature_analysis/boundary.json +8 -0
  54. package/runtime/python/okstra_ctl/phases/feature_analysis/entry.py +63 -0
  55. package/runtime/python/okstra_ctl/{report_html/view_models/feature_analysis.py → phases/feature_analysis/report.py} +12 -5
  56. package/runtime/python/okstra_ctl/phases/feature_analysis/spec.md +22 -0
  57. package/runtime/python/okstra_ctl/phases/feature_analysis/validation.py +27 -0
  58. package/runtime/python/okstra_ctl/phases/feature_analysis/wizard.py +95 -0
  59. package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
  60. package/runtime/python/okstra_ctl/phases/final_verification/profile.md +1 -1
  61. package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
  62. package/runtime/python/okstra_ctl/phases/final_verification/spec.md +1 -1
  63. package/runtime/python/okstra_ctl/phases/implementation/__init__.py +1 -0
  64. package/runtime/python/okstra_ctl/phases/implementation/boundary.json +17 -0
  65. package/runtime/python/okstra_ctl/{implementation_stage.py → phases/implementation/entry.py} +22 -10
  66. package/runtime/{prompts/host-orchestration/implementation.md → python/okstra_ctl/phases/implementation/host-rules.md} +1 -1
  67. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-deliverable.md +1 -1
  68. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-executor.md +4 -3
  69. package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-verifier.md +4 -4
  70. package/runtime/{prompts/profiles/implementation.md → python/okstra_ctl/phases/implementation/profile.md} +5 -5
  71. package/runtime/python/okstra_ctl/{report_html/view_models/implementation.py → phases/implementation/report.py} +3 -3
  72. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation/report_assets}/implementation-input.template.md +1 -1
  73. package/runtime/python/okstra_ctl/phases/implementation/spec.md +238 -0
  74. package/runtime/python/okstra_ctl/phases/implementation/validation.py +205 -0
  75. package/runtime/python/okstra_ctl/phases/implementation/wizard.py +39 -0
  76. package/runtime/python/okstra_ctl/phases/implementation_option_selection/__init__.py +1 -0
  77. package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +80 -0
  78. package/runtime/python/okstra_ctl/phases/implementation_option_selection/boundary.json +10 -0
  79. package/runtime/python/okstra_ctl/phases/implementation_option_selection/comparison.py +168 -0
  80. package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +27 -0
  81. package/runtime/{prompts/profiles/implementation-option-selection.md → python/okstra_ctl/phases/implementation_option_selection/profile.md} +2 -2
  82. package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
  83. package/runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md +83 -0
  84. package/runtime/python/okstra_ctl/{implementation_options.py → phases/implementation_option_selection/validation.py} +3 -3
  85. package/runtime/python/okstra_ctl/phases/implementation_option_selection/votes.py +194 -0
  86. package/runtime/python/okstra_ctl/phases/implementation_planning/__init__.py +1 -0
  87. package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +2345 -0
  88. package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +12 -0
  89. package/runtime/python/okstra_ctl/phases/implementation_planning/entry.py +161 -0
  90. package/runtime/python/okstra_ctl/phases/implementation_planning/guidance.py +178 -0
  91. package/runtime/{prompts/lead → python/okstra_ctl/phases/implementation_planning/instructions}/plan-body-verification.md +61 -51
  92. package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +3295 -0
  93. package/runtime/{prompts/profiles/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/profile.md} +74 -25
  94. package/runtime/python/okstra_ctl/phases/implementation_planning/report.py +237 -0
  95. package/runtime/{templates/reports → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning-input.template.md +2 -2
  96. package/runtime/python/okstra_ctl/phases/implementation_planning/spec.md +204 -0
  97. package/runtime/python/okstra_ctl/phases/implementation_planning/validation.py +597 -0
  98. package/runtime/python/okstra_ctl/phases/implementation_planning/wizard.py +166 -0
  99. package/runtime/python/okstra_ctl/phases/improvement_discovery/boundary.json +12 -0
  100. package/runtime/python/okstra_ctl/{improvement_lenses.py → phases/improvement_discovery/lenses.py} +1 -6
  101. package/runtime/{prompts/profiles/improvement-discovery.md → python/okstra_ctl/phases/improvement_discovery/profile.md} +5 -5
  102. package/runtime/python/okstra_ctl/{report_html/view_models/improvement_discovery.py → phases/improvement_discovery/report.py} +3 -3
  103. package/runtime/{templates/reports → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery-input.template.md +1 -2
  104. package/runtime/python/okstra_ctl/phases/improvement_discovery/spec.md +29 -0
  105. package/runtime/{validators/validate_improvement_report.py → python/okstra_ctl/phases/improvement_discovery/validation.py} +5 -14
  106. package/runtime/python/okstra_ctl/phases/project_analysis/__init__.py +1 -0
  107. package/runtime/python/okstra_ctl/phases/project_analysis/boundary.json +8 -0
  108. package/runtime/python/okstra_ctl/phases/project_analysis/entry.py +11 -0
  109. package/runtime/python/okstra_ctl/{report_html/view_models/project_analysis.py → phases/project_analysis/report.py} +3 -3
  110. package/runtime/python/okstra_ctl/phases/project_analysis/spec.md +33 -0
  111. package/runtime/python/okstra_ctl/phases/project_analysis/validation.py +55 -0
  112. package/runtime/python/okstra_ctl/phases/release_handoff/__init__.py +1 -0
  113. package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +17 -0
  114. package/runtime/python/okstra_ctl/phases/release_handoff/entry.py +147 -0
  115. package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +446 -0
  116. package/runtime/{prompts/profiles/release-handoff.md → python/okstra_ctl/phases/release_handoff/profile.md} +3 -3
  117. package/runtime/python/okstra_ctl/{report_html/view_models/release_handoff.py → phases/release_handoff/report.py} +3 -3
  118. package/runtime/{templates/reports → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff-input.template.md +1 -1
  119. package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +233 -0
  120. package/runtime/python/okstra_ctl/phases/release_handoff/wizard.py +84 -0
  121. package/runtime/python/okstra_ctl/phases/requirements_discovery/__init__.py +1 -0
  122. package/runtime/python/okstra_ctl/phases/requirements_discovery/boundary.json +9 -0
  123. package/runtime/{prompts/profiles/requirements-discovery.md → python/okstra_ctl/phases/requirements_discovery/profile.md} +2 -3
  124. package/runtime/python/okstra_ctl/{report_html/view_models/requirements_discovery.py → phases/requirements_discovery/report.py} +3 -3
  125. package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +132 -0
  126. package/runtime/{validators/validate_fanout.py → python/okstra_ctl/phases/requirements_discovery/validation.py} +11 -12
  127. package/runtime/python/okstra_ctl/phases/technical_verification/__init__.py +1 -0
  128. package/runtime/python/okstra_ctl/phases/technical_verification/boundary.json +9 -0
  129. package/runtime/python/okstra_ctl/phases/technical_verification/entry.py +100 -0
  130. package/runtime/{prompts/profiles/technical-verification.md → python/okstra_ctl/phases/technical_verification/profile.md} +1 -1
  131. package/runtime/python/okstra_ctl/{report_html/view_models/technical_verification.py → phases/technical_verification/report.py} +2 -2
  132. package/runtime/python/okstra_ctl/phases/technical_verification/spec.md +37 -0
  133. package/runtime/python/okstra_ctl/phases/technical_verification/validation.py +90 -0
  134. package/runtime/python/okstra_ctl/plan_approval.py +70 -0
  135. package/runtime/python/okstra_ctl/plan_items_cli.py +2 -2130
  136. package/runtime/python/okstra_ctl/profile_show.py +3 -3
  137. package/runtime/python/okstra_ctl/render.py +9 -2
  138. package/runtime/python/okstra_ctl/report_assembly.py +11 -90
  139. package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
  140. package/runtime/python/okstra_ctl/report_projections.py +1 -36
  141. package/runtime/python/okstra_ctl/report_routing.py +23 -0
  142. package/runtime/python/okstra_ctl/report_synthesis_packet.py +4 -73
  143. package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
  144. package/runtime/python/okstra_ctl/report_views.py +1 -1
  145. package/runtime/python/okstra_ctl/run.py +67 -349
  146. package/runtime/python/okstra_ctl/stage_map.py +13 -0
  147. package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
  148. package/runtime/python/okstra_ctl/wizard/__init__.py +31 -31
  149. package/runtime/python/okstra_ctl/wizard/api.py +18 -0
  150. package/runtime/python/okstra_ctl/wizard/outcome.py +3 -12
  151. package/runtime/python/okstra_ctl/wizard/registry.py +20 -12
  152. package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
  153. package/runtime/python/okstra_ctl/wizard/steps_plan.py +10 -263
  154. package/runtime/python/okstra_ctl/wizard/steps_roles.py +2 -1
  155. package/runtime/python/okstra_ctl/work_categories.py +1 -1
  156. package/runtime/python/okstra_ctl/worker_prompt_contract.py +36 -0
  157. package/runtime/python/okstra_ctl/workflow.py +26 -143
  158. package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
  159. package/runtime/skills/okstra-run/SKILL.md +1 -1
  160. package/runtime/templates/reports/quick-input.template.md +1 -1
  161. package/runtime/templates/reports/task-brief.template.md +1 -1
  162. package/runtime/validators/validate-brief.py +2 -2
  163. package/runtime/validators/validate-run.py +299 -3940
  164. package/runtime/validators/validate_analysis_report.py +14 -126
  165. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +0 -147
  166. package/runtime/python/okstra_ctl/technical_verification.py +0 -195
  167. /package/runtime/{prompts/profiles/change-impact-analysis.json → python/okstra_ctl/phases/change_impact_analysis/profile.json} +0 -0
  168. /package/runtime/{prompts/profiles/change-impact-analysis.md → python/okstra_ctl/phases/change_impact_analysis/profile.md} +0 -0
  169. /package/runtime/{templates/reports → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis-input.template.md +0 -0
  170. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.html +0 -0
  171. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.md +0 -0
  172. /package/runtime/{prompts/profiles/error-analysis.json → python/okstra_ctl/phases/error_analysis/profile.json} +0 -0
  173. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.html +0 -0
  174. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.md +0 -0
  175. /package/runtime/{prompts/profiles/feature-analysis.json → python/okstra_ctl/phases/feature_analysis/profile.json} +0 -0
  176. /package/runtime/{prompts/profiles/feature-analysis.md → python/okstra_ctl/phases/feature_analysis/profile.md} +0 -0
  177. /package/runtime/{templates/reports → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis-input.template.md +0 -0
  178. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.html +0 -0
  179. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.md +0 -0
  180. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-diff-review.md +0 -0
  181. /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-self-check.md +0 -0
  182. /package/runtime/{prompts/profiles/implementation.json → python/okstra_ctl/phases/implementation/profile.json} +0 -0
  183. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.html +0 -0
  184. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.md +0 -0
  185. /package/runtime/{prompts/profiles/implementation-option-selection.json → python/okstra_ctl/phases/implementation_option_selection/profile.json} +0 -0
  186. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.html +0 -0
  187. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.md +0 -0
  188. /package/runtime/{prompts/host-orchestration/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/host-rules.md} +0 -0
  189. /package/runtime/{prompts/profiles/implementation-planning.json → python/okstra_ctl/phases/implementation_planning/profile.json} +0 -0
  190. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.html +0 -0
  191. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.md +0 -0
  192. /package/runtime/{prompts/profiles/improvement-discovery.json → python/okstra_ctl/phases/improvement_discovery/profile.json} +0 -0
  193. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.html +0 -0
  194. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.md +0 -0
  195. /package/runtime/{prompts/profiles/project-analysis.json → python/okstra_ctl/phases/project_analysis/profile.json} +0 -0
  196. /package/runtime/{prompts/profiles/project-analysis.md → python/okstra_ctl/phases/project_analysis/profile.md} +0 -0
  197. /package/runtime/{templates/reports → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis-input.template.md +0 -0
  198. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.html +0 -0
  199. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.md +0 -0
  200. /package/runtime/{prompts/profiles/release-handoff.json → python/okstra_ctl/phases/release_handoff/profile.json} +0 -0
  201. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.html +0 -0
  202. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.md +0 -0
  203. /package/runtime/python/okstra_ctl/{fanout.py → phases/requirements_discovery/fanout.py} +0 -0
  204. /package/runtime/{prompts/profiles/requirements-discovery.json → python/okstra_ctl/phases/requirements_discovery/profile.json} +0 -0
  205. /package/runtime/{templates/reports → python/okstra_ctl/phases/requirements_discovery/report_assets}/fan-out-unit.template.md +0 -0
  206. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.html +0 -0
  207. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.md +0 -0
  208. /package/runtime/{prompts/profiles/technical-verification.json → python/okstra_ctl/phases/technical_verification/profile.json} +0 -0
  209. /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.html +0 -0
  210. /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.md +0 -0
@@ -0,0 +1,52 @@
1
+ """방향 비교와 기술 검증이 함께 읽는 미확정 사실 계약."""
2
+ from __future__ import annotations
3
+
4
+ from collections.abc import Mapping
5
+ from typing import Any, TypedDict
6
+
7
+ from .clarification_items import USER_INPUT_BLOCKS, progress_blocking_ids
8
+
9
+
10
+ class VerificationFact(TypedDict):
11
+ id: str
12
+ candidateId: str
13
+ factIndex: int
14
+ fact: str
15
+ whyItMatters: str
16
+ evidence: list[str]
17
+
18
+
19
+ class TechnicalVerificationError(ValueError):
20
+ """시험 입력 또는 관측 결과가 원본 사실과 일치하지 않는다."""
21
+
22
+
23
+ def technical_verification_facts(data: Mapping[str, Any]) -> list[VerificationFact]:
24
+ """안전 차단이 없는 후보의 명시적인 기술 검증 사실만 추출한다."""
25
+ blockers = progress_blocking_ids(
26
+ data.get("clarificationItems"), USER_INPUT_BLOCKS, report_data=data
27
+ )
28
+ if blockers:
29
+ raise TechnicalVerificationError(
30
+ "unresolved user decisions: " + ", ".join(blockers)
31
+ )
32
+ selection = data.get("implementationOptionSelection") or {}
33
+ facts: list[VerificationFact] = []
34
+ for candidate in selection.get("candidateAudit") or []:
35
+ if candidate.get("safetyBlockers"):
36
+ continue
37
+ for index, fact in enumerate(candidate.get("unresolvedFeasibilityFacts") or []):
38
+ if fact.get("resolutionKind") != "technical-verification":
39
+ continue
40
+ facts.append(
41
+ {
42
+ "id": f"TV-{len(facts) + 1:03d}",
43
+ "candidateId": candidate["id"],
44
+ "factIndex": index,
45
+ "fact": fact["fact"],
46
+ "whyItMatters": fact["whyItMatters"],
47
+ "evidence": fact["evidence"],
48
+ }
49
+ )
50
+ if not facts:
51
+ raise TechnicalVerificationError("no eligible technical-verification facts")
52
+ return facts
@@ -15,11 +15,11 @@ Public surface (re-exported here; the skill calls it through the
15
15
  - ``render_args()`` - final args for ``okstra render-bundle`` (``render``).
16
16
  - ``wizard_outcome()`` - final args plus persistence actions and confirmation (``render``).
17
17
 
18
- Module order is the import order: ``ids`` → ``state`` → ``prompts`` → ``sources``
19
- → ``roles`` → ``statefile`` → ``steps_*`` → ``confirmation`` → ``registry`` →
20
- ``engine`` → ``render`` → ``cli``. A module imports only modules before it;
21
- ``tests/contract/test_no_import_cycles.py`` keeps it that way.
18
+ Package initialization loads identifiers and state types only. Public execution
19
+ functions are composed by ``api`` when requested. Phase modules can import state
20
+ and prompt readers without initializing the registry that imports those phases.
22
21
  """
22
+
23
23
  from __future__ import annotations
24
24
 
25
25
  from .ids import (
@@ -118,31 +118,31 @@ from .state import (
118
118
  WizardError,
119
119
  WizardState,
120
120
  )
121
- from .roles import (
122
- next_role_prompt,
123
- )
124
- from .statefile import (
125
- load_state_file,
126
- save_state_file,
127
- )
128
- from .confirmation import (
129
- confirmation_block,
130
- )
131
- from .registry import (
132
- STEPS,
133
- STEP_BY_ID,
134
- )
135
- from .engine import (
136
- init_state,
137
- next_prompt,
138
- prompt_payload,
139
- submit,
140
- )
141
- from .render import (
142
- render_args,
143
- render_role_args,
144
- )
145
- from .outcome import wizard_outcome
146
- from .cli import (
147
- main,
121
+
122
+ _API_EXPORTS = (
123
+ "next_role_prompt",
124
+ "load_state_file",
125
+ "save_state_file",
126
+ "confirmation_block",
127
+ "STEPS",
128
+ "STEP_BY_ID",
129
+ "init_state",
130
+ "next_prompt",
131
+ "prompt_payload",
132
+ "submit",
133
+ "render_args",
134
+ "render_role_args",
135
+ "wizard_outcome",
136
+ "main",
148
137
  )
138
+
139
+ __all__ = [name for name in globals() if not name.startswith("_")] + list(_API_EXPORTS)
140
+
141
+
142
+ def __getattr__(name: str):
143
+ """기존 공개 이름을 실행 조립 모듈에 연결한다."""
144
+ if name not in _API_EXPORTS:
145
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
146
+ from . import api
147
+
148
+ return getattr(api, name)
@@ -0,0 +1,18 @@
1
+ """질문 실행기의 공개 조립 지점. 단계의 값·프롬프트 판독에서는 적재하지 않는다."""
2
+
3
+ from .roles import next_role_prompt as next_role_prompt
4
+ from .statefile import (
5
+ load_state_file as load_state_file,
6
+ save_state_file as save_state_file,
7
+ )
8
+ from .confirmation import confirmation_block as confirmation_block
9
+ from .registry import STEPS as STEPS, STEP_BY_ID as STEP_BY_ID
10
+ from .engine import (
11
+ init_state as init_state,
12
+ next_prompt as next_prompt,
13
+ prompt_payload as prompt_payload,
14
+ submit as submit,
15
+ )
16
+ from .render import render_args as render_args, render_role_args as render_role_args
17
+ from .outcome import wizard_outcome as wizard_outcome
18
+ from .cli import main as main
@@ -25,18 +25,9 @@ def _render_argv(rendered: dict[str, Any], *, host_runtime: str) -> list[str]:
25
25
  def _wizard_persist_actions(state: WizardState) -> list[dict[str, str]]:
26
26
  if state.task_type != "release-handoff":
27
27
  return []
28
- if not state.pr_template_path:
29
- return []
30
- if state.pr_template_scope not in ("project", "global"):
31
- return []
32
- return [
33
- {
34
- "command": "config.set",
35
- "key": "pr-template-path",
36
- "scope": state.pr_template_scope,
37
- "value": state.pr_template_path,
38
- }
39
- ]
28
+ from okstra_ctl.phases.release_handoff.wizard import pr_template_persist_actions
29
+
30
+ return pr_template_persist_actions(state)
40
31
 
41
32
 
42
33
  def wizard_outcome(state: WizardState) -> dict[str, Any]:
@@ -1,6 +1,20 @@
1
1
  """단계 등록표 — 순서가 곧 질문 순서인 `STEPS`, `STEP_BY_ID`, 등록표를 되감는 `_reset_from` 과 되감기를 일으키는 단계(edit target, brief carry)."""
2
2
  from __future__ import annotations
3
3
 
4
+ from okstra_ctl.phases.change_impact_analysis.entry import (
5
+ _build_feature_evidence,
6
+ _build_feature_evidence_pick,
7
+ _submit_feature_evidence,
8
+ _submit_feature_evidence_pick,
9
+ )
10
+
11
+ from okstra_ctl.phases.implementation_planning.wizard import (
12
+ _selected_direction_candidates,
13
+ _planning_rerun_selected,
14
+ _build_selected_direction_pick,
15
+ _submit_selected_direction_pick,
16
+ )
17
+
4
18
  from typing import Optional
5
19
 
6
20
  from .ids import (
@@ -119,27 +133,25 @@ from .steps_identity import (
119
133
  _submit_task_type,
120
134
  _submit_task_type_text,
121
135
  )
122
- from .steps_analysis import (
123
- _analysis_inputs_after_reuse,
136
+ from okstra_ctl.phases.feature_analysis.wizard import (
124
137
  _build_analysis_target,
125
138
  _build_analysis_target_pick,
139
+ _submit_analysis_target,
140
+ _submit_analysis_target_pick,
141
+ )
142
+ from .steps_analysis import (
143
+ _analysis_inputs_after_reuse,
126
144
  _build_design_prep_confirm,
127
145
  _build_design_prep_decision,
128
146
  _build_design_prep_overrides,
129
- _build_feature_evidence,
130
- _build_feature_evidence_pick,
131
147
  _build_project_evidence,
132
148
  _build_project_evidence_pick,
133
149
  _design_prep_confirm_applies,
134
150
  _design_prep_decision_applies,
135
151
  _design_prep_overrides_applies,
136
- _submit_analysis_target,
137
- _submit_analysis_target_pick,
138
152
  _submit_design_prep_confirm,
139
153
  _submit_design_prep_decision,
140
154
  _submit_design_prep_overrides,
141
- _submit_feature_evidence,
142
- _submit_feature_evidence_pick,
143
155
  _submit_project_evidence,
144
156
  _submit_project_evidence_pick,
145
157
  )
@@ -151,12 +163,9 @@ from .steps_plan import (
151
163
  _build_handoff_stage_pick,
152
164
  _build_reverify_scope_pick,
153
165
  _build_reverify_scope_stages,
154
- _build_selected_direction_pick,
155
166
  _build_stage_pick,
156
167
  _fix_cycle_confirm_required,
157
- _planning_rerun_selected,
158
168
  _reverify_scope_step_pending,
159
- _selected_direction_candidates,
160
169
  _submit_approve_plan_confirm,
161
170
  _submit_approved_plan,
162
171
  _submit_approved_plan_pick,
@@ -164,7 +173,6 @@ from .steps_plan import (
164
173
  _submit_handoff_stage_pick,
165
174
  _submit_reverify_scope_pick,
166
175
  _submit_reverify_scope_stages,
167
- _submit_selected_direction_pick,
168
176
  _submit_stage_pick,
169
177
  )
170
178
  from .steps_options import (
@@ -12,7 +12,6 @@ from okstra_ctl.analysis_inputs import (
12
12
  AnalysisReportCandidate,
13
13
  list_evidence_candidates,
14
14
  load_analysis_report_candidate,
15
- resolve_analysis_target,
16
15
  resolve_evidence_inputs,
17
16
  )
18
17
  from okstra_ctl.design_prep import (
@@ -25,13 +24,9 @@ from okstra_ctl.design_prep import (
25
24
  from .ids import (
26
25
  PICK_SKIP,
27
26
  PICK_TYPE_CUSTOM,
28
- S_ANALYSIS_TARGET,
29
- S_ANALYSIS_TARGET_PICK,
30
27
  S_DESIGN_PREP_CONFIRM,
31
28
  S_DESIGN_PREP_DECISION,
32
29
  S_DESIGN_PREP_OVERRIDES,
33
- S_FEATURE_EVIDENCE,
34
- S_FEATURE_EVIDENCE_PICK,
35
30
  S_PROJECT_EVIDENCE,
36
31
  S_PROJECT_EVIDENCE_PICK,
37
32
  _RESUME_REUSE_PHASES,
@@ -128,32 +123,6 @@ def _submit_analysis_evidence_pick(
128
123
  return t["echo_variants"]["selected"].format(path=candidate.report_path)
129
124
 
130
125
 
131
- def _build_feature_evidence_pick(state: WizardState) -> Prompt:
132
- return _build_analysis_evidence_pick(
133
- state, step=S_FEATURE_EVIDENCE_PICK, relation="feature-baseline"
134
- )
135
-
136
-
137
- def _submit_feature_evidence_pick(state: WizardState, value: str) -> Optional[str]:
138
- return _submit_analysis_evidence_pick(
139
- state, value, step=S_FEATURE_EVIDENCE_PICK,
140
- field_name="feature_evidence_path",
141
- pending_name="feature_evidence_pending_text",
142
- )
143
-
144
-
145
- def _build_feature_evidence(state: WizardState) -> Prompt:
146
- t = _p(state.workspace_root, S_FEATURE_EVIDENCE)
147
- return Prompt(step=S_FEATURE_EVIDENCE, kind="text", label=t["label"],
148
- echo_template=t["echo_template"])
149
-
150
-
151
- def _submit_feature_evidence(state: WizardState, value: str) -> Optional[str]:
152
- candidate = _accept_analysis_evidence(state, value, "feature_evidence_path")
153
- state.feature_evidence_pending_text = False
154
- return f"feature-evidence: {candidate.report_path}"
155
-
156
-
157
126
  def _build_project_evidence_pick(state: WizardState) -> Prompt:
158
127
  return _build_analysis_evidence_pick(
159
128
  state, step=S_PROJECT_EVIDENCE_PICK, relation="project-context"
@@ -181,72 +150,6 @@ def _submit_project_evidence(state: WizardState, value: str) -> Optional[str]:
181
150
  return f"project-evidence: {candidate.report_path}"
182
151
 
183
152
 
184
- def _feature_description(feature: dict[object, object]) -> str:
185
- name = str(feature.get("name") or "")
186
- summary = str(feature.get("summary") or "")
187
- entry_point = str(
188
- feature.get("entryPoint") or feature.get("entrypoint") or ""
189
- )
190
- return " · ".join(value for value in (name, summary, entry_point) if value)
191
-
192
-
193
- def _build_analysis_target_pick(state: WizardState) -> Prompt:
194
- t = _p(state.workspace_root, S_ANALYSIS_TARGET_PICK)
195
- try:
196
- candidate = load_analysis_report_candidate(
197
- Path(state.project_root), Path(state.project_evidence_path)
198
- )
199
- except AnalysisInputError as exc:
200
- raise WizardError(str(exc)) from exc
201
- options = [
202
- _opt(str(feature["id"]), str(feature["id"]), _feature_description(feature))
203
- for feature in candidate.feature_index
204
- if isinstance(feature, dict) and isinstance(feature.get("id"), str)
205
- ][:3]
206
- options.append(_opt(PICK_TYPE_CUSTOM, t["options"][PICK_TYPE_CUSTOM]))
207
- return Prompt(step=S_ANALYSIS_TARGET_PICK, kind="pick", label=t["label"],
208
- options=options, echo_template=t["echo_template"])
209
-
210
-
211
- def _accept_analysis_target(state: WizardState, value: str) -> str:
212
- candidates: dict[Path, AnalysisReportCandidate] = {}
213
- for path in _analysis_evidence_paths(state):
214
- try:
215
- candidate = load_analysis_report_candidate(Path(state.project_root), path)
216
- except AnalysisInputError as exc:
217
- raise WizardError(str(exc)) from exc
218
- candidates[candidate.report_path] = candidate
219
- try:
220
- target = resolve_analysis_target(
221
- value, _resolve_analysis_evidence(state), candidates
222
- )
223
- except AnalysisInputError as exc:
224
- raise WizardError(str(exc)) from exc
225
- requested_value = target["requestedValue"]
226
- if not isinstance(requested_value, str):
227
- raise WizardError("analysis target resolver returned an invalid requestedValue")
228
- state.analysis_target = requested_value
229
- state.analysis_target_pending_text = False
230
- return requested_value
231
-
232
-
233
- def _submit_analysis_target_pick(state: WizardState, value: str) -> Optional[str]:
234
- if value == PICK_TYPE_CUSTOM:
235
- state.analysis_target_pending_text = True
236
- return None
237
- return f"analysis-target: {_accept_analysis_target(state, value)}"
238
-
239
-
240
- def _build_analysis_target(state: WizardState) -> Prompt:
241
- t = _p(state.workspace_root, S_ANALYSIS_TARGET)
242
- return Prompt(step=S_ANALYSIS_TARGET, kind="text", label=t["label"],
243
- echo_template=t["echo_template"])
244
-
245
-
246
- def _submit_analysis_target(state: WizardState, value: str) -> Optional[str]:
247
- return f"analysis-target: {_accept_analysis_target(state, value)}"
248
-
249
-
250
153
  def _design_prep_items_by_id(state: WizardState) -> dict[str, dict[str, Any]]:
251
154
  try:
252
155
  items = load_design_prep_items(Path(state.approved_plan_path))