okstra 0.102.2 → 0.102.3

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 (161) hide show
  1. package/README.kr.md +5 -5
  2. package/README.md +5 -5
  3. package/docs/kr/architecture/storage-model.md +1 -1
  4. package/docs/kr/architecture.md +7 -11
  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/okstra-antigravity-exec.sh +1 -2
  12. package/runtime/bin/okstra-codex-exec.sh +1 -2
  13. package/runtime/bin/okstra-render-final-report.py +2 -9
  14. package/runtime/bin/okstra-spawn-followups.py +4 -6
  15. package/runtime/bin/okstra-trace-cleanup.sh +24 -4
  16. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  17. package/runtime/prompts/lead/report-writer.md +1 -1
  18. package/runtime/prompts/profiles/_common-contract.md +9 -11
  19. package/runtime/python/okstra_ctl/codex_dispatch.py +4 -12
  20. package/runtime/python/okstra_ctl/consumers.py +35 -0
  21. package/runtime/python/okstra_ctl/container.py +4 -6
  22. package/runtime/python/okstra_ctl/dispatch_core.py +4 -12
  23. package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
  24. package/runtime/python/okstra_ctl/handoff.py +2 -1
  25. package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
  26. package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
  27. package/runtime/python/okstra_ctl/report_views.py +7 -4
  28. package/runtime/python/okstra_ctl/run.py +3 -10
  29. package/runtime/python/okstra_ctl/stage_targets.py +18 -0
  30. package/runtime/python/okstra_ctl/wizard.py +24 -25
  31. package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
  32. package/runtime/python/okstra_token_usage/report.py +2 -5
  33. package/runtime/validators/validate-report-views.py +2 -1
  34. package/runtime/validators/validate-run.py +1 -11
  35. package/src/commands/lifecycle/install.mjs +5 -5
  36. package/src/commands/lifecycle/uninstall.mjs +4 -4
  37. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
  38. package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
  39. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
  40. package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
  41. package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
  42. package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
  43. package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
  44. package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
  45. package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
  46. package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
  47. package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
  48. package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
  49. package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
  50. package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
  51. package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
  52. package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
  53. package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
  54. package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
  55. package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
  56. package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
  57. package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
  58. package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
  59. package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
  60. package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
  61. package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
  62. package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
  63. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
  64. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
  65. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
  66. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
  67. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
  68. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
  69. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
  70. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
  71. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
  72. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
  73. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
  74. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
  75. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
  76. package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
  77. package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
  78. package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
  79. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
  80. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
  81. package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
  82. package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
  83. package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
  84. package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
  85. package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
  86. package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
  87. package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
  88. package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
  89. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
  90. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
  91. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
  92. package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
  93. package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
  94. package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
  95. package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
  96. package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
  97. package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
  98. package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
  99. package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
  100. package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
  101. package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
  102. package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
  103. package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
  104. package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
  105. package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
  106. package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
  107. package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
  108. package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
  109. package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
  110. package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
  111. package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
  112. package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
  113. package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
  114. package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
  115. package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
  116. package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
  117. package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
  118. package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
  119. package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
  120. package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
  121. package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
  122. package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
  123. package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
  124. package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
  125. package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
  126. package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
  127. package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
  128. package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
  129. package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
  130. package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
  131. package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
  132. package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
  133. package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
  134. package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
  135. package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
  136. package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
  137. package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
  138. package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
  139. package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
  140. package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
  141. package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
  142. package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
  143. package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
  144. package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
  145. package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
  146. package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
  147. package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
  148. package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
  149. package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
  150. package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
  151. package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
  152. package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
  153. package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
  154. package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
  155. package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
  156. package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
  157. package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
  158. package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
  159. package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
  160. package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
  161. 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
- ```