okstra 0.38.1 → 0.40.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.
Files changed (80) hide show
  1. package/README.kr.md +1 -1
  2. package/README.md +1 -1
  3. package/docs/kr/architecture.md +18 -2
  4. package/docs/kr/cli.md +1 -1
  5. package/docs/project-structure-overview.md +2 -3
  6. package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +326 -0
  7. package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +337 -0
  8. package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +410 -0
  9. package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +728 -0
  10. package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +113 -0
  11. package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +173 -0
  12. package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +154 -0
  13. package/docs/task-process/requirements-discovery.md +1 -1
  14. package/package.json +3 -2
  15. package/runtime/BUILD.json +2 -2
  16. package/runtime/{python → bin}/lib/okstra/usage.sh +3 -2
  17. package/runtime/bin/okstra-codex-exec.sh +3 -3
  18. package/runtime/bin/okstra-trace-cleanup.sh +64 -26
  19. package/runtime/prompts/profiles/_common-contract.md +9 -5
  20. package/runtime/prompts/profiles/final-verification.md +18 -16
  21. package/runtime/prompts/profiles/implementation-planning.md +1 -0
  22. package/runtime/prompts/profiles/requirements-discovery.md +18 -1
  23. package/runtime/prompts/wizard/prompts.ko.json +11 -0
  24. package/runtime/python/okstra_ctl/consumers.py +1 -1
  25. package/runtime/python/okstra_ctl/fanout.py +35 -0
  26. package/runtime/python/okstra_ctl/migrate.py +21 -42
  27. package/runtime/python/okstra_ctl/reconcile.py +2 -2
  28. package/runtime/python/okstra_ctl/render_final_report.py +0 -1
  29. package/runtime/python/okstra_ctl/run.py +0 -29
  30. package/runtime/python/okstra_ctl/run_context.py +9 -12
  31. package/runtime/python/okstra_ctl/seeding.py +0 -192
  32. package/runtime/python/okstra_ctl/wizard.py +70 -5
  33. package/runtime/python/okstra_ctl/work_categories.py +21 -0
  34. package/runtime/python/okstra_ctl/worktree.py +74 -77
  35. package/runtime/python/okstra_project/__init__.py +0 -6
  36. package/runtime/python/okstra_project/dirs.py +0 -8
  37. package/runtime/schemas/final-report-v1.0.schema.json +34 -27
  38. package/runtime/skills/okstra-context-loader/SKILL.md +1 -1
  39. package/runtime/skills/okstra-convergence/SKILL.md +1 -1
  40. package/runtime/skills/okstra-inspect/SKILL.md +1 -1
  41. package/runtime/skills/okstra-run/SKILL.md +2 -0
  42. package/runtime/templates/prd/brief.template.md +1 -1
  43. package/runtime/templates/reports/fan-out-unit.template.md +25 -0
  44. package/runtime/templates/reports/final-report.template.md +24 -13
  45. package/runtime/templates/reports/final-verification-input.template.md +16 -5
  46. package/runtime/templates/reports/i18n/en.json +6 -3
  47. package/runtime/templates/reports/i18n/ko.json +6 -3
  48. package/runtime/templates/worker-prompt-preamble.md +7 -0
  49. package/runtime/validators/lib/fixtures.sh +2 -2
  50. package/runtime/validators/lib/validate-assets.sh +9 -0
  51. package/runtime/validators/validate-implementation-plan-stages.py +19 -11
  52. package/runtime/validators/validate-run.py +114 -0
  53. package/runtime/validators/validate-schedule.py +4 -4
  54. package/runtime/validators/validate_fanout.py +99 -0
  55. package/src/_proc.mjs +31 -0
  56. package/src/check-project.mjs +1 -25
  57. package/src/config.mjs +7 -31
  58. package/src/doctor.mjs +10 -29
  59. package/src/install.mjs +8 -36
  60. package/src/migrate.mjs +1 -18
  61. package/src/okstra-dirs.mjs +0 -11
  62. package/src/setup.mjs +1 -154
  63. package/src/uninstall.mjs +6 -13
  64. package/runtime/templates/okstra.CLAUDE.md +0 -104
  65. /package/runtime/{python → bin}/lib/okstra/cli.sh +0 -0
  66. /package/runtime/{python → bin}/lib/okstra/globals.sh +0 -0
  67. /package/runtime/{python → bin}/lib/okstra/interactive.sh +0 -0
  68. /package/runtime/{python → bin}/lib/okstra/project-resolver.sh +0 -0
  69. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-batch.sh +0 -0
  70. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-list.sh +0 -0
  71. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-open.sh +0 -0
  72. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-projects.sh +0 -0
  73. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-reconcile.sh +0 -0
  74. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-reindex.sh +0 -0
  75. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-rerun.sh +0 -0
  76. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-show.sh +0 -0
  77. /package/runtime/{python → bin}/lib/okstra-ctl/cmd-tail.sh +0 -0
  78. /package/runtime/{python → bin}/lib/okstra-ctl/main.sh +0 -0
  79. /package/runtime/{python → bin}/lib/okstra-ctl/prepare.sh +0 -0
  80. /package/runtime/{python → bin}/lib/okstra-ctl/usage.sh +0 -0
@@ -0,0 +1,410 @@
1
+ # okstra-run phase 전환 시 tmux pane 정리 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:** okstra-run 에서 새 내부 phase 가 시작될 때 이전 phase 의 okstra pane(worker-agent + trace)을 자동으로 닫아 좀비 pane 누적을 없앤다.
6
+
7
+ **Architecture:** `okstra-trace-cleanup.sh` 의 pane 식별을 "registry trace pane ∪ title-allowlist worker-agent pane (lead pane 제외)" 합집합으로 통일한다. lead 는 `_common-contract.md` 규약에 따라 phase 전환 직전 이 스크립트를 무인자(kill) 모드로 호출한다. 최종 run 종료 prompt 와 SessionEnd 훅은 같은 스크립트를 공유한다.
8
+
9
+ **Tech Stack:** Bash (tmux), Python pytest (실 tmux 서버 기반 단위 테스트), okstra 빌드 파이프라인(`npm run build`).
10
+
11
+ 설계 근거: [docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md](../specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md)
12
+
13
+ ---
14
+
15
+ ## File Structure
16
+
17
+ - Modify: `scripts/okstra-trace-cleanup.sh` — pane 식별을 통합 합집합으로 확장. 단일 참조점(SessionEnd 훅 / phase 자동정리 / 최종 prompt 공용).
18
+ - Modify: `tests/test_okstra_trace_cleanup.py` — title-allowlist kill / lead·비-okstra pane 보존 회귀 가드 추가.
19
+ - Modify: `prompts/profiles/_common-contract.md` — phase-start 자동정리 규약 추가 + 최종 prompt 대상 통합.
20
+ - Modify: `docs/kr/architecture.md` — Live-log mirror 절에 phase-start 정리 + worker-agent pane 식별 명시.
21
+ - Modify: `CHANGES.md` — 사용자 영향 엔트리.
22
+
23
+ `runtime/` 는 빌드 출력이므로 직접 수정 금지 — 위 source 수정 후 `npm run build` 로 동기화.
24
+
25
+ ---
26
+
27
+ ## Task 1: `okstra-trace-cleanup.sh` 를 worker-agent pane 까지 정리하도록 확장
28
+
29
+ **Files:**
30
+ - Modify: `scripts/okstra-trace-cleanup.sh` (전체 본문 재작성)
31
+ - Test: `tests/test_okstra_trace_cleanup.py`
32
+
33
+ - [ ] **Step 1: 실패하는 테스트 추가**
34
+
35
+ `tests/test_okstra_trace_cleanup.py` 의 맨 끝(파일 마지막 줄 `assert other_file.exists(), ...` 다음)에 아래 헬퍼와 4개 테스트를 추가한다.
36
+
37
+ ```python
38
+ def _split_pane_titled(session: str, title: str) -> str:
39
+ """split 으로 pane 을 만들고 지정한 title 을 셋팅한 뒤 pane id 반환."""
40
+ pid = _split_pane(session)
41
+ res = _tmux("select-pane", "-t", pid, "-T", title)
42
+ assert res.returncode == 0, res.stderr
43
+ return pid
44
+
45
+
46
+ def test_kills_worker_agent_panes_by_title(
47
+ tmp_path: Path, session_name: str
48
+ ) -> None:
49
+ """registry 없이도 worker-agent pane 은 title allowlist 로 식별돼 죽는다."""
50
+ lead_pane = _new_detached_session(session_name)
51
+ agent_claude = _split_pane_titled(session_name, "✳ claude-worker")
52
+ agent_codex = _split_pane_titled(session_name, "codex-worker")
53
+ agent_report = _split_pane_titled(session_name, "report-writer-worker")
54
+
55
+ result = _run_cleanup({
56
+ "TMPDIR": str(tmp_path), # registry 디렉터리 없음
57
+ "TMUX_PANE": lead_pane,
58
+ })
59
+ assert result.returncode == 0, result.stderr
60
+
61
+ remaining = set(_list_pane_ids(session_name))
62
+ assert lead_pane in remaining, "lead pane 은 보존되어야 한다"
63
+ assert agent_claude not in remaining
64
+ assert agent_codex not in remaining
65
+ assert agent_report not in remaining
66
+
67
+
68
+ def test_preserves_non_okstra_panes(
69
+ tmp_path: Path, session_name: str
70
+ ) -> None:
71
+ """allowlist 외 title pane(사용자 메인/개발 pane)은 절대 죽이지 않는다."""
72
+ lead_pane = _new_detached_session(session_name)
73
+ user_dev = _split_pane_titled(session_name, "가격 계산 기능 개발")
74
+ editor = _split_pane_titled(session_name, "vim")
75
+ agent_codex = _split_pane_titled(session_name, "codex-worker")
76
+
77
+ result = _run_cleanup({
78
+ "TMPDIR": str(tmp_path),
79
+ "TMUX_PANE": lead_pane,
80
+ })
81
+ assert result.returncode == 0, result.stderr
82
+
83
+ remaining = set(_list_pane_ids(session_name))
84
+ assert user_dev in remaining, "사용자 dev pane 은 보존"
85
+ assert editor in remaining, "무관한 pane 은 보존"
86
+ assert agent_codex not in remaining, "okstra agent pane 만 죽는다"
87
+
88
+
89
+ def test_excludes_lead_pane_even_if_title_matches(
90
+ tmp_path: Path, session_name: str
91
+ ) -> None:
92
+ """lead 자신의 pane 은 title 이 allowlist 에 걸려도 죽이지 않는다 (불변)."""
93
+ lead_pane = _new_detached_session(session_name)
94
+ _tmux("select-pane", "-t", lead_pane, "-T", "claude-worker")
95
+ sibling = _split_pane_titled(session_name, "codex-worker")
96
+
97
+ result = _run_cleanup({
98
+ "TMPDIR": str(tmp_path),
99
+ "TMUX_PANE": lead_pane,
100
+ })
101
+ assert result.returncode == 0, result.stderr
102
+
103
+ remaining = set(_list_pane_ids(session_name))
104
+ assert lead_pane in remaining, "lead pane 은 title 매칭돼도 보존"
105
+ assert sibling not in remaining
106
+
107
+
108
+ def test_list_includes_agent_and_trace(
109
+ tmp_path: Path, session_name: str
110
+ ) -> None:
111
+ """--list 는 registry trace pane + title-match agent pane 을 합쳐 출력."""
112
+ lead_pane = _new_detached_session(session_name)
113
+ trace = _split_pane_titled(session_name, "codex-worker-93421-trace")
114
+ agent = _split_pane_titled(session_name, "report-writer-worker")
115
+
116
+ safe = "".join(c if c.isalnum() else "_" for c in lead_pane)
117
+ registry_dir = tmp_path / "okstra-trace-panes"
118
+ registry_dir.mkdir()
119
+ (registry_dir / f"{safe}.list").write_text(f"{trace}\n")
120
+
121
+ result = _run_cleanup_with_mode(tmp_path, lead_pane, "--list")
122
+ assert result.returncode == 0, result.stderr
123
+ lines = [line for line in result.stdout.splitlines() if line]
124
+ ids = {line.split("\t", 1)[0] for line in lines}
125
+ assert trace in ids
126
+ assert agent in ids
127
+ assert lead_pane not in ids
128
+
129
+ # --list 는 죽이지 않는다.
130
+ remaining = set(_list_pane_ids(session_name))
131
+ assert {trace, agent}.issubset(remaining)
132
+ ```
133
+
134
+ - [ ] **Step 2: 테스트 실행해서 실패 확인**
135
+
136
+ Run: `python3 -m pytest tests/test_okstra_trace_cleanup.py -v`
137
+ Expected: 새 4개 테스트 FAIL — 현재 스크립트는 title-match 를 모르고, registry 가 없으면 조기 종료(`test_kills_worker_agent_panes_by_title` 가 agent pane 을 못 죽임). 기존 테스트는 PASS.
138
+
139
+ - [ ] **Step 3: 스크립트 전체 재작성**
140
+
141
+ `scripts/okstra-trace-cleanup.sh` 의 **전체 내용**을 아래로 교체한다.
142
+
143
+ ```bash
144
+ #!/usr/bin/env bash
145
+ #
146
+ # okstra-trace-cleanup.sh — manage tmux panes created during an okstra run for
147
+ # the current Claude Code (lead) session.
148
+ #
149
+ # Two pane sources are cleaned for the lead's session:
150
+ # 1. Trace panes — `tail -F` siblings spawned by the codex/gemini wrappers
151
+ # (`okstra-codex-exec.sh`, `okstra-gemini-exec.sh`). Tracked in a registry
152
+ # keyed by the lead's `$TMUX_PANE`.
153
+ # 2. Worker-agent panes — panes the harness gives to dispatched okstra
154
+ # subagents (`claude-worker`, `codex-worker`, `gemini-worker`,
155
+ # `report-writer-worker`). Not registered anywhere by okstra; identified by
156
+ # a title allowlist within the lead's tmux session.
157
+ #
158
+ # The lead's own pane (`$TMUX_PANE`) is NEVER killed, even if its title matches
159
+ # the allowlist. The scan is scoped to the lead's session (`list-panes -s`),
160
+ # never the whole server (`-a`).
161
+ #
162
+ # Two modes:
163
+ # (default) kill every okstra pane (sources 1+2) and remove the registry
164
+ # file. Used by the `SessionEnd` hook, by the lead's per-phase
165
+ # auto-clean, and by the lead's end-of-run prompt (yes-branch).
166
+ # --list print one line per okstra pane (`<pane_id>\t<pane_title>`) so the
167
+ # lead can show the user what would be closed. Empty stdout when
168
+ # nothing is tracked.
169
+ #
170
+ # Failures are tolerated silently — a stale pane id, missing $TMUX, or a locked
171
+ # tmux client must never prevent Claude from exiting cleanly.
172
+
173
+ set -u
174
+
175
+ MODE="kill"
176
+ case "${1:-}" in
177
+ "") MODE="kill" ;;
178
+ --list) MODE="list" ;;
179
+ --dry-run) MODE="list" ;; # alias
180
+ -h|--help)
181
+ cat <<'USAGE'
182
+ usage: okstra-trace-cleanup.sh [--list]
183
+
184
+ (no args) kill every okstra pane for $TMUX_PANE (trace + worker-agent);
185
+ remove the trace registry file.
186
+ --list print "<pane_id>\t<pane_title>" per okstra pane; no kill.
187
+ --dry-run alias for --list.
188
+ USAGE
189
+ exit 0 ;;
190
+ *)
191
+ printf 'okstra-trace-cleanup.sh: unknown option: %s\n' "$1" >&2
192
+ exit 2 ;;
193
+ esac
194
+
195
+ # No tmux pane context → nothing to clean / list.
196
+ if [[ -z "${TMUX_PANE:-}" ]]; then
197
+ exit 0
198
+ fi
199
+
200
+ registry_dir="${TMPDIR:-/tmp}/okstra-trace-panes"
201
+ safe_pane="${TMUX_PANE//[^A-Za-z0-9]/_}"
202
+ registry_file="$registry_dir/${safe_pane}.list"
203
+
204
+ # Collect okstra pane ids for the lead session: registered trace panes ∪
205
+ # title-allowlisted worker-agent panes, always excluding the lead pane itself.
206
+ collect_okstra_panes() {
207
+ local -a panes=()
208
+ local pid title
209
+
210
+ # (1) Registered trace panes — scoped to THIS lead's registry only, so
211
+ # concurrent Claude instances do not stomp each other's trace panes.
212
+ if [[ -f "$registry_file" ]]; then
213
+ while IFS= read -r pid; do
214
+ [[ -n "$pid" ]] || continue
215
+ [[ "$pid" == "$TMUX_PANE" ]] && continue
216
+ panes+=("$pid")
217
+ done < "$registry_file"
218
+ fi
219
+
220
+ # (2) Title-allowlisted worker-agent panes in the lead's session.
221
+ # `list-panes -s -t <pane>` resolves the session containing that pane, so the
222
+ # scan never reaches other sessions (no `-a`).
223
+ while IFS=$'\t' read -r pid title; do
224
+ [[ -n "$pid" ]] || continue
225
+ [[ "$pid" == "$TMUX_PANE" ]] && continue
226
+ case "$title" in
227
+ *claude-worker*|*codex-worker*|*gemini-worker*|*report-writer-worker*)
228
+ panes+=("$pid") ;;
229
+ esac
230
+ done < <(tmux list-panes -s -t "$TMUX_PANE" \
231
+ -F '#{pane_id}'$'\t''#{pane_title}' 2>/dev/null || true)
232
+
233
+ # Dedupe — a live trace pane can match both the registry and the title scan.
234
+ if (( ${#panes[@]} )); then
235
+ printf '%s\n' "${panes[@]}" | awk 'NF && !seen[$0]++'
236
+ fi
237
+ }
238
+
239
+ if [[ "$MODE" == "list" ]]; then
240
+ while IFS= read -r pane_id; do
241
+ [[ -n "$pane_id" ]] || continue
242
+ # `display-message -p` resolves a *live* pane's title; for stale ids tmux
243
+ # exits non-zero — fall back to an empty title rather than failing.
244
+ title=$(tmux display-message -p -t "$pane_id" '#{pane_title}' 2>/dev/null || true)
245
+ printf '%s\t%s\n' "$pane_id" "$title"
246
+ done < <(collect_okstra_panes)
247
+ exit 0
248
+ fi
249
+
250
+ while IFS= read -r pane_id; do
251
+ [[ -n "$pane_id" ]] || continue
252
+ tmux kill-pane -t "$pane_id" 2>/dev/null || true
253
+ done < <(collect_okstra_panes)
254
+
255
+ rm -f "$registry_file" 2>/dev/null || true
256
+ exit 0
257
+ ```
258
+
259
+ - [ ] **Step 4: 테스트 실행해서 통과 확인**
260
+
261
+ Run: `python3 -m pytest tests/test_okstra_trace_cleanup.py -v`
262
+ Expected: 신규 4개 + 기존 7개 모두 PASS. (tmux 없는 환경이면 모듈 전체 skip — 그 경우 tmux 있는 환경에서 재확인.)
263
+
264
+ - [ ] **Step 5: 빌드 동기화 + 커밋**
265
+
266
+ ```bash
267
+ cd /Volumes/Workspaces/workspace/projects/Okstra
268
+ npm run build
269
+ git add scripts/okstra-trace-cleanup.sh tests/test_okstra_trace_cleanup.py runtime/
270
+ git commit -m "feat(scripts/okstra-trace-cleanup): worker-agent pane 까지 title allowlist 로 정리"
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Task 2: `_common-contract.md` 에 phase-start 자동정리 규약 추가
276
+
277
+ **Files:**
278
+ - Modify: `prompts/profiles/_common-contract.md` (현재 32–43행 wrap-up 섹션 주변)
279
+
280
+ - [ ] **Step 1: wrap-up 섹션 헤더와 첫 bullet 을 두 pane 종류로 확장**
281
+
282
+ 아래 old 를 new 로 교체한다 (`Edit`).
283
+
284
+ old:
285
+ ```
286
+ - Phase wrap-up — worker trace pane disposition (shared, MUST be the *last* step before returning control to the user):
287
+ - Codex / Gemini worker wrappers spawn `tail -F` trace panes in the lead's tmux session, titled `<cli>-<role>-<pid>-trace` (e.g. `codex-worker-93421-trace`, `gemini-executor-93422-trace`) — the matching caller (worker) pane is titled `<cli>-<role>-<pid>` so worker ↔ trace pairs can be matched by the shared `<pid>` suffix. They survive every worker invocation by design so the operator can scroll back through the final output, but accumulate across phases and clutter the screen.
288
+ ```
289
+
290
+ new:
291
+ ```
292
+ - Phase-start pane reset (shared — runs BEFORE dispatching each new worker batch):
293
+ - okstra creates two kinds of tmux pane per run: (a) **worker-agent panes** the harness gives to dispatched subagents (titled `claude-worker` / `codex-worker` / `gemini-worker` / `report-writer-worker`), and (b) **trace panes** the codex/gemini wrappers spawn (`<cli>-<role>-<pid>-trace`). Both accumulate across internal phases because each new phase dispatches a fresh worker batch and the prior panes are never reclaimed.
294
+ - When `$TMUX_PANE` is set, the lead MUST run `$HOME/.okstra/bin/okstra-trace-cleanup.sh` (no args) **immediately before** dispatching the next phase's workers — i.e. just before emitting each `PROGRESS: phase-5.5-convergence round=<N>` marker and just before `PROGRESS: phase-6-synthesis dispatching report-writer-worker`. This closes every prior-phase okstra pane (worker-agent + trace) for the lead session, while NEVER killing the lead's own pane.
295
+ - This is **automatic and silent** — NO user prompt. Report it in one short line (e.g. `이전 phase okstra pane 3개 정리`) and proceed. It is silent-skipped when `$TMUX_PANE` is unset; the lead MUST NOT fabricate a synthetic pane list in that case.
296
+ - Phase wrap-up — okstra pane disposition (shared, MUST be the *last* step before returning control to the user):
297
+ - At run end the only residual okstra panes are the LAST phase's (e.g. the `report-writer-worker` agent pane and any codex/gemini trace pane). `okstra-trace-cleanup.sh --list` returns one tab-separated `<pane_id>\t<pane_title>` line per residual okstra pane (worker-agent + trace) for this lead session.
298
+ ```
299
+
300
+ - [ ] **Step 2: 최종 prompt bullet 들의 "trace pane" 문구를 "okstra pane" 으로 정합화**
301
+
302
+ 같은 섹션의 후속 bullet 들에서 아래 old 를 new 로 교체한다 (`Edit`).
303
+
304
+ old:
305
+ ```
306
+ - When `$TMUX_PANE` is set, after the final-report file has been written and the routing recommendation has been issued, the lead MUST run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --list` exactly once. The output is a tab-separated `<pane_id>\t<pane_title>` list of every trace pane registered for this Claude session.
307
+ - If the list is empty, skip the question — there is nothing to ask about.
308
+ - Otherwise the lead MUST present the user with a strict binary choice **before** declaring the phase complete. Use one prompt of this shape (Korean preferred, English acceptable if the rest of the run is in English):
309
+ > 현재 phase 종료 시점입니다. 다음 worker trace pane 이 열려 있습니다 — 닫을까요?
310
+ > <인용된 `--list` 출력>
311
+ > (예) 모두 닫기 / (아니오) 그대로 두기
312
+ ```
313
+
314
+ new:
315
+ ```
316
+ - When `$TMUX_PANE` is set, after the final-report file has been written and the routing recommendation has been issued, the lead MUST run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --list` exactly once. The output lists every residual okstra pane (worker-agent + trace) for this Claude session, never the lead's own pane.
317
+ - If the list is empty, skip the question — there is nothing to ask about (the phase-start resets above usually already cleared prior phases).
318
+ - Otherwise the lead MUST present the user with a strict binary choice **before** declaring the phase complete. Use one prompt of this shape (Korean preferred, English acceptable if the rest of the run is in English):
319
+ > 현재 phase 종료 시점입니다. 다음 okstra pane 이 열려 있습니다 — 닫을까요?
320
+ > <인용된 `--list` 출력>
321
+ > (예) 모두 닫기 / (아니오) 그대로 두기
322
+ ```
323
+
324
+ - [ ] **Step 3: 검증 — 렌더링 + 워크플로 validator**
325
+
326
+ Run:
327
+ ```bash
328
+ cd /Volumes/Workspaces/workspace/projects/Okstra
329
+ bash validators/validate-workflow.sh
330
+ grep -n "Phase-start pane reset" prompts/profiles/_common-contract.md
331
+ ```
332
+ Expected: validator 통과(exit 0), grep 가 신규 규약 1행 매칭.
333
+
334
+ - [ ] **Step 4: 빌드 동기화 + 커밋**
335
+
336
+ ```bash
337
+ cd /Volumes/Workspaces/workspace/projects/Okstra
338
+ npm run build
339
+ git add prompts/profiles/_common-contract.md runtime/
340
+ git commit -m "feat(prompts/profiles): phase 시작 시 이전 phase okstra pane 자동 정리 규약"
341
+ ```
342
+
343
+ ---
344
+
345
+ ## Task 3: 문서 갱신 (architecture.md + CHANGES.md)
346
+
347
+ **Files:**
348
+ - Modify: `docs/kr/architecture.md` (Live-log mirror 절, 약 912–913행)
349
+ - Modify: `CHANGES.md` (최상단 신규 엔트리)
350
+
351
+ - [ ] **Step 1: architecture.md Live-log mirror 절에 phase-start 정리 문단 추가**
352
+
353
+ `docs/kr/architecture.md` 의 913행(현재 "**Claude `/exit` 시 자동 정리**: …" 로 시작하는 bullet) **바로 다음 줄**에 아래 bullet 을 삽입한다 (`Edit` — 913행 bullet 끝의 줄바꿈 뒤에 추가).
354
+
355
+ ```
356
+ - **phase 전환 시 자동 정리 + worker-agent pane 포함**: `okstra-trace-cleanup.sh` 는 trace pane(registry) 뿐 아니라 dispatch 된 서브에이전트가 점유하는 worker-agent pane(title `claude-worker` / `codex-worker` / `gemini-worker` / `report-writer-worker`)도 lead 세션(`list-panes -s`) 범위에서 title allowlist 로 식별해 닫는다. lead 자신의 pane(`$TMUX_PANE`)은 title 이 걸려도 절대 죽이지 않는다. lead 는 새 phase 의 worker 를 dispatch 하기 직전(`PROGRESS: phase-5.5-convergence` / `phase-6-synthesis` 마커 직전) 이 스크립트를 무인자로 호출해 이전 phase pane 을 prompt 없이 정리한다. run 최종 종료 시점의 잔여만 기존 `--list` + 이진 prompt 로 확인한다.
357
+ ```
358
+
359
+ - [ ] **Step 2: CHANGES.md 에 사용자 영향 엔트리 추가**
360
+
361
+ `CHANGES.md` 최상단(가장 최근 엔트리 위)에 아래를 추가한다 (`Edit` — 파일 첫 엔트리 헤더 바로 위에 삽입). 날짜·형식은 기존 엔트리 컨벤션을 따른다.
362
+
363
+ ```
364
+ ## 2026-06-02 — okstra-run phase 전환 시 tmux pane 자동 정리
365
+
366
+ - **증상**: okstra-run 진행 중 lead 가 phase 마다 새 worker(claude/codex/gemini/report-writer)를 dispatch 하면, 이전 phase 의 worker-agent pane 과 wrapper trace pane 이 닫히지 않고 누적돼 화면이 좀비 pane 으로 채워졌다. 정리는 run 맨 끝 1회뿐이었고 worker-agent pane 은 아예 관리 대상이 아니었다.
367
+ - **변경**: `okstra-trace-cleanup.sh` 가 trace pane(registry) + worker-agent pane(title allowlist, lead 세션 범위, lead pane 제외)을 합쳐 정리하도록 확장. lead 는 새 phase dispatch 직전 이 스크립트를 무인자로 호출해 이전 phase pane 을 자동(무콜) 정리하고, run 최종 종료 시점의 잔여만 기존 이진 prompt 로 확인한다.
368
+ - **사용자 영향**: tmux 안에서 okstra-run 을 돌릴 때 새 phase 가 시작되면 이전 phase 의 worker/trace pane 이 자동으로 닫혀 화면에 좀비 pane 이 쌓이지 않는다. 사용자가 무관한 pane(메인/개발)은 건드리지 않는다.
369
+ ```
370
+
371
+ - [ ] **Step 3: 커밋**
372
+
373
+ ```bash
374
+ cd /Volumes/Workspaces/workspace/projects/Okstra
375
+ git add docs/kr/architecture.md CHANGES.md
376
+ git commit -m "docs(architecture,changes): phase 전환 시 okstra pane 자동 정리 문서화"
377
+ ```
378
+
379
+ ---
380
+
381
+ ## Task 4: 전체 검증
382
+
383
+ - [ ] **Step 1: 전체 단위 테스트**
384
+
385
+ Run: `python3 -m pytest tests/ -q`
386
+ Expected: 전부 PASS (또는 tmux 미존재로 trace-cleanup 모듈만 skip — 그 경우 tmux 환경에서 Task 1 Step 4 재확인 필요).
387
+
388
+ - [ ] **Step 2: 워크플로 validator + CLI 스모크**
389
+
390
+ Run:
391
+ ```bash
392
+ cd /Volumes/Workspaces/workspace/projects/Okstra
393
+ bash validators/validate-workflow.sh
394
+ node bin/okstra --version
395
+ ```
396
+ Expected: validator exit 0, 버전 출력.
397
+
398
+ - [ ] **Step 3: diff 리뷰 (critique mode)**
399
+
400
+ Run: `git log --oneline main..HEAD && git diff main..HEAD --stat`
401
+ 점검: (a) `runtime/` 가 source 변경과 일치하게 재생성됐는지, (b) 새 토큰 `Phase-start pane reset` 의 grep 일관성, (c) `okstra-trace-cleanup.sh` 의 lead-pane 제외 불변이 list/kill 양쪽에 적용됐는지.
402
+
403
+ ---
404
+
405
+ ## Self-Review (작성자 체크 완료)
406
+
407
+ - **Spec coverage**: 스크립트 통합(§스크립트 변경)=Task 1, contract(§contract 변경)=Task 2, 테스트(§테스트)=Task 1 Step 1, 문서/전파(§영향)=Task 3. 모든 spec 섹션이 task 로 매핑됨.
408
+ - **Placeholder scan**: TBD/TODO 없음. 모든 코드 step 에 완전한 코드 포함.
409
+ - **Type/식별자 consistency**: `collect_okstra_panes`, allowlist 4개 title, `okstra-trace-cleanup.sh` 인터페이스(`--list`/무인자)가 Task 1·2·3 에서 동일 명칭으로 일관.
410
+ - **알려진 한계**(동시-run title 충돌, 선언적 enforcement)는 spec 에 명시 — 코드 변경 없음.