okstra 0.62.0 → 0.64.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.
- package/docs/kr/architecture.md +1 -1
- package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +320 -0
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +42 -0
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +337 -0
- package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +66 -0
- package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +87 -0
- package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +113 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +5 -2
- package/runtime/agents/TODO.md +9 -2
- package/runtime/agents/workers/claude-worker.md +7 -3
- package/runtime/agents/workers/codex-worker.md +6 -2
- package/runtime/agents/workers/gemini-worker.md +6 -2
- package/runtime/agents/workers/report-writer-worker.md +6 -1
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +23 -4
- package/runtime/prompts/profiles/implementation-planning.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +17 -1
- package/runtime/python/okstra_ctl/backfill.py +23 -4
- package/runtime/python/okstra_ctl/consumers.py +118 -1
- package/runtime/python/okstra_ctl/paths.py +11 -0
- package/runtime/python/okstra_ctl/run.py +147 -67
- package/runtime/python/okstra_ctl/run_context.py +2 -0
- package/runtime/python/okstra_ctl/wizard.py +127 -29
- package/runtime/skills/okstra-convergence/SKILL.md +3 -1
- package/runtime/skills/okstra-report-writer/SKILL.md +2 -0
- package/runtime/skills/okstra-run/SKILL.md +1 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +37 -0
- package/runtime/templates/reports/final-report.template.md +6 -9
- package/runtime/templates/reports/i18n/en.json +1 -1
- package/runtime/templates/reports/i18n/ko.json +1 -1
- package/runtime/templates/worker-prompt-preamble.md +10 -0
- package/runtime/validators/validate-implementation-plan-stages.py +10 -5
- package/runtime/validators/validate-run.py +20 -3
- package/src/install.mjs +21 -0
- package/src/uninstall.mjs +17 -17
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Lead-Worker 완료 인지 (self-scheduled 폴링) 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 lead 가 비동기 dispatch 한 워커의 완료를 mailbox/idle 알림 없이 self-scheduled 폴링으로 스스로 인지해, 사용자의 수동 nudge 없이 다음 phase 로 진행하게 만든다.
|
|
6
|
+
|
|
7
|
+
**Architecture:** lead 는 워커를 기존대로 비동기 dispatch 한 뒤 단일 self-wakeup 스케줄을 걸고 턴을 종료한다. 깨어날 때마다 dispatch 한 워커 전원의 `worker-results` 파일 출현+헤더 검증으로 완료를 직접 확인하고, 전원 완료(또는 워커별 deadline 초과) 시 스케줄을 해제하고 진행한다. 변경은 코드가 아니라 프롬프트/SKILL 명세 레이어 중심이다.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Claude Code Agent Teams, Monitor 툴 / scheduled-tasks(cron, `/loop`), bash 검증 스크립트, okstra SKILL markdown.
|
|
10
|
+
|
|
11
|
+
**설계 출처:** [docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md](../specs/2026-06-10-lead-worker-completion-polling-design.md)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ⚠️ BLOCKING 게이트
|
|
16
|
+
|
|
17
|
+
**Task 1 (실측)이 통과하지 않으면 Task 2~9 를 진행하지 않는다.** Task 1 에서 "self-wakeup 이 정지 lead 를 재개시키지 못한다"가 확인되면, 이 plan 전체를 폐기하고 spec §3 의 **방향 A(`team_name` 없는 foreground 동기 dispatch)** 로 별도 plan 을 작성한다. 방향 A 는 공식 문서가 명시적으로 보장하는 유일한 폴백이다.
|
|
18
|
+
|
|
19
|
+
> **갱신 (2026-06-10): Task 1 통과** ([PROBE](2026-06-10-lead-worker-completion-polling-PROBE.md)). 채택 메커니즘 = **`Bash run_in_background` + `until` 루프**. 아래 모든 Task 의 `<WAKEUP>` 표기는 이 패턴으로 치환한다:
|
|
20
|
+
> ```bash
|
|
21
|
+
> # lead 가 워커 dispatch 직후 run_in_background:true 로 띄우는 폴링 스크립트
|
|
22
|
+
> deadline=$((SECONDS + <per_worker_deadline_seconds>))
|
|
23
|
+
> until [ -f "<result_path_A>" ] && [ -f "<result_path_B>" ] ...; do
|
|
24
|
+
> [ $SECONDS -ge $deadline ] && { echo "POLL_TIMEOUT"; exit 1; }
|
|
25
|
+
> sleep 5
|
|
26
|
+
> done
|
|
27
|
+
> echo "ALL_WORKERS_DONE"
|
|
28
|
+
> ```
|
|
29
|
+
> 완료(또는 timeout exit) 시 harness 가 lead 를 자동 재개한다. **Task 7(self-wakeup 도구 권한 seed)은 불필요** — `Bash(run_in_background)` 는 이미 권한 내이고, background task 는 완료 시 자가 소멸하므로 도구 권한 추가·스케줄 해제 lifecycle 이 없다. Task 2 의 종료 lifecycle 에서 "cron 해제"는 "background task 자가 소멸"로 대체하고, deadline 은 위 `SECONDS` 가드로 구현한다.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## File Structure
|
|
34
|
+
|
|
35
|
+
| 파일 | 책임 | 변경 |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md` | Task 1 실측 결과 기록 | Create |
|
|
38
|
+
| `agents/SKILL.md` | Phase 4/5/6 dispatch 후 완료 폴링 루프 명세, 동기 전제 문구 정정 | Modify |
|
|
39
|
+
| `agents/workers/claude-worker.md` | "Agent() call blocks" 동기 전제 정정 | Modify |
|
|
40
|
+
| `skills/okstra-report-writer/SKILL.md` | Phase 6 dispatch 후 완료 폴링 명세 | Modify |
|
|
41
|
+
| `skills/okstra-team-contract/SKILL.md` | worker-completion 폴링 규약 + soft timeout terminal status | Modify |
|
|
42
|
+
| `skills/okstra-convergence/SKILL.md` | 라운드별 reverify 집합 폴링 적용 | Modify |
|
|
43
|
+
| `templates/reports/settings.template.json` | self-wakeup 도구 권한 seed | Modify |
|
|
44
|
+
| `agents/TODO.md` | 수정 B/C 해소 표시 | Modify |
|
|
45
|
+
| `tests-e2e/scenario-<id>-worker-completion-polling.sh` | 폴링 종료 lifecycle e2e | Create |
|
|
46
|
+
|
|
47
|
+
명세 변경의 SSOT 는 `agents/SKILL.md` + `skills/okstra-team-contract/SKILL.md` 이며, 나머지 SKILL 은 그 규약을 참조한다 (DRY — 폴링 알고리즘을 여러 파일에 복붙하지 않는다).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### Task 1: 실측 검증 게이트 (BLOCKING — 메커니즘 확정)
|
|
52
|
+
|
|
53
|
+
**목적:** spec §5 의 세 가지를 interactive 세션에서 실측해 self-wakeup 메커니즘(Monitor vs cron)을 확정한다. 이 Task 는 명세를 바꾸지 않는다 — 오직 런타임 동작을 관측해 기록한다.
|
|
54
|
+
|
|
55
|
+
**Files:**
|
|
56
|
+
- Create: `docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md`
|
|
57
|
+
|
|
58
|
+
- [ ] **Step 1: 비동기 워커 + cron self-wakeup 재개 실측**
|
|
59
|
+
|
|
60
|
+
interactive Claude Code 세션에서:
|
|
61
|
+
1. `team_name` 을 포함한 `Agent(...)` 로 더미 워커를 띄운다. 워커 프롬프트: "sleep 90 후 `/tmp/okstra-probe/worker-A.done` 에 `done` 을 써라" (background Bash 사용).
|
|
62
|
+
2. dispatch 직후, cron(`/loop` 또는 `CronCreate`)으로 1분 간격 self-wakeup 을 건다. wakeup 프롬프트: "`/tmp/okstra-probe/worker-A.done` 이 있으면 'PROBE: detected' 출력 후 cron 해제, 없으면 'PROBE: waiting' 출력".
|
|
63
|
+
3. lead 턴을 종료한다 (추가 입력 없이).
|
|
64
|
+
|
|
65
|
+
관측 기준:
|
|
66
|
+
- 사용자 입력 **없이** lead 가 1분 후 자동으로 깨어나 'PROBE: waiting' 을 출력하는가?
|
|
67
|
+
- 파일 출현 후 깨어남에서 'PROBE: detected' 를 출력하고 cron 을 해제하는가?
|
|
68
|
+
|
|
69
|
+
- [ ] **Step 2: Monitor 툴 재개 실측**
|
|
70
|
+
|
|
71
|
+
같은 더미 워커 시나리오를 Monitor 툴로 반복:
|
|
72
|
+
1. `Agent(team_name: …)` 로 더미 워커 dispatch.
|
|
73
|
+
2. Monitor 로 `bash -c 'until [ -f /tmp/okstra-probe/worker-A.done ]; do sleep 2; done; echo READY'` 를 건다 (Monitor 가 sleep 제약 우회/스트리밍을 어떻게 다루는지 관측).
|
|
74
|
+
3. lead 턴 종료.
|
|
75
|
+
|
|
76
|
+
관측 기준: Monitor 가 `READY` 라인을 스트리밍해 lead 를 자동 재개시키는가? cron 대비 토큰/반응 차이는?
|
|
77
|
+
|
|
78
|
+
- [ ] **Step 3: 복수 워커 집합 폴링 실측**
|
|
79
|
+
|
|
80
|
+
워커 2개(`worker-A.done`, `worker-B.done`)를 서로 다른 sleep(60s, 120s)으로 띄우고, Step 1 또는 Step 2 의 승자 메커니즘으로 **단일 스케줄이 두 파일을 모두 추적**하는지 확인. 한 개만 끝났을 때 'PROBE: partial (A done, B waiting)', 둘 다 끝나면 해제.
|
|
81
|
+
|
|
82
|
+
- [ ] **Step 4: 결과 기록**
|
|
83
|
+
|
|
84
|
+
`...-PROBE.md` 에 기록:
|
|
85
|
+
- cron 자동 재개: 성공/실패 (관측 근거)
|
|
86
|
+
- Monitor 자동 재개: 성공/실패 (관측 근거)
|
|
87
|
+
- 복수 워커 단일-스케줄 폴링: 성공/실패
|
|
88
|
+
- **채택 메커니즘** (Monitor 우선, 실패 시 cron, 둘 다 실패 시 방향 A 전환)
|
|
89
|
+
- headless 경로 주의: 본 실측은 interactive 한정. okstra.sh spawn 도 interactive([scripts/okstra.sh:173](../../../scripts/okstra.sh))이므로 동일 가정하되, 가능하면 okstra.sh spawn 으로 1회 교차 확인.
|
|
90
|
+
|
|
91
|
+
- [ ] **Step 5: 게이트 판정 + 커밋**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git add docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md
|
|
95
|
+
git commit -m "test(run): self-scheduled 워커 완료 폴링 실측 결과 기록"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
판정: 채택 메커니즘이 정해지면 Task 2 로 진행. 둘 다 실패면 STOP — 방향 A plan 작성으로 전환하고 사용자에게 보고.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Task 2: 완료 폴링 규약 정의 (team-contract SSOT)
|
|
103
|
+
|
|
104
|
+
**전제:** Task 1 에서 채택된 메커니즘을 `<WAKEUP>` 로 표기. 아래 명세의 self-wakeup 도구 호출만 Task 1 승자로 치환한다. 폴링 알고리즘·종료 lifecycle·복수 워커 집합 로직은 메커니즘 무관하게 동일하다.
|
|
105
|
+
|
|
106
|
+
**Files:**
|
|
107
|
+
- Modify: `skills/okstra-team-contract/SKILL.md` (신규 섹션 "Worker-completion detection (self-scheduled polling)")
|
|
108
|
+
|
|
109
|
+
- [ ] **Step 1: 규약 본문 작성**
|
|
110
|
+
|
|
111
|
+
다음 내용을 새 섹션으로 추가한다 (정확한 문안은 작성 시 SKILL 톤에 맞춤):
|
|
112
|
+
|
|
113
|
+
```markdown
|
|
114
|
+
## Worker-completion detection (self-scheduled polling)
|
|
115
|
+
|
|
116
|
+
Lead dispatches workers asynchronously (Agent with team_name returns
|
|
117
|
+
`Spawned successfully` immediately — NOT a completion). Lead MUST NOT
|
|
118
|
+
treat the spawn ack as completion, and MUST NOT end its turn with a
|
|
119
|
+
prose "waiting for ..." statement. Instead:
|
|
120
|
+
|
|
121
|
+
1. Record the dispatched workers' Result Paths as the **pending set**
|
|
122
|
+
(from run-manifest / launch prompt `**Result Path:**`).
|
|
123
|
+
2. Arm a SINGLE self-wakeup via <WAKEUP> (one schedule for ALL workers,
|
|
124
|
+
not one per worker).
|
|
125
|
+
3. End the turn.
|
|
126
|
+
4. On each wakeup, for every path still in the pending set: verify the
|
|
127
|
+
file exists AND passes the standardized worker-result header check.
|
|
128
|
+
Move passing workers to the **done set**.
|
|
129
|
+
5. Termination:
|
|
130
|
+
- pending set empty → disarm <WAKEUP>, proceed to next phase.
|
|
131
|
+
- a worker exceeds its per-worker deadline (see soft-timeout below)
|
|
132
|
+
→ record `timeout`, remove from pending set, redispatch-once or
|
|
133
|
+
proceed.
|
|
134
|
+
- any error/abort path → ALWAYS disarm <WAKEUP> (no zombie schedule).
|
|
135
|
+
6. Per-worker soft timeout: 2× the task-type expected duration table
|
|
136
|
+
below. (Supersedes TODO.md 수정 B.)
|
|
137
|
+
|
|
138
|
+
| Task type | Expected per-worker | Deadline (2×) |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| requirements-discovery | 10 min | 20 min |
|
|
141
|
+
| error-analysis | 15 min | 30 min |
|
|
142
|
+
| implementation-planning | 20 min | 40 min |
|
|
143
|
+
| implementation | 20 min | 40 min |
|
|
144
|
+
| final-verification | 10 min | 20 min |
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- [ ] **Step 2: 일관성 grep**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
grep -rn "Spawned successfully\|self-scheduled\|pending set\|Worker-completion detection" skills/okstra-team-contract/SKILL.md
|
|
151
|
+
```
|
|
152
|
+
Expected: 새 섹션이 단일 위치에 존재. 다른 SKILL 에 폴링 알고리즘 중복 없음.
|
|
153
|
+
|
|
154
|
+
- [ ] **Step 3: 커밋**
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git add skills/okstra-team-contract/SKILL.md
|
|
158
|
+
git commit -m "feat(skills/okstra-team-contract): 워커 완료 self-scheduled 폴링 규약 정의"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### Task 3: 동기 전제 문구 정정 (claude-worker + SKILL)
|
|
164
|
+
|
|
165
|
+
**Files:**
|
|
166
|
+
- Modify: `agents/workers/claude-worker.md:87-89` (Stop Condition)
|
|
167
|
+
- Modify: `agents/SKILL.md:381` (Common Mistakes 항목)
|
|
168
|
+
|
|
169
|
+
- [ ] **Step 1: claude-worker.md 정정**
|
|
170
|
+
|
|
171
|
+
`agents/workers/claude-worker.md:89` 의 "Lead's `Agent()` call blocks until you return your final assistant message." 는 `team_name` dispatch 에서 거짓이다. 다음으로 교체:
|
|
172
|
+
|
|
173
|
+
```markdown
|
|
174
|
+
You are an in-process Claude subagent. When dispatched with `team_name`
|
|
175
|
+
(Teams mode), Lead's `Agent()` call returns `Spawned successfully`
|
|
176
|
+
immediately and does NOT block on your completion — Lead detects your
|
|
177
|
+
completion via self-scheduled polling of your worker-results file
|
|
178
|
+
(see okstra-team-contract "Worker-completion detection"). Therefore you
|
|
179
|
+
MUST write your worker-results file at the canonical Result Path before
|
|
180
|
+
returning; that file's appearance is the ONLY signal Lead uses.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- [ ] **Step 2: SKILL.md:381 정정**
|
|
184
|
+
|
|
185
|
+
"when the Agent call finally returns" 전제를 self-scheduled 폴링으로 갱신하고, heartbeat sidecar 규칙은 보조 liveness 신호로 유지하되 "완료 인지 = 결과 파일 출현"으로 명확히 한다.
|
|
186
|
+
|
|
187
|
+
- [ ] **Step 3: 일관성 grep**
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
grep -rn "blocks until you return\|Agent call finally returns\|call blocks" agents/
|
|
191
|
+
```
|
|
192
|
+
Expected: 동기-blocking 전제 문구가 더 이상 남아있지 않음 (0 hits, 또는 의도된 foreground 맥락만).
|
|
193
|
+
|
|
194
|
+
- [ ] **Step 4: 커밋**
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
git add agents/workers/claude-worker.md agents/SKILL.md
|
|
198
|
+
git commit -m "fix(agents): Agent dispatch 동기-blocking 전제를 비동기-폴링으로 정정"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Task 4: Phase 4/5 dispatch 후 폴링 루프 명세 (agents/SKILL.md)
|
|
204
|
+
|
|
205
|
+
**Files:**
|
|
206
|
+
- Modify: `agents/SKILL.md` (Phase 4/5 실행 섹션, 대략 219-249)
|
|
207
|
+
|
|
208
|
+
- [ ] **Step 1: 폴링 진입 명세 추가**
|
|
209
|
+
|
|
210
|
+
Phase 4/5 dispatch 직후, lead 가 okstra-team-contract "Worker-completion detection" 규약에 따라 self-wakeup 폴링을 무장하고 턴을 종료하도록 명시. PROGRESS 체크포인트 추가:
|
|
211
|
+
|
|
212
|
+
```markdown
|
|
213
|
+
- `PROGRESS: phase-5-poll pending=<n> done=<m>` — emitted on each wakeup
|
|
214
|
+
while the pending set is non-empty.
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
DRY: 폴링 알고리즘은 team-contract SSOT 를 참조만 한다 (복붙 금지).
|
|
218
|
+
|
|
219
|
+
- [ ] **Step 2: 일관성 grep + 커밋**
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
grep -rn "phase-5-poll\|Worker-completion detection" agents/SKILL.md
|
|
223
|
+
git add agents/SKILL.md
|
|
224
|
+
git commit -m "feat(agents): Phase 4/5 워커 dispatch 후 완료 폴링 진입 명세"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### Task 5: Phase 6 report-writer 폴링 명세 (okstra-report-writer)
|
|
230
|
+
|
|
231
|
+
**Files:**
|
|
232
|
+
- Modify: `skills/okstra-report-writer/SKILL.md` (Phase 6 dispatch template 직후)
|
|
233
|
+
|
|
234
|
+
- [ ] **Step 1: dispatch 후 폴링 명세**
|
|
235
|
+
|
|
236
|
+
[skills/okstra-report-writer/SKILL.md:27-41](../../../skills/okstra-report-writer/SKILL.md) 의 dispatch 템플릿 뒤에, "dispatch 후 report-writer 의 data.json + worker-results 파일 출현을 team-contract 규약대로 폴링하여 완료를 인지한다. spawn ack 를 완료로 착각하지 말 것" 을 추가.
|
|
237
|
+
|
|
238
|
+
- [ ] **Step 2: 일관성 grep + 커밋**
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
grep -rn "Worker-completion detection\|Spawned successfully" skills/okstra-report-writer/SKILL.md
|
|
242
|
+
git add skills/okstra-report-writer/SKILL.md
|
|
243
|
+
git commit -m "feat(skills/okstra-report-writer): Phase 6 report-writer 완료 폴링 명세"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Task 6: convergence 라운드 폴링 적용 (okstra-convergence)
|
|
249
|
+
|
|
250
|
+
**Files:**
|
|
251
|
+
- Modify: `skills/okstra-convergence/SKILL.md` (reverify dispatch 섹션)
|
|
252
|
+
|
|
253
|
+
- [ ] **Step 1: 라운드별 집합 폴링 참조 추가**
|
|
254
|
+
|
|
255
|
+
각 convergence 라운드의 reverify dispatch 집합(가변 1~N)에 동일한 team-contract 폴링 규약을 적용한다는 문장 추가. 라운드마다 pending set 이 재구성됨을 명시.
|
|
256
|
+
|
|
257
|
+
- [ ] **Step 2: 일관성 grep + 커밋**
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
grep -rn "Worker-completion detection" skills/okstra-convergence/SKILL.md
|
|
261
|
+
git add skills/okstra-convergence/SKILL.md
|
|
262
|
+
git commit -m "feat(skills/okstra-convergence): 라운드별 reverify 완료 폴링 적용"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### Task 7: self-wakeup 도구 권한 seed (settings.template.json)
|
|
268
|
+
|
|
269
|
+
**Files:**
|
|
270
|
+
- Modify: `templates/reports/settings.template.json`
|
|
271
|
+
|
|
272
|
+
- [ ] **Step 1: Task 1 승자 도구 권한 추가**
|
|
273
|
+
|
|
274
|
+
Task 1 에서 cron 채택 시 `CronCreate`/`CronList`/`CronDelete` 를, Monitor 채택 시 `Monitor` 를 `permissions.allow` 에 추가한다. 사용자 머신 전파를 위해 personal `.claude/` 가 아니라 이 템플릿에 seed (CLAUDE.md artifact-home 규칙).
|
|
275
|
+
|
|
276
|
+
- [ ] **Step 2: JSON 유효성 + 커밋**
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
jq . templates/reports/settings.template.json >/dev/null && echo "valid"
|
|
280
|
+
git add templates/reports/settings.template.json
|
|
281
|
+
git commit -m "feat(templates): self-wakeup 폴링 도구 권한 seed"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### Task 8: TODO.md 수정 B/C 해소
|
|
287
|
+
|
|
288
|
+
**Files:**
|
|
289
|
+
- Modify: `agents/TODO.md`
|
|
290
|
+
|
|
291
|
+
- [ ] **Step 1: 수정 B/C 항목에 해소 메모**
|
|
292
|
+
|
|
293
|
+
"수정 B — Leader-side 워커 soft timeout" 와 "수정 C 후보 — worker-results 파일 폴링 루프" 항목에, 본 plan(self-scheduled 폴링)으로 통합·해소됨을 기록하고 spec/plan 경로를 링크. 변경 이력에 2026-06-10 항목 추가.
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 2: 커밋**
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
git add agents/TODO.md
|
|
299
|
+
git commit -m "docs(agents): 워커 완료 폴링으로 TODO 수정 B/C 해소 기록"
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
### Task 9: e2e 시나리오 + build 검증
|
|
305
|
+
|
|
306
|
+
**Files:**
|
|
307
|
+
- Create: `tests-e2e/scenario-<id>-worker-completion-polling.sh`
|
|
308
|
+
- Test: `bash validators/validate-workflow.sh`, `npm run build`
|
|
309
|
+
|
|
310
|
+
- [ ] **Step 1: 종료 lifecycle e2e 작성**
|
|
311
|
+
|
|
312
|
+
`tests-e2e/scenario-<id>-<name>.sh` 규약(mktemp OKSTRA_HOME, trap EXIT cleanup)에 따라, 폴링 종료 lifecycle 의 검증 가능한 부분을 스크립트화: pending/done set 추적, deadline 시 timeout 기록, 스케줄 해제 확인. (LLM 비결정 동작은 e2e 가 아니라 Task 1 PROBE 가 담당 — e2e 는 결정적 산출물/상태 전이만 검증.)
|
|
313
|
+
|
|
314
|
+
- [ ] **Step 2: 워크플로우 validator + build**
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
bash validators/validate-workflow.sh
|
|
318
|
+
npm run build
|
|
319
|
+
node bin/okstra doctor
|
|
320
|
+
```
|
|
321
|
+
Expected: validator 통과, build 가 변경된 SKILL/agent/template 을 runtime/ 으로 동기화, doctor 정상.
|
|
322
|
+
|
|
323
|
+
- [ ] **Step 3: 커밋**
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
git add tests-e2e/ runtime/
|
|
327
|
+
git commit -m "test(e2e): 워커 완료 폴링 종료 lifecycle 시나리오 + build 동기화"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Self-Review (작성자 체크)
|
|
333
|
+
|
|
334
|
+
- **Spec 커버리지:** §1 문제→Task 1 실측 재현. §3 방향 C→Task 2~7. §4.1 메커니즘→Task 2/4. §4.2 복수 워커→Task 1 Step3 + Task 2. §4.3 종료 lifecycle→Task 2 Step1. §4.4 Monitor/cron→Task 1. §5 실측 게이트→Task 1(BLOCKING). §6 변경 범위→Task 2~9 파일 일치. §7 미해결→Task 1 이 캐시 TTL/Monitor 형태 확정.
|
|
335
|
+
- **Placeholder:** `<WAKEUP>` / `<id>` 는 Task 1 결과·시나리오 번호로 채워지는 의도된 변수이며, 그 치환 규칙을 각 Task 에 명시함 (막연한 TODO 아님).
|
|
336
|
+
- **타입/이름 일관성:** "pending set" / "done set" / "Worker-completion detection" / `<WAKEUP>` 용어가 Task 2~6 에서 동일하게 사용됨.
|
|
337
|
+
- **알려진 한계:** SKILL 명세 변경은 LLM 동작을 *유도*할 뿐 코드로 *강제*하지 못한다 (CLAUDE.md Rule 3). 결정적 강제가 가능한 부분(종료 lifecycle 의 산출물/상태)만 Task 9 e2e 가 검증하고, 나머지는 Task 1 실측 + 실사용 관측에 의존함을 명시.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# executor 세부모델 선택에 "기타(직접입력)" cascade — 설계
|
|
2
|
+
|
|
3
|
+
## 배경 / 문제
|
|
4
|
+
|
|
5
|
+
okstra-run wizard 의 모델 선택은 세부모델(opus/sonnet/haiku 등)을 바로 보여 준다. 사용자는
|
|
6
|
+
"provider 를 먼저 고르고 그다음 세부모델을 보여 주는 2단계 cascade" + 목록에 없는 모델을
|
|
7
|
+
직접 입력할 수단을 원한다.
|
|
8
|
+
|
|
9
|
+
executor 는 **이미** 2단계다: executor pick(provider: claude/codex/gemini) →
|
|
10
|
+
executor_model pick(provider 별 세부모델, [`_build_executor_model`](../../../scripts/okstra_ctl/wizard.py),
|
|
11
|
+
[`_executor_model_options`](../../../scripts/okstra_ctl/wizard.py)). 빠진 것은 세부모델
|
|
12
|
+
단계의 **"기타(직접입력 = 사용자 정의 모델 ID)"** 옵션뿐이다.
|
|
13
|
+
|
|
14
|
+
## 결정 (사용자 확인 완료)
|
|
15
|
+
|
|
16
|
+
| # | 결정 | 근거 |
|
|
17
|
+
|---|------|------|
|
|
18
|
+
| D1 | cascade 범위 = **executor 만** | lead 는 Claude Code 세션 자체라 provider 변경 불가; report-writer 는 in-process Claude 서브에이전트라 codex/gemini 불가 (아래 비목표) |
|
|
19
|
+
| D2 | "기타" = **사용자 정의 모델 ID** (선택한 provider 기준) | provider 는 claude/codex/gemini 3개 그대로, 세부모델만 자유 입력 |
|
|
20
|
+
| D3 | 기존 `pick → text` 패턴 재사용 | base-ref 의 `S_BASE_REF_PICK → S_BASE_REF_TEXT` 와 동일 구조 |
|
|
21
|
+
|
|
22
|
+
## 비목표
|
|
23
|
+
|
|
24
|
+
- **report-writer / lead 를 provider 선택 대상으로 만들지 않는다.** report-writer 는
|
|
25
|
+
`subagent_type: "report-writer-worker"` 인 in-process Claude 서브에이전트로, `Write` 툴로
|
|
26
|
+
data.json 을 저작하고 renderer 를 실행한다 ([team-contract:40](../../../skills/okstra-team-contract/SKILL.md),
|
|
27
|
+
[report-writer dispatch](../../../skills/okstra-report-writer/SKILL.md)). codex/gemini 실행경로가
|
|
28
|
+
없으므로 wizard 에만 옵션을 넣으면 "가짜 옵션"이 된다. codex/gemini report-writer 는 별도
|
|
29
|
+
백엔드 프로젝트로 분리.
|
|
30
|
+
|
|
31
|
+
## 구현 범위 (모두 `wizard.py` + `prompts.ko.json`)
|
|
32
|
+
|
|
33
|
+
> ⚠️ 두 파일은 현재 다른 작업(approve-plan-confirm)으로 동시 편집 중. **그 작업이 커밋되어
|
|
34
|
+
> 파일이 풀린 뒤** 적용한다. 적용 전 `git status` 로 두 파일이 clean 인지 확인.
|
|
35
|
+
|
|
36
|
+
1. **새 상태** `S_EXECUTOR_MODEL_TEXT`(상수) + state 필드는 기존 `executor_model` 재사용.
|
|
37
|
+
2. **세부모델 pick 에 기타 옵션 추가** — `_build_executor_model` 의 옵션 목록 끝에
|
|
38
|
+
`_opt(PICK_CUSTOM, <기타 라벨>)` 추가 (기존 `PICK_TYPE_CUSTOM` / `PICK_OTHER` 패턴과 동일한
|
|
39
|
+
sentinel 상수 신설: `PICK_MODEL_CUSTOM`).
|
|
40
|
+
3. **분기** — `_submit_executor_model`: 값이 `PICK_MODEL_CUSTOM` 이면 다음 step 으로
|
|
41
|
+
`S_EXECUTOR_MODEL_TEXT` 반환; 아니면 기존대로 `_validate_model(executor, value)`.
|
|
42
|
+
4. **text step** `_build_executor_model_text`(label = prompts.ko.json) +
|
|
43
|
+
`_submit_executor_model_text`: 입력값을 `state.<executor>_model` 에 그대로 저장(자유 모델 ID
|
|
44
|
+
이므로 화이트리스트 검증 면제 — 비어 있으면 재프롬프트).
|
|
45
|
+
5. **STEP 그래프 등록** — `_RESUME_FILLED_STEPS` 등 관련 목록에 신규 step 반영.
|
|
46
|
+
6. **i18n** `prompts.ko.json` 에 `executor_model.options` 기타 라벨 + `executor_model_text`
|
|
47
|
+
label/echo_template 추가. (en 미러가 있으면 함께.)
|
|
48
|
+
|
|
49
|
+
## 테스트
|
|
50
|
+
|
|
51
|
+
- `tests/test_okstra_ctl_wizard.py`: (a) 세부모델 단계에 기타 옵션이 노출, (b) 기타 선택 시
|
|
52
|
+
`S_EXECUTOR_MODEL_TEXT` 로 전이, (c) 자유 입력 모델 ID 가 검증 통과 후 state 에 저장, (d) 빈
|
|
53
|
+
입력은 재프롬프트.
|
|
54
|
+
|
|
55
|
+
## enforcement / 한계
|
|
56
|
+
|
|
57
|
+
- 자유 입력 모델 ID 는 화이트리스트 검증을 면제하므로 **존재하지 않는 모델명도 통과**한다.
|
|
58
|
+
이는 사용자가 신규/프리뷰 모델을 쓰기 위한 의도된 탈출구다. 잘못된 id 는 실행 시점에
|
|
59
|
+
해당 provider CLI/Agent 가 거른다.
|
|
60
|
+
|
|
61
|
+
## 영향 / 전파
|
|
62
|
+
|
|
63
|
+
- seed/배포 소스(`scripts/`, `prompts/`)에 land → `npm run build` → `runtime/` →
|
|
64
|
+
`okstra install`. 개인 `.claude/` 직접 수정 아님.
|
|
65
|
+
- 사용자 영향(CHANGES.md): "executor 세부모델 선택에서 목록에 없는 모델을 '기타(직접입력)'으로
|
|
66
|
+
직접 지정할 수 있다."
|
package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# implementation run-산출물 stage 격리 (parallel stage worktree race 해소) — 설계
|
|
2
|
+
|
|
3
|
+
## 배경 / 문제
|
|
4
|
+
|
|
5
|
+
[2026-06-06 stage worktree 격리 설계](2026-06-06-stage-worktree-isolation-design.md)는 `implementation`
|
|
6
|
+
의 **git 작업**을 stage 별 worktree(`.../<task-id>/stage-<N>/`, 브랜치 `<prefix>-<task-id>-s<N>`)와
|
|
7
|
+
flock registry 예약으로 격리했다. 그러나 **run 산출물/집계 레이어는 격리하지 않았다.**
|
|
8
|
+
|
|
9
|
+
`fontradar-v2-api:dev-9185` 실측: 사용자가 stage-1·stage-2 `implementation` run 을 같은 task-key 로
|
|
10
|
+
동시 실행 → git 커밋(`feat-dev-9185-s2`)은 브랜치로 안전히 분리됐지만, 두 run 이 같은
|
|
11
|
+
`runs/implementation/` 산출물 디렉터리를 공유해 stage-1 executor 가 자기 결과를 수동 백업해야 했다.
|
|
12
|
+
이것이 메모리에 기록된 **"parallel stage worktree race"** 해저드다.
|
|
13
|
+
|
|
14
|
+
## 검증된 현재 메커니즘 (코드 근거)
|
|
15
|
+
|
|
16
|
+
- `RUN_DIR = runs/<task-type>` = `runs/implementation` — 경로에 **stage 세그먼트 없음**
|
|
17
|
+
([paths.py:125](../../../scripts/okstra_ctl/paths.py:125)). 하위 `manifests/ state/ prompts/ reports/
|
|
18
|
+
status/ sessions/ logs/ worker-results/ carry/` 가 전부 task-type 단위로 공유된다.
|
|
19
|
+
- 파일은 seq-named(`-<task-type>-<seq>`)이라 파일명 충돌은 없지만, **seq 가 stage 를 인코딩하지
|
|
20
|
+
않는다** → `final-report-implementation-001.md`(stage2) / `-002.md`(stage1) 처럼 번호↔stage 매핑이
|
|
21
|
+
뒤섞인다.
|
|
22
|
+
- `lead-pane.id` 는 `<RUN_DIR>/state/lead-pane.id` 로 **seq 도 없는 단일 공유 파일**
|
|
23
|
+
([_common-contract.md:34](../../../prompts/profiles/_common-contract.md:34)) → 동시 run 이 서로 덮어써
|
|
24
|
+
pane cleanup 이 엉뚱한 pane 을 닫는다.
|
|
25
|
+
- `consumers.jsonl` 은 **공유 stage 원장**이고 run-root 당 append mutex 를 가진다
|
|
26
|
+
([consumers.py:1](../../../scripts/okstra_ctl/consumers.py:1), [run_context.py:112](../../../scripts/okstra_ctl/run_context.py:112)).
|
|
27
|
+
이것은 **공유가 정상**(stage 간 조율 SSOT)이다.
|
|
28
|
+
- stage 번호는 prepare 시점에 이미 resolve 된다
|
|
29
|
+
([run.py:387 `_resolve_effective_stages`](../../../scripts/okstra_ctl/run.py:387)) → RUN_DIR 계산에
|
|
30
|
+
주입 가능.
|
|
31
|
+
|
|
32
|
+
## 목표 / 비목표
|
|
33
|
+
|
|
34
|
+
### 목표
|
|
35
|
+
- `implementation` run 산출물을 **stage 별로 완전 격리**해, 독립 stage 동시 실행(이미 설계가 의도)이
|
|
36
|
+
산출물 레이어까지 안전하게 만든다.
|
|
37
|
+
- 2026-06-06 설계의 worktree 격리와 **대칭**되게 한다(worktree `stage-<N>/` ↔ run `stage-<N>/`).
|
|
38
|
+
|
|
39
|
+
### 비목표
|
|
40
|
+
- `implementation` 외 task-type(`requirements-discovery` / `error-analysis` /
|
|
41
|
+
`implementation-planning` / `final-verification` / `release-handoff` / `improvement-discovery`)의
|
|
42
|
+
run 경로는 **불변**(stage 개념 없음 → `runs/<task-type>/` 유지).
|
|
43
|
+
- `consumers.jsonl`·registry 를 stage 별로 쪼개지 **않는다** — 이들은 stage 간 조율 SSOT 로 공유 유지.
|
|
44
|
+
- 자동 fan-out·자동 머지 도입 없음(2026-06-06 비목표 계승).
|
|
45
|
+
|
|
46
|
+
## 설계 결정
|
|
47
|
+
|
|
48
|
+
| # | 결정 | 근거 |
|
|
49
|
+
|---|------|------|
|
|
50
|
+
| D1 | `implementation` 의 `RUN_DIR = runs/implementation/stage-<N>/` (stage 세그먼트 삽입). 그 외 task-type 은 `runs/<task-type>/` 그대로. | worktree `stage-<N>/` 와 대칭. stage 는 prepare 시 resolve 됨. |
|
|
51
|
+
| D2 | seq 는 **stage 디렉터리 내부**에서 유지 — `runs/implementation/stage-<N>/reports/final-report-implementation-<seq>.md`. 한 stage 의 재실행(rerun)을 seq 로 구분. | stage 1개 ↔ run 1개지만 rerun 존재. |
|
|
52
|
+
| D3 | `consumers.jsonl` 은 stage 위(부모) `runs/implementation/consumers.jsonl` 에 **공유 유지**. mutex 도 그 위치. | 공유 stage 원장. stage 별로 쪼개면 ready-set 계산 불가. |
|
|
53
|
+
| D4 | `lead-pane.id` 는 stage-격리된 `<RUN_DIR>/state/lead-pane.id` 로 자동 이동(D1 의 부수효과) → 동시 run pane cross-talk 제거. | 단일 공유 파일 문제 해소. |
|
|
54
|
+
| D5 | 비-git/degradation 경로(`skipped-not-git` 등)는 stage 격리 미적용 시 기존 `runs/implementation/` 로 fallback(2026-06-06 degradation 신호 계승). | render-only/non-git 테스트 보존. |
|
|
55
|
+
|
|
56
|
+
## 구현 범위 (개요 — 정확한 sweep 은 plan 에서)
|
|
57
|
+
|
|
58
|
+
1. **`paths.py` `compute_run_paths`** — `task_type == implementation` 이고 stage 가 주어지면
|
|
59
|
+
`run_dir = runs_dir / "implementation" / f"stage-{N}"`. stage 미지정(비-impl)이면 현행 그대로.
|
|
60
|
+
stage 파라미터 추가(부수효과 없음 유지).
|
|
61
|
+
2. **`run.py`** — resolve 한 effective stage 를 `compute_run_paths` 에 전달. `consumers.jsonl` 경로는
|
|
62
|
+
stage 위(부모)로 고정(현행이 run-root 기준이면 위치 보존 확인).
|
|
63
|
+
3. **읽기/집계 측 sweep** — `render.py`, `render_final_report.py`, `report_views.py`,
|
|
64
|
+
`context_cost.py`, `index.py`, `reconcile.py`, `backfill.py`, `workflow.py`, `locks.py` 가
|
|
65
|
+
`runs/<task-type>/...` 를 가정하는 부분을 stage-aware 로. (대부분 ctx 의 `RUN_DIR`/path dict 를
|
|
66
|
+
쓰면 자동 흡수되나, hard-coded `runs/implementation` 문자열은 개별 확인.)
|
|
67
|
+
4. **validators** — `validate-run.py`, `validate_fanout.py`, `validate-workflow.sh`,
|
|
68
|
+
`validators/lib/fixtures.sh` 의 run-경로 가정 갱신.
|
|
69
|
+
5. **contract/skill** — `_common-contract.md` 의 `<RUN_DIR>` placeholder 는 치환이라 무변경 가능성이
|
|
70
|
+
크나, `runs/<task-type>/` 를 직접 적은 문구(report-writer dispatch 경로 등) 확인.
|
|
71
|
+
6. **테스트** — 동시 stage-1/stage-2 run 이 서로 다른 `stage-<N>/` 산출물 트리를 쓰고 `lead-pane.id`
|
|
72
|
+
가 분리되며 `consumers.jsonl` 은 공유됨을 e2e 로 가드. 비-impl task-type 경로 불변 회귀.
|
|
73
|
+
|
|
74
|
+
## 마이그레이션 / 호환
|
|
75
|
+
|
|
76
|
+
- **pre-1.0 무호환 정책**: 기존 `runs/implementation/` 루트에 있던 산출물은 새 reader 가 stage 경로에서
|
|
77
|
+
찾으므로 **이전 위치 보고서는 자동 인식 안 됨**. in-flight task(dev-9185 등)는 수동 정리 또는 재실행
|
|
78
|
+
대상으로 둔다(읽기 fallback 도입하지 않음 — 무호환 정책).
|
|
79
|
+
- 사용자 영향(CHANGES.md): "implementation 산출물이 `runs/implementation/stage-<N>/` 로 stage 별
|
|
80
|
+
격리돼, 같은 task 의 여러 stage 를 동시 실행해도 보고서·state 가 섞이지 않는다."
|
|
81
|
+
|
|
82
|
+
## enforcement 정직성 / 한계
|
|
83
|
+
|
|
84
|
+
- 동시성의 강제는 여전히 **registry flock 예약 + consumers ledger**다(2026-06-06 SSOT). 본 설계는
|
|
85
|
+
그 위에서 **산출물 격리**만 더해 이미 지원되는 동시성을 안전하게 만든다.
|
|
86
|
+
- `consumers.jsonl`·registry 는 의도적으로 공유 — 완전 무공유가 아니다. 격리되는 것은 per-run
|
|
87
|
+
출력(reports/state/worker-results 등)이다.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Lead-Worker 완료 인지: self-scheduled 폴링 설계
|
|
2
|
+
|
|
3
|
+
- 작성일: 2026-06-10
|
|
4
|
+
- 상태: 설계 승인됨 (구현 전, 실측 게이트 미통과)
|
|
5
|
+
- 관련 미구현 항목: [agents/TODO.md](../../../agents/TODO.md) "수정 B — Leader-side 워커 soft timeout", "수정 C 후보 — worker-results 파일 폴링 루프"
|
|
6
|
+
|
|
7
|
+
## 1. 문제 (런타임으로 확정)
|
|
8
|
+
|
|
9
|
+
okstra lead 가 워커를 dispatch 한 뒤, **워커가 작업을 끝냈는데도 lead 가 완료를 인지하지 못하고 정지**한다. lead 는 "완료 통지를 기다립니다" 같은 자연어 상태로 턴을 종료하고, 사용자가 "아직도?" 같은 입력을 **수동으로** 넣어야만 재개된다.
|
|
10
|
+
|
|
11
|
+
런타임 증거 — `fontradar-v2-api:calcule-des-prix-1-1:dev-9185` stage 2 implementation 런 (lead 세션 jsonl `82424fb3-…`):
|
|
12
|
+
|
|
13
|
+
| dispatch | Agent tool_result | 사용자가 수동으로 깨운 입력 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| claude executor (10:15) | `Spawned successfully. agent_id: claude-worker-2@…` | "아직도?" (15:37) |
|
|
16
|
+
| codex verifier (15:55) | `Spawned successfully. agent_id: codex-worker@…` | "아직도?" (16:21) |
|
|
17
|
+
| report-writer (16:26) | `Spawned successfully. agent_id: report-writer@…` | "아지도?" (16:37) |
|
|
18
|
+
|
|
19
|
+
**한 런에서 3번**, 모든 워커 dispatch 마다 발생했다. report-writer 는 dispatch 직후(16:26) 이미 16:33 에 보고서 파일을 다 썼지만, lead 는 사용자의 16:37 입력 전까지 11분간 정지했다. 워커가 *안 끝난 것*이 아니라 워커는 *끝났는데 lead 가 모른 것*이다.
|
|
20
|
+
|
|
21
|
+
## 2. 근본 원인
|
|
22
|
+
|
|
23
|
+
- Claude Code Agent Teams 에서 `Agent(team_name: …)` dispatch 는 **비동기 spawn-and-return** 이다 (teammate = 별도 Claude 인스턴스). 호출은 `Spawned successfully` 만 즉시 반환하고, 완료는 mailbox 의 idle 알림으로 push 되어야 한다.
|
|
24
|
+
- 그러나 okstra 의 dispatch 명세는 **동기 blocking 을 전제**로 작성돼 있다 — [agents/workers/claude-worker.md:89](../../../agents/workers/claude-worker.md) "Agent() call blocks until you return", [agents/SKILL.md:381](../../../agents/SKILL.md) "when the Agent call finally returns".
|
|
25
|
+
- 실험적 기능인 Agent Teams 의 idle 자동 알림이 lead 를 깨우지 못하는 경우가 있다(공식 문서 Limitations "Task status can lag"). 그 누락이 발생하면 lead 를 깨울 이벤트가 사라지고 무한 정지한다.
|
|
26
|
+
- 영향 범위는 **lead 가 띄우는 모든 teammate** 다 (claude / codex / gemini / report-writer). codex/gemini wrapper 의 `BashOutput` 폴링은 *wrapper subagent ↔ CLI* 레이어일 뿐, *lead ↔ wrapper subagent* dispatch 레이어는 별개로 비동기다 (위 표의 codex 행이 증거).
|
|
27
|
+
|
|
28
|
+
## 3. 검토한 대안과 채택 근거
|
|
29
|
+
|
|
30
|
+
공식 문서(`sub-agents.md`, `agent-teams.md`, `headless.md`, `scheduled-tasks.md`) 근거로 세 방향을 비교했다.
|
|
31
|
+
|
|
32
|
+
| 방향 | 병렬 유지 | mailbox 의존 | 양쪽 경로 작동 | 자동(수동 nudge 제거) | 런타임 보장 |
|
|
33
|
+
|---|---|---|---|---|---|
|
|
34
|
+
| A. foreground 동기 dispatch (`team_name` 제거) | ❌ 순차화 | — | ✅ | ✅ | 문서 명시 보장 |
|
|
35
|
+
| B. 워커가 `SendMessage` 로 완료 통지 | ✅ | ❌ idle 알림과 같은 mailbox → 동일 누락 위험 | ❌ | △ | 미보장 (stopped lead auto-resume 문장 부재) |
|
|
36
|
+
| **C. self-scheduled 폴링** (채택) | ✅ | ✅ 무관 (파일 출현으로 판정) | ✅ | ✅ | session-scoped, interactive 전제 |
|
|
37
|
+
|
|
38
|
+
- **방향 B 기각**: "정지한 lead 가 inbound SendMessage 로 auto-resume 한다"는 보장이 문서에 없다. auto-resume 보장은 *부모→자식(stopped subagent)* 방향뿐이다. 게다가 SendMessage 와 idle 알림은 동일한 "Mailbox" 채널이라 같은 누락 위험을 공유한다.
|
|
39
|
+
- **방향 C 채택 가능 근거 (핵심)**: self-scheduled 폴링은 "idle 상태로 살아있는 interactive 세션"에서만 동작하고 headless `claude -p` 에서는 불가하다. 그런데 okstra lead 는 **양쪽 경로 모두 interactive** 다:
|
|
40
|
+
- okstra.sh spawn 경로: [scripts/okstra.sh:173-175](../../../scripts/okstra.sh) 가 `claude --model … --session-id … "$PROMPT"` 를 `exec` 한다. `-p`/`--print` 가 **없다** → 대화형 세션, 턴 종료 후 idle 로 생존.
|
|
41
|
+
- in-session(`okstra-run`) 경로: 사용자의 대화형 세션 안에서 동작.
|
|
42
|
+
- 방향 C 는 병렬 유지 + mailbox 무관 + 양쪽 경로 + 수동 nudge 제거를 모두 만족하는 유일한 후보다.
|
|
43
|
+
|
|
44
|
+
## 4. 설계
|
|
45
|
+
|
|
46
|
+
### 4.1 메커니즘
|
|
47
|
+
|
|
48
|
+
lead 가 워커를 (기존대로) 비동기 dispatch 한 뒤:
|
|
49
|
+
|
|
50
|
+
1. 자기 자신을 주기적으로 깨우는 **단일 스케줄**을 건다 (Monitor 툴 우선, cron 폴백 — 4.4 참조).
|
|
51
|
+
2. 턴을 종료한다.
|
|
52
|
+
3. 스케줄이 lead 를 깨울 때마다, dispatch 한 워커들의 `worker-results` 파일 출현 + 헤더 검증으로 **완료를 직접 확인**한다 (mailbox/idle 알림에 의존하지 않는다).
|
|
53
|
+
4. 미완이면 다시 깨우도록 두고, 종료 조건 충족 시 스케줄을 해제하고 다음 phase 로 진행한다.
|
|
54
|
+
|
|
55
|
+
### 4.2 복수 워커 처리
|
|
56
|
+
|
|
57
|
+
Phase 4/5 는 보통 claude·codex·gemini 를 **병렬 N개** 띄운다. 워커가 몇 개든:
|
|
58
|
+
|
|
59
|
+
- **스케줄은 하나만** 건다. 워커마다 스케줄을 거는 것이 아니라, **하나의 wakeup 이 매번 N개 결과 파일 전체를 확인**한다.
|
|
60
|
+
- 추적 대상 = lead 가 dispatch 한 워커 전원의 `**Result Path:**` 집합 (이미 run-manifest / launch 프롬프트에 존재).
|
|
61
|
+
- 매 wakeup: 미완 집합의 각 파일을 확인 → 출현 + 헤더 검증 통과한 워커는 완료 집합으로 이동.
|
|
62
|
+
- in-process claude · CLI wrapper codex/gemini 혼합이든, 전부 "결과 파일 출현"이라는 단일 신호로 통일 감지한다. 파일 경로만 다를 뿐 폴링 로직은 N 에 무관하게 동일하다.
|
|
63
|
+
- 동일 패턴이 Phase 5.5 convergence 라운드(라운드마다 가변 워커 집합)에도 그대로 적용된다.
|
|
64
|
+
|
|
65
|
+
### 4.3 종료 lifecycle (BLOCKING)
|
|
66
|
+
|
|
67
|
+
스케줄을 반드시 해제해야 한다 — 해제하지 않으면 cron 이 7일 만료까지 좀비로 발화하며 토큰을 태우고 다음 런까지 방해한다.
|
|
68
|
+
|
|
69
|
+
| 상황 | 동작 |
|
|
70
|
+
|---|---|
|
|
71
|
+
| 전원 완료 (미완 집합이 빔) | **스케줄 즉시 해제** → 다음 phase 진행 |
|
|
72
|
+
| 부분 완료 | 미완 워커만 계속 대기 (재예약) |
|
|
73
|
+
| 워커별 deadline 초과 | 해당 워커를 `timeout` 으로 기록 → 미완 집합에서 제거 → redispatch 또는 진행 |
|
|
74
|
+
| 에러 / 중단 | 어떤 경로로 끝나든 **스케줄 반드시 해제** (좀비 방지) |
|
|
75
|
+
|
|
76
|
+
- **워커별 soft timeout**: codex/gemini 는 claude 보다 느릴 수 있으므로 deadline 은 워커별이다. [agents/TODO.md:121-153](../../../agents/TODO.md) 의 task-type 별 예상 duration 표(요구사항-탐색 10분, 오류-분석 15분, 구현-계획 20분 등 × 2배)를 그대로 deadline 산정에 사용한다. 즉 미구현 "수정 B" 가 방향 C 의 deadline 조건으로 통합된다 — 별도 메커니즘이 아니다.
|
|
77
|
+
- cron 7일 만료는 최후 백스톱일 뿐 정상 해제 경로가 아니다.
|
|
78
|
+
|
|
79
|
+
### 4.4 메커니즘 선택: Monitor vs cron
|
|
80
|
+
|
|
81
|
+
- **Monitor 툴(우선 후보)**: 완료를 stdout 으로 내보내는 background 스크립트를 스트리밍 감시 → 폴링 자체를 없앰. 매 iteration 마다 전체 프롬프트를 재실행하는 cron 보다 토큰·캐시 효율이 높고 반응이 빠르다.
|
|
82
|
+
- **cron / `/loop`(폴백)**: 최소 granularity 1분, jitter 는 인터벌의 최대 절반. 고정 인터벌이면 2~5분, 워커가 10~20분 걸리므로 self-paced(`/loop` bare) 가 토큰 효율적.
|
|
83
|
+
- 최종 선택은 §5 실측 게이트 결과로 확정한다.
|
|
84
|
+
|
|
85
|
+
## 5. 검증 게이트 (Rule 6 — 구현 1단계, BLOCKING)
|
|
86
|
+
|
|
87
|
+
지금까지의 결론은 전부 **공식 문서 분석 + 코드 확인 기반 정적 결론(미실행)** 이다. 구현의 첫 단계는 다음을 interactive 세션에서 **실측**하는 것이다:
|
|
88
|
+
|
|
89
|
+
1. lead 가 dispatch 한 비동기 워커(teammate/background subagent)가 별도 세션에서 도는 동안, Monitor/cron self-wakeup 이 lead 를 자동 재개시키는가.
|
|
90
|
+
2. 깨어난 lead 가 그 워커의 결과 파일 출현을 Bash 로 감지할 수 있는가.
|
|
91
|
+
3. Monitor 와 cron 중 어느 쪽이 실제로 동작하며 토큰 효율이 나은가.
|
|
92
|
+
|
|
93
|
+
이 실측이 통과하기 전에는 SKILL 명세 변경을 확정하지 않는다. 실패 시 폴백은 방향 A(report-writer 등 단일 워커는 `team_name` 없는 foreground 동기 dispatch)이며, 이는 문서가 명시적으로 보장하는 유일한 경로다.
|
|
94
|
+
|
|
95
|
+
> **갱신 (2026-06-10): 게이트 통과.** 실측 결과 채택 메커니즘은 cron/Monitor 가 아니라 **`Bash run_in_background` + `until` 루프**로 확정됐다. harness-tracked background 완료가 정지 lead 를 자동 재개시키며(실험 1), 단일 background 폴링이 복수 워커 결과 파일을 추적한다(실험 2). background task 는 완료 시 자가 소멸하므로 §4.3 의 "스케줄 해제 / 좀비 cron 방지" 부담이 소멸하고, §4.4 의 Monitor/cron 은 대안으로 격하된다. 상세: [실측 기록](../plans/2026-06-10-lead-worker-completion-polling-PROBE.md).
|
|
96
|
+
|
|
97
|
+
## 6. 변경 범위 (영향 파일)
|
|
98
|
+
|
|
99
|
+
- [agents/SKILL.md](../../../agents/SKILL.md) — Phase 4/5/6 dispatch 후 "self-scheduled 폴링으로 완료 인지" 루프 명세 추가. 동기 전제 문구(:381 "when the Agent call finally returns") 정정.
|
|
100
|
+
- [agents/workers/claude-worker.md:89](../../../agents/workers/claude-worker.md) — "Agent() call blocks until you return" 동기 전제 정정.
|
|
101
|
+
- [skills/okstra-report-writer/SKILL.md](../../../skills/okstra-report-writer/SKILL.md) — Phase 6 dispatch 후 완료 폴링 명세.
|
|
102
|
+
- [skills/okstra-team-contract/SKILL.md](../../../skills/okstra-team-contract/SKILL.md) — terminal status / soft timeout 규칙 보강.
|
|
103
|
+
- [skills/okstra-convergence/SKILL.md](../../../skills/okstra-convergence/SKILL.md) — 라운드별 reverify 집합 폴링 적용.
|
|
104
|
+
- [templates/reports/settings.template.json](../../../templates/reports/settings.template.json) — cron/Monitor 관련 도구 권한 seed (필요 시).
|
|
105
|
+
- [agents/TODO.md](../../../agents/TODO.md) — "수정 B" / "수정 C 후보" 를 본 설계로 해소·통합.
|
|
106
|
+
|
|
107
|
+
변경은 모두 **명세(프롬프트/SKILL) 레이어** 중심이며, 동기 전제를 비동기-폴링 모델로 정정하는 것이 핵심이다. 사용자 머신 전파를 위해 seed/template 파일에 반영한다 (personal `.claude/` 아님).
|
|
108
|
+
|
|
109
|
+
## 7. 미해결 / 리스크
|
|
110
|
+
|
|
111
|
+
- 프롬프트 캐시 TTL 의 구체 수치는 공식 문서에 없어 미확인 — 폴링 간격 최적값은 실측으로 조정.
|
|
112
|
+
- Monitor 툴이 별도-세션 워커의 완료를 감지하는 정확한 방식(파일 watch 스크립트 형태)은 실측 단계에서 확정.
|
|
113
|
+
- in-session 경로에서 lead 가 okstra 스킬 흐름 한가운데 cron 을 걸 때, wakeup 프롬프트가 okstra phase 흐름을 자연스럽게 이어가도록 self-describing 해야 한다 (구현 plan 에서 설계).
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED