okstra 0.102.2 → 0.102.4

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 (167) hide show
  1. package/README.kr.md +5 -5
  2. package/README.md +5 -5
  3. package/docs/kr/architecture/storage-model.md +8 -3
  4. package/docs/kr/architecture.md +12 -13
  5. package/docs/kr/cli.md +4 -4
  6. package/docs/kr/container.md +1 -1
  7. package/docs/kr/performance-improvement-plan-v2.md +2 -2
  8. package/docs/project-structure-overview.md +2 -2
  9. package/package.json +7 -2
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/bin/lib/okstra/interactive.sh +12 -0
  12. package/runtime/bin/okstra-antigravity-exec.sh +1 -2
  13. package/runtime/bin/okstra-codex-exec.sh +1 -2
  14. package/runtime/bin/okstra-render-final-report.py +2 -9
  15. package/runtime/bin/okstra-spawn-followups.py +4 -6
  16. package/runtime/bin/okstra-trace-cleanup.sh +24 -4
  17. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  18. package/runtime/prompts/lead/report-writer.md +1 -1
  19. package/runtime/prompts/profiles/_common-contract.md +9 -11
  20. package/runtime/python/okstra_ctl/codex_dispatch.py +6 -13
  21. package/runtime/python/okstra_ctl/consumers.py +35 -0
  22. package/runtime/python/okstra_ctl/container.py +4 -6
  23. package/runtime/python/okstra_ctl/dispatch_core.py +8 -13
  24. package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
  25. package/runtime/python/okstra_ctl/handoff.py +2 -1
  26. package/runtime/python/okstra_ctl/implementation_outcome.py +271 -0
  27. package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
  28. package/runtime/python/okstra_ctl/path_hints.py +665 -0
  29. package/runtime/python/okstra_ctl/render.py +4 -3
  30. package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
  31. package/runtime/python/okstra_ctl/report_views.py +7 -4
  32. package/runtime/python/okstra_ctl/run.py +3 -10
  33. package/runtime/python/okstra_ctl/run_context.py +4 -2
  34. package/runtime/python/okstra_ctl/stage_targets.py +18 -0
  35. package/runtime/python/okstra_ctl/wizard.py +37 -26
  36. package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
  37. package/runtime/python/okstra_project/state.py +40 -2
  38. package/runtime/python/okstra_token_usage/report.py +2 -5
  39. package/runtime/validators/validate-report-views.py +2 -1
  40. package/runtime/validators/validate-run.py +1 -11
  41. package/src/commands/lifecycle/install.mjs +5 -5
  42. package/src/commands/lifecycle/uninstall.mjs +4 -4
  43. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
  44. package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
  45. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
  46. package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
  47. package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
  48. package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
  49. package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
  50. package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
  51. package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
  52. package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
  53. package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
  54. package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
  55. package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
  56. package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
  57. package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
  58. package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
  59. package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
  60. package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
  61. package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
  62. package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
  63. package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
  64. package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
  65. package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
  66. package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
  67. package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
  68. package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
  69. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
  70. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
  71. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
  72. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
  73. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
  74. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
  75. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
  76. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
  77. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
  78. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
  79. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
  80. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
  81. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
  82. package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
  83. package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
  84. package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
  85. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
  86. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
  87. package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
  88. package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
  89. package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
  90. package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
  91. package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
  92. package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
  93. package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
  94. package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
  95. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
  96. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
  97. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
  98. package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
  99. package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
  100. package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
  101. package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
  102. package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
  103. package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
  104. package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
  105. package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
  106. package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
  107. package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
  108. package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
  109. package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
  110. package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
  111. package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
  112. package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
  113. package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
  114. package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
  115. package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
  116. package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
  117. package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
  118. package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
  119. package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
  120. package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
  121. package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
  122. package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
  123. package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
  124. package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
  125. package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
  126. package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
  127. package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
  128. package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
  129. package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
  130. package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
  131. package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
  132. package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
  133. package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
  134. package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
  135. package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
  136. package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
  137. package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
  138. package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
  139. package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
  140. package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
  141. package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
  142. package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
  143. package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
  144. package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
  145. package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
  146. package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
  147. package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
  148. package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
  149. package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
  150. package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
  151. package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
  152. package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
  153. package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
  154. package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
  155. package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
  156. package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
  157. package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
  158. package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
  159. package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
  160. package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
  161. package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
  162. package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
  163. package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
  164. package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
  165. package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
  166. package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
  167. package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +0 -110
@@ -1,289 +0,0 @@
1
- # Stage Worktree 격리 P2 — started-exclusion 순수 빌딩블록 구현 계획
2
-
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** A2(started-exclusion)의 순수 로직 — registry의 active stage 번호 조회 헬퍼와 `_resolve_effective_stages`의 `started`/`reserved` 제외 — 를 단위 테스트로 완결한다. worktree 발급·base 계산·`_reserve_implementation_stages` 연결은 P3.
6
-
7
- **Architecture:** [run.py:264 `_resolve_effective_stages`](../../../scripts/okstra_ctl/run.py)는 현재 ready 판정에서 `done`만 본다. 여기에 `started_stages`/`reserved_stages`(둘 다 default 빈 set) 파라미터를 더해, ready 집합과 `--stage N` 단일 요청 모두에서 이미 점유된 stage를 제외한다. 점유 출처는 둘 — `consumers.jsonl`의 `started`(관찰)와 registry의 active stage-key 예약(SSOT). registry 조회는 P1의 stage-key 엔트리를 읽는 `list_active_stage_numbers` 헬퍼로 추가한다. 두 함수 모두 순수/조회라 단위 테스트로 끝난다.
8
-
9
- **Tech Stack:** Python 3 (`scripts/okstra_ctl/worktree_registry.py`, `run.py`), pytest.
10
-
11
- 설계 문서: [docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md](../specs/2026-06-06-stage-worktree-isolation-design.md) §2.3, §3.3
12
-
13
- ---
14
-
15
- ## File Structure
16
-
17
- - Modify: `scripts/okstra_ctl/worktree_registry.py`
18
- - `list_active_stage_numbers()` — 신규 (P1의 stage-key 엔트리에서 active stage 번호 집합 조회)
19
- - Modify: `scripts/okstra_ctl/run.py`
20
- - `_resolve_effective_stages()` — `started_stages`/`reserved_stages` 파라미터 추가 ([run.py:233](../../../scripts/okstra_ctl/run.py))
21
- - Test: `tests/test_okstra_worktree_registry.py`, `tests/test_okstra_run_stage_resolution.py` (신규 또는 기존 stage 테스트 파일)
22
-
23
- P3(별도 plan)이 이 둘을 `_reserve_implementation_stages`에서 소비하고 worktree 발급·base 계산을 연결한다. P2는 그 의존만 만든다.
24
-
25
- ---
26
-
27
- ### Task 1: registry `list_active_stage_numbers` 조회 헬퍼
28
-
29
- **Files:**
30
- - Modify: `scripts/okstra_ctl/worktree_registry.py` (신규 함수, `release` 위)
31
- - Test: `tests/test_okstra_worktree_registry.py`
32
-
33
- - [ ] **Step 1: Write the failing test**
34
-
35
- ```python
36
- def test_list_active_stage_numbers_returns_reserved_stages():
37
- from okstra_ctl.worktree_registry import reserve, release, list_active_stage_numbers
38
- # task-key 엔트리는 stage 가 아니므로 제외되어야 한다
39
- reserve(project_id="p", task_group="g", task_id="t",
40
- worktree_path="/wt/t", branch="feat-t", base_ref="main")
41
- reserve(project_id="p", task_group="g", task_id="t", stage_number=2,
42
- worktree_path="/wt/t/stage-2", branch="feat-t-s2", base_ref="b")
43
- reserve(project_id="p", task_group="g", task_id="t", stage_number=3,
44
- worktree_path="/wt/t/stage-3", branch="feat-t-s3", base_ref="b")
45
- assert list_active_stage_numbers("p", "g", "t") == {2, 3}
46
-
47
-
48
- def test_list_active_stage_numbers_excludes_released_and_other_tasks():
49
- from okstra_ctl.worktree_registry import reserve, release, list_active_stage_numbers
50
- reserve(project_id="p", task_group="g", task_id="t", stage_number=2,
51
- worktree_path="/wt/t/stage-2", branch="feat-t-s2", base_ref="b")
52
- # 다른 task 의 stage 는 섞이면 안 된다
53
- reserve(project_id="p", task_group="g", task_id="other", stage_number=2,
54
- worktree_path="/wt/o/stage-2", branch="feat-other-s2", base_ref="b")
55
- assert list_active_stage_numbers("p", "g", "t") == {2}
56
-
57
-
58
- def test_list_active_stage_numbers_empty_when_none():
59
- from okstra_ctl.worktree_registry import list_active_stage_numbers
60
- assert list_active_stage_numbers("p", "g", "nope") == set()
61
- ```
62
-
63
- - [ ] **Step 2: Run test to verify it fails**
64
-
65
- Run: `cd /Volumes/Workspaces/workspace/projects/Okstra && python3 -m pytest tests/test_okstra_worktree_registry.py -k list_active_stage -v`
66
- Expected: FAIL — `cannot import name 'list_active_stage_numbers'`.
67
-
68
- - [ ] **Step 3: Write minimal implementation**
69
-
70
- ```python
71
- # worktree_registry.py — release() 정의 바로 위에 추가
72
- def list_active_stage_numbers(
73
- project_id: str, task_group: str, task_id: str,
74
- ) -> set:
75
- """Return the set of stage numbers with an active stage-key reservation
76
- for this task. Used by the stage resolver to exclude stages a concurrent
77
- run already holds (the occupancy SSOT). Excludes the task-key entry
78
- (stage is None) and released entries."""
79
- prefix = task_key(project_id, task_group, task_id) + "#stage-"
80
- with _registry_lock():
81
- data = _load()
82
- out = set()
83
- for key, row in data["tasks"].items():
84
- if (key.startswith(prefix)
85
- and row.get("status") == "active"
86
- and row.get("stage") is not None):
87
- out.add(row["stage"])
88
- return out
89
- ```
90
-
91
- - [ ] **Step 4: Run test to verify it passes**
92
-
93
- Run: `cd /Volumes/Workspaces/workspace/projects/Okstra && python3 -m pytest tests/test_okstra_worktree_registry.py -v`
94
- Expected: PASS.
95
-
96
- - [ ] **Step 5: Commit**
97
-
98
- ```bash
99
- cd /Volumes/Workspaces/workspace/projects/Okstra
100
- git add scripts/okstra_ctl/worktree_registry.py tests/test_okstra_worktree_registry.py
101
- git commit -m "feat(worktree-registry): list active stage reservations for a task"
102
- ```
103
-
104
- ---
105
-
106
- ### Task 2: `_resolve_effective_stages` started/reserved 제외 (A2)
107
-
108
- **Files:**
109
- - Modify: `scripts/okstra_ctl/run.py:233` (`_resolve_effective_stages`)
110
- - Test: `tests/test_okstra_run_stage_resolution.py` (신규 파일)
111
-
112
- - [ ] **Step 1: Write the failing test**
113
-
114
- ```python
115
- # tests/test_okstra_run_stage_resolution.py (신규)
116
- import sys
117
- from pathlib import Path
118
-
119
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
120
-
121
- import pytest
122
-
123
- from okstra_ctl.run import _resolve_effective_stages, PrepareError
124
-
125
- # stages 는 _parse_stage_map_into_ctx 가 만드는 dict 모양과 동일:
126
- # {"stage_number": int, "depends_on": list[int], "step_count": int}
127
- def _stage(n, deps, steps=3):
128
- return {"stage_number": n, "depends_on": deps, "step_count": steps}
129
-
130
-
131
- def test_auto_raises_when_all_unfinished_stages_occupied():
132
- stages = [_stage(1, []), _stage(2, []), _stage(3, [])]
133
- # stage 1 done, stage 2 started(다른 run), stage 3 reserved(다른 run)
134
- # → 잡을 ready 가 없음. P2 에서는 기존 raise 동작을 유지(호출자 의미 전환은 P3).
135
- with pytest.raises(PrepareError, match="no stage is ready"):
136
- _resolve_effective_stages(
137
- stages, done_stages={1}, requested="auto",
138
- started_stages={2}, reserved_stages={3},
139
- )
140
-
141
-
142
- def test_auto_picks_only_unoccupied_ready_stage():
143
- stages = [_stage(1, []), _stage(2, []), _stage(3, [])]
144
- got = _resolve_effective_stages(
145
- stages, done_stages=set(), requested="auto",
146
- started_stages={1}, reserved_stages=set(),
147
- )
148
- assert got == [2, 3] # 1 은 started 라 제외, 2·3 만 batch
149
-
150
-
151
- def test_numeric_stage_rejected_when_started():
152
- stages = [_stage(2, [])]
153
- with pytest.raises(PrepareError, match="already in progress or reserved"):
154
- _resolve_effective_stages(
155
- stages, done_stages=set(), requested="2",
156
- started_stages={2}, reserved_stages=set(),
157
- )
158
-
159
-
160
- def test_numeric_stage_rejected_when_reserved():
161
- stages = [_stage(2, [])]
162
- with pytest.raises(PrepareError, match="already in progress or reserved"):
163
- _resolve_effective_stages(
164
- stages, done_stages=set(), requested="2",
165
- started_stages=set(), reserved_stages={2},
166
- )
167
-
168
-
169
- def test_defaults_preserve_legacy_behavior():
170
- # started/reserved 미지정 → 기존 동작 (done 만 고려)
171
- stages = [_stage(1, []), _stage(2, [1])]
172
- assert _resolve_effective_stages(stages, done_stages={1}, requested="auto") == [2]
173
- ```
174
-
175
- - [ ] **Step 2: Run test to verify it fails**
176
-
177
- Run: `cd /Volumes/Workspaces/workspace/projects/Okstra && python3 -m pytest tests/test_okstra_run_stage_resolution.py -v`
178
- Expected: FAIL — `_resolve_effective_stages()` got unexpected keyword `started_stages` (그리고 numeric reject 메시지 불일치).
179
-
180
- - [ ] **Step 3: Write minimal implementation**
181
-
182
- ```python
183
- # run.py — _resolve_effective_stages 교체 (시그니처 + 제외 로직)
184
- def _resolve_effective_stages(
185
- stages: list,
186
- done_stages: set,
187
- requested: str,
188
- budget: int = RUN_STEP_BUDGET,
189
- started_stages: set = None,
190
- reserved_stages: set = None,
191
- ) -> list:
192
- """Return the ordered list of stage numbers this run executes.
193
-
194
- `requested` is "auto" or a decimal string. For "auto" the run batches all
195
- ready stages (depends-on all done, itself neither done nor occupied) in
196
- stage-number order up to `budget` effective steps. A numeric request is a
197
- single forced stage. `started_stages`/`reserved_stages` are stages a
198
- concurrent run already holds (consumers.jsonl `started` and the registry
199
- stage reservations); they are excluded so two simultaneous runs never pick
200
- the same stage. Raises PrepareError on rejection cases."""
201
- started_stages = started_stages or set()
202
- reserved_stages = reserved_stages or set()
203
- occupied = done_stages | started_stages | reserved_stages
204
- if requested != "auto":
205
- try:
206
- n = int(requested)
207
- except ValueError:
208
- raise PrepareError(
209
- f"--stage must be 'auto' or an integer, got {requested!r}"
210
- )
211
- target = next((s for s in stages if s["stage_number"] == n), None)
212
- if target is None:
213
- raise PrepareError(
214
- f"--stage {n} not in Stage Map "
215
- f"(have {[s['stage_number'] for s in stages]})"
216
- )
217
- if n in done_stages:
218
- raise PrepareError(
219
- f"--stage {n} already completed (consumers.jsonl status:done exists)"
220
- )
221
- if n in started_stages or n in reserved_stages:
222
- raise PrepareError(
223
- f"--stage {n} already in progress or reserved by another run"
224
- )
225
- return [n]
226
-
227
- ready = [
228
- s for s in stages
229
- if s["stage_number"] not in occupied
230
- and all(d in done_stages for d in s["depends_on"])
231
- ]
232
- if not ready:
233
- raise PrepareError(
234
- "no stage is ready: every remaining stage has unsatisfied depends-on"
235
- )
236
- batch: list = []
237
- total = 0
238
- for s in ready:
239
- sc = s.get("step_count", 0) or 0
240
- if batch and total + sc > budget:
241
- break
242
- batch.append(s["stage_number"])
243
- total += sc
244
- return batch
245
- ```
246
-
247
- > 변경점: 시그니처에 `started_stages`/`reserved_stages`를 더하고, ready 집합 계산과 `--stage N` numeric 경로 양쪽에서 `occupied`(= done ∪ started ∪ reserved)를 제외한다. **`if not ready: raise` 동작은 기존 그대로 유지** — backward compat를 위해 빈-리스트 의미 전환은 호출자(P3)와 함께 한다. P2 단계에서는 occupied로 ready가 비어도 기존과 동일하게 `PrepareError`가 난다(동시 병렬 둘째 run의 "정상 종료" 전환은 P3 호출자 레벨에서 점유 여부를 구분해 처리).
248
-
249
- - [ ] **Step 4: Run test to verify it passes**
250
-
251
- Run: `cd /Volumes/Workspaces/workspace/projects/Okstra && python3 -m pytest tests/test_okstra_run_stage_resolution.py -v`
252
- Expected: PASS (5개).
253
-
254
- - [ ] **Step 5: Run the broader suite for regressions**
255
-
256
- Run: `cd /Volumes/Workspaces/workspace/projects/Okstra && python3 -m pytest tests/ -k "stage or resolve or reserve or multi_stage" -v`
257
- Expected: PASS — occupied 제외는 순수 추가다. 기존 호출자 `_reserve_implementation_stages`는 `started_stages`/`reserved_stages`를 전달하지 않아 default 빈 set으로 동일 동작하고, `if not ready: raise`도 그대로 유지되므로 `test_q7`/multi-stage e2e 회귀가 없어야 한다. 만약 회귀가 나면 **BLOCKED 보고**(임의로 기존 테스트를 고치지 말 것).
258
-
259
- - [ ] **Step 6: Commit**
260
-
261
- ```bash
262
- cd /Volumes/Workspaces/workspace/projects/Okstra
263
- git add scripts/okstra_ctl/run.py tests/test_okstra_run_stage_resolution.py
264
- git commit -m "feat(run): exclude started/reserved stages from resolution (A2)"
265
- ```
266
-
267
- ---
268
-
269
- ## Self-Review
270
-
271
- **Spec coverage (P2 범위):**
272
- - §2.3 ready 집합 = depends-on done **+ started 없음 + registry 미예약** → Task 2 ✓ (점유 = done|started|reserved)
273
- - §2.3 registry 예약이 점유 SSOT → Task 1 `list_active_stage_numbers`가 그 조회면 ✓
274
- - §3.3 `--stage N` 점유 시 거부 → Task 2 numeric reject ✓
275
- - worktree 발급·base 계산·`_reserve_implementation_stages` 연결·CLI → **P3 범위(본 plan 비포함)**
276
-
277
- **Placeholder scan:** 없음 — 모든 step에 실제 코드.
278
-
279
- **Type consistency:** `started_stages`/`reserved_stages`(set), `list_active_stage_numbers`(→ set) 이 Task 1↔2 간 일치. `_resolve_effective_stages` 반환 타입 list 유지.
280
-
281
- **backward compat:** P2는 `_resolve_effective_stages`에 occupied 제외를 더하는 **순수 추가**다. `if not ready: raise`는 기존 그대로 유지하므로, `started_stages`/`reserved_stages`를 전달하지 않는 기존 호출자(`_reserve_implementation_stages`)는 default 빈 set으로 동일하게 동작한다. 동시 병렬 둘째 run의 "정상 종료" 의미 전환과 호출자 연결은 P3.
282
-
283
- ## 검증 (P2 완료 기준)
284
-
285
- ```bash
286
- cd /Volumes/Workspaces/workspace/projects/Okstra
287
- python3 -m pytest tests/test_okstra_worktree_registry.py tests/test_okstra_run_stage_resolution.py -v
288
- python3 -m pytest tests/ -q # 전체 회귀
289
- ```