LogoSkills

sequential-workflow

Supporting reference module for /cc-dev:batch โ€” per-issue cycle detail, Stall Budget ladder, and error recovery. Not a standalone command entry point.

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ณ„์นญ@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:batch entry point (Epic branch โ†’ Story branch โ†’ Sub-task branch, per branch-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-workflow may 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:run Step 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 " );
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:

  1. Build failure: melos run analyze or flutter build failure
  2. Test failure: Unit test or widget test failure
  3. Code review issue: Major fix request raised
  4. 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:unstuck returns 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) ์žฌํ‰๊ฐ€
  • @console-feature - Console feature patterns
  • @bloc - BLoC state management
  • @flutter-ui - UI component implementation
  • @test - Test writing