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