| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ณ์นญ | @sequential-workflow |
| ๋ชจ๋ธ | inherit |
| ์ฌ์ฉ ๋๊ตฌ |
Read
,
Edit
,
Write
,
Bash
,
Glob
,
Grep
,
Task
|
| MCP ์๋ฒ | zenhub |
| ์ง์ | /cc-dev:batch |
โ ๏ธ This is a supporting reference module, not the command definition. The canonical
/cc-dev:batchentry point (Epic branch โ Story branch โ Sub-task branch, perbranch-hierarchy) is commands/batch.md. That file references this one specifically for the Stall Budget ladder and Error Recovery sections below โ it is not a competing implementation.@sequential-workflowmay still be invoked directly for a single-Story sequential cycle outside of a full Epic batch.
Sequential Workflow Agent#
A supporting workflow module detailing the per-issue processing cycle, stall-budget ladder, and error recovery used by
/cc-dev:batch.
Triggers#
@sequential-workflow(direct invocation for a single-Story sequential cycle)-
Referenced internally by
/cc-dev:batch(commands/batch.md) for Stall Budget / Error Recovery detail
Workflow Cycle#
Phase 1: Issue Selection#
1. Query Story children under the Epic (each Story ' s own Sub-tasks are
discovered and processed within that Story ' s own cycle โ see
branch-hierarchy: Sub-task ' s parent is Story, not Epic)
2. Filter issues in the New Issues pipeline
3. Sort by priority and issue number
4. Select the first issue
Phase 2: Start Work#
0. โ Claim guard โ claimStatus(issue) ๊ฐ " other-live " ๋ฉด ์ด Story ๋ ๋ค๋ฅธ ์ธ์
์ด ์ก๊ณ ์๋ค.
์ฐฉ์ํ์ง ์๊ณ SKIPPED-OCCUPIED ๋ก ๊ธฐ๋กํ ๋ค ๋ค์ Story ๋ก ๋์ด๊ฐ๋ค(๋ณด๋ยท๋์ฅ์ ๊ฑด๋๋ฆฌ์ง ์๋๋ค).
ํ์ SoT: ../rules/zenhub-conventions.md โ Work Claim Contract
1. Move the issue to the " In Progress " pipeline + acquireClaim(issue)
โ ์ด๋๋ง ํ๊ณ ๋์ฅ์ ์ฐ์ง ์์ผ๋ฉด ๋ค์ ์ธ์
์ด ์ด In Progress ๋ฅผ ๋ถ๋ชจ cascade ์ ๊ตฌ๋ถํ์ง ๋ชปํ๋ค
โ cascade the same move up through any parent still in a pre-progress pipeline
(New Issues/Icebox/Product Backlog/Sprint Backlog) โ see
agents/dev/issue-state-agent.md โ cascadeStartToParents. Matters here specifically
because this module may be invoked directly for a single Story outside a full batch,
so the parent Epic may not have been touched yet.
2. Create branch: feature/{issue}-{slug}
3. Analyze issue requirements (title, body, acceptance criteria)
Phase 3: Implementation#
1. Analyze existing codebase
2. Implement code matching the requirements
3. Write tests (as needed)
4. Verify build and analysis pass
Phase 4: PR Creation#
1. Commit changes (include Closes #{issue})
2. Push branch
3. Create PR (gh pr create)
4. Move issue to " Review/QA " pipeline (reflectBoardState(issue, " review " ) โ ์ ์ ๋ ์ ์ง)
Phase 5: Code Review Response#
1. Check review feedback
2. โญ ๋ณ๊ฒฝ ์์ฒญ(CHANGES_REQUESTED) ๋๋ CI ์คํจ ์: ์ด์๋ฅผ Review/QA โ " In Progress " ๋ก ๋๋๋ฆฐ๋ค
(์ฌ์์
์ค์์ ๋ณด๋์ ๋ฐ์). fail-closed find() ๋ก pipelineId ํด์.
3. Add fix commits โ re-push โ ๋ค์ " Review/QA " ๋ก ์ด๋
4. Wait for approval
Phase 6: Completion and Next Issue#
1. Squash merge PR
1.5. โ ์ด๋ฆฐ ์์ ํ์ธ โ ์ด ์ด์์ ์ด๋ฆฐ ์์์ด ์์ผ๋ฉด **๋ซ์ง ์๋๋ค**(์ด๋ฏธ `Closes #N` ์ผ๋ก ๋ซํ๋ค๋ฉด
`gh issue reopen` ์ผ๋ก ๋ณต๊ตฌ). ํ์ ์ `openChildrenStatus()` tri-state โ `rules/zenhub-conventions.md`
โ " Parent Closure Invariant " . Story/Sub-task leaf ์์๋ ์ฌ์ค์ no-op ์ด๋ค.
2. โญ ๋ช
์์ Close + ๊ฒ์ฆ (ํ์ โ auto-close ์์กด ๊ธ์ง):
PR base ๊ฐ `development`(์ ์ฅ์ ๊ธฐ๋ณธ ๋ธ๋์น๊ฐ ์๋ ์ ์์)๋ฉด `Closes #N` ์ด ๋ฐํํ์ง ์๋๋ค.
- STATE=$(gh issue view {N} --json state -q .state); [ " $STATE " != CLOSED ] & & gh issue close {N} --reason completed
- mcp__zenhub__searchClosedIssues({query: " #{N} " }) ์ ์์ผ๋ฉด โ updateIssue({issueId, state: " CLOSED " })
3. Return to development + git pull --ff-only origin development + submodule sync/update
4. Go back to Phase 1 โ **๋จ, ์ข
๋ฃ ์กฐ๊ฑด์ ๊ฑธ๋ฆฌ์ง ์์ ๋๋ง**(์๋ ๋ฃจํ ๊ณ์ฝ):
- Phase 1 ์ฌ์กฐํ๊ฐ ์ด๋ฒ run ์ `attempted` ์งํฉ์ **์๋** ์ด์๋ฅผ 0๊ฐ ๋ด๋์ผ๋ฉด ์ ์งํ๋ค
(`attempted` = ์ด๋ฒ run ์์ ์ฐฉ์ํ ์ด์ ๋ฒํธ ์งํฉ. ์ฑ๊ณตยทBLOCKED ๋ชจ๋ ๋ฃ๋๋ค โ
BLOCKED ๋ฅผ ๋นผ๋ฉด ๊ฐ์ ์ด์๋ฅผ ์์ํ ๋ค์ ๊ณ ๋ฅธ๋ค)
- ์กฐํ ์คํจ๋ ๋น ์งํฉ์ด ์๋๋ค โ `unknown` ์ " ๋ค ๋๋ฌ๋ค " ๊ฐ ์๋๋ผ **์ ์ง + ๊ธฐ๋ก**์ด๋ค
- ์ฐ์ K = 3 pass ๋์ ์ด๋ค ์ด์๋ closed ๋๋ BLOCKED ๋ก ์ ์ด๋์ง ์์ผ๋ฉด ์ ์งํ๋ค
(no-progress stop โ ์ด์๊ฐ ๊ณ์ ๋์ค๋๋ฐ ์๋ฌด๊ฒ๋ ๋๋์ง ์๋ ์ํ)
โ ๏ธ Phase 6 ๋ GitHub
Closes #N์๋ ๋ซํ์ ์์กดํ์ง ์๋๋ค. ๋น-default base ๋จธ์ง๋ ์๋์ผ๋ก ๋ซํ์ง ์์ ์ด์๊ฐ Review/QA ์ ์๊ตฌ ์๋ฅํ๋ฏ๋ก, GitHub state ๋ฅผ source of truth ๋ก ์ง์ ๋ซ๊ณ ZenHub ๋๊ธฐํ๋ฅผ ๊ฒ์ฆํ๋ค(/cc-dev:runStep 8 ๊ณผ ๋์ผ ํจํด).
์ด์ ์ํ ๋ฃจํ ๊ณ์ฝ contract:L-sequential-workflow.phase6-next-issue#
Phase 6 โ Phase 1 ๋ก ๋๋์๊ฐ๋ ๋ฐ๊นฅ ๋ฃจํ๋ ์ง๊ธ๊น์ง ์ ์ง ์ ์ด๊ฐ ์์๋ค. ํ๋ ์ ์๋
../rules/orchestration-graph.md ยง2, ๊ฐ์ ์ฌ๊ธฐ:
inv: ๋งค pass ์ง์
ยท์ข
๋ฃ ์ attempted ๋ ๋จ์กฐ ์ฆ๊ฐํ๊ณ ์ด๋ฒ run ์์ ์ฐฉ์ํ ๋ชจ๋ ์ด์๋ฅผ ๋ด๋๋ค
(attempted ์ ๋ฃ์ง ์๊ณ ๊ฐ์ ์ด์๋ฅผ ๋ค์ ๊ณ ๋ฅด๋ ๊ฒฝ๋ก ๊ธ์ง)
prog: remaining = |Phase 1 ํ๋ณด โ attempted|, pass ํ๋๋ง๋ค ๊ฐํ ๊ฐ์
no-prog: remaining ์ด ์ค์ง ์์ pass ๋ noProgressStreak++ (์์ฐ์์ ์ฐจ๊ฐ)
term: remaining == 0 (= attempted ์ ์๋ ์ด์๊ฐ ์๋ค) || noProgressStreak == 3
budget: pass ๋น ์ด์ 1๊ฐ ยท noProgressStreak K = 3 ์ฐ์ pass ยท ์ด์๋น ์ฌ๋ค๋ฆฌ ์์ฐ 4 attempts
(run ๋น ์ด์ ์ ์ํ์ ๋ฐ์ดํฐ ์ฃผ๋ โ ์์ฐ์ K ์ ์ด์๋ณ ์ฌ๋ค๋ฆฌ ์นด์ดํฐ๊ฐ ์ง๋ค)
exhaust: ์ ์ง + ๋จ์ ํ๋ณดยทBLOCKED ๋ชฉ๋ก์ ์ปจํ
์ด๋ ์ด์ ์ฝ๋ฉํธ์ ๋ด๊ตฌ ๊ธฐ๋ก. ์กฐ์ฉํ ์ข
๋ฃ ๊ธ์ง
resume: ZenHub ํ์ดํ๋ผ์ธ ์ฌ์กฐํ + ๊ฐ ์ด์์ ` < !-- cc-dev:stall-ladder -- > ` ์ฝ๋ฉํธ.
attempted ๋ run ๋ฒ์(๋ํ ๊ตฌ์กฐ๋ผ `/clear` ๋ฅผ ๋ชป ๋๋๋ค) โ ๊ทธ๋์ ์ฌ๊ฐ๋ฅผ ๊ฐ๋ก์ง๋ฅด๋
์์ฐ์ K ๊ฐ ์๋๋ผ ์ด์๋ณ **๋ด๊ตฌ** ์ฌ๋ค๋ฆฌ ์นด์ดํฐ๊ฐ ์ง๋ค
log: ์ ํ๋ง๋ค ํ ์ค โ `โถ #1415 selected (attempted 3, remaining 5โ4, streak 0)`
+ ์ ์ง ์ ์ด์ ํ ์ค(`remaining==0` | `noProgressStreak==3` | `query=unknown`)
ZenHub MCP Usage#
Workspace Info Query (once at session start)#
const workspace = await mcp__zenhub__getWorkspacePipelinesAndRepositories();
const pipelines = workspace.pipelines;
const repos = workspace.githubRepositories; // โ ๏ธ ํ๋๋ช
์ githubRepositories (repositories ์๋)
// fail-closed ํด์ โ ๋ชป ์ฐพ์ผ๋ฉด throw (rename/์คํ ์ undefined.id ๋ฌด์ ๋๋ฝ ๋ฐฉ์ง)
const pid = (n) = > { const p = pipelines.find(p = > p.name === n); if (!p) throw new Error(` ' ${n} ' ์์. ๋ผ์ด๋ธ: ${pipelines.map(p = > p.name).join( " , " )}`); return p; };
const newIssues = pid( " New Issues " );
const inProgress = pid( " In Progress " );
const reviewQA = pid( " Review/QA " );
Issue Search#
mcp__zenhub__searchLatestIssues({ query: " SALES-001 " })
// Query issues by pipeline
mcp__zenhub__getIssuesInPipeline({
pipelineId: newIssues.id,
repositoryIds: [repos[0].id]
})
Pipeline Move#
// In Progress
mcp__zenhub__moveIssueToPipeline({
issueId: " {graphql_id} " ,
pipelineId: inProgress.id
})
// Review/QA
mcp__zenhub__moveIssueToPipeline({
issueId: " {graphql_id} " ,
pipelineId: reviewQA.id
})
Note: Pipeline ID and Repository ID differ per workspace. Do not hardcode them.
Branch Strategy#
# Create issue work branch
git checkout development
git pull origin development
git checkout -b feature/{issue_number}-{short-slug}
# Example
git checkout -b feature/1415-sales-kpi-summary
์์ฐจ ์์กด ์ฌ์ฌ์ด๋ฉด ์คํ ๋ชจ๋๋ฅผ ๊ณ ๋ คํ๋ค (์ ํํ)#
์ด ๋ชจ๋์ด ๋๋ ์ฌ์ดํด โ ํ ๋ฒ์ ์ด์ ํ๋, ์ ์ด์์ ๊ฒฐ๊ณผ ์์ ๋ค์ ์ด์๊ฐ ์์ด๋ ํํ โ ๊ฐ ์์ฐจ ์์กด ์ฌ์ฌ์ด๋ผ๋ฉด, ๊ทธ๊ฒ GitHub ๋ค์ดํฐ๋ธ Stacked PR ์ด ์ ํํ ๋ง๋ ์๋ฆฌ๋ค(์คํ์ ํธ๋ฆฌ๊ฐ ์๋๋ผ ์ ํ ์ฌ์ฌ์ด๋ผ ์๋ก ๋ ๋ฆฝ์ธ ํ์ ๋ ๋ชป ๋ด๋๋ค โ ๋ ๋ฆฝ ํ์ ๋ ์ง๊ธ์ฒ๋ผ Orca ๋ณ๋ ฌ ์ํฌํธ๋ฆฌ๋ก ๋๋ค). ๊ธฐ๋ณธ๊ฐ์ ์์ ๊ธฐ์กด ๋ฐฉ์์ด๊ณ , ์คํ์ ์ผ์ผ ์ผ์ง๋ ์ ํํ ์คํ ๋ชจ๋๋ค. ์ฑํ ํ๋จยทCI ๋น์ฉ ๋ง๊ตํ์ stacked-prs ๋ฅผ ๋ฐ๋ฅธ๋ค.
์ ์ ๋ง ์ง์ผ๋ฉด:
-
๊ฐ์ฅ ํฐ ์ค์ต: ์ ์ด์๊ฐ ๋จธ์ง๋์ด base ๊ฐ ์์ง์ผ ๋๋ง๋ค ๋ท ์ด์๋ฅผ ์์ผ๋ก rebase ํ๋ ๋ฃจํ๊ฐ
์ฌ๋ผ์ง๋ค.
gh stack sync์ cascade rebase ์ ๋จธ์ง ํ ์๋ retarget ์ด ๋์ ํ๋ค. -
๋จธ์ง: ์คํ์์๋ auto-merge ๊ฐ ๋ฏธ์ง์์ด๋ค. Phase 6 ์ ๋จธ์ง๋ฅผ
gh pr merge๋์gh stack merge๋ก ํ๋ค. ์ค๊ฐ PR ๋จ๋ ๋จธ์ง๋ ๋ถ๊ฐ๋ฅํ๊ณ , ํญ์ ์๋ ๊ฒ๋ค์ด ํจ๊ป ๋จธ์ง๋๋ค. -
์ด์ ์ข
๋ฃ: ์คํ์ด๋ผ๊ณ ์๋ ์ข
๋ฃ๋ฅผ ๊ฐ์ ํ์ง ๋ง๋ผ. ์คํ ๋จธ์ง ์
Closes #N์ด ์ด๋ป๊ฒ ๋์ํ๋์ง๋ ๋ฌธ์์ ๋ช ์๊ฐ ์๋ค. Phase 6 ์ ๋ช ์์ gh issue close+ ZenHub ๊ฒ์ฆ ์ ์ฐจ๋ฅผ ๊ทธ๋๋ก ์ ์งํ๋ค.
Commit Rules#
# Korean commit message + Gitmoji
feat(console): โจ ๋งค์ถ KPI ์์ฝ ์นด๋ ๊ตฌํ (#1415)
- ์ด ๊ฒฐ์ ์ก ํ์
- ์ด ํ๋งค๋ ํ์
- ์ ์ ๋๋น ์ฆ๊ฐ๋ฅ ํ์
Closes #1415
Co-Authored-By: Claude Opus 4.5 < noreply@anthropic.com >
PR Creation Rules#
gh pr create \
--base development \
--title " feat(console): โจ ๋งค์ถ KPI ์์ฝ ์นด๋ ๊ตฌํ (#1415) " \
--body " $(cat < < ' EOF '
## Summary
- Implement sales KPI summary card component
- Display total payment amount and sales volume
- Calculate month-over-month growth rate
## Related Issue
Closes #1415
## Test Plan
- [ ] Verify KPI card rendering
- [ ] Verify data binding
- [ ] Validate growth rate calculation
๐ค Generated with [Claude Code](https://claude.com/claude-code)
EOF
) "
Stop Conditions#
The workflow automatically stops when:
- Build failure:
melos run analyzeorflutter buildfailure - Test failure: Unit test or widget test failure
- Code review issue: Major fix request raised
- User request: Explicit stop request
Per-story scope, not Epic scope. A single Story getting stuck must NOT halt the whole Epic. When a Story exhausts the stall ladder below, it is marked
BLOCKED('unstuck_exhausted')and the batch continues to the next Story (idempotent resume re-enters it later โ see batch.md Phase 0 โ but the ladder budget carries over in the durable counter below: an exhausted ladder is not reset to Rung 1 by a resume).
Stall Budget โ 3-Rung Ladder#
On repeated failure within one Story, climb the ladder rung by rung. Do not loop rung 1 forever.
์ด ์ฌ๋ค๋ฆฌ๊ฐ ๊ตฌํ์ธก ๋ฃจํ์ ๊ธฐ๋ณธ
exhaust:๋ค (repo-wide default).../rules/orchestration-graph.mdยง2 ๊ฐ ์ด ๋ฌธ์๋ฅผ ๊ธฐ๋ณธ ์ฌ๋ค๋ฆฌ๋ก ์ง์ ํ๋ค โ ๊ฐ๋ณ ๋ฃจํ๋ ์๊ธฐ ์ฌ๋ค๋ฆฌ๋ฅผ ๋ฐ๋ช ํ์ง ๋ง๊ณ ํธ์ถ ์ง์ ์contract:L-sequential-workflow.stall-ladder๋ฅผ ์ธ์ฉํ๊ณ ์๋ ๊ฐ์ ์์ํ๋ค(๊ฐ์ ์๊ธฐ ๋ฌธ์๋ก ๋ณต์ฌํ๋ฉด ๋ ๋ฒ์งธ ๊ท๋ฒ ์ฌ๋ณธ์ด ์๊ธด๋ค). ํ๋ ์ด๋ฆ(inv:/prog:/term:/budget:/exhaust:/resume:/log:)์ ์ ์๋ ๊ทธ ๋ฌธ์ ยง2 ์ ์๋ค.
Rung 1 โ Same-strategy retry (existing): budget = 2 attempts
Re-run the same fix **at most 2 times** (e.g. lint/format/build
auto-fix as in Error Recovery below). An unquantified " small, bounded "
count is not a budget โ in practice it never terminates.
Each retry MUST change at least one input: command/flags, the changed
file set, or the environment. A re-run with an identical input set is
not an attempt but a repeat โ it consumes no budget and goes straight
to Rung 2 (`no-prog:` ์๋ฐ).
Rung 2 โ Lateral reframe (on repeated IDENTICAL failure):
budget = 2 reframes, โค 1 persona switch
When the SAME failure repeats (judged SEMANTICALLY, not by string
diff โ see note), escalate to /cc-dev:unstuck solo with an affinity
persona from the symptom table below. A reframe โ a retry: the next
move must differ in KIND from what already failed.
**At most 2 reframed attempts**, and **at most ONE persona switch**
within them (persona #1 comes from the symptom table; the one switch
is spent only when reframe #1 ' s named change did not move the failure).
Each reframed attempt must NAME which of {tool, layer, data,
assumption} it changed โ that name IS this rung ' s progress measure.
An attempt that can name none of the four is not a reframe: it
consumes no budget and escalates to Rung 3.
Rung 3 โ BLOCKED + CONTINUE (๋ณด๋ ๋ฐ์ ํฌํจ):
ํก์ reframe ๋ ์์ง๋๊ณ Story ๊ฐ ์ฌ์ ํ ์ ํ๋ฆฌ๋ฉด blockIssue(issue, ' unstuck_exhausted ' )
ํ ๋ฐฐ์น๋ฅผ CONTINUE ํ๋ค(Epic ์ ์ฒด ์ค๋จ ๊ธ์ง). ๊ทธ ํ ๋ฒ์ ํธ์ถ์ด ์๋ ์
์ ๋ฌถ์ด ์ํํ๋ค:
- ์ฐจ๋จ ์์กด์ด ์์ผ๋ฉด createBlockage({blockedIssueId, blockingIssueId}) ๋ก ๊ธฐ๋ก
(์ฐจ๋จ์๊ฐ ์ด์์ผ ๋๋ง โ CI ์คํจยท์์ฐ ์์ง์๋ ๊ฐ์ง ์ด์๋ฅผ ๋ง๋ค์ง ์๋๋ค)
- ํ์ฑ ์์
๊ณผ ๊ตฌ๋ถ๋๋๋ก holding ์ปฌ๋ผ(Sprint Backlog)์ผ๋ก ์ด๋ โ In Progress ์ ๋ฐฉ์น ๊ธ์ง
- **์ ์ ํด์ ** โ ๋น ๋จ๋ฆฌ๋ฉด ์ด Story ๋ TTL(4h)๊น์ง ๋ค๋ฅธ ์ธ์
์๊ฒ " ๋๊ฐ ํ๊ณ ์๋ค " ๋ก ์ฝํ๋ค
- ์ ์ยทblockedโunblocked ๊ณ์ฝ์ rules/zenhub-conventions.md โ Pipeline State Contract ์ฐธ์กฐ
- ์์ง๋ ์ฌ๋ค๋ฆฌ ์ํ๋ฅผ ์๋ ์นด์ดํฐ ์ฝ๋ฉํธ์ state:blocked(unstuck_exhausted) ๋ก ํ์ ํ๋ค
(BLOCKED Story ๋ Phase 0 ๋ฉฑ๋ฑ resume ์ผ๋ก ๋ค์ ์งํ์ง๋ง, **์ฌ๋ค๋ฆฌ๋ rung 1 ๋ก ๋ฆฌ์
๋์ง
์๋๋ค** โ ๋จ์ ์์ฐ์ด ์์ ๋๋ง ์ฌ์๋ํ๋ค. ์๋ " Ladder Counter Persistence " ์ฐธ์กฐ.)
Rung 2 โ Affinity Symptom Table#
Pick the starting persona by the meaning of the stuck state (default CONTRARIAN). Persona definitions live in
plugins/cc-spec/references/LATERAL_PERSONAS.md โ do not restate them here.
| Symptom (semantic) | /cc-dev:unstuck call |
|---|---|
| Same error repeated Nร | /cc-dev:unstuck solo hacker |
| Flip-flop / oscillation between fixes | /cc-dev:unstuck solo architect |
| Missing fact / unverified info blocks progress | /cc-dev:unstuck solo researcher |
| Over-built / complexity-buried blocker | /cc-dev:unstuck solo simplifier |
| Unknown / premise itself suspect (default) | /cc-dev:unstuck solo contrarian |
LLM-SEMANTIC, never lexical. "Is this the SAME failure again?" and "which symptom is this?" are judged by meaning, not whitespace/token overlap of error text. The audience is Korean-first: Korean has no word boundaries and attaches ์กฐ์ฌ, so two log lines describing one blocker can share almost no tokens ("๋น๋๊ฐ ์คํจ" vs "๋น๋๋ ๋ ์คํจ"). Match by what is actually stuck, not by characters.
/cc-dev:unstuckreturns options, not a verdict โ it does not decide for the workflow. If a reframed next move is actionable, the workflow may try it (that counts as Rung 2, bounded at 2 reframes / โค1 persona switch as above); if none unblocks the Story, proceed to Rung 3.
Ladder Counter Persistence โ ์ฌ๊ฐ๋ฅผ ๊ฐ๋ก์ง๋ฅด๋ ์์ฐ#
๋ํ ์นด์ดํฐ๋ /clear ๋ฅผ ๋์ง ๋ชปํ๊ณ , batch.md Phase 0 ์ ๋ฉฑ๋ฑ resume ์ BLOCKED child ๋ฅผ ๋์ค์
๋ค์ ์ง๋๋ค. ์นด์ดํฐ๋ฅผ ์ด๋์๋ ์ ์ง ์์ผ๋ฉด ๊ทธ ์ฌ์ง์
์ด ์ฌ๋ค๋ฆฌ๋ฅผ rung 1 ๋ถํฐ ๋ค์ ๋๋ ค์ โ ๋งค pass ๋
bounded ์ธ๋ฐ resume ์ ๊ฐ๋ก์ง๋ฅด๋ฉด ๋ฌด์ ํ ๋ฃจํ๊ฐ ๋๋ค. ๊ทธ๋์ ์นด์ดํฐ์ ์๋ฏธ ์์ฝ์ ์ด์์ ์ ๋๋ค.
- ์์น: ๋งํ ๊ทธ ์ด์ ์์ ์ ๋ง์ปค ์ฝ๋ฉํธ ` < !-- cc-dev:stall-ladder -- > `
(upsert ํ๋กํ ์ฝ์ `../skills/pr-work-artifact/SKILL.md` ์ ๋ง์ปค ์ฝ๋ฉํธ ๊ท์ฝ์ ์ฌ์ฌ์ฉ โ ๋ณต์ ๊ธ์ง)
- ํญ๋ชฉ: | rung | attempts_used | persona | persona_switched(0|1) | changed({tool|layer|data|assumption})
| last_cause(LLM-SEMANTIC ์์ฝ) | state: climbing / blocked(unstuck_exhausted) |
- ๊ฐฑ์ ์์ : **rung ์ ์ด๋ง๋ค ์ฆ์**(๋ค์ attempt ๋ฅผ ์์ํ๊ธฐ ์ ์) upsert ํ๋ค. ๋ชฐ์์ ์ฐ๋ฉด
ํฌ๋์ ํ ๋ฒ์ ์นด์ดํฐ๊ฐ ์ฌ๋ผ์ง๊ณ ์์ฐ์ด ๋ฆฌ์
๋๋ค.
- ์ฌ๊ฐ: ์ด ์ด์๋ฅผ ๋ค์ ์ง์ผ๋ฉด ์ฝ๋ฉํธ๋ฅผ **๋จผ์ ์ฝ๊ณ ** ๋จ์ ์์ฐ๋ถํฐ ์ด์ด ์ด๋ค. ์ฝ๋ฉํธ๊ฐ ์์ผ๋ฉด
rung 1 / attempts_used 0 ์ด ์ด๊ธฐ๊ฐ์ด๊ณ , **์กฐํ ์คํจ๋ " ์์ " ์ด ์๋๋ผ unknown** ์ด๋ฏ๋ก ์ฌ๋ค๋ฆฌ๋ฅผ
์๋ก ์์ํ์ง ์๊ณ blocked ๋ก ๋๋ค(`../rules/orchestration-graph.md` ยง3.2 empty-set pass).
- batch ํ์์์ ๋ ๋: `../commands/batch.md` โ " Stall Ladder " ์ ์๋ ๋์ฅ(attempt ledger)์
**์ปจํ
์ด๋ ์ชฝ ๋ฐ๊นฅ ์์ฐ**(child 1๊ฐ๋น ๋์ ์ฒ๋ฆฌ pass ์)์ด๊ณ , ์ด ์ฝ๋ฉํธ๋ **๊ทธ pass ์์ชฝ์
rung/attempt** ๋ค. ๋จ์๊ฐ ๋ค๋ฅด๋ฏ๋ก ์๋ก ๋ฎ์ด์ฐ์ง ์๊ณ ๊ณฑํด์ง๋ค(outer ร inner). ๋ ์ค ํ๋๋ผ๋
์์ง๋๋ฉด ์ฌ์๋๋ ์๋ค.
๋ฃจํ ๊ณ์ฝ contract:L-sequential-workflow.stall-ladder (ํ๋ ์ ์๋
../rules/orchestration-graph.md ยง2, ๊ฐ์ ์ฌ๊ธฐ):
inv: ๋งค attempt ์ง์
ยท์ข
๋ฃ ์ (rung, attempts_used) ๊ฐ ๋ง์ปค ์ฝ๋ฉํธ์ ๊ฐ๊ณผ ์ผ์นํ๋ค
Rung 1 attempt ๋ ์ง์ attempt ์ ์
๋ ฅ ์งํฉ์ด ๋ค๋ฅด๋ค
prog: attemptsLeft = (2 - rung1Used) + (2 - rung2Used), ๋งค attempt ๊ฐํ ๊ฐ์
no-prog: ์
๋ ฅ์ด ๊ฐ์ ์ฌ์คํ(Rung 1) ๋๋ {tool,layer,data,assumption} ์ค ๋ฌด์๋
์ด๋ฆ ๋์ง ๋ชปํ ๋ฆฌํ๋ ์(Rung 2) ์ ์์ฐ์ ์ฐ์ง ์๊ณ ๊ณง๋ฐ๋ก ๋ค์ rung ์ผ๋ก ์ฌ๋ฆฐ๋ค
term: ๋งํ ๊ฒ์ดํธ๊ฐ ํต๊ณผ || attemptsLeft == 0 โ Rung 3
budget: Rung 1 = 2 attempts ยท Rung 2 = 2 reframes(persona ๊ต์ฒด โค 1) ยท Rung 3 = ์ข
๋จ 1ํ
= ์ด์๋น ์ต๋ 4 attempts, **batch ์ฌ์คํ์ ๊ฐ๋ก์ง๋ฌ ํฉ์ฐ**ํ๋ค(๋ํ ์นด์ดํฐ ์๋)
exhaust: Rung 3 = blockIssue(issue, ' unstuck_exhausted ' ) (๋ณด๋ + ์ ์ ํด์ ) + ํ์ CONTINUE.
๋์คํจ์น๋ ์์ปค ์์์ `AskUserQuestion` ์ exhaust ๋ก ์ฐ์ง ์๋๋ค(๋ฌผ์ด๋ณผ ์ฌ๋์ด ์๋ค)
resume: ๋งํ ์ด์์ ` < !-- cc-dev:stall-ladder -- > ` ์ฝ๋ฉํธ๋ฅผ ์ฝ์ด ์์น๋ฅผ ํ์ ํ๋ค.
์ฝ๋ฉํธ upsert ๋ ๋ฉฑ๋ฑ์ด๊ณ , ์ฌ๋ค๋ฆฌ๋ resume ๋ง๋ค rung 1 ๋ก ๋๋์๊ฐ์ง ์๋๋ค
log: rung ์ ์ด๋ง๋ค ํ ์ค(rung ยท attempt index ยท ๊ณ ๋ฅธ persona) โ
`๐ช rung 2 attempt 1/2 persona=hacker changed=assumption cause={์๋ฏธ ์์ฝ}`
Rung 3 ๋๋ฌ ์ ์์ฌ ์ํ์ **ํ๋ฝ์ํจ ์ด์**๋ฅผ ๊ฐ์ ์ฝ๋ฉํธ์ ๋ด๊ตฌ ๊ธฐ๋ก
Error Recovery#
On Build Failure (Rung 1)#
# Analyze error
melos run analyze 2 > & 1 | head -50
# Common fixes
melos run format
melos run build
Tooling degradation (GD-01):
melos๋ถ์ฌ ์dart analyze/dart format/flutter test๋ฅผ ์ง์ ํธ์ถํ๋ ๊ฒ์ผ๋ก ํด๋ฐฑํ๋ค(= /cc-dev:run "Step 0 Degradation Contract"). ๋น๋ ๋๊ตฌ ๋ฏธ์ค์น๋ ์์ ์๋ฐ์ด ์๋๋ผ degrade + ๊ฒฝ๊ณ ๋์ โcommand -v melos๋ก ๋จผ์ ํ์ธํ๊ณ ๋ถ๊ธฐํ๋ผ.
On Repeated Identical Failure (Rung 2)#
# Same failure (semantically) after Rung 1 retries โ lateral reframe
/cc-dev:unstuck solo < affinity-persona > # see Affinity Symptom Table
On Stall Exhausted (Rung 3)#
# Reframe didn ' t unblock โ mark BLOCKED and move on
mark Story BLOCKED( ' unstuck_exhausted ' ); CONTINUE to next Story # Epic NOT halted
On Merge Conflict#
git fetch origin development
git rebase origin/development
# After resolving conflicts
git rebase --continue
On Stack Command Failure (์คํ ๋ชจ๋์์๋ง)#
์คํ ๋ชจ๋(stacked-prs)๋ก ๋ ๋๋ ์ ์๋ rebase ๋์
gh stack sync / gh stack rebase ๊ฐ cascade ๋ก ์ฒ๋ฆฌํ๋ค. ์คํจ๋ exit code ๋ก ๊ตฌ๋ถํด ๋์ํ๋ค โ
์
๋ค "๊ฐ์ ๋ช
๋ น ์ฌ์คํ" ์ผ๋ก๋ ํ๋ฆฌ์ง ์๋๋ค.
| exit | ์๋ฏธ | ์กฐ์น |
|---|---|---|
3 |
rebase ์ถฉ๋ |
์ถฉ๋ ํ์ผ์ ํด๊ฒฐํ๊ณ
gh stack rebase --continue
. ๋๋๋ฆด ๊ฑฐ๋ฉด
gh stack rebase --abort
. ํด๊ฒฐ ์์ฒด๋
merge-conflict-resolution
๊ท์ฝ์ ๊ทธ๋๋ก ๋ฐ๋ฅธ๋ค.
Rung 1 ์ฌ์๋๋ก ์ธ์ง ์๋๋ค
โ ์ฌ๋์ด ๋ง๋ ํด๊ฒฐ์ด ์ ์
๋ ฅ์ด๋ฏ๋ก
--continue
๋ ์ฌ์คํ์ด ์๋๋ผ ์งํ์ด๋ค
|
7 |
์ด๋ฏธ rebase ์งํ ์ค |
์ rebase ๋ฅผ
์์ํ์ง ๋ง๋ผ.
์งํ ์ค์ธ ๊ฒ์
--continue
๋ก ๋๋ด๊ฑฐ๋
--abort
๋ก ๋๋๋ฆฐ ๋ค์๋ง ๋ค์ ๋ช
๋ น์ ๋ธ๋ค. ์งํ ์ํ๋
.git/gh-stack-rebase-state
์ ๋จ๋๋ค
|
8 |
๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์คํ ์ ๊ธ |
๋ณ๋ ฌ ์ํฌํธ๋ฆฌยท์ธ์
์ด ๊ฐ์ ์คํ์ ๋์์ ๋ง์ง๊ณ ์๋ค๋ ์ ํธ๋ค. ์ฌ์๋ ๋ฃจํ ๊ธ์ง โ ์ด๊ฑด ์คํจ๊ฐ ์๋๋ผ
์ง๋ ฌํ ๋ฌธ์
๋ค. ์ ๊ธ์ด ํ๋ฆด ๋๊น์ง ๊ธฐ๋ค๋ ธ๋ค
1ํ๋ง
์ฌ์คํํ๊ณ , ๊ทธ๋๋
8
์ด๋ฉด Rung 2 ๋ก ์ฌ๋ฆฐ๋ค(๋๊ฐ ์ก๊ณ ์๋์ง๋ถํฐ ๊ท๋ช
). ์ด ๋๊ธฐ๋ ์
๋ ฅ์ด ๋ฐ๋์ง ์์ผ๋ฏ๋ก Rung 1 ์์ฐ์ ์ฐ์ง ์๋๋ค
|
โ ๏ธ ๋ก์ปฌ ์คํ๊ณผ ์๊ฒฉ ์คํ์ด ๊ฐ๋ผ์ง๋ฉด(diverged) ๋ํํ์์๋ 3ํ์ ๋ฌป์ง๋ง, ๋น๋ํํ์์๋ ์๋ฌด๊ฒ๋ ๋ฐ๊พธ์ง ์๊ณ ์ค๋จํ๋ค. ๋ฌด์ธ ์คํ์์ ์ด ์ค๋จ์ "์คํจ ์ฌ์๋" ๋ก ์ฒ๋ฆฌํ์ง ๋ง๊ณ BLOCKED ๋ก ์ฌ๋ ค๋ผ.
Checklist#
Verification items for each issue:
- Understand issue requirements
- Create branch
- Implement code
- Pass build/analysis
- Create commit (include Closes #)
- Create PR
- Move pipeline (In Progress โ Review/QA)
- Address review feedback
- ์คํจ๊ฐ ์์๋ค๋ฉด ์ฌ๋ค๋ฆฌ ์นด์ดํฐ๋ฅผ ์ด์ ์ฝ๋ฉํธ์ ๊ธฐ๋ก(resume ์ด rung 1 ๋ก ๋ฆฌ์ ๋์ง ์์)
-
Switch to next issue โ
attempted์ ๋ฃ๊ณ ์ข ๋ฃ ์กฐ๊ฑด(remaining / K=3) ์ฌํ๊ฐ
Related Agents#
@console-feature- Console feature patterns@bloc- BLoC state management@flutter-ui- UI component implementation@test- Test writing