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.
- package/README.kr.md +14 -3
- package/README.md +14 -3
- package/docs/kr/architecture.md +8 -3
- package/docs/kr/cli.md +55 -1
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +638 -0
- package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +131 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +13 -0
- package/runtime/agents/workers/claude-worker.md +2 -0
- package/runtime/agents/workers/codex-worker.md +2 -0
- package/runtime/agents/workers/gemini-worker.md +2 -0
- package/runtime/agents/workers/report-writer-worker.md +1 -0
- package/runtime/prompts/launch.template.md +11 -0
- package/runtime/prompts/profiles/implementation.md +10 -0
- package/runtime/prompts/profiles/release-handoff.md +97 -0
- package/runtime/python/lib/okstra/cli.sh +1 -1
- package/runtime/python/okstra_ctl/render.py +9 -2
- package/runtime/python/okstra_ctl/run.py +30 -0
- package/runtime/python/okstra_ctl/workflow.py +30 -2
- package/runtime/python/okstra_ctl/worktree.py +235 -0
- package/runtime/skills/okstra-context-loader/SKILL.md +1 -1
- package/runtime/skills/okstra-convergence/SKILL.md +11 -5
- package/runtime/skills/okstra-report-finder/SKILL.md +1 -0
- package/runtime/skills/okstra-report-writer/SKILL.md +6 -0
- package/runtime/skills/okstra-run/SKILL.md +2 -1
- package/runtime/skills/okstra-status/SKILL.md +3 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +19 -0
- package/runtime/skills/okstra-time-summary/SKILL.md +1 -0
- package/runtime/templates/reports/error-analysis-input.template.md +1 -0
- package/runtime/templates/reports/final-report.template.md +129 -18
- package/runtime/templates/reports/implementation-input.template.md +1 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +1 -0
- package/runtime/templates/reports/quick-input.template.md +1 -0
- package/runtime/templates/reports/release-handoff-input.template.md +73 -0
- package/runtime/templates/reports/task-brief.template.md +5 -0
- 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,
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
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`,
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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**:
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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-planning`
|
|
11
12
|
- Requested Outcome:
|
|
12
13
|
|