okstra 0.99.1 → 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,274 @@
1
+ # implementation 커밋·step 입도 완화 Implementation Plan
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:** `implementation` executor 의 test/impl 분리 커밋을 한 커밋으로 병합(A)하고, planning step 의 입도 정의를 격상하며 step 캡을 6→8 로 올린다(B).
6
+
7
+ **Architecture:** okstra 의 phase 동작은 `prompts/profiles/*.md`(LLM 자연어 계약)와 `validators/*.py`(기계 강제)로 나뉜다. 캡의 enforcement SSOT 는 validator 한 곳, 프로파일·문서의 `≤ 8` 문구는 그 미러다. 커밋 정책은 자연어 프로파일에만 존재한다.
8
+
9
+ **Tech Stack:** Python 3 (validator + pytest), Markdown 프로파일/문서, Node 빌드(`npm run build` → `runtime/` 동기화, `npm run check` CI).
10
+
11
+ 설계 출처: [`docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md`](../specs/2026-06-23-implementation-step-commit-granularity-design.md).
12
+
13
+ ## Global Constraints
14
+
15
+ - **최소 변경**: planning 의 `RED:` / `GREEN:` step 토큰, validator S10c/S10d, TDD discipline 자체는 변경 금지.
16
+ - **enforcement SSOT**: step 캡 숫자는 validator 모듈 상수 `HARD_STEP_CAP = 8` 한 곳에만 코드로 정의. 프로파일·문서는 자연어 미러.
17
+ - **pre-1.0**: 호환 셔임 없음. 단 이번 변경은 기존 산출 plan(≤6 step)을 깨지 않음(캡 완화는 단조 확장).
18
+ - **`runtime/` 직접 수정 금지** — build output. 소스(`prompts/`, `validators/`)만 수정.
19
+ - **커밋 메시지**: Conventional Commits, AI 트레일러 금지. 동시 세션 환경이므로 amend 금지 — 항상 새 커밋.
20
+ - **완료 게이트**: 마지막에 `npm run check` exit 0 확인(test:js 실패 시 test:py 안 돎).
21
+
22
+ ---
23
+
24
+ ### Task 1: B — step 캡 상수화 + 경계 검증 (validator)
25
+
26
+ **Files:**
27
+ - Modify: `validators/validate-implementation-plan-stages.py` (상수 추가 + S5 검사)
28
+ - Modify: `tests/contract/test_validate_implementation_plan_stages.py` (8-step 통과 회귀 테스트 추가)
29
+ - Modify: `tests/fixtures/plans/invalid_step_overflow.md` (7-step → 9-step)
30
+
31
+ **Interfaces:**
32
+ - Produces: 모듈 상수 `HARD_STEP_CAP = 8` — Task 2 의 프로파일·문서 `≤ 8` 문구가 이 값을 미러.
33
+ - Consumes: 기존 헬퍼 `_one_stage_plan(slice_line, accept_line, steps, ...)`(steps = `(action, expected)` 리스트, step-count 셀 자동), `_run_validator_path(plan_path)`, `tmp_path` fixture.
34
+
35
+ - [ ] **Step 1: 8-step 통과 회귀 테스트 추가 (먼저 실패하는 테스트)**
36
+
37
+ `tests/contract/test_validate_implementation_plan_stages.py` 의 `test_step_overflow_rejected`(현재 line 80 부근) 바로 아래에 추가:
38
+
39
+ ```python
40
+ def test_eight_steps_allowed(tmp_path):
41
+ """캡 상향(6→8): 8 step 단일 stage 는 S5 를 발화하지 않는다."""
42
+ steps = [("RED: 실패 테스트 작성", "FAIL")] + [
43
+ (f"GREEN: 구현 {i}", "PASS") for i in range(2, 9)
44
+ ] # 총 8 step
45
+ body = _one_stage_plan(
46
+ "Slice value: bar 가 동작한다",
47
+ "Acceptance: pytest -k bar PASS",
48
+ steps,
49
+ )
50
+ plan = tmp_path / "eight_steps.md"
51
+ plan.write_text(body, encoding="utf-8")
52
+ r = _run_validator_path(plan)
53
+ assert r.returncode == 0, r.stderr
54
+ ```
55
+
56
+ - [ ] **Step 2: 새 테스트 실행 → 실패 확인 (RED)**
57
+
58
+ Run: `python3 -m pytest tests/contract/test_validate_implementation_plan_stages.py::test_eight_steps_allowed -v`
59
+ Expected: FAIL — 현재 validator 는 `steps > 6` 이라 8-step 이 S5 로 거부되어 `returncode == 1`.
60
+
61
+ - [ ] **Step 3: validator 에 `HARD_STEP_CAP = 8` 도입 + S5 교체 (GREEN)**
62
+
63
+ `validators/validate-implementation-plan-stages.py` 상수 영역(현재 line 23 `REQUIRED_SUBSECTIONS` 위)에 추가:
64
+
65
+ ```python
66
+ HARD_STEP_CAP = 8
67
+ ```
68
+
69
+ `_check_each_stage_section` 의 S5 블록(현재 line 167-171)을 교체:
70
+
71
+ ```python
72
+ # S5: effective step count
73
+ steps = _count_effective_steps(section)
74
+ if steps > HARD_STEP_CAP:
75
+ errs.append(ValidationError("S5", s.stage_number,
76
+ f"effective step count {steps} exceeds {HARD_STEP_CAP}"))
77
+ ```
78
+
79
+ `_check_slice_tdd` docstring(현재 line 199-210) 중 step 설명이 숫자 `6` 을 언급하면 `8` 로 정합(현재 docstring 에 `6` 직접 언급 없음 — 있으면만 수정).
80
+
81
+ - [ ] **Step 4: 새 테스트 통과 확인 (GREEN)**
82
+
83
+ Run: `python3 -m pytest tests/contract/test_validate_implementation_plan_stages.py::test_eight_steps_allowed -v`
84
+ Expected: PASS
85
+
86
+ - [ ] **Step 5: 기존 overflow fixture 를 9-step 으로 확장**
87
+
88
+ 캡이 8 이 되어 7-step fixture 는 더 이상 S5 를 발화하지 않으므로 `test_step_overflow_rejected` 가 깨진다. `tests/fixtures/plans/invalid_step_overflow.md` 의 Stage Map step-count 셀과 Stepwise 표를 9-step 으로:
89
+
90
+ Stage Map 행(현재 `| 1 | overloaded stage | (none) | 7 | src/foo.ts |`)의 `7` → `9`:
91
+
92
+ ```
93
+ | 1 | overloaded stage | (none) | 9 | src/foo.ts |
94
+ ```
95
+
96
+ Stepwise 표 마지막(현재 `| 7 | step seven | g.ts | cmd | OK |`) 뒤에 2행 추가:
97
+
98
+ ```
99
+ | 8 | step eight | h.ts | cmd | OK |
100
+ | 9 | step nine | i.ts | cmd | OK |
101
+ ```
102
+
103
+ - [ ] **Step 6: 전체 validator 테스트 통과 확인**
104
+
105
+ Run: `python3 -m pytest tests/contract/test_validate_implementation_plan_stages.py -v`
106
+ Expected: PASS (전체). 특히 `test_step_overflow_rejected`(9>8 로 S5 발화)와 `test_eight_steps_allowed` 둘 다 PASS.
107
+
108
+ - [ ] **Step 7: 커밋**
109
+
110
+ ```bash
111
+ git add validators/validate-implementation-plan-stages.py tests/contract/test_validate_implementation_plan_stages.py tests/fixtures/plans/invalid_step_overflow.md
112
+ git commit -m "feat(validate): step 캡 6→8 상향 및 HARD_STEP_CAP 상수화"
113
+ ```
114
+
115
+ ---
116
+
117
+ ### Task 2: B — step 입도 declaration 미러 (프로파일·문서)
118
+
119
+ **Files:**
120
+ - Modify: `prompts/profiles/implementation-planning.md` (line 60, 81, 88, 89, 130)
121
+ - Modify: `docs/kr/architecture.md` (line 341)
122
+ - Modify: `docs/project-structure-overview.md` (line 276)
123
+
124
+ **Interfaces:**
125
+ - Consumes: Task 1 의 `HARD_STEP_CAP = 8` — 아래 문구의 `8` 은 그 값의 자연어 미러.
126
+
127
+ 문서 변경이라 단위 테스트 없음 — 각 변경 후 grep 으로 잔여 구표현이 없는지 확인한다.
128
+
129
+ - [ ] **Step 1: `implementation-planning.md` step 정의·캡 격상**
130
+
131
+ line 81 의 substring 교체:
132
+ - `**Effective row count ≤ 6** (excluding header / divider / blank). Each step is one action completable in 2–5 minutes;`
133
+ → `**Effective row count ≤ 8** (excluding header / divider / blank). Each step is one cohesive, self-contained change (시간 하한 없음; 함께 바뀌는 여러 파일을 포함할 수 있다);`
134
+
135
+ line 60 의 `the per-stage effective step count (≤6)` → `(≤8)`.
136
+
137
+ line 88 의 `(b) effective steps would exceed 6` → `(b) effective steps would exceed 8`.
138
+
139
+ line 89 의 `overrides the ≤6-step merging allowance` → `overrides the ≤8-step merging allowance`.
140
+
141
+ line 130 의 `reject the draft if any stage exceeds 6` → `reject the draft if any stage exceeds 8`.
142
+
143
+ - [ ] **Step 2: 문서 2곳 미러**
144
+
145
+ `docs/kr/architecture.md` line 341 의 `각 stage 의 effective step ≤ 6` → `각 stage 의 effective step ≤ 8`.
146
+
147
+ `docs/project-structure-overview.md` line 276 의 `stage 당 step ≤ 6 등` → `stage 당 step ≤ 8 등`.
148
+
149
+ - [ ] **Step 3: 잔여 구표현 grep 검증**
150
+
151
+ Run:
152
+ ```bash
153
+ grep -rn "≤ *6\|≤6-step\|exceed 6\|exceeds 6\|2.5 min\|2–5 min\|completable in 2" prompts/profiles/implementation-planning.md docs/kr/architecture.md docs/project-structure-overview.md
154
+ ```
155
+ Expected: 출력 없음(exit 1). 남는 게 있으면 해당 줄을 추가 수정.
156
+
157
+ - [ ] **Step 4: 커밋**
158
+
159
+ ```bash
160
+ git add prompts/profiles/implementation-planning.md docs/kr/architecture.md docs/project-structure-overview.md
161
+ git commit -m "docs(planning): step 입도 정의 격상 및 캡 ≤8 미러"
162
+ ```
163
+
164
+ ---
165
+
166
+ ### Task 3: A — executor 커밋 병합 정책
167
+
168
+ **Files:**
169
+ - Modify: `prompts/profiles/_implementation-executor.md` (line 29, 30-31, 74)
170
+ - Modify: `prompts/profiles/_implementation-deliverable.md` (line 14, 20, 38)
171
+
172
+ 문서 변경이라 단위 테스트 없음 — grep 으로 구정책 문구 잔여를 확인한다.
173
+
174
+ - [ ] **Step 1: TDD loop 의 커밋 순서 변경 (`_implementation-executor.md` line 31)**
175
+
176
+ 현재:
177
+ ```
178
+ - Order of operations per plan step: (1) write/extend the test that captures the step's acceptance criterion and confirm it fails for the right reason, (2) commit the failing test (`test(<scope>): ...`), (3) implement the minimum change to make it pass, (4) commit the implementation (`feat|fix(<scope>): ...`), (5) refactor without changing behaviour and commit separately if any cleanup is made (`refactor(<scope>): ...`). The failing-then-passing transition between steps (2) and (4) is the `TDD evidence` required by the final report.
179
+ ```
180
+ 교체:
181
+ ```
182
+ - Order of operations per plan step: (1) write/extend the test that captures the step's acceptance criterion and confirm it fails for the right reason, (2) implement the minimum change to make it pass, (3) commit the test and its implementation together in a single commit (`feat|fix(<scope>): ...`) — do NOT commit the failing test separately, (4) refactor without changing behaviour and commit separately if any cleanup is made (`refactor(<scope>): ...`). The failing-then-passing transition is preserved as `TDD evidence` in the final report (failing output captured before the merged commit, passing output after), not as two separate commits.
183
+ ```
184
+
185
+ - [ ] **Step 2: 커밋 매핑 단위 변경 (`_implementation-executor.md` line 74)**
186
+
187
+ 현재:
188
+ ```
189
+ - One commit MUST correspond to one plan step (or one cohesive sub-step). Do NOT bundle unrelated steps into a single commit, and do NOT split a single step across commits unless the plan explicitly sequenced it that way.
190
+ ```
191
+ 교체:
192
+ ```
193
+ - One commit corresponds to one TDD cycle — a `RED:` step and its `GREEN:` step(s) are merged into a single `feat|fix` commit; an optional `REFACTOR:` step MAY be a separate `refactor` commit. Never split a test and its implementation into separate commits. Do NOT bundle unrelated cycles into a single commit.
194
+ ```
195
+
196
+ - [ ] **Step 3: head-less 문구 정합 (`_implementation-executor.md` line 29)**
197
+
198
+ line 29 의 `RED → GREEN → refactor → per-step commits → ` → `RED → GREEN → refactor → per-cycle commit → `.
199
+
200
+ - [ ] **Step 4: deliverable TDD evidence 문구 (`_implementation-deliverable.md` line 20)**
201
+
202
+ 현재:
203
+ ```
204
+ - **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output BEFORE the implementation commit and the passing-test output AFTER, with commit SHAs framing the transition.
205
+ ```
206
+ 교체:
207
+ ```
208
+ - **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output captured BEFORE the merged commit and the passing-test output after, citing the single `feat|fix` commit SHA (test and implementation share one commit).
209
+ ```
210
+
211
+ - [ ] **Step 5: deliverable Commit list / Plan coverage 정합 (`_implementation-deliverable.md` line 14, 38)**
212
+
213
+ line 14 의 `each commit's SHA (or short SHA), message, and the plan step it satisfies` → `each commit's SHA (or short SHA), message, and the plan step(s) / TDD cycle it satisfies`.
214
+
215
+ line 38 의 Plan coverage 항목 끝에 한 문장 추가: `A RED step and its GREEN step pointing to the same merged commit SHA is NOT a coverage gap — one SHA may be shared by both.`
216
+
217
+ - [ ] **Step 6: 구정책 문구 잔여 grep 검증**
218
+
219
+ Run:
220
+ ```bash
221
+ grep -rn "commit the failing test\|framing the transition\|per-step commits\|One commit MUST correspond to one plan step" prompts/profiles/_implementation-executor.md prompts/profiles/_implementation-deliverable.md
222
+ ```
223
+ Expected: 출력 없음(exit 1).
224
+
225
+ - [ ] **Step 7: 커밋**
226
+
227
+ ```bash
228
+ git add prompts/profiles/_implementation-executor.md prompts/profiles/_implementation-deliverable.md
229
+ git commit -m "feat(executor): test/impl 단일 커밋 병합, refactor 별도 허용"
230
+ ```
231
+
232
+ ---
233
+
234
+ ### Task 4: 마무리 — CHANGES 기록 + CI 게이트
235
+
236
+ **Files:**
237
+ - Modify: `CHANGES.md`
238
+
239
+ - [ ] **Step 1: CHANGES.md 항목 추가**
240
+
241
+ `CHANGES.md` 최상단 항목 형식을 따라(기존 항목 위) 한국어 항목 추가. 핵심 줄:
242
+ ```markdown
243
+ ### implementation 커밋·step 입도 완화
244
+
245
+ - `implementation` executor 가 실패 테스트와 구현을 한 `feat|fix` 커밋으로 병합한다(refactor 는 별도 커밋 허용). 커밋 매핑 단위가 plan step → TDD 사이클로 바뀐다.
246
+ - `implementation-planning` step 정의가 "2–5분 micro-action"에서 "완결적·응집 변경 단위"로 격상되고, stage 당 step 캡이 6 → 8 로 상향된다(`HARD_STEP_CAP`).
247
+ - **사용자 영향:** 다음 release 후 `npx -y okstra@latest install` 1회로 전파. 신규 planning run 부터 step 이 굵어지고 implementation 커밋이 더 적게 묶인다. 기존 산출 plan(≤6 step)은 그대로 통과 — breaking 아님.
248
+ ```
249
+ (기존 `CHANGES.md` 의 실제 헤딩/항목 스타일을 Read 로 확인해 형식을 맞출 것.)
250
+
251
+ - [ ] **Step 2: 빌드 동기화 확인**
252
+
253
+ Run: `npm run build`
254
+ Expected: exit 0. `runtime/` 에 변경된 프로파일·validator 가 동기화됨(커밋하지 않음 — gitignored build output).
255
+
256
+ - [ ] **Step 3: CI 게이트 통과 확인**
257
+
258
+ Run: `npm run check`
259
+ Expected: exit 0. (실패 시 해당 스위트 출력으로 원인 파악 후 수정 — 완료 선언 전 반드시 exit 0.)
260
+
261
+ - [ ] **Step 4: 커밋**
262
+
263
+ ```bash
264
+ git add CHANGES.md
265
+ git commit -m "docs(changes): implementation 커밋·step 입도 완화 항목 추가"
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Self-Review
271
+
272
+ - **Spec coverage:** A(커밋 병합) → Task 3. B(캡 상수화) → Task 1, B(declaration 미러) → Task 2. 테스트 영향(fixture 9-step + 8-step 회귀) → Task 1. CHANGES → Task 4. 비-목표(TDD/토큰/S10 유지)는 Global Constraints 로 고정. 누락 없음.
273
+ - **Placeholder scan:** 모든 코드/문구 변경에 before→after 또는 정확한 코드 블록 제시. `CHANGES.md` 형식만 구현 시 Read 확인으로 위임(헤딩 스타일 보존 목적, 내용은 명시).
274
+ - **Type/identifier consistency:** `HARD_STEP_CAP`(Task 1 정의) ↔ Task 2 의 `≤ 8` 미러 일치. `RED:`/`GREEN:`/`REFACTOR:` 토큰은 변경하지 않음(Global Constraints)으로 Task 3 의 새 커밋 문구와 정합.
@@ -0,0 +1,138 @@
1
+ # implementation stage 다중선택 + 무인 연쇄 설계
2
+
3
+ ## 1. 배경
4
+
5
+ `okstra-run` 으로 `implementation` 작업을 시작하면 wizard 의 `stage_pick` 단계에서 진행할 stage 를 고른다. 현재 이 picker 에는 두 가지 불편이 있다.
6
+
7
+ 1. **stage 진행 상태가 보이지 않는다.** implementation picker 의 각 옵션은 `"{번호}: {제목} [depends-on: … | steps: …]"` 형식뿐이다([wizard.py:1824-1836](../../../scripts/okstra_ctl/wizard.py:1824)). 어느 stage 가 이미 완료(done)됐는지, 다른 run 이 점유(started/reserved)했는지, depends-on 이 충족돼 지금 실행 가능한지(ready)가 화면에 전혀 표시되지 않는다. 점유/완료된 stage 를 고르면 prepare 런타임까지 가서야 `StageTargetError` 로 거부된다 — 사전 표시가 아니라 **사후 거부**다.
8
+
9
+ 2. **한 번에 한 stage 만 고를 수 있다.** `implementation` picker 는 단일선택이라([wizard.py:1837-1842](../../../scripts/okstra_ctl/wizard.py:1837)), 여러 stage 를 순서대로 진행하려면 사용자가 stage 마다 `okstra-run` 을 다시 돌려야 한다.
10
+
11
+ `[done]/[미완]` 상태 마커 인프라([wizard.py:1827-1831](../../../scripts/okstra_ctl/wizard.py:1827))와 `multi=True` 체크박스 picker([`_build_handoff_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1919), [`_submit_handoff_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1947))는 **이미 wizard 안에 검증된 형태로 존재**한다. 전자는 `final-verification` 경로에서만, 후자는 `release-handoff` 경로에서만 켜져 있을 뿐이다. 이 설계는 두 인프라를 `implementation` picker 로 확장하고, 그 위에 현재 세션이 오케스트레이터가 되는 무인 연쇄 루프를 얹는다.
12
+
13
+ ## 2. 목표 / 비목표
14
+
15
+ ### 목표
16
+ - (A) implementation stage picker 에 각 stage 의 진행 상태(완료/진행·예약중/준비됨/대기)를 표시한다.
17
+ - (B) stage 를 체크박스(다중선택)로 고를 수 있게 하고, "전체(남은 미완료 stage 모두)" 옵션을 제공한다.
18
+ - (B) 선택한 stage 들을 의존성 순서로 자동 진행한다 — 현재 `okstra-run` 세션이 오케스트레이터가 되어 stage 를 하나씩 prepare·실행·완료 확인 후 다음으로 넘어가는 **무인 연쇄**.
19
+
20
+ ### 비목표
21
+ - "1 run = 1 stage" 격리 모델을 바꾸지 않는다. stage 별 worktree 격리, registry stage-key 예약, base commit 계산은 그대로 유지된다. 연쇄는 단일-stage run 을 N 회 순차 실행하는 것이지, 한 run 에 여러 stage 를 묶는 것이 아니다.
22
+ - `release-handoff` 의 `--stages`(여러 done stage 를 1 PR 로 묶는 머지)와는 무관하다. 이 설계의 "다중 stage" 는 **실행** 대상이지 머지 대상이 아니다.
23
+ - 비대화형 CLI 진입점(`okstra.sh`, `node bin/okstra`)의 `--stage <auto|N>` 단일-stage 의미는 보존한다. 다중선택은 대화형 wizard picker 에만 추가한다.
24
+
25
+ ## 3. 브레인스토밍 결론 (확정된 결정)
26
+
27
+ | 결정 항목 | 선택 |
28
+ |---|---|
29
+ | 다중 stage 실행 모델 | 순차 자동 디스패치 (각 stage = 독립 run, stage 격리 유지) |
30
+ | stage 경계 사람 게이트 | 완전 무인 연쇄 (done 되면 즉시 다음 stage) |
31
+ | 연쇄 주체 | 현재 `okstra-run` 세션이 오케스트레이터 |
32
+ | 부분 선택 시 미완료 의존성 | 의존 stage 자동 포함 (closure) |
33
+ | 무인 연쇄 중 예외 게이트(동시-run 충돌 / git stale-SHA 재조정) | 연쇄 멈추고 사용자에게 인계 |
34
+ | picker 의 `auto` 옵션 | 대화형 picker 에서 제거 (CLI `--stage auto` 는 유지) |
35
+
36
+ ## 4. 기능 A — stage 진행 상태 표시
37
+
38
+ ### 4.1 동작
39
+ implementation picker 의 각 stage 옵션 뒤에 4-상태 마커를 붙인다.
40
+
41
+ | 마커 | 의미 | 판정 출처 |
42
+ |---|---|---|
43
+ | `[완료]` | done | `consumers.jsonl` status:done |
44
+ | `[진행중]` | 다른 run 점유 | `consumers.jsonl` status:started + registry `list_active_stage_numbers` |
45
+ | `[준비됨]` | depends-on 모두 done | ready 판정 |
46
+ | `[대기]` | depends-on 미충족 | ready 여집합 |
47
+
48
+ 표시 예: `2: 결제 어댑터 [depends-on: 1 | steps: 5] [준비됨]`
49
+
50
+ ### 4.2 변경 지점
51
+ - [`_build_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1812) 가 현재 `is_fv` 일 때만 읽는 done 집합 외에, implementation 경로에서도 **done / started / reserved** 집합을 읽어 상태를 계산한다. 상태 판정은 wizard 가 직접 재구현하지 않고 prepare 측 SSOT 를 재사용한다 — done/started 는 [`read_consumers`](../../../scripts/okstra_ctl/consumers.py) 로, reserved 는 [`worktree_registry.list_active_stage_numbers`](../../../scripts/okstra_ctl/worktree_registry.py:278) 로, ready 는 [`stage_targets.resolve_effective_stages`](../../../scripts/okstra_ctl/stage_targets.py:40) 의 ready 계산식(`all(d in done_stages for d in depends_on)`)을 공유한다.
52
+ - 마커 문자열은 [`prompts/wizard/prompts.ko.json`](../../../prompts/wizard/prompts.ko.json) 의 `stage_pick.options` 에 `[완료]/[진행중]/[준비됨]/[대기]` 4종을 정의한다. 기존 `[done]/[미완]`(final-verification 용)은 그대로 두되, 이 4종과 의미가 겹치지 않게 분리 유지한다.
53
+
54
+ ### 4.3 final-verification 영향
55
+ `final-verification` picker 의 기존 `[done]/[미완]` 표시는 변경하지 않는다. 기능 A 의 4-상태는 `state.task_type == "implementation"` 분기에서만 적용한다.
56
+
57
+ ## 5. 기능 B — 다중선택 체크박스 + 무인 연쇄
58
+
59
+ ### 5.1 picker 다중선택 (B1)
60
+ [`_build_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1812) 의 implementation 분기를 `release-handoff` picker 패턴([wizard.py:1940-1944](../../../scripts/okstra_ctl/wizard.py:1940))과 동일하게 `Prompt(..., multi=True, ...)` 로 만든다.
61
+
62
+ - picker 에서 `auto` 옵션을 **제거**한다([wizard.py:1820-1821](../../../scripts/okstra_ctl/wizard.py:1820) 의 implementation 분기). 기능 A 로 `[준비됨]` 이 보이므로 사용자가 ready stage 를 직접 체크한다.
63
+ - 맨 위에 `전체 (남은 미완료 stage 모두)` 옵션을 추가한다.
64
+ - 이미 `[완료]` 또는 `[진행중]` 인 stage 는 **선택 대상에서 제외**한다(picker 옵션으로 내보내되 선택 시 submit 이 거부, 또는 옵션 자체를 비활성 표기). 선택 가능한 것은 `[준비됨]` 과 `[대기]` 다.
65
+ - 다중선택 입력/직렬화 프로토콜은 손대지 않는다. `Prompt.multi` 필드([wizard.py:436](../../../scripts/okstra_ctl/wizard.py:436))와 SKILL.md 의 `multi:true → AskUserQuestion(multiSelect:true) → CSV join` 규약([SKILL.md:47](../../../skills/okstra-run/SKILL.md:47), [:101](../../../skills/okstra-run/SKILL.md:101))이 이미 존재한다.
66
+
67
+ ### 5.2 선택 정규화 — 의존성 closure + 위상정렬 (B2)
68
+ [`_submit_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1845) 을 CSV 파싱으로 교체한다(현재 단수 정수/`auto`/whole-task 만 허용). 처리 순서:
69
+
70
+ 1. **파싱**: `value.split(",")` 로 선택 집합 수집([`_submit_handoff_stage_pick`](../../../scripts/okstra_ctl/wizard.py:1949) 패턴 재사용). 빈 선택은 `WizardError` 로 재질문.
71
+ 2. **전체 치환**: `전체` 가 포함되면 **선택 가능한 stage 전부**(done/started/reserved 가 아닌, 즉 `[준비됨]`+`[대기]`)로 확장하고 다른 개별 선택과 동시 선택은 거부(handoff 의 `whole_task_exclusive` 패턴). started/reserved 는 다른 run 이 점유 중이므로 `전체` 에 포함하지 않는다.
72
+ 3. **선택 가능성 검증**: 각 선택이 done/started/reserved 가 아닌지 확인. 점유/완료 stage 선택은 거부.
73
+ 4. **의존성 closure**: 선택한 stage 가 의존하는 **미완료** stage 를 선택에 자동 추가한다. (이미 done 인 의존성은 추가 불필요.) 추가된 stage 는 echo 로 사용자에게 알린다("3 이 함께 포함됩니다"). (started/reserved 인 의존성도 미완료라 closure 에 포함될 수 있으나, 그 stage 의 render-bundle 은 점유로 거부되어 SKILL.md Step 7 에서 연쇄가 정상 종료된다.)
74
+ 5. **위상정렬**: closure 집합을 depends-on 그래프의 위상순서로 정렬해 `state.selected_stages`(정렬된 CSV)에 저장한다.
75
+
76
+ closure + 위상정렬은 **순수 의존성 그래프 연산**이므로 [`stage_targets.py`](../../../scripts/okstra_ctl/stage_targets.py)(이미 ready 판정·의존성 충족 계산을 보유한 SSOT)에 새 헬퍼로 둔다. 입력은 `(stage_number, depends_on)` 형태로 추상화해, wizard 의 `StageMeta` 리스트([`_parse_stage_objects`](../../../scripts/okstra_ctl/wizard.py:937))와 run.py 의 dict stage_map([`_parse_stage_map_into_ctx`](../../../scripts/okstra_ctl/run.py:585)) 양쪽이 같은 헬퍼를 쓰게 한다. wizard.py 가 그래프 연산을 자체 구현하지 않게 한다(단일 참조점).
77
+
78
+ `state.selected_stages: str = ""` 필드를 [`WizardState`](../../../scripts/okstra_ctl/wizard.py:367) 에 추가한다. 기존 단수 `selected_stage` 는 비대화형 CLI 경로·final-verification 이 계속 쓰므로 유지한다(둘의 역할이 다르다).
79
+
80
+ ### 5.3 render-args 확장 (B3)
81
+ [`render_args`](../../../scripts/okstra_ctl/wizard.py:3398) 의 implementation 분기가 위상정렬된 `selected_stages` CSV 를 출력하게 한다. 현재 implementation 은 단수 `stage` 만 내보낸다([wizard.py:3412-3413](../../../scripts/okstra_ctl/wizard.py:3412)). handoff 가 쓰는 `stages` 키([wizard.py:3441](../../../scripts/okstra_ctl/wizard.py:3441))와 의미가 다르므로(handoff=머지 대상, implementation=순차 실행 대상), implementation 전용으로 명확히 구분되는 키 이름을 쓴다(예: `chain-stages`). 단일 stage 만 골랐으면 CSV 원소 1개 = 기존 단일 run 과 동일하게 동작한다.
82
+
83
+ ### 5.4 SKILL.md 무인 연쇄 루프 (B4)
84
+ 연쇄 책임은 오케스트레이터 계층인 [`skills/okstra-run/SKILL.md`](../../../skills/okstra-run/SKILL.md) 에만 둔다. wizard.py(입력 1회 수집 → render-args 1세트)·python prepare(render-only, 단일-stage 강제)는 단일 stage 단위를 그대로 유지한다.
85
+
86
+ 현재 흐름은 Step 6([SKILL.md:247-254](../../../skills/okstra-run/SKILL.md:247))에서 lead 인계 후 단일 run 으로 종료된다([SKILL.md:293](../../../skills/okstra-run/SKILL.md:293)). 여기에 연쇄 루프를 추가한다:
87
+
88
+ 1. render-args 의 `chain-stages` CSV(위상정렬됨)를 큐로 받는다.
89
+ 2. 큐의 다음 stage `N` 에 대해 `render-bundle --stage N` 을 호출한다(나머지 render-args 인자는 첫 호출에서 고정; base commit 은 prepare 가 predecessor done commit 으로 자동 계산한다).
90
+ 3. 현재 세션(lead)이 그 bundle 의 Phase 1~7 을 인라인 실행하고, Phase 6 에서 `done` 행을 append 한다([`append_consumer`](../../../scripts/okstra_ctl/consumers.py:53), 프로파일 사이드카 [`_implementation-deliverable.md:50-56`](../../../prompts/profiles/_implementation-deliverable.md:50)).
91
+ 4. 다음 사이클의 prepare 가 직전 stage 의 done(또는 carry 사이드카 backfill, [`backfill_done_from_carry`](../../../scripts/okstra_ctl/consumers.py:160))을 읽어 의존성 게이트를 자동으로 연다.
92
+ 5. 큐가 빌 때까지 2~4 를 반복한다. 매 stage 경계에서 컨텍스트를 정리한다(여러 stage 누적 방지).
93
+
94
+ stage 시작/완료마다 한 줄 진행 보고("stage N/M 시작", "stage N done → 다음 stage K")를 출력한다.
95
+
96
+ ### 5.5 예외 게이트 처리 (B5)
97
+ 매 `render-bundle` 마다 발생할 수 있는 **동시-run 충돌 감지**([SKILL.md:208-223](../../../skills/okstra-run/SKILL.md:208))와 **git stale-SHA 재조정**([SKILL.md:225-245](../../../skills/okstra-run/SKILL.md:225)) 게이트는 사람 판단이 필요하다. 무인 연쇄 중 이 게이트가 뜨면:
98
+
99
+ - 그 stage 에서 **연쇄를 멈추고** 게이트를 사용자에게 그대로 제시한다.
100
+ - 사용자가 게이트를 해소하면 그 자리에서 연쇄를 재개한다(남은 큐를 이어서 처리).
101
+ - 이것이 "완전 무인" 의 안전 경계다 — 데이터 손상·동시 점유 충돌은 사람이 확인한다.
102
+
103
+ ## 6. 변경 지점 요약
104
+
105
+ | # | 파일 | 변경 |
106
+ |---|---|---|
107
+ | A1 | [`scripts/okstra_ctl/wizard.py:1812`](../../../scripts/okstra_ctl/wizard.py:1812) `_build_stage_pick` | implementation 경로에 4-상태 마커 + done/started/reserved 집합 읽기 |
108
+ | A2 | [`prompts/wizard/prompts.ko.json`](../../../prompts/wizard/prompts.ko.json) | `[완료]/[진행중]/[준비됨]/[대기]` 마커 문자열 추가 |
109
+ | B1 | [`scripts/okstra_ctl/wizard.py:1837`](../../../scripts/okstra_ctl/wizard.py:1837) `_build_stage_pick` | `multi=True`, `전체` 옵션, `auto` 제거, 점유/완료 stage 선택 제외 |
110
+ | B2 | [`scripts/okstra_ctl/wizard.py:1845`](../../../scripts/okstra_ctl/wizard.py:1845) `_submit_stage_pick` | CSV 파싱 → closure → 위상정렬 → `state.selected_stages` |
111
+ | B2 | [`scripts/okstra_ctl/wizard.py:367`](../../../scripts/okstra_ctl/wizard.py:367) `WizardState` | `selected_stages: str` 필드 추가 |
112
+ | B2 | [`scripts/okstra_ctl/stage_targets.py`](../../../scripts/okstra_ctl/stage_targets.py) | closure + 위상정렬 순수 헬퍼(SSOT) |
113
+ | B3 | [`scripts/okstra_ctl/wizard.py:3398`](../../../scripts/okstra_ctl/wizard.py:3398) `render_args` | implementation 이 위상정렬 `chain-stages` CSV 출력 |
114
+ | B4 | [`skills/okstra-run/SKILL.md:247`](../../../skills/okstra-run/SKILL.md:247) Step 6 이후 | 무인 연쇄 루프 + 진행 보고 |
115
+ | B5 | [`skills/okstra-run/SKILL.md`](../../../skills/okstra-run/SKILL.md) | 연쇄 중 예외 게이트 → 중단·인계·재개 정책 |
116
+
117
+ `runtime/` 은 빌드 산출물이므로 손대지 않는다. 위 소스 변경 후 `npm run build` 로 동기화한다.
118
+
119
+ ## 7. 아키텍처 일관성
120
+
121
+ - **단일 참조점**: stage 상태/ready/의존성 판정은 prepare 측 SSOT([`stage_targets.py`](../../../scripts/okstra_ctl/stage_targets.py), [`consumers.py`](../../../scripts/okstra_ctl/consumers.py), [`worktree_registry.py`](../../../scripts/okstra_ctl/worktree_registry.py))를 wizard 가 재사용한다. wizard 가 상태 계산이나 의존성 그래프 연산을 자체 구현하지 않는다.
122
+ - **3 진입점 수렴 유지**: 다중선택은 대화형 wizard picker 에만 추가되고, 세 진입점은 여전히 [`prepare_task_bundle`](../../../scripts/okstra_ctl/run.py:1851) 로 수렴한다. 연쇄는 그 위 오케스트레이터(SKILL.md)에서 prepare 를 N 회 호출하는 것이지 prepare 를 우회하지 않는다.
123
+ - **격리 모델 불변**: render-bundle 한 번 = stage 하나 = worktree 하나 = registry 예약 하나. 이 불변식은 그대로다.
124
+ - **pre-1.0**: 호환 shim 없이 implementation picker 의 단일선택 동작을 다중선택으로 교체한다(단일 stage 1개 선택 = 기존 동작 동치).
125
+
126
+ ## 8. 테스트 계획
127
+
128
+ - `tests/wizard/`: `_submit_stage_pick` 다중선택 파싱, `전체` 치환·배타성, 점유/완료 stage 거부, closure 자동 포함, 위상정렬 순서.
129
+ - `tests/wizard/`: `_build_stage_pick` 가 implementation 에서 4-상태 마커를 정확히 부여(각 상태별 픽스처).
130
+ - `stage_targets.py` 헬퍼: closure + 위상정렬 순수 함수 단위 테스트(순환 의존 입력은 검증 단계에서 이미 단조 stage 번호로 차단되지만, 헬퍼 자체의 결정성 확인).
131
+ - e2e(`tests-e2e/`): 2-stage 의존 체인을 다중선택 → 무인 연쇄로 진행해 stage 1 done 후 stage 2 가 자동 prepare 되는지. 무인 연쇄 루프 자체는 SKILL.md(프롬프트)라 의존성 게이트(done→다음 ready 해금)는 prepare 단위 테스트로 커버하고, 연쇄 오케스트레이션은 시나리오 스크립트로 확인.
132
+
133
+ ## 9. 위험 / 주의
134
+
135
+ - **컨텍스트 누적**: 현재 세션이 여러 stage 를 연속 실행하면 컨텍스트가 커진다. stage 경계 컨텍스트 정리(5.4-5)를 명시 지시로 둔다.
136
+ - **done 누락 시 게이트 미해금**: lead 가 Phase 6 의 `done` append 를 빠뜨리면 다음 stage 의 depends-on 이 안 풀린다. carry 사이드카 backfill 이 안전망이지만([`backfill_done_from_carry`](../../../scripts/okstra_ctl/consumers.py:160)), 연쇄 루프는 각 사이클에서 직전 stage 의 done(또는 carry)을 확인한 뒤 다음으로 넘어가야 한다.
137
+ - **의존성이 타 run 점유**: 선택한 `[대기]` stage 의 미완료 의존성이 다른 run 에 started/reserved 상태면 closure 가 그것을 큐에 넣지 못한다(점유 제외). 이 경우 그 대기 stage 는 의존성이 done 될 때까지 실행 불가이며, 무인 연쇄는 "다음 ready stage 없음" 으로 자연 종료하고 남은 큐를 사용자에게 보고한다.
138
+ - **마커 문자열 충돌**: 기능 A 의 `[준비됨]` 등 새 토큰은 final-verification 의 `[done]/[미완]` 과 분리 유지한다. 새 토큰 추가 후 prompts.ko.json 전반을 grep 해 중복·오용이 없는지 확인한다.
@@ -0,0 +1,120 @@
1
+ # implementation 커밋·step 입도 완화 설계
2
+
3
+ ## 1. 배경과 문제
4
+
5
+ `implementation-planning` 이 산출하는 stage 의 step 단위와, `implementation` executor 의 커밋 단위가
6
+ 지나치게 잘게 쪼개진다는 사용자 피드백에서 출발한다.
7
+
8
+ 현행 동작을 코드 기준으로 정리하면:
9
+
10
+ - **step 정의**: [`prompts/profiles/implementation-planning.md:81`](../../../prompts/profiles/implementation-planning.md)
11
+ — `### Stepwise Execution Order` 의 step 은 "one action completable in 2–5 minutes",
12
+ effective row count `≤ 6`.
13
+ - **커밋 정의**: [`prompts/profiles/_implementation-executor.md:30-31`](../../../prompts/profiles/_implementation-executor.md)
14
+ — step 당 TDD 루프가 `(2) commit the failing test (test(...))` → `(4) commit the
15
+ implementation (feat|fix(...))` → `(5) refactor 별도 커밋` 으로 한 step 을 커밋 2~3 개로 분해.
16
+ [`:74`](../../../prompts/profiles/_implementation-executor.md) "One commit MUST correspond to one plan step".
17
+
18
+ 즉 "파일 하나에 커밋 하나" 라는 체감의 실제 원인은 파일 단위 분할이 아니라
19
+ **TDD RED/GREEN 분리 커밋 강제 × 2–5분 micro-step × ≤6 캡** 조합이다.
20
+
21
+ 이를 두 갈래로 완화한다.
22
+
23
+ - **A. 커밋 합치기** — test 커밋과 impl 커밋을 한 커밋으로 병합. refactor 는 별도 커밋 허용.
24
+ - **B. step 입도 상향** — step 정의를 "완결적·응집 변경 단위" 로 격상하고 캡을 `6 → 8` 로 상향.
25
+
26
+ ## 2. 설계 원칙과 범위 결정
27
+
28
+ - **최소 변경 (사용자 결정)**: planning 의 `RED:` / `GREEN:` step 표기와 validator S10c/S10d 는
29
+ **유지**한다. TDD discipline(테스트 먼저) 자체도 유지한다. 바꾸는 것은 executor 의 커밋 병합 정책과
30
+ step 입도 정의/캡뿐이다.
31
+ - **파생 결정 (커밋 매핑 단위)**: planning step 표기를 유지하면 한 stage 안에 `RED:` step 과
32
+ `GREEN:` step 이 별도 행으로 남는다. 따라서 executor 의 커밋 매핑 단위를 "1 커밋 = 1 step" 에서
33
+ **"1 커밋 = 1 TDD 사이클(RED step + 그 GREEN step(들))"** 로 바꿔야 test+impl 이 한 커밋으로 묶인다.
34
+ 이것이 A 의 본체다.
35
+ - **enforcement / declaration 분리**: 캡의 실제 강제 지점(enforcement SSOT)은 validator
36
+ [`validators/validate-implementation-plan-stages.py`](../../../validators/validate-implementation-plan-stages.py) 의
37
+ S5 검사 한 곳이다. 프로파일·문서의 `≤ 8` 문구는 LLM 이 읽는 자연어 declaration 으로,
38
+ validator 상수를 미러링한다. 캡 숫자를 validator 모듈 상수 `HARD_STEP_CAP = 8` 로 추출해
39
+ 코드 측 단일 참조점을 만든다.
40
+ - **YAGNI**: TDD 폐기 ❌, 캡의 "권장/hard" 2단 구조 ❌ (단일 hard cap 8).
41
+ - **pre-1.0 호환성**: 별도 호환 셔임 없음. 단, 이번 변경은 기존 산출 plan 을 깨지 않는다(캡 완화는
42
+ 단조 확장이고, 커밋 정책은 executor 미래 동작에만 영향).
43
+
44
+ ## 3. 변경 상세 (A — 커밋 합치기)
45
+
46
+ ### 3.1 `prompts/profiles/_implementation-executor.md`
47
+
48
+ - **`:30-31` Mandatory TDD loop 의 "Order of operations per plan step"**
49
+ - 현행: (1) 실패 테스트 작성·실패 확인 → (2) `test(<scope>): ...` 실패 커밋 → (3) 최소 구현 →
50
+ (4) `feat|fix(<scope>): ...` 구현 커밋 → (5) refactor 시 `refactor(<scope>): ...` 별도 커밋.
51
+ - 변경: (1) 실패 테스트 작성·실패 확인 → (2) 최소 구현으로 통과 →
52
+ (3) **테스트와 구현을 한 커밋**(`feat|fix(<scope>): ...`)으로 — "실패 테스트 별도 커밋" 단계 제거 →
53
+ (4) behavior-보존 refactor 가 있으면 `refactor(<scope>): ...` 별도 커밋 허용.
54
+ - "The failing-then-passing transition between steps (2) and (4) is the TDD evidence" 문장은
55
+ "실패→통과 전환은 final report 의 evidence 로 기록(병합 커밋 직전 failing 출력 + 직후 passing 출력)" 으로 대체.
56
+ - **`:74` "One commit MUST correspond to one plan step"**
57
+ - 변경: "One commit corresponds to one TDD cycle — the RED step plus its GREEN step(s) are
58
+ merged into a single `feat|fix` commit; an optional REFACTOR step MAY be a separate commit.
59
+ Never split a test and its implementation into separate commits." 다만 "서로 무관한 step 을 한
60
+ 커밋에 묶지 말 것" 제약은 유지.
61
+ - **`:29` head-less 문구**: "RED → GREEN → refactor → per-step commits" → "… → per-cycle commit"
62
+ 으로 정합성만 맞춤.
63
+
64
+ ### 3.2 `prompts/profiles/_implementation-deliverable.md`
65
+
66
+ - **`:20` TDD evidence**: "show the failing-test output BEFORE the implementation commit and the
67
+ passing-test output AFTER, with commit SHAs framing the transition" →
68
+ test/impl 이 한 커밋이라 두 SHA framing 이 불가하므로
69
+ "병합 커밋 직전 캡처한 failing-test 출력과 직후 passing-test 출력을, 단일 `feat|fix` 커밋 SHA 를
70
+ 인용해 제시" 로 변경.
71
+ - **`:14` Commit list**: "the plan step it satisfies" → "the plan step(s)/TDD cycle it satisfies"
72
+ 로 표현만 정합.
73
+ - **`:38` Plan coverage**: "every step ... must point to a commit" 는 유지하되, RED step 과 그
74
+ GREEN step 이 **동일 병합 커밋**을 가리키는 것은 coverage 위반이 아님을 한 줄로 명시(같은 SHA 를
75
+ 두 step 이 공유 가능).
76
+
77
+ ## 4. 변경 상세 (B — step 입도)
78
+
79
+ ### 4.1 캡 상수화 (enforcement SSOT)
80
+
81
+ - [`validators/validate-implementation-plan-stages.py`](../../../validators/validate-implementation-plan-stages.py)
82
+ `:169-171` (S5): 모듈 상단에 `HARD_STEP_CAP = 8` 상수를 도입하고 `if steps > HARD_STEP_CAP:`
83
+ 로 교체, 메시지도 상수를 참조. `_check_slice_tdd` docstring 의 step 설명도 정합.
84
+
85
+ ### 4.2 declaration 미러 (자연어)
86
+
87
+ - [`prompts/profiles/implementation-planning.md`](../../../prompts/profiles/implementation-planning.md):
88
+ - `:81`: `Effective row count ≤ 6` → `≤ 8`; "Each step is one action completable in 2–5 minutes" →
89
+ "Each step is one cohesive, self-contained change (시간 하한 없음; 함께 바뀌는 여러 파일 포함 가능)".
90
+ - `:60`, `:88`, `:89`, `:130`: 본문 중 `6` / `≤6-step` 언급을 `8` / `≤8-step` 으로 미러.
91
+ - [`docs/kr/architecture.md:341`](../../kr/architecture.md): "effective step ≤ 6" → "≤ 8".
92
+ - [`docs/project-structure-overview.md:276`](../../project-structure-overview.md): "step ≤ 6" → "≤ 8".
93
+
94
+ ## 5. 테스트 영향
95
+
96
+ - [`tests/contract/test_validate_implementation_plan_stages.py`](../../../tests/contract/test_validate_implementation_plan_stages.py)
97
+ `test_step_overflow_rejected` 는 fixture
98
+ [`tests/fixtures/plans/invalid_step_overflow.md`](../../../tests/fixtures/plans/invalid_step_overflow.md)
99
+ 의 7-step 으로 S5 를 발화시킨다. 캡이 8 이 되면 7-step 은 통과하므로 fixture 를 **9-step** 으로
100
+ 확장하고 Stage Map 의 `step-count` 셀을 `7 → 9` 로 맞춘다(S7 mismatch 방지, S5 만 깨끗이 발화).
101
+ - `valid_three_stage_parallel.md`(10행, stage 당 분산)·`valid_one_stage.md`(3행) 는 stage 당 step 이
102
+ 8 이하라 수정 불필요.
103
+ - A 변경(커밋 정책)은 프롬프트 자연어라 직접 강제하는 단위 테스트가 없다. deliverable evidence 문구
104
+ 변경도 검증기 토큰 대상이 아니다 — grep 으로 잔여 "framing the transition" / "commit the failing"
105
+ 문구가 남지 않았는지만 확인.
106
+
107
+ ## 6. 사용자 영향 (CHANGES.md)
108
+
109
+ [`CHANGES.md`](../../../CHANGES.md) 에 항목 추가, `사용자 영향:` 줄 포함:
110
+
111
+ - 다음 release 후 `npx -y okstra@latest install` 1회로 전파.
112
+ - 신규 `implementation-planning` run 부터 step 이 굵어지고 stage 당 step 수가 줄며,
113
+ `implementation` run 의 커밋이 "기능 1커밋 + (선택) refactor 1커밋" 으로 묶인다.
114
+ - breaking 아님 — 기존 산출 plan(≤6 step)은 그대로 통과하고, 캡 완화는 단조 확장.
115
+
116
+ ## 7. 비-목표
117
+
118
+ - TDD 폐기 — 테스트 먼저 규율, planning 의 `RED:`/`GREEN:` 토큰, S10c/S10d 는 유지.
119
+ - 캡의 "권장/hard" 2단 구조 — 단일 hard cap 8 만 둔다.
120
+ - planning step 모델을 "RED/GREEN 통합 단일 step" 으로 재설계 — 사용자 결정에 따라 최소 변경 유지.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.99.1",
3
+ "version": "0.100.0",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.99.1",
3
- "builtAt": "2026-06-22T19:24:09.094Z",
2
+ "package": "0.100.0",
3
+ "builtAt": "2026-06-23T07:02:11.224Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -11,13 +11,13 @@ are collected and convergence finished. Phase 1-5 do not need it.
11
11
  ## Required deliverable shape (final report, in addition to the standard sections)
12
12
 
13
13
  - **Plan link & approval evidence**: path to the approved `final-report.md`, the exact quoted approval marker, AND the executed stage number / title quoted from the Stage Map row.
14
- - **Commit list**: each commit's SHA (or short SHA), message, and the plan step it satisfies
14
+ - **Commit list**: each commit's SHA (or short SHA), message, and the plan step(s) / TDD cycle it satisfies
15
15
  - **Diff summary**: `git diff --stat <base>..HEAD` output, plus a per-file one-line summary of changes
16
16
  - **Out-of-plan edits block**: every file edited that was not in the approved plan's file list, with rationale (empty block is acceptable and preferred)
17
17
  - **Clarification answers carried in**: when `instruction-set/clarification-response.md` exists, it holds the user's answers to the approved plan's `## 1. Clarification Items` rows. The report MUST render the `## 0. Clarification Response Carried In From Previous Run` section (set `clarificationCarryIn.sourceFile` to that path) and, for every carried-over `## 1.` row whose answer appears there, record the answer in the `User input` cell and flip `Status` to `resolved`. A row left `open`/`answered` despite a matching user answer is a contract violation; an answer that materially changes scope beyond the approved plan is routed to a new `implementation-planning` run, not silently executed.
18
18
  - **Stage sidecar evidence**: the JSON payload of `runs/<impl-task-key>/carry/stage-<N>.json` is embedded verbatim in a fenced ```json``` block, AND the `consumers.jsonl` rows this run appended are quoted line-by-line, so reviewers can audit the carry surface without grepping artifact directories.
19
19
  - **Validation evidence**: actual command output (stdout/stderr) for every `pre / mid / post` validation command from the plan. Truncated output is acceptable but the command line and exit code MUST be exact. No paraphrasing of test results.
20
- - **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output BEFORE the implementation commit and the passing-test output AFTER, with commit SHAs framing the transition.
20
+ - **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output captured BEFORE the merged commit and the passing-test output after, citing the single `feat|fix` commit SHA (test and implementation share one commit).
21
21
  - **Verifier results**: a section per verifier present in the resolved roster (`Claude verifier`, `Codex verifier`, and `Antigravity verifier` when opted in) containing:
22
22
  - their independent verdict (PASS / CONCERNS / FAIL),
23
23
  - cited diff snippets supporting the verdict,
@@ -35,7 +35,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
35
35
 
36
36
  ## Self-review pass before finalising the report (`Claude lead` runs this; do not delegate to a generic subagent)
37
37
 
38
- 1. **Plan coverage** — every step in the approved plan's recommended option must point to a commit (or an explicit `Skipped: <reason>` entry). List gaps.
38
+ 1. **Plan coverage** — every step in the approved plan's recommended option must point to a commit (or an explicit `Skipped: <reason>` entry). List gaps. A `RED:` step and its `GREEN:` step pointing to the same merged commit SHA is NOT a coverage gap — one SHA may be shared by both.
39
39
  2. **Evidence completeness** — every `Validation evidence` and `TDD evidence` claim has the actual command line and exit code? No paraphrased "tests pass" without output?
40
40
  3. **Out-of-plan honesty** — files in the diff that are NOT in the plan list must appear in the `Out-of-plan edits` block. Cross-check with `git diff --name-only`.
41
41
  4. **Verifier dissent preserved** — if the verifiers in the resolved roster disagree, the disagreement is visible in the report? Synthesis hides nothing?
@@ -26,9 +26,9 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
26
26
  - **Claude executor:** Read `_implementation-self-check.md` end-to-end before appending the `status:"done"` row, then write one confirming line per item to your audit sidecar.
27
27
  - **CLI executor (codex / antigravity):** the CLI process cannot Read this path (outside its sandbox). The lead appends this file's body into the persisted executor prompt at dispatch time, immediately after the preflight body (see `codex_dispatch.py` `_implementation_executor_tail`). The head-less executor honours both gates from the single prompt.
28
28
  - **Stage discipline transcription (when a preceding stage is `done`):** the lead MUST transcribe the `Stage discipline` rule (from this run's rendered profile — the INCLUDEd `_stage-discipline.md` body) verbatim into the dispatched CLI executor prompt, so a codex/antigravity executor honors the prior-stage behavior-freeze. Declaration-level — no wrapper sentinel.
29
- - **Non-interactive auto-execution (BLOCKING when the executor provider is `codex` or `antigravity`).** A CLI executor runs head-less (`codex exec` / antigravity equivalent) — there is no human at the keyboard. Skills loaded during the run (tdd, coding-preflight, and others) contain "get user approval", "state your plan to the user and wait", or "ask before proceeding" gates written for interactive sessions; in this run those gates are **already satisfied** by the upstream `implementation-planning` approval (the plan this stage executes was human-approved). The executor MUST NOT stop to request approval, MUST NOT end its turn after only producing a plan, and MUST carry the stage through end-to-end — RED → GREEN → refactor → per-step commits → `### Stage Carry Evidence`. The ONLY skill step to skip is the interactive user-approval prompt itself; every other skill rule (TDD discipline, conventions, real-IO isolation) still binds. The lead MUST transcribe this bullet verbatim into the dispatched CLI executor prompt (same reason as the preflight transcription rule above — the CLI process does not share lead context). Stopping early for approval in a head-less run is the observed empty-exit failure (exit 0, no diff): treat it as `contract-violated`.
29
+ - **Non-interactive auto-execution (BLOCKING when the executor provider is `codex` or `antigravity`).** A CLI executor runs head-less (`codex exec` / antigravity equivalent) — there is no human at the keyboard. Skills loaded during the run (tdd, coding-preflight, and others) contain "get user approval", "state your plan to the user and wait", or "ask before proceeding" gates written for interactive sessions; in this run those gates are **already satisfied** by the upstream `implementation-planning` approval (the plan this stage executes was human-approved). The executor MUST NOT stop to request approval, MUST NOT end its turn after only producing a plan, and MUST carry the stage through end-to-end — RED → GREEN → refactor → per-cycle commit → `### Stage Carry Evidence`. The ONLY skill step to skip is the interactive user-approval prompt itself; every other skill rule (TDD discipline, conventions, real-IO isolation) still binds. The lead MUST transcribe this bullet verbatim into the dispatched CLI executor prompt (same reason as the preflight transcription rule above — the CLI process does not share lead context). Stopping early for approval in a head-less run is the observed empty-exit failure (exit 0, no diff): treat it as `contract-violated`.
30
30
  - **Mandatory TDD loop**: BEFORE the first `Edit` or `Write` call, the executor MUST apply a red-green-refactor loop for every code change in this run. This is required; skipping it is a `contract-violated` outcome. This governs HOW each step is executed (failing test first → minimal implementation → refactor); it does not override the approved plan's WHAT/file scope.
31
- - Order of operations per plan step: (1) write/extend the test that captures the step's acceptance criterion and confirm it fails for the right reason, (2) commit the failing test (`test(<scope>): ...`), (3) implement the minimum change to make it pass, (4) commit the implementation (`feat|fix(<scope>): ...`), (5) refactor without changing behaviour and commit separately if any cleanup is made (`refactor(<scope>): ...`). The failing-then-passing transition between steps (2) and (4) is the `TDD evidence` required by the final report.
31
+ - Order of operations per plan step: (1) write/extend the test that captures the step's acceptance criterion and confirm it fails for the right reason, (2) implement the minimum change to make it pass, (3) commit the test and its implementation together in a single commit (`feat|fix(<scope>): ...`) — do NOT commit the failing test separately, (4) refactor without changing behaviour and commit separately if any cleanup is made (`refactor(<scope>): ...`). The failing-then-passing transition is preserved as `TDD evidence` in the final report (failing output captured before the merged commit, passing output after), not as two separate commits.
32
32
  - Doc-only / config-only / pure-rename steps that have no observable runtime behaviour are exempt from the failing-test requirement, but the executor MUST cite the exemption per step in the final report (`TDD exemption: <reason>`).
33
33
  - When the touched area has no existing test harness, the executor MUST stand up the minimum harness needed to host one regression test for this run rather than skipping TDD entirely. Record the harness-bootstrap step as an `Out-of-plan edit` if it is not in the plan.
34
34
  - **DB / IO / SQL changes require real execution — mock-only is NOT validation evidence:** when this run's diff touches DB/IO/SQL (ORM / query-builder code — sequelize / typeorm / prisma / knex / raw SQL — `*.repository.*`, model/entity files, `migrations/**`, `*.sql`, or any changed query string), a mocked unit test cannot observe the SQL the query builder actually emits — a mocked suite once passed while `count({ col: 'FontFamily.fontFamily' })` threw `Unknown column` on the real DB. The executor MUST run the change against a real (or faithful-replica) datastore — the `db-test` validation step (plan `validation` db step, else `project.json.qaCommands.db-test`), targeting a **local / replica** DB — and cite its exact command + exit code in the final report's `Validation evidence`. If no real DB / `db-test` command is reachable, do NOT claim the change verified: label the DB portion `정적 분석상 …, 미검증(실행 안 함)` in the report, surface it in the routing recommendation, and never downplay the real run as "too heavy". `git push` stays forbidden (universal list); the unverified DB state is carried forward so `final-verification` cannot accept it and `release-handoff` cannot push.
@@ -71,5 +71,5 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
71
71
  - Body (when present) explains *why*, not *what*; wrap at ~100 chars.
72
72
  - Do NOT append okstra artefact paths to the commit message — no `Plan: .okstra/...`, no `Report: ...`, no `Run: ...`, no `Task: ...` footers, and no other reference to files under `.okstra/`. Those paths belong in the final report's `Plan link & approval evidence` section, not in git history; they rot quickly and leak internal layout into the upstream changelog.
73
73
  - Allowed footers are limited to standard Conventional Commits trailers (`BREAKING CHANGE: ...`, `Refs: <issue/ticket-id>`, `Closes #<n>`). When citing a ticket, use the ticket id only (e.g. `Refs: DEV-9423`) — never a filesystem path.
74
- - One commit MUST correspond to one plan step (or one cohesive sub-step). Do NOT bundle unrelated steps into a single commit, and do NOT split a single step across commits unless the plan explicitly sequenced it that way.
74
+ - One commit corresponds to one TDD cycle a `RED:` step and its `GREEN:` step(s) are merged into a single `feat|fix` commit; an optional `REFACTOR:` step MAY be a separate `refactor` commit. Never split a test and its implementation into separate commits. Do NOT bundle unrelated cycles into a single commit.
75
75
  - The exact message used for each commit MUST be reproduced verbatim in the final report's `Commit list` so reviewers can audit it without re-running `git log`.