okstra 0.8.0 → 0.9.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 (37) hide show
  1. package/README.kr.md +14 -3
  2. package/README.md +14 -3
  3. package/docs/kr/architecture.md +8 -3
  4. package/docs/kr/cli.md +55 -1
  5. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +638 -0
  6. package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +131 -0
  7. package/package.json +1 -1
  8. package/runtime/BUILD.json +2 -2
  9. package/runtime/agents/SKILL.md +13 -0
  10. package/runtime/agents/workers/claude-worker.md +2 -0
  11. package/runtime/agents/workers/codex-worker.md +2 -0
  12. package/runtime/agents/workers/gemini-worker.md +2 -0
  13. package/runtime/agents/workers/report-writer-worker.md +1 -0
  14. package/runtime/prompts/launch.template.md +11 -0
  15. package/runtime/prompts/profiles/implementation.md +10 -0
  16. package/runtime/prompts/profiles/release-handoff.md +97 -0
  17. package/runtime/python/lib/okstra/cli.sh +1 -1
  18. package/runtime/python/okstra_ctl/render.py +9 -2
  19. package/runtime/python/okstra_ctl/run.py +30 -0
  20. package/runtime/python/okstra_ctl/workflow.py +30 -2
  21. package/runtime/python/okstra_ctl/worktree.py +235 -0
  22. package/runtime/skills/okstra-context-loader/SKILL.md +1 -1
  23. package/runtime/skills/okstra-convergence/SKILL.md +11 -5
  24. package/runtime/skills/okstra-report-finder/SKILL.md +1 -0
  25. package/runtime/skills/okstra-report-writer/SKILL.md +6 -0
  26. package/runtime/skills/okstra-run/SKILL.md +2 -1
  27. package/runtime/skills/okstra-status/SKILL.md +3 -1
  28. package/runtime/skills/okstra-team-contract/SKILL.md +19 -0
  29. package/runtime/skills/okstra-time-summary/SKILL.md +1 -0
  30. package/runtime/templates/reports/error-analysis-input.template.md +1 -0
  31. package/runtime/templates/reports/final-report.template.md +129 -18
  32. package/runtime/templates/reports/implementation-input.template.md +1 -0
  33. package/runtime/templates/reports/implementation-planning-input.template.md +1 -0
  34. package/runtime/templates/reports/quick-input.template.md +1 -0
  35. package/runtime/templates/reports/release-handoff-input.template.md +73 -0
  36. package/runtime/templates/reports/task-brief.template.md +5 -0
  37. package/runtime/validators/validate-run.py +6 -1
@@ -0,0 +1,235 @@
1
+ """Implementation-phase git worktree provisioning.
2
+
3
+ Implementation runs operate on an isolated git worktree rooted under
4
+ `~/.okstra/worktrees/<project_id>/<task_group_segment>/<task_id_segment>-<run_seq>`.
5
+ The executor mutates files there; verifiers read from the same path.
6
+ The worktree is always kept after the run for inspection, manual PR
7
+ authoring, and rollback verification.
8
+
9
+ Pre-conditions handled here:
10
+ - Skip non-`implementation` task-types entirely.
11
+ - Skip when `project_root` itself already sits inside a non-main git
12
+ worktree (the run reuses the caller's working tree).
13
+ - Refuse to clobber an existing path or branch — raise PrepareError.
14
+
15
+ Side effects: `git worktree add -b <branch> <path> <base_ref>` is invoked
16
+ in `project_root`. The function does NOT chdir.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import os
21
+ import subprocess
22
+ from dataclasses import dataclass
23
+ from pathlib import Path
24
+ from typing import Optional
25
+
26
+
27
+ OKSTRA_WORKTREES_RELATIVE = Path(".okstra/worktrees")
28
+
29
+
30
+ # Work-category → short branch prefix. Mirrors the values accepted by
31
+ # `--work-category` (bugfix / feature / refactor / ops / improvement) and
32
+ # falls back to `task` when the category is unset or unrecognised.
33
+ _WORK_CATEGORY_PREFIX = {
34
+ "feature": "feat",
35
+ "bugfix": "fix",
36
+ "refactor": "refactor",
37
+ "ops": "ops",
38
+ "improvement": "improve",
39
+ "docs": "doc",
40
+ "doc": "doc",
41
+ }
42
+
43
+
44
+ @dataclass
45
+ class WorktreeProvision:
46
+ """Result of `provision_implementation_worktree`.
47
+
48
+ status:
49
+ - "created": fresh worktree at `path` on `branch`
50
+ - "skipped-non-implementation": task-type was not `implementation`
51
+ - "skipped-in-worktree": project_root is already inside a non-main
52
+ worktree; the run reuses `project_root` and no new worktree is
53
+ materialised
54
+ - "skipped-not-git": project_root has no `.git` (worktree path
55
+ cannot be provisioned; degrade gracefully)
56
+ """
57
+ status: str
58
+ path: str = "" # absolute path of the executor worktree (or project_root when reused)
59
+ branch: str = "" # branch checked out in the worktree (empty when reused / not-git)
60
+ base_ref: str = "" # commit SHA the worktree was branched from (empty when not created)
61
+ note: str = "" # human-readable explanation, surfaced in team-state / manifests
62
+
63
+
64
+ def _work_category_prefix(work_category: str) -> str:
65
+ key = (work_category or "").strip().lower()
66
+ return _WORK_CATEGORY_PREFIX.get(key, "task")
67
+
68
+
69
+ def _git(project_root: Path, *args: str) -> subprocess.CompletedProcess:
70
+ return subprocess.run(
71
+ ["git", "-C", str(project_root), *args],
72
+ capture_output=True, text=True, check=False,
73
+ )
74
+
75
+
76
+ def _is_inside_non_main_worktree(project_root: Path) -> bool:
77
+ """True iff project_root is inside a git worktree that is NOT the
78
+ repository's main checkout. Detection rule: `--git-dir` (per-worktree
79
+ .git pointer) differs from `--git-common-dir` (shared object store).
80
+ """
81
+ common = _git(project_root, "rev-parse", "--git-common-dir")
82
+ per_tree = _git(project_root, "rev-parse", "--git-dir")
83
+ if common.returncode != 0 or per_tree.returncode != 0:
84
+ return False
85
+ # Both paths can be relative to project_root; resolve before compare.
86
+ common_abs = (project_root / common.stdout.strip()).resolve()
87
+ per_tree_abs = (project_root / per_tree.stdout.strip()).resolve()
88
+ return common_abs != per_tree_abs
89
+
90
+
91
+ def _is_git_repo(project_root: Path) -> bool:
92
+ res = _git(project_root, "rev-parse", "--is-inside-work-tree")
93
+ return res.returncode == 0 and res.stdout.strip() == "true"
94
+
95
+
96
+ def _branch_exists(project_root: Path, branch: str) -> bool:
97
+ res = _git(project_root, "rev-parse", "--verify", "--quiet", f"refs/heads/{branch}")
98
+ return res.returncode == 0
99
+
100
+
101
+ def _head_sha(project_root: Path) -> str:
102
+ res = _git(project_root, "rev-parse", "HEAD")
103
+ if res.returncode != 0:
104
+ return ""
105
+ return res.stdout.strip()
106
+
107
+
108
+ def compute_worktree_path(
109
+ *,
110
+ project_id: str,
111
+ task_group_segment: str,
112
+ task_id_segment: str,
113
+ run_seq: int,
114
+ ) -> Path:
115
+ """Pure path computation. Mirrors `okstra_root` location convention.
116
+
117
+ Uses `OKSTRA_HOME` when set (test hook), else `~/.okstra`.
118
+ """
119
+ okstra_home = os.environ.get("OKSTRA_HOME", "").strip()
120
+ base = Path(okstra_home) if okstra_home else (Path.home() / ".okstra")
121
+ return (
122
+ base / "worktrees" / project_id
123
+ / task_group_segment / f"{task_id_segment}-{int(run_seq):03d}"
124
+ )
125
+
126
+
127
+ def compute_branch_name(
128
+ *,
129
+ work_category: str,
130
+ task_id_segment: str,
131
+ run_seq: int,
132
+ ) -> str:
133
+ return f"{_work_category_prefix(work_category)}-{task_id_segment}-{int(run_seq):03d}"
134
+
135
+
136
+ def provision_implementation_worktree(
137
+ *,
138
+ task_type: str,
139
+ project_root: Path,
140
+ project_id: str,
141
+ task_group_segment: str,
142
+ task_id_segment: str,
143
+ run_seq: int,
144
+ work_category: str,
145
+ ) -> WorktreeProvision:
146
+ """Materialise (or skip) the executor worktree for this run.
147
+
148
+ The caller passes the same `run_seq` used by the reports/manifests
149
+ artefacts so the worktree directory is colocated by sequence number.
150
+
151
+ Raises:
152
+ PrepareError-like RuntimeError when worktree creation fails
153
+ (path clash, branch clash, `git worktree add` non-zero). The
154
+ caller (`run.py`) catches and re-raises as PrepareError to keep
155
+ a single error surface.
156
+ """
157
+ if task_type != "implementation":
158
+ return WorktreeProvision(
159
+ status="skipped-non-implementation",
160
+ path=str(project_root),
161
+ note="worktree provisioning skipped: task-type is not 'implementation'",
162
+ )
163
+
164
+ if not _is_git_repo(project_root):
165
+ return WorktreeProvision(
166
+ status="skipped-not-git",
167
+ path=str(project_root),
168
+ note=(
169
+ "worktree provisioning skipped: project_root is not inside a git "
170
+ "repository; executor will operate directly on project_root"
171
+ ),
172
+ )
173
+
174
+ if _is_inside_non_main_worktree(project_root):
175
+ return WorktreeProvision(
176
+ status="skipped-in-worktree",
177
+ path=str(project_root),
178
+ note=(
179
+ "worktree provisioning skipped: project_root is already inside a "
180
+ "non-main git worktree; executor reuses the caller's worktree"
181
+ ),
182
+ )
183
+
184
+ worktree_path = compute_worktree_path(
185
+ project_id=project_id,
186
+ task_group_segment=task_group_segment,
187
+ task_id_segment=task_id_segment,
188
+ run_seq=run_seq,
189
+ )
190
+ branch = compute_branch_name(
191
+ work_category=work_category,
192
+ task_id_segment=task_id_segment,
193
+ run_seq=run_seq,
194
+ )
195
+
196
+ if worktree_path.exists():
197
+ raise RuntimeError(
198
+ f"executor worktree path already exists: {worktree_path}. "
199
+ "Remove it with `git worktree remove <path>` (or `rm -rf` if it is "
200
+ "not a registered worktree) before retrying this implementation run."
201
+ )
202
+ if _branch_exists(project_root, branch):
203
+ raise RuntimeError(
204
+ f"executor worktree branch already exists: {branch}. "
205
+ "Delete it (`git branch -D <branch>`) or bump OKSTRA_RUN_SEQ_OVERRIDE "
206
+ "before retrying."
207
+ )
208
+
209
+ base_ref = _head_sha(project_root)
210
+ if not base_ref:
211
+ raise RuntimeError(
212
+ "could not resolve HEAD sha in project_root; cannot create worktree"
213
+ )
214
+
215
+ worktree_path.parent.mkdir(parents=True, exist_ok=True)
216
+ res = _git(
217
+ project_root,
218
+ "worktree", "add", "-b", branch, str(worktree_path), base_ref,
219
+ )
220
+ if res.returncode != 0:
221
+ raise RuntimeError(
222
+ f"`git worktree add` failed (exit={res.returncode}): "
223
+ f"{(res.stderr or res.stdout).strip()}"
224
+ )
225
+
226
+ return WorktreeProvision(
227
+ status="created",
228
+ path=str(worktree_path),
229
+ branch=branch,
230
+ base_ref=base_ref,
231
+ note=(
232
+ f"executor worktree created at {worktree_path} on branch {branch} "
233
+ f"(base {base_ref[:12]})"
234
+ ),
235
+ )
@@ -40,7 +40,7 @@ task-manifest.json is the canonical metadata source. The following fields must b
40
40
  | `projectId` | Project ID |
41
41
  | `taskGroup` | Task group |
42
42
  | `taskId` | Task ID |
43
- | `taskType` | Analysis type (requirements-discovery, error-analysis, final-verification, implementation-planning) |
43
+ | `taskType` | Analysis type (requirements-discovery, error-analysis, implementation-planning, implementation, final-verification, release-handoff) |
44
44
  | `workCategory` | bugfix / feature / improvement / refactor / ops-change / unknown |
45
45
  | `recommendedWorkers` | List of selected workers |
46
46
  | `currentStatus` | Current task status |
@@ -37,12 +37,18 @@ Configure this in the `convergence` block of `task-manifest.json`. If the block
37
37
 
38
38
  Read the worker result files generated in Phase 4/5 and extract individual findings.
39
39
 
40
- 1. In the "Findings" section of each worker's results, identify individual items by number (F-001, F-002, ...).
41
- 2. For each finding, record the summary, evidence (file path, line number, basis), and the worker who identified it.
42
- 3. Claude Lead groups findings based on semantic similarity:
43
- - When 2 or more workers report the same or similar findings immediately reach `full consensus`
44
- - Only one worker confirms `unique`, enter the verification queue
40
+ 1. In the "Findings" section of each worker's results, identify individual items by number (F-001, F-002, ...) and parse the ticket identifier attached to each item:
41
+ - For table-form findings, read the `Ticket ID` column.
42
+ - For bullet/numbered findings, parse `[TICKETID: <id>]` from the item title.
43
+ - Items with multiple tickets (e.g. `TICKET-123, TICKET-456`) expand to a set of ticket keys.
44
+ - Items tagged `unknown` keep the literal `unknown` as their ticket key.
45
+ 2. For each finding, record the summary, evidence (file path, line number, basis), the worker who identified it, and the parsed ticket set.
46
+ 3. Claude Lead groups findings based on semantic similarity AND ticket-set equality:
47
+ - Same semantics + same ticket set across 2+ workers → immediately reach `full consensus`.
48
+ - Same semantics but disjoint ticket sets → keep as separate groups (do NOT over-merge across tickets).
49
+ - Only one worker confirms a finding → `unique`, enter the verification queue.
45
50
  4. When grouping is ambiguous, prefer splitting over merging (avoid over-merging).
51
+ 5. Persist each finding's ticket set in the convergence state artifact under a `ticketIds` field on the finding record. Re-verification rounds carry the same field forward.
46
52
 
47
53
  ### Round 1-N: Re-verification Loop
48
54
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: okstra-report-finder
3
3
  description: Use when the user provides a task key and needs to find the final report path, or wants to read a previous okstra report to continue work based on its findings. Trigger words include "find report", "show report for", "read the okstra report", "continue from report".
4
+ user-invocable: false
4
5
  ---
5
6
 
6
7
  # OKSTRA Report Finder
@@ -172,6 +172,12 @@ The Korean translation in parentheses is optional but the English keyword is man
172
172
 
173
173
  The final-report template `okstra-final-report.template.md` Section 4.5 already encodes this contract — copy that block verbatim and fill in.
174
174
 
175
+ ### Release-handoff section contract (release-handoff runs only)
176
+
177
+ When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 4.6 Release Handoff Deliverables` with all seven sub-sections (`4.6.1` Source Verification Report, `4.6.2` Feature Branch & Working-Tree State, `4.6.3` User Selections, `4.6.4` Executed Commands, `4.6.5` Commit List, `4.6.6` Pull Request Outcome, `4.6.7` Routing Recommendation). The drafter does **not** invent values for these sub-sections — every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. If the user picked `skip` (H1) or `cancel` (H3), keep 4.6.3 populated but leave 4.6.4–4.6.6 explicitly empty per the template's empty-state lines.
178
+
179
+ The final-report template `okstra-final-report.template.md` Section 4.6 already encodes this contract — copy that block verbatim and fill in. For non-`release-handoff` runs, omit Section 4.6 entirely.
180
+
175
181
  ### Mandatory worker-results file (BLOCKING)
176
182
 
177
183
  You (the report-writer-worker subagent) MUST also write a worker-results audit file at the path the lead provides as `**Worker Result Path:**`, defaulting to:
@@ -116,7 +116,7 @@ Validate that slugified `task_group` and `task_id` each contain at least one alp
116
116
 
117
117
  ## Step 4: Choose task-type
118
118
 
119
- `AskUserQuestion` with five fixed options:
119
+ `AskUserQuestion` with six fixed options:
120
120
 
121
121
  | Option | Description |
122
122
  |---|---|
@@ -125,6 +125,7 @@ Validate that slugified `task_group` and `task_id` each contain at least one alp
125
125
  | `implementation-planning` | Plan options + request user approval |
126
126
  | `implementation` | Execute approved plan (requires `--approved-plan`) |
127
127
  | `final-verification` | Acceptance + residual-risk review |
128
+ | `release-handoff` | Drive commit / push / PR with user-selected actions after `accepted` final-verification |
128
129
 
129
130
  For existing tasks, present `nextRecommendedPhase` as the first option (recommended default).
130
131
 
@@ -128,6 +128,7 @@ Output format:
128
128
  - `implementation-planning`: `<state>`
129
129
  - `implementation`: `<state>`
130
130
  - `final-verification`: `<state>`
131
+ - `release-handoff`: `<state>`
131
132
 
132
133
  ### Safe Resume Checkpoint
133
134
 
@@ -147,7 +148,8 @@ The status response always includes one of the following options:
147
148
  2. **Restart current phase**
148
149
  - Indicates whether the task can be re-run with the same `task-key` and the current `taskType`.
149
150
  3. **Start next phase**
150
- - If `workflow.nextRecommendedPhase` is one of `error-analysis`, `implementation-planning`, or `final-verification`, that phase is proposed as the next candidate for the Okstra run.
151
+ - If `workflow.nextRecommendedPhase` is one of `error-analysis`, `implementation-planning`, `final-verification`, or `release-handoff`, that phase is proposed as the next candidate for the Okstra run.
152
+ - If `nextRecommendedPhase` is `pending-release-handoff`, the prior `final-verification` run completed but its verdict still has to be inspected before entering `release-handoff` — surface this as a verdict-gated next step and present `release-handoff` as a candidate only when the cited verdict is `accepted`.
151
153
  4. **Need more information**
152
154
  - If `nextRecommendedPhase` is `pending-routing-decision` or `routingStatus` is `pending`, this indicates that additional information is required.
153
155
 
@@ -209,6 +209,25 @@ A successful worker result must include the following sections in this exact ord
209
209
 
210
210
  Code evidence must include file paths and line numbers.
211
211
 
212
+ ### Ticket Tagging (mandatory for sections 1–5)
213
+
214
+ Every item in sections 1–5 MUST be tagged with the ticket(s) it relates to. This applies whenever the run's task type is `requirements-discovery`, `error-analysis`, `implementation-planning`, or `implementation`.
215
+
216
+ - **Table-form items**: include a `Ticket ID` column. The column is placed immediately after the row-ID column (e.g. after `F-001`, `M-001`).
217
+ - **Bullet / numbered-list items**: prepend `[TICKETID: <id>]` to the item title, immediately after the row ID and before the body text. Example: `- F-001 [TICKETID: TICKET-123] — <summary> (path:line)`.
218
+ - **Section headers in the final report** (e.g. `### 4.5.3 Recommended Option`): append `[TICKETID: <id>]` to the header when the section is scoped to a specific ticket. Headers that span all tickets in the run omit the tag.
219
+
220
+ Ticket ID fill rule (in order):
221
+
222
+ 1. Use the `Issue / Ticket` value from the run's input template.
223
+ 2. If empty, fall back to the `Task ID` value (no prefix; write `8852` not `task:8852`).
224
+ 3. If both are absent, write `unknown`. This is allowed but signals an input-template defect — the worker SHOULD also record a `Missing Information` item noting the absent identifier.
225
+ 4. When a single item maps to multiple tickets, separate them with commas: `TICKET-123, TICKET-456`. Ticket IDs containing commas are not supported.
226
+
227
+ Workers MUST apply these rules to every item in sections 1–5. Lead and report-writer MUST preserve the tagging when carrying worker findings into the final report.
228
+
229
+ For phases other than the four listed above (e.g. `release-handoff`, `final-verification`), ticket tagging is optional.
230
+
212
231
  ### Optional errors sidecar (worker-reported)
213
232
 
214
233
  A worker MAY produce an errors sidecar file at:
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: okstra-time-summary
3
3
  description: Use when the user asks how long an okstra task took, time spent per task type, per-worker elapsed time, or for a duration/runtime breakdown of a specific task-id. Trigger words include "작업 시간", "소요 시간", "time summary", "duration", "elapsed", "얼마나 걸렸", "시간 분석".
4
+ user-invocable: false
4
5
  ---
5
6
 
6
7
  # OKSTRA Time Summary
@@ -7,6 +7,7 @@
7
7
  - Task ID:
8
8
  - Related Tasks:
9
9
  - Issue / Ticket:
10
+ - 값이 비면 워커는 `Task ID`로 폴백한다 (prefix 없이 `8852`처럼). 한 run이 여러 ticket을 동시에 다루면 콤마로 구분 (`TICKET-123, TICKET-456`). 어느 쪽으로도 식별 불가하면 `unknown`을 허용한다.
10
11
  - Task Type: `error-analysis`
11
12
  - Requested Outcome:
12
13
 
@@ -28,6 +28,23 @@
28
28
  - Summarize the core problem, requirement, or verification target in 3 to 5 bullets.
29
29
  - Base the summary on the brief, source materials, and worker results.
30
30
 
31
+ ## Ticket Coverage
32
+
33
+ 이 run이 다룬 ticket을 한 자리에서 확인하는 인덱스 표입니다. 본 보고서의 본문 항목들은 모두 `Ticket ID` 컬럼 또는 `[TICKETID: <id>]` 태그로 ticket과 묶여 있으며, 이 표는 그 역방향 인덱스입니다.
34
+
35
+ - 한 run이 단일 ticket만 다루는 경우: 표 대신 다음 한 줄로 대체할 수 있습니다 — `- Single ticket run: <TICKET-or-task-fallback>`
36
+ - 다중 ticket이거나, `Issue / Ticket`이 비어 `Task ID` 폴백을 쓴 항목이 섞여 있는 경우: 표를 채웁니다.
37
+
38
+ | Ticket ID | 등장 섹션 | 관련 항목 IDs |
39
+ |-----------|-----------|---------------|
40
+ | `<TICKET-123>` | `1.1, 3.1, 4.5.4` | `F-001, F-003, A1` |
41
+
42
+ 규칙:
43
+
44
+ - `Ticket ID` 컬럼은 본문에서 등장한 ticket 키와 정확히 동일한 문자열을 사용합니다. `Issue / Ticket`이 비어 폴백된 경우 `Task ID` 값을 prefix 없이 그대로 적습니다 (예: `8852`). 어느 쪽으로도 식별 불가한 경우 `unknown`을 사용합니다.
45
+ - `등장 섹션`은 본 보고서의 섹션 번호를 콤마로 구분합니다. 동일 ticket이 여러 섹션에 등장하면 모두 나열합니다.
46
+ - `관련 항목 IDs`는 `F-001`, `M-002`, `A1`, `Q1` 같은 row ID를 콤마로 나열합니다. 섹션 헤더 단위로만 ticket이 표시된 경우(개별 row ID가 없는 경우)에는 헤더 번호 자체를 적습니다 (예: `4.5.3`).
47
+
31
48
  ## Execution Status by Agent
32
49
  - Summarize the status, assigned model, and key finding for each worker.
33
50
  - Do not replace worker outputs with unsupported claims.
@@ -46,11 +63,20 @@
46
63
 
47
64
  ## 1. Cross Verification Results
48
65
  ### 1.1 Consensus
49
- - Record the conclusions and evidence that multiple workers support.
66
+
67
+ | ID | Ticket ID | Statement | Supporting workers | Evidence (path:line / log / worker report) |
68
+ |----|-----------|-----------|--------------------|---------------------------------------------|
69
+ | C-001 | `<TICKET-or-fallback>` | <합의된 결론> | claude, codex, gemini | <증거 위치> |
70
+
71
+ - 합의된 결론을 row마다 기록합니다. `Ticket ID`는 본 보고서 상단 `Ticket Coverage` 규칙을 따릅니다.
50
72
 
51
73
  ### 1.2 Differences
52
- - Record meaningful differences in conclusions, interpretation, or evidence handling.
53
- - If there is no meaningful difference, state that clearly.
74
+
75
+ | ID | Ticket ID | Disagreement | Workers (position) | Evidence |
76
+ |----|-----------|--------------|--------------------|----------|
77
+ | D-001 | `<TICKET-or-fallback>` | <차이 요약> | claude (A) / codex (B) / gemini (-) | <증거 위치> |
78
+
79
+ - 유의미한 차이가 없을 경우 표 대신 다음 한 줄을 적습니다 — `- 유의미한 차이 없음. 1.1 Consensus가 그대로 유효합니다.`
54
80
 
55
81
  ## 2. Final Verdict
56
82
  - State the final conclusion clearly.
@@ -58,14 +84,26 @@
58
84
 
59
85
  ## 3. Evidence and Detailed Analysis
60
86
  ### 3.1 Primary Evidence
61
- - Cite concrete evidence such as file paths, line numbers, brief contents, logs, or worker reports.
87
+
88
+ | ID | Ticket ID | Evidence | Source (path:line / log / worker report) |
89
+ |----|-----------|----------|------------------------------------------|
90
+ | E-001 | `<TICKET-or-fallback>` | <증거 한 줄 요약> | <출처> |
62
91
 
63
92
  ### 3.2 Secondary Evidence or Alternate Interpretations
64
- - Record supporting evidence, alternate hypotheses, or lower-confidence interpretations when relevant.
93
+
94
+ | ID | Ticket ID | Hypothesis or supporting evidence | Source / confidence |
95
+ |----|-----------|-----------------------------------|---------------------|
96
+ | S-001 | `<TICKET-or-fallback>` | <보조 증거 또는 대안 해석> | <출처 + low/mid> |
97
+
98
+ - 해당 없음 시: `- 보조 증거 또는 대안 해석 없음.`
65
99
 
66
100
  ## 4. Missing Information and Risks
67
- - Explicitly state any item that requires `I don't know` or `uncertain`.
68
- - Record the missing information and risks that weaken the current conclusion.
101
+
102
+ | ID | Ticket ID | Item | Risk if ignored |
103
+ |----|-----------|------|-----------------|
104
+ | R-001 | `<TICKET-or-fallback>` | <누락 정보 또는 불확실 항목> | <무시할 때의 위험> |
105
+
106
+ - `I don't know` / `uncertain`으로 표기해야 하는 항목은 모두 표 안에 두고 본문 산문 형식으로 흩지 않습니다.
69
107
 
70
108
  ## 4.5 Implementation Plan Deliverables (implementation-planning runs only)
71
109
 
@@ -75,7 +113,11 @@
75
113
 
76
114
  ### 4.5.1 Option Candidates (옵션 후보)
77
115
  - 최소 두 개의 구현 옵션을 제시합니다. 각 옵션마다 다음을 포함합니다.
78
- - **File Structure**: `Create: <path> — <responsibility>` / `Modify: <path>:<line-range> — <change summary>` / `Delete: <path> — <reason>` 형식으로 파일 단위 책임을 한 줄씩 명시합니다.
116
+ - **File Structure**: 다음 형식으로 파일 단위 책임을 한 줄씩 명시합니다. 행마다 `Ticket ID` 컬럼을 채웁니다.
117
+
118
+ | ID | Ticket ID | Action | Path (and line-range) | Change summary |
119
+ |----|-----------|--------|------------------------|----------------|
120
+ | OF-001 | `<TICKET-or-fallback>` | Create / Modify / Delete | `<path>[:<line-range>]` | <한 줄 요약> |
79
121
  - 영향을 받는 인터페이스 / 공개 계약 / 다운스트림 소비자.
80
122
  - 폭발 반경 추정(units, configs, deployment manifests, data migrations).
81
123
 
@@ -88,15 +130,30 @@
88
130
  - 어떤 옵션을 권장하는지와 이유를 작성합니다. 근거는 `4.5.2`의 비교 결과 + 디자인 원칙(isolation, files-that-change-together, follow-established-patterns, YAGNI)에 묶어 설명합니다.
89
131
 
90
132
  ### 4.5.4 Stepwise Execution Order (단계별 실행 순서)
91
- 1. 한 단계는 약 2~5분 안에 완료할 수 있는 작은 작업이어야 합니다(예: "X에 실패하는 테스트 작성", "테스트 실행해 실패 확인", "최소 구현", "테스트 통과 확인", "commit").
92
- 2. 모든 단계는 정확한 파일 경로와 정확한 명령어를 포함해야 합니다. 코드 단계라면 실제 코드 또는 diff 스케치를 함께 적습니다.
93
- 3. TDD 순서(failing test → implementation → green → commit)가 가능한 영역이라면 이 순서를 따릅니다.
133
+
134
+ | Step | Ticket ID | Action (≤ 5min) | Files | Command / Test | Expected outcome |
135
+ |------|-----------|------------------|-------|----------------|-------------------|
136
+ | 1 | `<TICKET-or-fallback>` | <예: 실패하는 테스트 작성> | `tests/foo_test.py` | `pytest tests/foo_test.py::test_x -v` | FAIL with <reason> |
137
+
138
+ 규칙:
139
+
140
+ - 한 step은 약 2~5분 안에 완료할 수 있는 작은 작업이어야 합니다(예: "X에 실패하는 테스트 작성", "테스트 실행해 실패 확인", "최소 구현", "테스트 통과 확인", "commit").
141
+ - 모든 step은 정확한 파일 경로와 정확한 명령어를 포함합니다. 코드 단계라면 실제 코드 또는 diff 스케치를 함께 적습니다 (`Action` 셀에 줄바꿈 가능).
142
+ - TDD 순서(failing test → implementation → green → commit)가 가능한 영역이라면 이 순서를 따릅니다.
143
+ - 한 step이 여러 ticket을 동시에 진행한다면 `Ticket ID`에 콤마로 함께 적습니다.
94
144
 
95
145
  ### 4.5.5 Dependency / Migration Risk (의존성·마이그레이션 위험)
96
146
  - 순서 제약, 데이터 백필, feature-flag 선행 조건, 팀 간 조율 등을 모두 나열합니다.
97
147
 
98
148
  ### 4.5.6 Validation Checklist (검증 체크리스트)
99
- - pre / mid / post 검증 항목을 각각 정확한 명령어 또는 관찰 가능한 결과로 적습니다. 추상적 서술은 금지.
149
+
150
+ | Phase | Ticket ID | Check | Command / Observation | Expected outcome |
151
+ |-------|-----------|-------|------------------------|-------------------|
152
+ | pre | `<TICKET-or-fallback>` | <체크 이름> | `<정확한 명령어 또는 관찰 지점>` | <기대 출력 / 상태> |
153
+ | mid | `<TICKET-or-fallback>` | <체크 이름> | `<...>` | <...> |
154
+ | post | `<TICKET-or-fallback>` | <체크 이름> | `<...>` | <...> |
155
+
156
+ 추상적 서술 금지. 모든 row는 명령어 또는 관찰 가능한 결과를 포함해야 합니다.
100
157
 
101
158
  ### 4.5.7 Rollback Strategy (롤백 전략)
102
159
  - 정확한 revert 경로(commits, flags, migrations 등)와 롤백을 트리거하는 신호(에러율, latency, 사용자 보고 등)를 명시합니다.
@@ -108,6 +165,60 @@
108
165
  ### 4.5.9 Open Questions
109
166
  - pre-planning에서 발견된 모든 모호점을 항목으로 남겨, 사용자가 승인 전에 해소해야 할 질문 목록으로 사용합니다.
110
167
 
168
+ ## 4.6 Release Handoff Deliverables (release-handoff runs only)
169
+
170
+ > **이 섹션은 `task-type` = `release-handoff` 실행 결과에만 포함하세요. 다른 task-type에서는 섹션 전체를 삭제하고 5번 섹션으로 넘어갑니다.**
171
+ >
172
+ > 이 섹션은 git/gh mutating 명령이 실행된 phase의 감사 기록입니다. 모든 mutating command 는 반드시 위 `User Selections` 표의 사용자 응답과 1:1로 대응되어야 하며, 대응되지 않는 mutating command 가 있으면 self-review 가 `contract-violated` 로 종료해야 합니다.
173
+
174
+ ### 4.6.1 Source Verification Report (선행 final-verification 인용)
175
+ - Path (project-relative): `<runs/final-verification/.../reports/final-report-final-verification-<seq>.md>`
176
+ - Quoted final verdict line (정확히 `accepted` 토큰을 포함해야 함):
177
+ > <원문 인용>
178
+ - 만약 원본 verdict 가 `accepted` 가 아니라면 본 run 은 **실행되지 않아야 했습니다**. self-review 단계에서 contract-violated 로 처리하고 routing 을 `final-verification` 으로 되돌립니다.
179
+
180
+ ### 4.6.2 Feature Branch & Working-Tree State (run 시작 시점)
181
+ - Feature branch (`git rev-parse --abbrev-ref HEAD`): `<branch-name>`
182
+ - `git status --short` 출력:
183
+ ```
184
+ <원문 그대로>
185
+ ```
186
+ - 기존 PR 존재 여부 (`gh pr list --head <branch> --state open --json url --jq '.[0].url'`): `<URL or empty>`
187
+
188
+ ### 4.6.3 User Selections (메뉴 응답 기록)
189
+ | 질문 ID | 질문 본문 | 사용자 응답 (원문) | 응답이 가능한 보기 |
190
+ |---------|-----------|--------------------|--------------------|
191
+ | H1 | 어떤 작업을 실행할까요? | <`commit only` / `commit + PR` / `skip`> | `commit only` / `commit + PR` / `skip` |
192
+ | H2 | PR base 브랜치를 골라주세요. (H1=`commit + PR` 인 경우에만 묻습니다) | <`staging` / `preprod` / `prod` / `main` / `dev` / 사용자가 입력한 브랜치명> | `staging` / `preprod` / `prod` / `main` / `dev` / 직접 입력 |
193
+ | H3 | 워커가 작성한 commit 메시지 / PR 본문 초안을 어떻게 처리할까요? | <`use as-is` / `edit then proceed` / `cancel`> | `use as-is` / `edit then proceed` / `cancel` |
194
+
195
+ H1 이 `skip` 이거나 H3 가 `cancel` 인 경우, 본 섹션 다음의 4.6.4 ~ 4.6.6 은 빈 결과로 채우고 (mutating 명령 미실행) 4.6.7 routing 만 채웁니다.
196
+
197
+ ### 4.6.4 Executed Commands (실행한 git / gh 명령 로그)
198
+ - **Mutating commands**: 정확한 명령행 / exit code / 한 줄 stdout 요약을 한 행씩 모두 기록합니다. 누락은 contract-violated 입니다.
199
+ - **Read-only inspection commands**: 요약 또는 명령행 목록만 적어도 됩니다.
200
+
201
+ | # | command (verbatim) | exit code | stdout/stderr 요약 |
202
+ |---|---------------------|-----------|--------------------|
203
+ | 1 | `<예: git add path/to/file.py>` | `0` | `<요약>` |
204
+
205
+ ### 4.6.5 Commit List (생성된 commit)
206
+ - 각 commit 의 short SHA / full SHA / subject / 영향 파일 목록을 한 항목씩 기록합니다.
207
+ - staged 변경이 없어 commit 이 만들어지지 않았다면 다음 한 줄만 적습니다.
208
+ > `- No commit was produced (working tree had no staged changes).`
209
+
210
+ ### 4.6.6 Pull Request Outcome (PR 결과)
211
+ - 다음 네 가지 중 정확히 하나의 형식으로 한 줄을 적습니다.
212
+ - `- No PR action requested.` (H1=`commit only` 또는 `skip` 인 경우)
213
+ - `- PR created: <url>` + 타이틀 + base 브랜치
214
+ - `- PR reused: <url>` (run 시작 시점에 같은 head 의 open PR 이 이미 존재해 `gh pr create` 를 생략한 경우)
215
+ - `- PR creation skipped: <reason>` (H3=`cancel`, 또는 push/PR 생성 도중 사용자가 중단 지시한 경우. reason 은 풀어 쓴 한 문장)
216
+
217
+ ### 4.6.7 Routing Recommendation (마지막 phase 라우팅)
218
+ - `release-handoff` 는 lifecycle 의 종착 phase 이므로 일반적으로 `done` 으로 라우팅합니다.
219
+ - 단, H1=`skip` 또는 H3=`cancel` 로 종료된 경우 사용자가 추후 재진입해 다시 release-handoff 를 실행할 수 있는지 한 줄로 명시합니다.
220
+ - 형식 예시: `- Routing: done. PR <url> opened against <base>; no follow-up required.`
221
+
111
222
  ## 5. Clarification Requests for the Next Run
112
223
 
113
224
  이 섹션은 다음 run으로 넘어가기 전에 사용자에게 받아야 할 입력을 정리하는 자리입니다. `task-type`이 `error-analysis` 또는 `requirements-discovery`이고 지금까지의 증거만으로는 확신 있는 최종 판단이 어려울 때 반드시 채웁니다. 그 외의 `task-type`에서는 lead가 추가 run이 필요하다고 판단했을 때만 채우고, 그렇지 않다면 `- 추가 정보 요청 없음. Section 2의 최종 판단이 그대로 유효합니다.` 라고만 한 줄 적은 뒤 Section 6으로 넘어갑니다.
@@ -130,9 +241,9 @@
130
241
 
131
242
  이 하위 섹션에는 **사용자가 다음 run 전에 첨부 또는 공유해 주셨으면 하는 자료**만 적습니다. 질문이 아니라 자료 요청입니다. 자료가 어디에 있는지(파일 경로, 페이지 URL, 데이터베이스 쿼리 결과 등), 어떤 시점/조건의 데이터를 받아야 하는지, 받은 자료를 어디에 두면 되는지(예: `<project-root>/.project-docs/<task-group>/<task-id>/` 아래)를 함께 적습니다. 받을 자료가 없다면 `- 추가로 요청드릴 자료가 없습니다.` 한 줄만 남깁니다.
132
243
 
133
- | 자료 ID | 무엇을 / 왜 필요한지 (문장으로 서술) | 어디에서 가져올 수 있는지 (파일 경로, 시스템 이름, URL 등) | 어디에 두면 되는지 / 어떻게 전달해 주실지 | Status | 사용자가 첨부한 위치 또는 메모 (다음 run 전에 사용자가 채움) |
134
- |---------|--------------------------------------|------------------------------------------------------------|--------------------------------------------|--------|---------------------------------------------------------------|
135
- | A1 | <어떤 자료를 왜 받아야 하는지를 1~2문장으로. 예: "오류가 처음 보고된 시각 전후 30분 동안의 worker 로그가 필요합니다. 어떤 task가 실패했고 그때 큐에 무엇이 쌓여 있었는지를 함께 확인해야 root cause 가설을 좁힐 수 있기 때문입니다." > | <예: "Datadog 로그에서 `service:worker env:prod` 필터, 시각 범위 2026-04-30 09:30~10:30 KST" / 또는 정확한 파일 경로> | <예: "`.project-docs/tasks/8852/logs/` 아래에 `worker-2026-04-30.log` 라는 이름으로 저장해 주시면 됩니다."> | open | <빈칸으로 두고 다음 run 전에 사용자가 채움> |
244
+ | 자료 ID | Ticket ID | 무엇을 / 왜 필요한지 (문장으로 서술) | 어디에서 가져올 수 있는지 (파일 경로, 시스템 이름, URL 등) | 어디에 두면 되는지 / 어떻게 전달해 주실지 | Status | 사용자가 첨부한 위치 또는 메모 (다음 run 전에 사용자가 채움) |
245
+ |---------|-----------|--------------------------------------|------------------------------------------------------------|--------------------------------------------|--------|---------------------------------------------------------------|
246
+ | A1 | `<TICKET-or-fallback>` | <어떤 자료를 왜 받아야 하는지를 1~2문장으로. 예: "오류가 처음 보고된 시각 전후 30분 동안의 worker 로그가 필요합니다. 어떤 task가 실패했고 그때 큐에 무엇이 쌓여 있었는지를 함께 확인해야 root cause 가설을 좁힐 수 있기 때문입니다." > | <예: "Datadog 로그에서 `service:worker env:prod` 필터, 시각 범위 2026-04-30 09:30~10:30 KST" / 또는 정확한 파일 경로> | <예: "`.project-docs/tasks/8852/logs/` 아래에 `worker-2026-04-30.log` 라는 이름으로 저장해 주시면 됩니다."> | open | <빈칸으로 두고 다음 run 전에 사용자가 채움> |
136
247
 
137
248
  ### 5.2 사용자 확인 질문 (Questions for the User)
138
249
 
@@ -144,9 +255,9 @@
144
255
  - **무엇을 묻는가**: 약어 없이 풀어 쓴 완전한 문장의 질문.
145
256
  - **어떤 형태의 답을 기대하는가**: 예/아니오인지, 둘 중 하나를 고르는 선택인지, 숫자/날짜/파일경로인지, 아니면 짧은 자유서술인지. 가능하면 보기를 함께 제시합니다.
146
257
 
147
- | 질문 ID | 이 답이 필요한 이유 (왜) | 질문 본문 (무엇을 묻는지, 풀어 쓴 문장) | 기대하는 답의 형태 / 보기 | Blocking (예 / 아니오) | Status | 사용자 답변 (다음 run 전에 사용자가 채움) |
148
- |---------|--------------------------|-----------------------------------------|----------------------------|------------------------|--------|--------------------------------------------|
149
- | Q1 | <예: "이 결정에 따라 `bugfix`로 이어갈지 `feature`로 이어갈지가 갈리며, 다음 run에서 사용할 task-type이 달라집니다."> | <예: "지난 주 새벽에 보고된 결제 실패가 일회성 사고였는지, 아니면 같은 증상이 다시 발생한 적이 있는지 알려주실 수 있을까요? 같은 증상이 다시 발생했다면 가장 최근 발생 시각과 영향 받은 사용자 수도 함께 부탁드립니다."> | <예: "다음 중 한 줄로 답해 주시면 됩니다 — (a) 일회성으로 그 후 재발 없음, (b) 재발 있음, 가장 최근 시각: YYYY-MM-DD HH:MM, 영향 사용자 수 약 N명"> | 예 | open | <빈칸으로 두고 다음 run 전에 사용자가 채움> |
258
+ | 질문 ID | Ticket ID | 이 답이 필요한 이유 (왜) | 질문 본문 (무엇을 묻는지, 풀어 쓴 문장) | 기대하는 답의 형태 / 보기 | Blocking (예 / 아니오) | Status | 사용자 답변 (다음 run 전에 사용자가 채움) |
259
+ |---------|-----------|--------------------------|-----------------------------------------|----------------------------|------------------------|--------|--------------------------------------------|
260
+ | Q1 | `<TICKET-or-fallback>` | <예: "이 결정에 따라 `bugfix`로 이어갈지 `feature`로 이어갈지가 갈리며, 다음 run에서 사용할 task-type이 달라집니다."> | <예: "지난 주 새벽에 보고된 결제 실패가 일회성 사고였는지, 아니면 같은 증상이 다시 발생한 적이 있는지 알려주실 수 있을까요? 같은 증상이 다시 발생했다면 가장 최근 발생 시각과 영향 받은 사용자 수도 함께 부탁드립니다."> | <예: "다음 중 한 줄로 답해 주시면 됩니다 — (a) 일회성으로 그 후 재발 없음, (b) 재발 있음, 가장 최근 시각: YYYY-MM-DD HH:MM, 영향 사용자 수 약 N명"> | 예 | open | <빈칸으로 두고 다음 run 전에 사용자가 채움> |
150
261
 
151
262
  ## 6. Recommended Next Steps
152
263
 
@@ -7,6 +7,7 @@
7
7
  - Task ID:
8
8
  - Related Tasks:
9
9
  - Issue / Ticket:
10
+ - 값이 비면 워커는 `Task ID`로 폴백한다 (prefix 없이 `8852`처럼). 한 run이 여러 ticket을 동시에 다루면 콤마로 구분 (`TICKET-123, TICKET-456`). 어느 쪽으로도 식별 불가하면 `unknown`을 허용한다.
10
11
  - Task Type: `implementation`
11
12
  - Requested Outcome:
12
13
 
@@ -7,6 +7,7 @@
7
7
  - Task ID:
8
8
  - Related Tasks:
9
9
  - Issue / Ticket:
10
+ - 값이 비면 워커는 `Task ID`로 폴백한다 (prefix 없이 `8852`처럼). 한 run이 여러 ticket을 동시에 다루면 콤마로 구분 (`TICKET-123, TICKET-456`). 어느 쪽으로도 식별 불가하면 `unknown`을 허용한다.
10
11
  - Task Type: `implementation-planning`
11
12
  - Requested Outcome:
12
13
 
@@ -7,6 +7,7 @@
7
7
  - Task ID:
8
8
  - Related Tasks:
9
9
  - Issue / Ticket:
10
+ - 값이 비면 워커는 `Task ID`로 폴백한다 (prefix 없이 `8852`처럼). 한 run이 여러 ticket을 동시에 다루면 콤마로 구분 (`TICKET-123, TICKET-456`). 어느 쪽으로도 식별 불가하면 `unknown`을 허용한다.
10
11
  - Requested Task Type:
11
12
  - Requested Outcome:
12
13