LogoSkills

dev:run

Full development cycle automation from issue creation to merge

ํ•ญ๋ชฉ๋‚ด์šฉ
Invoke/dev:run
Aliases/dr
Categorypetmedi-development
Complexityhigh
MCP Serverszenhub

/dev:run#

Full development cycle automation from work content to issue creation through merge approval

Triggers#

  • When starting new feature/bug/refactoring work
  • When full cycle execution is needed from work content alone
  • When batch processing issue creation โ†’ implementation โ†’ PR โ†’ review โ†’ merge

Usage#

Basic Usage#

# Start full cycle with work content
/dev:run  " ์ €์ž ๋ชฉ๋ก ํ™”๋ฉด ์ถ”๊ฐ€ "

Start with Existing Issue (from Step 4)#

/dev:run 1810
# ๋˜๋Š”
/dev:issue 1810

Parameters#

ParameterRequiredDescriptionExample
work_content โœ…* Description of the work "์ €์ž ๋ชฉ๋ก ํ™”๋ฉด ์ถ”๊ฐ€"
issue_number โœ…* Existing issue number 1810

*Either work content or issue number is required


Options#

Auto-Decision Options (defaults)#

When options are not specified, they are determined automatically:

OptionDefaultAuto-Decision Rule
--type Auto-inferred Keyword analysis: "add/create"โ†’feat, "fix/repair"โ†’fix, "improve"โ†’refactor
--scope Auto-inferred Extract Entity/Feature name from work content, ask if unclear
--point Auto-estimated Complexity analysis: single file(1), multiple files(3), multiple layers(5), with BDD(8)
--bdd On screen detection List/detail/form keyword detection โ†’ auto BDD scenario writing
--base Auto-detected Auto-detect parent issue branch (development if none)

Explicit Options#

# Specify type
/dev:run --type feat  " Add author list screen " 

 # Specify scope
/dev:run --scope console-author  " Add author list screen " 

 # Specify point
/dev:run --point 5  " Add author list screen " 

 # Sprint assignment
/dev:run --sprint current  " Add author list screen " 

 # PR only (no merge wait)
/dev:run --no-merge  " Add author list screen " 

 # Explicit base branch (manual parent branch setting)
/dev:run --base epic/1810-author-feature 1812

# Skip review (urgent hotfix)
/dev:run --skip-review  " Urgent fix " 

 # Force BDD scenarios (even for non-screen features)
/dev:run --bdd  " API client refactoring " 

 # Skip BDD scenarios and BDD Coverage Gate (even for screen features)
/dev:run --skip-bdd  " Simple list modification " 

 # Skip tests (urgent)
/dev:run --skip-tests  " Urgent fix "

Execution Flow (13 Steps)#

Step-by-Step Prerequisites and Verification#

StepPhasePrerequisitesVerification
1Work content analysisNone-
2ZenHub issue creationStep 1 completeissue.id exists
3Move to Product BacklogStep 2 completepipeline verified
4Branch creationSteps 2,3 completebranch exists
5Move to In ProgressStep 4 completepipeline verified
6 BDD scenario writing Step 5 complete, screen feature .feature file exists
7Implementation workStep 5 completecommits exist
7.5 Backend code generation Step 7 complete, when Backend changes exist generation success
8Test writing/executionStep 7 completetests passed
8.3 BDD Coverage Gate Step 8 complete, .feature exists step_coverage 100%, assertions exist
8.5 Pre-push verification + DCM format/lint 0-issue gate + DCM quality improvement Step 8.3 complete dcm format, dart analyze 0 issues, dcm analyze error 0 issues
8.7 Code Review Gate Step 8.5 complete 0 Critical issues
9PR creationStep 8.7 completePR URL exists
10Move to Review/QAStep 9 completepipeline verified
11 Apply additional review feedback Step 10 complete review complete
12Wait for merge approvalStep 11 completeuser approval
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    /dev:run  " ์ž‘์—… ๋‚ด์šฉ "                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                 โ”‚
โ”‚  Step 1: ์ž‘์—… ๋‚ด์šฉ ๋ถ„์„                                          โ”‚
โ”‚  โ”œโ”€โ”€ ์ž‘์—… ์œ ํ˜• ์ถ”๋ก  (feat/fix/chore/refactor)                    โ”‚
โ”‚  โ”œโ”€โ”€ ์Šค์ฝ”ํ”„ ์ถ”์ถœ (feature๋ช…)                                     โ”‚
โ”‚  โ”œโ”€โ”€ ํ™”๋ฉด ํƒ€์ž… ๊ฐ์ง€ (๋ชฉ๋ก/์ƒ์„ธ/ํผ)                                โ”‚
โ”‚  โ””โ”€โ”€ ์˜ˆ์ƒ ๋ณต์žก๋„ ์‚ฐ์ • (Story Point)                              โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 2: ZenHub ์ด์Šˆ ์ƒ์„ฑ                                        โ”‚
โ”‚  โ”œโ”€โ”€ mcp__zenhub__createGitHubIssue                             โ”‚
โ”‚  โ”œโ”€โ”€ ์ด์Šˆ ํƒ€์ž… ์ž๋™ ์„ค์ • (Feature/Task/Bug)                      โ”‚
โ”‚  โ”œโ”€โ”€ ๋ผ๋ฒจ ์ž๋™ ์ง€์ •                                              โ”‚
โ”‚  โ””โ”€โ”€ Estimate ์„ค์ •                                              โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 3: Product Backlog ์ด๋™                                   โ”‚
โ”‚  โ”œโ”€โ”€ mcp__zenhub__moveIssueToPipeline                           โ”‚
โ”‚  โ””โ”€โ”€ Pipeline: Product Backlog                                  โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 4: ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ โš ๏ธ ํ•„์ˆ˜ (๊ณ„์ธต ๋ธŒ๋žœ์น˜ ์ „๋žต)                    โ”‚
โ”‚  โ”œโ”€โ”€ ๋ถ€๋ชจ ์ด์Šˆ ๊ฐ์ง€ (ZenHub parentIssueId ์กฐํšŒ)                  โ”‚
โ”‚  โ”œโ”€โ”€ base ๋ธŒ๋žœ์น˜ ๊ฒฐ์ •:                                          โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Sub-task โ†’ Story ๋ธŒ๋žœ์น˜ ๊ธฐ๋ฐ˜                            โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Story โ†’ Epic ๋ธŒ๋žœ์น˜ ๊ธฐ๋ฐ˜                                โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Epic โ†’ development ๊ธฐ๋ฐ˜                                โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ ๋…๋ฆฝ ์ด์Šˆ โ†’ development ๊ธฐ๋ฐ˜                            โ”‚
โ”‚  โ”œโ”€โ”€ ๋ถ€๋ชจ ๋ธŒ๋žœ์น˜ ๋ฏธ์กด์žฌ ์‹œ ์ž๋™ ์ƒ์„ฑ                               โ”‚
โ”‚  โ”œโ”€โ”€ issue-branch-agent ํ˜ธ์ถœ (base_branch ์ „๋‹ฌ)                 โ”‚
โ”‚  โ”œโ”€โ”€ {type}/{number}-{slug} ํ˜•์‹                                โ”‚
โ”‚  โ””โ”€โ”€ โš ๏ธ development/main์— ์ง์ ‘ ์ปค๋ฐ‹ ๊ธˆ์ง€                        โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 5: In Progress ์ด๋™                                       โ”‚
โ”‚  โ”œโ”€โ”€ issue-state-agent ํ˜ธ์ถœ                                     โ”‚
โ”‚  โ””โ”€โ”€ Pipeline: In Progress                                      โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 6: BDD ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ (screen feature ์‹œ)                          โ”‚
โ”‚  โ”œโ”€โ”€ bdd-scenario-agent ํ˜ธ์ถœ                                    โ”‚
โ”‚  โ”œโ”€โ”€ Gherkin Feature ํŒŒ์ผ ์ƒ์„ฑ                                   โ”‚
โ”‚  โ”œโ”€โ”€ Step Definition ์ƒ์„ฑ                                       โ”‚
โ”‚  โ””โ”€โ”€ ์ปค๋ฐ‹:  " test({scope}): โœ… BDD ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ "                    โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 7: ๊ตฌํ˜„ ์ž‘์—…                                               โ”‚
โ”‚  โ”œโ”€โ”€ ์ด์Šˆ ๋‚ด์šฉ ๊ธฐ๋ฐ˜ ๊ตฌํ˜„                                         โ”‚
โ”‚  โ””โ”€โ”€ ์ฆ๋ถ„ ์ปค๋ฐ‹ ์ƒ์„ฑ                                              โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 7.5: Backend ์ฝ”๋“œ ์ƒ์„ฑ (on Backend changes) โš ๏ธ                โ”‚
โ”‚  โ”œโ”€โ”€ melos run backend:pod:generate                             โ”‚
โ”‚  โ””โ”€โ”€ ์ปค๋ฐ‹:  " chore(backend): ๐Ÿ”ง ์ฝ”๋“œ ์ƒ์„ฑ "                          โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 8: ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐ ๊ฒ€์ฆ (ํ•„์ˆ˜ ๊ฒŒ์ดํŠธ) โš ๏ธ                      โ”‚
โ”‚  โ”œโ”€โ”€ [ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ - ํ•„์ˆ˜]                                    โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ UseCase ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (unit-test-agent)                   โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ BLoC ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (bloc-test-agent)                      โ”‚
โ”‚  โ”œโ”€โ”€ [๋ฐฑ์—”๋“œ ํ…Œ์ŠคํŠธ - on Backend changes ํ•„์ˆ˜]                        โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ ์—”๋“œํฌ์ธํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (serverpod-test-agent)            โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ ์„œ๋น„์Šค ๋กœ์ง ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (serverpod-test-agent)           โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ ์—”๋“œํฌ์ธํŠธ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (serverpod-test-agent)            โ”‚
โ”‚  โ”œโ”€โ”€ BDD Widget ํ…Œ์ŠคํŠธ (screen feature ์‹œ)                             โ”‚
โ”‚  โ”œโ”€โ”€ test-runner-agent ํ˜ธ์ถœ (require_tests: true)              โ”‚
โ”‚  โ”œโ”€โ”€ โš ๏ธ ๋ชจ๋“  tests passed ํ•„์ˆ˜ (๊ฒŒ์ดํŠธ ์‹คํŒจ ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ)        โ”‚
โ”‚  โ””โ”€โ”€ ์ปค๋ฐ‹:  " test({scope}): โœ… ํ…Œ์ŠคํŠธ ์ž‘์„ฑ "                          โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 8.3: BDD Coverage Gate โš ๏ธ (--skip-bdd ์‹œ ์Šคํ‚ต)              โ”‚
โ”‚  โ”œโ”€โ”€ .feature ํŒŒ์ผ ์Šค์บ” (ํ˜„์žฌ feature ๋ฒ”์œ„)                        โ”‚
โ”‚  โ”œโ”€โ”€ Given/When/Then ์Šคํ… ํŒŒ์‹ฑ                                    โ”‚
โ”‚  โ”œโ”€โ”€ step/ ํด๋”์—์„œ ๋งค์นญ step ํ•จ์ˆ˜ ๊ฒ€์ฆ                             โ”‚
โ”‚  โ”œโ”€โ”€ ๊ฐ step ํ•จ์ˆ˜ ๋‚ด assertion (expect/verify) ์กด์žฌ ํ™•์ธ            โ”‚
โ”‚  โ”œโ”€โ”€ โš ๏ธ step_coverage  <   100% ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ                      โ”‚
โ”‚  โ””โ”€โ”€ --skip-bdd ์‹œ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์Šคํ‚ต                          โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 8.5: Pre-push ๊ฒ€์ฆ + DCM format/lint 0๊ฑด + DCM ํ’ˆ์งˆ ๊ฐœ์„  โš ๏ธ ํ•„์ˆ˜โ”‚
โ”‚  โ”œโ”€โ”€ [Phase 1: DCM ํฌ๋งทํŒ… + Dart ๋ฆฐํŠธ ์ž๋™ ์ˆ˜์ • + 0๊ฑด ๊ฒŒ์ดํŠธ]      โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run format (dcm format โ€” dart format ๋Œ€์ฒด)         โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ dart fix --apply (๋ฆฐํŠธ ์ž๋™ ์ˆ˜์ •)                         โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run analyze:dart (Dart SDK ๋ถ„์„)                   โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ error/warning/info ์ž”์กด ์‹œ ์ˆ˜๋™ ์ˆ˜์ • (์ตœ๋Œ€ 2ํšŒ ๋ฐ˜๋ณต)      โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ โš ๏ธ 2ํšŒ ์‹œ๋„ ํ›„์—๋„ ์ด์Šˆ ์ž”์กด ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ              โ”‚
โ”‚  โ”œโ”€โ”€ [Phase 2: DCM ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ ]                                 โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run analyze:dcm (DCM ๋ฆฐํŠธ + ๋ฉ”ํŠธ๋ฆญ)               โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run fix:dcm (์ž๋™ ์ˆ˜์ • ๊ฐ€๋Šฅ ํ•ญ๋ชฉ ์ˆ˜์ •)             โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run check:unused-code (๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ๊ฒ€์‚ฌ)           โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run analyze:dcm (์ˆ˜์ • ํ›„ ์žฌ๊ฒ€์ฆ)                   โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ โš ๏ธ error ์‹ฌ๊ฐ๋„ ์ด์Šˆ ์ž”์กด ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ                 โ”‚
โ”‚  โ”œโ”€โ”€ [Phase 3: ์ตœ์ข… ๋ฆฐํŠธ ๊ฒ€์ฆ]                                     โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run analyze:dart (DCM ์ˆ˜์ • ํ›„ Dart ์žฌํ™•์ธ)         โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ melos run analyze:dcm (DCM ์ตœ์ข… ์žฌํ™•์ธ)                  โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ โš ๏ธ ์ด์Šˆ 0๊ฑด ํ•„์ˆ˜ โ€” ์ž”์กด ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ                   โ”‚
โ”‚  โ””โ”€โ”€ ๊ฒ€์ฆ ์‹คํŒจ ์‹œ Step 9 ์ง„ํ–‰ ๋ถˆ๊ฐ€                                โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 8.7: Code Review Gate โš ๏ธ (gstack ํŒจํ„ด)                    โ”‚
โ”‚  โ”œโ”€โ”€ /code-review --quick ์ž๋™ ์‹คํ–‰                              โ”‚
โ”‚  โ”œโ”€โ”€ 2-pass ๋ถ„์„:                                               โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Pass 1: Critical (์ฐจ๋‹จ) - ๋ณด์•ˆ, ๋ฐ์ดํ„ฐ ์•ˆ์ „์„ฑ, ๋ ˆ์ด์Šค์ปจ๋””์…˜ โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ Pass 2: Informational (PR body ํฌํ•จ)                   โ”‚
โ”‚  โ”œโ”€โ”€ Critical ๋ฐœ๊ฒฌ ์‹œ:                                          โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ ์ž๋™ ์ˆ˜์ • ์‹œ๋„ (์ตœ๋Œ€ 2ํšŒ)                                โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ ์ˆ˜์ • ๋ถˆ๊ฐ€ ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ                                โ”‚
โ”‚  โ”œโ”€โ”€ Informational ํ•ญ๋ชฉ โ†’ PR description์— ์ž๋™ ํฌํ•จ             โ”‚
โ”‚  โ””โ”€โ”€ --skip-review ์‹œ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์Šคํ‚ต                     โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 9: PR ์ƒ์„ฑ (๊ฒ€์ฆ ๊ฒŒ์ดํŠธ ํ†ต๊ณผ ํ›„, ๊ณ„์ธต ๋จธ์ง€)                  โ”‚
โ”‚  โ”œโ”€โ”€ โš ๏ธ ๋ธŒ๋žœ์น˜ ํ˜•์‹ ๊ฒ€์ฆ ํ•„์ˆ˜                                    โ”‚
โ”‚  โ”œโ”€โ”€ PR base ๊ฒฐ์ • (๊ณ„์ธต ๋ธŒ๋žœ์น˜ ์ „๋žต):                             โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Sub-task โ†’ Story ๋ธŒ๋žœ์น˜ (base)                          โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Story โ†’ Epic ๋ธŒ๋žœ์น˜ (base)                              โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Epic โ†’ development (base)                              โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ ๋…๋ฆฝ ์ด์Šˆ โ†’ development (base)                          โ”‚
โ”‚  โ”œโ”€โ”€ gh pr create --base {target_branch}                        โ”‚
โ”‚  โ”œโ”€โ”€ Closes #{issue_number} ์ž๋™ ํฌํ•จ                           โ”‚
โ”‚  โ””โ”€โ”€ ZenHub PR ์—ฐ๊ฒฐ                                             โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 10: Review/QA ์ด๋™                                        โ”‚
โ”‚  โ”œโ”€โ”€ mcp__zenhub__moveIssueToPipeline                           โ”‚
โ”‚  โ””โ”€โ”€ Pipeline: Review/QA                                        โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 11: ์ถ”๊ฐ€ ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜                                   โ”‚
โ”‚  โ”œโ”€โ”€ Step 8.7์—์„œ ์ž๋™ ์ฝ”๋“œ review complete๋จ                           โ”‚
โ”‚  โ”œโ”€โ”€ PR ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ ํ™•์ธ ๋ฐ ์ถ”๊ฐ€ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜                      โ”‚
โ”‚  โ”œโ”€โ”€ ์žฌ๊ฒ€ํ†  ํ•„์š” ์‹œ ๋ฐ˜๋ณต                                         โ”‚
โ”‚  โ””โ”€โ”€ /checklist:feature-complete ์‹คํ–‰                           โ”‚
โ”‚                                                                 โ”‚
โ”‚  Step 12: ๋จธ์ง€ ์Šน์ธ ๋Œ€๊ธฐ                                         โ”‚
โ”‚  โ”œโ”€โ”€ user approval ์š”์ฒญ                                            โ”‚
โ”‚  โ”œโ”€โ”€ ์Šน์ธ ์‹œ ์Šค์ฟผ์‹œ ๋จธ์ง€                                         โ”‚
โ”‚  โ””โ”€โ”€ GitHub  " Closes # "   ํ‚ค์›Œ๋“œ๋กœ ์ด์Šˆ ์ž๋™ Close                 โ”‚
โ”‚                                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Verification Gates (Required)#

Step 4 Branch Verification (Required)#

Direct commits on development/main branch prohibited:

# ํ˜„์žฌ ๋ธŒ๋žœ์น˜ ํ™•์ธ
BRANCH=$(git rev-parse --abbrev-ref HEAD)

# development/main ์ฒดํฌ
if [[ $BRANCH ==  " development "   || $BRANCH ==  " main "   ]]; then
  echo  " โŒ development/main์— ์ง์ ‘ ์ปค๋ฐ‹ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค " 
   echo  "     /dev:run ์Šคํ‚ฌ์€ ๋ฐ˜๋“œ์‹œ feature ๋ธŒ๋žœ์น˜์—์„œ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค " 
   echo  " " 
   echo  "     ์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ๋ฒ•: " 
   echo  "     1. /dev:run \ " ์ž‘์—… ๋‚ด์šฉ\ "   - ์ด์Šˆ ์ƒ์„ฑ๋ถ€ํ„ฐ ์‹œ์ž‘ " 
   echo  "     2. /dev:issue {number} - ๊ธฐ์กด ์ด์Šˆ๋กœ ์‹œ์ž‘ " 
   exit 1
fi

Step 9 Pre-PR Verification (Required)#

All of the following conditions must be met to create a PR:

  1. Branch format verification

        BRANCH=$(git rev-parse --abbrev-ref HEAD)
    if [[ ! $BRANCH =~ ^(epic|feature|fix|refactor|chore)/[0-9]+ ]]; then
      echo  " โŒ ๋ธŒ๋žœ์น˜ ํ˜•์‹ ์˜ค๋ฅ˜: $BRANCH " 
       echo  "     ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹: feature/30-description ๋˜๋Š” epic/10-description " 
       exit 1
    fi
    
  2. Issue link verification

    • Issue number extractable from branch name
    • ZenHub issue in In Progress state
  3. PR base verification (hierarchical branches)

        # base ๋ธŒ๋žœ์น˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ๊ณ„์ธต์ธ์ง€ ํ™•์ธ
    # Sub-task โ†’ Story ๋ธŒ๋žœ์น˜, Story โ†’ Epic ๋ธŒ๋žœ์น˜, Epic/๋…๋ฆฝ โ†’ development
    BASE_BRANCH= " ${baseBranch} " 
     git rev-parse --verify  " origin/${BASE_BRANCH} "   2 > /dev/null || {
      echo  " โŒ base ๋ธŒ๋žœ์น˜๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: $BASE_BRANCH " 
       exit 1
    }
    
  4. Commit verification

        # base ๋ธŒ๋žœ์น˜ ๋Œ€๋น„ ์ปค๋ฐ‹ ๊ฒ€์ฆ (๊ณ„์ธต ๋ธŒ๋žœ์น˜ ์ง€์›)
    COMMITS=$(git rev-list --count origin/${BASE_BRANCH}..HEAD)
    if [[ $COMMITS -eq 0 ]]; then
      echo  " โŒ ์ปค๋ฐ‹์ด ์—†์Šต๋‹ˆ๋‹ค. Step 7์„ ๋จผ์ € ์™„๋ฃŒํ•ด์ฃผ์„ธ์š” " 
       exit 1
    fi
    
  5. Pre-push verification + DCM format/lint 0-issue gate + DCM code quality improvement (Step 8.5)

        # Phase 1: DCM ํฌ๋งทํŒ… + Dart ๋ฆฐํŠธ ์ž๋™ ์ˆ˜์ • + 0๊ฑด ๊ฒŒ์ดํŠธ
    melos run format                     # dcm format (dart format ๋Œ€์ฒด)
    dart fix --apply                     # ์ž๋™ ์ˆ˜์ • ๊ฐ€๋Šฅํ•œ ๋ฆฐํŠธ ์ด์Šˆ ์ผ๊ด„ ์ˆ˜์ •
    melos run analyze:dart               # Dart SDK ๋ถ„์„ ์‹คํ–‰
    # โ†’ error/warning/info ๋ชจ๋‘ 0๊ฑด ํ•„์ˆ˜ (๋‚จ์•„์žˆ์œผ๋ฉด ์ˆ˜๋™ ์ˆ˜์ • ํ›„ ์žฌ๊ฒ€์ฆ, ์ตœ๋Œ€ 2ํšŒ)
    # โ†’ 2ํšŒ ์‹œ๋„ ํ›„์—๋„ ์ด์Šˆ ์ž”์กด ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ
    
    # Phase 2: DCM ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ 
    melos run analyze:dcm                # DCM ๋ฆฐํŠธ + ๋ฉ”ํŠธ๋ฆญ ๊ฒ€์‚ฌ
    melos run fix:dcm                    # ์ž๋™ ์ˆ˜์ • (๋ฆฐํŠธ)
    melos run check:unused-code          # ๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ๊ฒ€์‚ฌ
    melos run analyze:dcm                # ์ˆ˜์ • ํ›„ ์žฌ๊ฒ€์ฆ
    # โ†’ error ์‹ฌ๊ฐ๋„ ์ด์Šˆ 0๊ฑด ํ•„์ˆ˜
    
    # Phase 3: ์ตœ์ข… ๋ฆฐํŠธ ๊ฒ€์ฆ (DCM ์ˆ˜์ •์ด ์ƒˆ ๋ฆฐํŠธ ์ด์Šˆ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•˜๋Š”์ง€)
    melos run analyze:dart               # Dart SDK ์ตœ์ข… ํ™•์ธ
    melos run analyze:dcm                # DCM ์ตœ์ข… ํ™•์ธ
    

Step Skip Prevention#

Principle: Each step can only proceed after the previous step is complete

// ๋‹จ๊ณ„ ์ „์ œ์กฐ๊ฑด ๊ฒ€์ฆ
async function validateStepPrerequisites(stepNumber: number) {
  const todos = await getTodoList();

  // ์ด์ „ ๋‹จ๊ณ„๋“ค์ด ๋ชจ๋‘ completed์ธ์ง€ ํ™•์ธ
  for (let i = 1; i  <   stepNumber; i++) {
    const step = todos.find(t = >   t.content.startsWith(`Step ${i}`));
    if (step?.status !==  " completed "   & &   step?.status !==  " skipped " ) {
      throw new Error(`
        โŒ Step ${i}์ด(๊ฐ€) ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
        ํ˜„์žฌ ์ƒํƒœ: ${step?.status ||  ' unknown ' }

        ๋จผ์ € Step ${i}์„(๋ฅผ) ์™„๋ฃŒํ•ด์ฃผ์„ธ์š”.
      `);
    }
  }
}

Detailed Implementation#

Step 1: Work Content Analysis#

// ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ํƒ€์ž… ์ž๋™ ์ถ”๋ก 
const typeKeywords = {
  feat: [ " ์ถ”๊ฐ€ " ,  " ๊ตฌํ˜„ " ,  " ์ƒ์„ฑ " ,  " ๋งŒ๋“ค๊ธฐ " ,  " ํ™”๋ฉด " ],
  fix: [ " ์ˆ˜์ • " ,  " ๊ณ ์น˜๊ธฐ " ,  " ๋ฒ„๊ทธ " ,  " ์—๋Ÿฌ " ,  " ๋ฌธ์ œ " ],
  refactor: [ " ๊ฐœ์„  " ,  " ๋ฆฌํŒฉํ† ๋ง " ,  " ์ •๋ฆฌ " ,  " ์ตœ์ ํ™” " ],
  chore: [ " ์„ค์ • " ,  " ๋นŒ๋“œ " ,  " ํ™˜๊ฒฝ " ,  " ๋ฐฐํฌ " ],
  docs: [ " ๋ฌธ์„œ " ,  " README " ,  " ์ฃผ์„ " ],
  test: [ " ํ…Œ์ŠคํŠธ " ,  " test " ,  " ๊ฒ€์ฆ " ],
};

// ํ™”๋ฉด ํƒ€์ž… ๊ฐ์ง€
const screenKeywords = {
  list: [ " ๋ชฉ๋ก " ,  " ๋ฆฌ์ŠคํŠธ " ,  " list " ,  " ์กฐํšŒ " ,  " ๊ฒ€์ƒ‰ " ],
  detail: [ " ์ƒ์„ธ " ,  " detail " ,  " ๋ณด๊ธฐ " ],
  form: [ " ์ถ”๊ฐ€ " ,  " ์ƒ์„ฑ " ,  " ์ˆ˜์ • " ,  " ํŽธ์ง‘ " ,  " form " ,  " ๋“ฑ๋ก " ],
};

const analysis = {
  type: inferType(workContent),      // feat/fix/refactor...
  scope: extractScope(workContent),  // feature๋ช…
  screenType: detectScreen(workContent), // list/detail/form/null
  point: estimatePoint(workContent), // 1/3/5/8
  requiresBdd: screenType !== null,  // screen feature์ด๋ฉด true
};

Step 2: ZenHub Issue Creation#

// ์ด์Šˆ ํƒ€์ž… ๋งคํ•‘
const issueTypeMap = {
  feat:  " Feature " ,
  fix:  " Bug " ,
  refactor:  " Task " ,
  chore:  " Task " ,
  docs:  " Task " ,
  test:  " Task " ,
};

// GitHub ์ด์Šˆ ์ƒ์„ฑ
const issue = await mcp__zenhub__createGitHubIssue({
  repositoryId: githubRepoId,
  title: `${gitmoji} ${analysis.scope}: ${workContent}`,
  body: generateIssueBody(workContent, analysis),
  issueTypeId: getIssueTypeId(issueTypeMap[analysis.type]),
  labels: generateLabels(analysis),
});

// Estimate ์„ค์ •
await mcp__zenhub__setIssueEstimate({
  issueId: issue.id,
  estimate: analysis.point,
});

Step 3-5: Pipeline Move & Branch Creation (hierarchical branch strategy)#

// Product Backlog ์ด๋™
await mcp__zenhub__moveIssueToPipeline({
  issueId: issue.id,
  pipelineId: productBacklogPipelineId,
});

// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// Step 4: ๊ณ„์ธต ๋ธŒ๋žœ์น˜ ์ „๋žต - base ๋ธŒ๋žœ์น˜ ๋™์  ๊ฒฐ์ •
// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

// 4-1. ๋ถ€๋ชจ ์ด์Šˆ ๊ฐ์ง€
let baseBranch = options.base ||  " development " ;
let parentIssue = null;

if (!options.base) {
  // ZenHub์—์„œ ๋ถ€๋ชจ ์ด์Šˆ ์กฐํšŒ
  const issueDetails = await mcp__zenhub__searchLatestIssues({
    query: `#${issue.number}`,
  });
  const parentId = issueDetails[0]?.parentIssueId;

  if (parentId) {
    parentIssue = await mcp__zenhub__getIssue({ issueId: parentId });
    const parentType = parentIssue.issueType; //  " Epic "   |  " Feature "   | ...
    const parentNumber = parentIssue.number;

    // 4-2. ๋ถ€๋ชจ ๋ธŒ๋žœ์น˜ ์กด์žฌ ํ™•์ธ
    const parentBranchPrefix = parentType ===  " Epic "   ?  " epic "   :  " feature " ;
    const parentSlug = createSlug(parentIssue.title);
    const expectedParentBranch = `${parentBranchPrefix}/${parentNumber}-${parentSlug}`;

    const branchExists = await Bash(
      `git rev-parse --verify origin/${expectedParentBranch} 2 > /dev/null  & &   echo  " exists "   || echo  " missing " `
    );

    if (branchExists.trim() ===  " missing " ) {
      // 4-3. ๋ถ€๋ชจ ๋ธŒ๋žœ์น˜ ์ž๋™ ์ƒ์„ฑ (development ๊ธฐ๋ฐ˜)
      // ๋ถ€๋ชจ์˜ ๋ถ€๋ชจ๊ฐ€ ์žˆ์œผ๋ฉด ์žฌ๊ท€์ ์œผ๋กœ base ๊ฒฐ์ •
      const grandparentBranch = parentIssue.parentIssueId
        ? await resolveBaseBranch(parentIssue.parentIssueId)
        :  " development " ;

      await Bash(`
        git checkout ${grandparentBranch}
        git pull origin ${grandparentBranch}
        git checkout -b ${expectedParentBranch}
        git push -u origin ${expectedParentBranch}
      `);
      console.log(`๐ŸŒฟ ๋ถ€๋ชจ ๋ธŒ๋žœ์น˜ ์ž๋™ ์ƒ์„ฑ: ${expectedParentBranch}`);
    }

    baseBranch = expectedParentBranch;
    console.log(`๐Ÿ“ ๊ณ„์ธต ๋ธŒ๋žœ์น˜: ${baseBranch} ๊ธฐ๋ฐ˜์œผ๋กœ ๋ถ„๊ธฐ`);
  }
}

// 4-4. ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ (base ๋ธŒ๋žœ์น˜์—์„œ ๋ถ„๊ธฐ)
await Task({
  subagent_type:  " issue-branch-agent " ,
  prompt: `์ด์Šˆ #${issue.number} ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ (base: ${baseBranch})`,
  // base_branch ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ
});

// In Progress ์ด๋™
await mcp__zenhub__moveIssueToPipeline({
  issueId: issue.id,
  pipelineId: inProgressPipelineId,
});

Base Branch Decision Function

// ์žฌ๊ท€์  base ๋ธŒ๋žœ์น˜ ๊ฒฐ์ •
async function resolveBaseBranch(issueId: string): Promise < string >   {
  const issue = await mcp__zenhub__getIssue({ issueId });
  const branchPrefix = issue.issueType ===  " Epic "   ?  " epic "   :  " feature " ;
  const slug = createSlug(issue.title);
  const branchName = `${branchPrefix}/${issue.number}-${slug}`;

  // ๋ธŒ๋žœ์น˜ ์กด์žฌ ํ™•์ธ
  const exists = await Bash(
    `git rev-parse --verify origin/${branchName} 2 > /dev/null  & &   echo  " exists "   || echo  " missing " `
  );

  if (exists.trim() ===  " exists " ) {
    return branchName;
  }

  // ๋ถ€๋ชจ๊ฐ€ ์žˆ์œผ๋ฉด ์žฌ๊ท€, ์—†์œผ๋ฉด development
  if (issue.parentIssueId) {
    const parentBranch = await resolveBaseBranch(issue.parentIssueId);
    await Bash(`
      git checkout ${parentBranch}  & &   git pull origin ${parentBranch}
      git checkout -b ${branchName}
      git push -u origin ${branchName}
    `);
    return branchName;
  }

  // ์ตœ์ƒ์œ„ โ†’ development ๊ธฐ๋ฐ˜
  await Bash(`
    git checkout development  & &   git pull origin development
    git checkout -b ${branchName}
    git push -u origin ${branchName}
  `);
  return branchName;
}

Step 6: BDD Scenario Writing (for screen features)#

if (analysis.requiresBdd  & &   !options.skipBdd) {
  await Task({
    subagent_type:  " bdd-scenario-agent " ,
    prompt: `
      feature_name: ${analysis.scope}
      screen_type: ${analysis.screenType}

      ํ™”๋ฉด ํƒ€์ž…์— ๋งž๋Š” BDD ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
    `,
  });

  // ์ปค๋ฐ‹
  await Bash(`
    git add .
    git commit -m  " test(${analysis.scope}): โœ… BDD ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ

    - ${analysis.screenType} ํ™”๋ฉด ์‹œ๋‚˜๋ฆฌ์˜ค ์ถ”๊ฐ€
    - Step Definition ์ƒ์„ฑ

    Co-Authored-By: Claude  < noreply@anthropic.com > " 
   `);
}

Step 7-8: Implementation and Testing#

Agent Teams Parallel Mode (auto-detected)

When Agent Teams are available (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1), Steps 7 and 8 are parallelized. When not available, automatically falls back to existing sequential processing.

์‚ฌ์ „ ํ™•์ธ (Step 7 ์‹œ์ž‘ ์ „):
1. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ™•์ธ
2. teams_available = true โ†’ ๋ณ‘๋ ฌ ๋ชจ๋“œ ์ง„์ž…
3. teams_available = false โ†’ ์ˆœ์ฐจ ์‹คํ–‰ (์•„๋ž˜  " ์ˆœ์ฐจ ์‹คํ–‰ ํ๋ฆ„ "   ์„น์…˜)
4. ๋ณ‘๋ ฌ ๋ชจ๋“œ ์ง„์ž… ์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ํŒ€ ๊ตฌ์„ฑ ๊ณ„ํš ์ถœ๋ ฅ ํ›„ ์Šน์ธ ์š”์ฒญ

Step 7 Implementation Parallelization (frontend/backend simultaneous):

Agent Teams ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์‹œ:
  โ”œโ”€ Teammate 1: Backend ๊ตฌํ˜„
  โ”‚   โ”œโ”€ Serverpod model ์ •์˜
  โ”‚   โ”œโ”€ Endpoint ๊ตฌํ˜„
  โ”‚   โ”œโ”€ Service ๋กœ์ง
  โ”‚   โ””โ”€ melos run backend:pod:generate
  โ”‚
  โ””โ”€ Teammate 2: Frontend ๊ตฌํ˜„
      โ”œโ”€ Domain Layer (Entity, UseCase, Repository ์ธํ„ฐํŽ˜์ด์Šค)
      โ”œโ”€ Data Layer (Repository ๊ตฌํ˜„, DataSource)
      โ””โ”€ Presentation Layer (BLoC, Page, Widget)

  โ†’ ์™„๋ฃŒ ํ›„ Lead๊ฐ€ ํ†ตํ•ฉ ๊ฒ€์ฆ:
    - ํ”„๋ก ํŠธ/๋ฐฑ์—”๋“œ ์ธํ„ฐํŽ˜์ด์Šค ์ผ์น˜ ํ™•์ธ
    - Import ์ฐธ์กฐ ์ •ํ•ฉ์„ฑ ํ™•์ธ

Fallback (์ˆœ์ฐจ):
  Backend โ†’ Frontend ์ˆœ์ฐจ ์‹คํ–‰

Step 8 Test Parallelization:

Agent Teams ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์‹œ:
  โ”œโ”€ Teammate 1: Frontend Unit + BLoC ํ…Œ์ŠคํŠธ
  โ”‚   โ”œโ”€ UseCase ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (unit-test-agent)
  โ”‚   โ””โ”€ BLoC ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (bloc-test-agent)
  โ”‚
  โ”œโ”€ Teammate 2: Backend Unit + Integration ํ…Œ์ŠคํŠธ
  โ”‚   โ”œโ”€ ์—”๋“œํฌ์ธํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (serverpod-test-agent)
  โ”‚   โ”œโ”€ ์„œ๋น„์Šค ๋กœ์ง ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  โ”‚   โ””โ”€ ์—”๋“œํฌ์ธํŠธ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
  โ”‚
  โ””โ”€ Teammate 3: BDD Widget ํ…Œ์ŠคํŠธ (screen feature ์‹œ)
      โ”œโ”€ Gherkin ์‹œ๋‚˜๋ฆฌ์˜ค ๊ฒ€์ฆ
      โ””โ”€ Step Definition ์‹คํ–‰

  โ†’ ์™„๋ฃŒ ํ›„ Lead๊ฐ€ ๊ฒฐ๊ณผ ๋ณ‘ํ•ฉ:
    - ์ „์ฒด tests passed ์—ฌ๋ถ€ ์ง‘๊ณ„
    - ์‹คํŒจ ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ

Fallback (์ˆœ์ฐจ):
  Unit โ†’ BLoC โ†’ Backend โ†’ BDD ์ˆœ์ฐจ ์‹คํ–‰

Sequential Execution Flow (default / Fallback)

// ๊ตฌํ˜„ ์ž‘์—…
await Task({
  subagent_type:  " implementation-agent " ,
  prompt: `์ด์Šˆ #${issue.number} ๊ตฌํ˜„`,
});

// Backend ๋ณ€๊ฒฝ ๊ฐ์ง€
const hasBackendChanges = detectBackendChanges(issue);

// ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐ ๊ฒ€์ฆ (ํ•„์ˆ˜ ๊ฒŒ์ดํŠธ) โš ๏ธ
if (!options.skipTests) {
  const testTypes = [ " unit " ,  " bloc " ];
  if (analysis.requiresBdd) testTypes.push( " bdd " );
  if (hasBackendChanges) testTypes.push( " backend_unit " ,  " backend_integration " );

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // Phase 1: ํ…Œ์ŠคํŠธ ํ”Œ๋žœ ์ž‘์„ฑ
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // PR์˜ Test Plan ํ•ญ๋ชฉ์„ ๋จผ์ € ์ •์˜ โ€” ๊ตฌํ˜„ ์ฝ”๋“œ์˜ ํ•ต์‹ฌ ๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค
  const testPlan = generateTestPlan({
    workContent,
    scope: analysis.scope,
    testTypes,
    hasBackendChanges,
    requiresBdd: analysis.requiresBdd,
  });

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // Phase 2: ํ…Œ์ŠคํŠธ ํ”Œ๋žœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  await Task({
    subagent_type:  " test-runner-agent " ,
    prompt: `
      feature_name: ${analysis.scope}
      test_types: ${JSON.stringify(testTypes)}
      test_plan: ${JSON.stringify(testPlan)}
      auto_fix: true
      require_tests: true
      write_tests_for_plan: true
    `,
  });

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // Phase 3: ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๋ฐ ๊ฒฐ๊ณผ ์ˆ˜์ง‘
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // 3-1. ์ •์  ๋ถ„์„ (dart analyze) โ€” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ปดํŒŒ์ผ ๊ฒ€์ฆ
  const analyzeResult = await Bash(
    `dart analyze ${testPlan.map(t = >   t.file).join( '   ' )} 2 > & 1 | grep -c  " error " `
  );
  const analyzeErrors = parseInt(analyzeResult.stdout.trim());

  // 3-2. ํ…Œ์ŠคํŠธ ์‹คํ–‰ (์ •์  ๋ถ„์„ ํ†ต๊ณผ ์‹œ)
  let testResults = { totalPassed: 0, totalFailed: 0, items: [] };
  if (analyzeErrors === 0) {
    const testOutput = await Bash(
      `flutter test ${testPlan.map(t = >   t.file).filter(Boolean).join( '   ' )} 2 > & 1`
    );
    testResults = parseTestOutput(testOutput.stdout);
  }

  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  // Phase 4: ๊ฒฐ๊ณผ๋ฅผ PR Test Plan์— ๋ฐ˜์˜
  // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  prBodyExtras.testPlanResults = testPlan.map(item = >   ({
    ...item,
    analyzePass: analyzeErrors === 0,
    testPass: testResults.items.find(r = >   r.name === item.item)?.passed ?? null,
  }));
  prBodyExtras.testSummary = {
    analyzeErrors,
    totalPassed: testResults.totalPassed,
    totalFailed: testResults.totalFailed,
  };

  // โš ๏ธ ๊ฒŒ์ดํŠธ: ์ •์  ๋ถ„์„ ์‹คํŒจ ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ
  if (analyzeErrors  >   0) {
    throw new Error(`ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ •์  ๋ถ„์„ ์‹คํŒจ (${analyzeErrors}๊ฑด) - ์—๋Ÿฌ ์ˆ˜์ • ํ›„ ์žฌ์‹œ๋„`);
  }
  // โš ๏ธ ๊ฒŒ์ดํŠธ: ํ…Œ์ŠคํŠธ ์‹คํŒจ ์‹œ PR ์ƒ์„ฑ ์ฐจ๋‹จ (๋Ÿฐํƒ€์ž„ ์‹คํ–‰ ๊ฐ€๋Šฅํ–ˆ๋˜ ๊ฒฝ์šฐ)
  if (testResults.totalFailed  >   0) {
    throw new Error(`ํ…Œ์ŠคํŠธ ${testResults.totalFailed}๊ฑด ์‹คํŒจ - ์ˆ˜์ • ํ›„ ์žฌ์‹œ๋„`);
  }
} else {
  // --skip-tests ์‚ฌ์šฉ ์‹œ ์‚ฌ์šฉ์ž ํ™•์ธ ํ•„์ˆ˜
  const confirm = await AskUserQuestion({
    questions: [{
      header:  " ํ…Œ์ŠคํŠธ ์Šคํ‚ต ํ™•์ธ " ,
      question:  " ํ…Œ์ŠคํŠธ๋ฅผ ์Šคํ‚ตํ•˜๋ฉด ๊ฒ€์ฆ ์—†์ด PR์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๊ณ„์†ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? " ,
      options: [
        { label:  " ์Šคํ‚ต ํ™•์ธ " , description:  " ํ…Œ์ŠคํŠธ ์—†์ด ์ง„ํ–‰ (๊ธด๊ธ‰ ํ•ซํ”ฝ์Šค์šฉ) "   },
        { label:  " ํ…Œ์ŠคํŠธ ์‹คํ–‰ " , description:  " ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค "   },
      ],
    }],
  });
}

Step 8.3: BDD Coverage Gate#

// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// Step 8.3: BDD Coverage Gate
// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// .feature ํŒŒ์ผ์˜ ๋ชจ๋“  Gherkin step์ด ๊ตฌํ˜„๋œ step ํ•จ์ˆ˜๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š”์ง€ ๊ฒ€์ฆ
// step ํ•จ์ˆ˜์— assertion์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์ฆ

if (!options.skipBdd) {
  // 1. .feature ํŒŒ์ผ ์Šค์บ” (ํ˜„์žฌ feature ๋ฒ”์œ„)
  const featureDir = findFeatureTestDir(scope); // test/src/bdd/ ํ•˜์œ„
  const featureFiles = await Glob(`${featureDir}/**/*.feature`);

  if (featureFiles.length === 0) {
    console.warn(`โš ๏ธ .feature ํŒŒ์ผ ์—†์Œ (${featureDir}) โ€” BDD gate ์Šคํ‚ต`);
  } else {
    // 2. Given/When/Then ์Šคํ… ํŒŒ์‹ฑ
    const allSteps = [];
    for (const file of featureFiles) {
      const content = await Read(file);
      const steps = content.match(/^\s*(Given|When|Then|And|But)\s+(.+)$/gm) || [];
      for (const step of steps) {
        const keyword = step.match(/^\s*(Given|When|Then|And|But)/)[1];
        const pattern = step
          .replace(/^\s*(Given|When|Then|And|But)\s+/,  ' ' )
          .replace(/#.*$/,  ' ' )  // ํ•œ๊ธ€ ์ฃผ์„ ์ œ๊ฑฐ
          .trim();
        allSteps.push({ file, keyword, pattern });
      }
    }

    // 3. step/ ํด๋”์—์„œ ๋งค์นญ step ํ•จ์ˆ˜ ๊ฒ€์ฆ
    const stepDir = `${featureDir}/step`;
    const stepFiles = await Glob(`${stepDir}/**/*.dart`);
    const stepContents = {};
    for (const f of stepFiles) {
      stepContents[f] = await Read(f);
    }
    const allStepCode = Object.values(stepContents).join( ' \n ' );

    // step ํŒจํ„ด โ†’ camelCase ํ•จ์ˆ˜๋ช… ๋ณ€ํ™˜ ํ›„ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ
    const missingSteps = allSteps.filter(step = >   {
      const funcName = stepPatternToFunctionName(step.pattern);
      return !allStepCode.includes(funcName);
    });

    const stepCoverage = allSteps.length  >   0
      ? (allSteps.length - missingSteps.length) / allSteps.length
      : 1.0;

    // 4. ๊ฐ step ํ•จ์ˆ˜ ๋‚ด assertion ์กด์žฌ ํ™•์ธ
    const filesWithoutAssertions = stepFiles.filter(f = >   {
      const content = stepContents[f];
      // UnimplementedError๋Š” stub โ†’ assertion ๋ฏธ๊ตฌํ˜„์œผ๋กœ ๊ฐ„์ฃผ
      if (content.includes( ' UnimplementedError ' )) return true;
      // expect, verify, expectVisible, expectTextVisible ๋“ฑ ํ™•์ธ
      return !content.match(/expect\(|verify\(|expectVisible|expectTextVisible|expectAsync/);
    });

    // 5. Gate ํŒ์ •
    if (stepCoverage  <   1.0) {
      console.error(`โŒ BDD step coverage: ${(stepCoverage * 100).toFixed(1)}% (required: 100%)`);
      missingSteps.forEach(s = > 
         console.error(`   Missing: ${s.keyword} ${s.pattern} (${s.file})`)
      );
      console.error(`\n   ๐Ÿ’ก step ํ•จ์ˆ˜ ์ƒ์„ฑ: /bdd:generate ${scope} --only-steps true`);
      throw new Error(`BDD Coverage Gate failed: step_coverage=${(stepCoverage * 100).toFixed(1)}%`);
    }

    if (filesWithoutAssertions.length  >   0) {
      console.error(`โŒ Assertion ์—†๋Š” step ํŒŒ์ผ ${filesWithoutAssertions.length}๊ฑด:`);
      filesWithoutAssertions.forEach(f = >   console.error(`   ${f}`));
      console.error(`\n   ๐Ÿ’ก UnimplementedError stub์„ ์‹ค์ œ assertion์œผ๋กœ ๊ต์ฒดํ•˜์„ธ์š”`);
      throw new Error(`BDD Coverage Gate failed: ${filesWithoutAssertions.length} step files missing assertions`);
    }

    console.log(`โœ… Step 8.3 complete โ€” BDD coverage 100%, all ${allSteps.length} steps have assertions`);
  }
} else {
  console.warn(`โš ๏ธ BDD Coverage Gate skipped (--skip-bdd)`);
}

Step 8.5: Pre-push Verification + DCM Format/Lint 0-Issue Gate + DCM Code Quality Improvement#

// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// Phase 1: DCM ํฌ๋งทํŒ… + Dart ๋ฆฐํŠธ ์ž๋™ ์ˆ˜์ • (0๊ฑด ๋ชฉํ‘œ)
// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// โš ๏ธ ํฌ๋งคํ„ฐ: dcm format์œผ๋กœ ํ†ต์ผ (dart format ์‚ฌ์šฉ ๊ธˆ์ง€)
//    melos run format โ†’ ๋‚ด๋ถ€์ ์œผ๋กœ dcm format lib ์‹คํ–‰

// 1-1. DCM ํฌ๋งทํŒ… ์ ์šฉ
await Bash(`melos run format`);  // dcm format (dart format ๋Œ€์ฒด)

// 1-2. dart fix --apply ๋กœ ์ž๋™ ์ˆ˜์ • ๊ฐ€๋Šฅํ•œ ๋ฆฐํŠธ ์ด์Šˆ ์ผ๊ด„ ์ˆ˜์ •
//      (deprecated API ๋Œ€์ฒด, unnecessary_import ์ œ๊ฑฐ, prefer_const ์ ์šฉ ๋“ฑ)
await Bash(`dart fix --apply`);

// 1-3. ํฌ๋งทํŒ… + fix ๋ณ€๊ฒฝ ์ปค๋ฐ‹ (๋ณ€๊ฒฝ ์žˆ์„ ๋•Œ๋งŒ)
const hasFixChanges = await Bash(`git diff --name-only`);
if (hasFixChanges.trim()) {
  await Bash(`
    git add .
    git commit -m  " style: ๐ŸŽจ dart fix + format ์ž๋™ ์ˆ˜์ •

    - dart fix --apply ๋ฆฐํŠธ ์ž๋™ ์ˆ˜์ •
    - dcm format ์ฝ”๋“œ ์Šคํƒ€์ผ ์ •๋ฆฌ

    Co-Authored-By: Claude  < noreply@anthropic.com > " 
   `);
}

// 1-4. Dart SDK analyze ์‹คํ–‰ ๋ฐ ๊ฒฐ๊ณผ ํŒŒ์‹ฑ (dart analyze โ€” DCM๊ณผ ๋ณ„๋„)
const analyzeOutput = await Bash(`melos run analyze:dart 2 > & 1`);
const analyzeLines = analyzeOutput.split( ' \n ' )
  .filter(line = >   line.match(/\s+(info|warning|error)\s+[โ€ขยท-]/));

const totalAnalyzeIssues = analyzeLines.length;

// 1-5. ๋ฆฐํŠธ ์ด์Šˆ๊ฐ€ ๋‚จ์•„์žˆ์œผ๋ฉด ์ˆ˜๋™ ์ˆ˜์ • ์‹œ๋„ (์ตœ๋Œ€ 2ํšŒ ๋ฐ˜๋ณต)
if (totalAnalyzeIssues  >   0) {
  console.warn(`โš ๏ธ dart analyze ์ด์Šˆ ${totalAnalyzeIssues}๊ฑด ๋ฐœ๊ฒฌ`);

  for (let attempt = 0; attempt  <   2; attempt++) {
    // ๊ฐ ์ด์Šˆ์˜ ์†Œ์Šค ํŒŒ์ผ์„ ์ฝ๊ณ  ๋ฆฐํŠธ ๊ทœ์น™์— ๋งž๊ฒŒ ์ง์ ‘ ์ˆ˜์ •
    for (const issue of analyzeLines) {
      // ํŒŒ์ผ ๊ฒฝ๋กœ, ๋ผ์ธ, ๊ทœ์น™๋ช…์„ ํŒŒ์‹ฑํ•˜์—ฌ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •
      await fixAnalyzeIssue(issue);
    }

    // ์ˆ˜์ • ํ›„ ์žฌํฌ๋งท + ์žฌ๋ถ„์„
    await Bash(`dart fix --apply`);
    await Bash(`melos run format`);  // dcm format
    const recheck = await Bash(`melos run analyze:dart 2 > & 1`);
    const recheckLines = recheck.split( ' \n ' )
      .filter(line = >   line.match(/\s+(info|warning|error)\s+[โ€ขยท-]/));

    if (recheckLines.length === 0) {
      console.log(`โœ… dart analyze ์ด์Šˆ 0๊ฑด โ€” ๋ฆฐํŠธ ๊ฒŒ์ดํŠธ ํ†ต๊ณผ`);
      break;
    }

    if (attempt === 1  & &   recheckLines.length  >   0) {
      // 2ํšŒ ์‹œ๋„ ํ›„์—๋„ ์ด์Šˆ๊ฐ€ ๋‚จ์•„์žˆ์œผ๋ฉด ์ƒ์„ธ ์ถœ๋ ฅ + PR ์ฐจ๋‹จ
      console.error(`โŒ dart analyze ์ด์Šˆ ${recheckLines.length}๊ฑด ๋ฏธํ•ด๊ฒฐ โ€” PR ์ƒ์„ฑ ์ฐจ๋‹จ`);
      recheckLines.forEach(l = >   console.error(`   ${l.trim()}`));
      throw new Error(`Dart lint gate blocked: ${recheckLines.length} issues remaining`);
    }
  }

  // ์ˆ˜์ •๋œ ํŒŒ์ผ ์ปค๋ฐ‹
  const hasLintFixes = await Bash(`git diff --name-only`);
  if (hasLintFixes.trim()) {
    await Bash(`
      git add .
      git commit -m  " fix: ๐Ÿ› flutter analyze ๋ฆฐํŠธ ์ด์Šˆ ์ˆ˜์ •

      - error/warning/info ์ด์Šˆ 0๊ฑด ๋‹ฌ์„ฑ
      - ์ •์  ๋ถ„์„ ํด๋ฆฐ ์ƒํƒœ ํ™•๋ณด

      Co-Authored-By: Claude  < noreply@anthropic.com > " 
     `);
  }
} else {
  console.log(`โœ… flutter analyze ์ด์Šˆ 0๊ฑด โ€” ๋ฆฐํŠธ ๊ฒŒ์ดํŠธ ํ†ต๊ณผ`);
}

// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// Phase 2: DCM ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  (dcm-code-quality ์Šคํ‚ฌ ํ™œ์šฉ)
// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

// 2-1. DCM ๋ฆฐํŠธ + ๋ฉ”ํŠธ๋ฆญ ๊ฒ€์‚ฌ ์‹คํ–‰
const dcmRunResult = await Bash(`melos run analyze:dcm 2 > & 1`);

// 2-2. ์ž๋™ ์ˆ˜์ • ๊ฐ€๋Šฅ ํ•ญ๋ชฉ ์ˆ˜์ •
await Bash(`melos run fix:dcm`);

// 2-3. ๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ๊ฒ€์‚ฌ
await Bash(`melos run check:unused-code`);

// 2-4. ์ˆ˜์ • ํ›„ ์žฌ๊ฒ€์ฆ
const dcmVerifyResult = await Bash(`melos run analyze:dcm 2 > & 1`);

// 2-5. ์ˆ˜์ •๋œ ํŒŒ์ผ ์ปค๋ฐ‹
const hasDcmChanges = await Bash(`git diff --name-only`);
if (hasDcmChanges.trim()) {
  await Bash(`
    git add .
    git commit -m  " refactor: โ™ป๏ธ DCM ์ฝ”๋“œ ํ’ˆ์งˆ ์ž๋™ ์ˆ˜์ •

    - dcm fix . ์ž๋™ ์ˆ˜์ • ์ ์šฉ
    - ๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ์ •๋ฆฌ

    Co-Authored-By: Claude  < noreply@anthropic.com > " 
   `);
}

// 2-6. ์ž”์—ฌ ์ด์Šˆ ์š”์•ฝ โ†’ PR body์— ํฌํ•จ
const remainingIssues = parseDcmOutput(dcmVerifyResult);
if (remainingIssues.length  >   0) {
  prBodyExtras.dcmFindings = remainingIssues;
  console.log(`โ„น๏ธ DCM ์ž”์—ฌ ์ด์Šˆ ${remainingIssues.length}๊ฑด โ†’ PR body์— ํฌํ•จ`);
}

// 2-7. error ์‹ฌ๊ฐ๋„ ์ด์Šˆ๊ฐ€ ๋‚จ์•„์žˆ์œผ๋ฉด ์ฐจ๋‹จ
const errorIssues = remainingIssues.filter(i = >   i.severity ===  " error " );
if (errorIssues.length  >   0) {
  console.error(`โŒ DCM error ์ด์Šˆ ${errorIssues.length}๊ฑด ๋ฏธํ•ด๊ฒฐ โ€” PR ์ƒ์„ฑ ์ฐจ๋‹จ`);
  throw new Error( " DCM quality gate blocked " );
}

// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
// Phase 3: ์ตœ์ข… ๋ฆฐํŠธ ๊ฒ€์ฆ (DCM ์ˆ˜์ •์ด ์ƒˆ๋กœ์šด ๋ฆฐํŠธ ์ด์Šˆ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธ)
// โš ๏ธ dart analyze + dcm analyze ๋ชจ๋‘ ์‹คํ–‰ (๊ฒ€์‚ฌ ๋ฒ”์œ„๊ฐ€ ๋‹ค๋ฆ„)
//    - dart analyze: Dart SDK ๊ธฐ๋ณธ ๋ฆฐํŠธ + ํƒ€์ž… ์ฒดํฌ + ์–ธ์–ด ์ˆ˜์ค€ ์˜ค๋ฅ˜
//    - dcm analyze: DCM ์ „์šฉ ๋ฆฐํŠธ ๊ทœ์น™ + ๋ฉ”ํŠธ๋ฆญ + ์•ˆํ‹ฐํŒจํ„ด
// โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

// 3-1. Dart SDK ์ตœ์ข… ๊ฒ€์ฆ
const finalDartAnalyze = await Bash(`melos run analyze:dart 2 > & 1`);
const finalDartIssues = finalDartAnalyze.split( ' \n ' )
  .filter(line = >   line.match(/\s+(info|warning|error)\s+[โ€ขยท-]/));

if (finalDartIssues.length  >   0) {
  console.error(`โŒ ์ตœ์ข… ๊ฒ€์ฆ ์‹คํŒจ: dart analyze ์ด์Šˆ ${finalDartIssues.length}๊ฑด`);
  finalDartIssues.forEach(l = >   console.error(`   ${l.trim()}`));
  throw new Error(`Final dart lint gate blocked: ${finalDartIssues.length} issues remaining`);
}

// 3-2. DCM ์ตœ์ข… ๊ฒ€์ฆ
const finalDcmAnalyze = await Bash(`melos run analyze:dcm 2 > & 1`);
const finalDcmErrors = parseDcmOutput(finalDcmAnalyze).filter(i = >   i.severity ===  " error " );

if (finalDcmErrors.length  >   0) {
  console.error(`โŒ ์ตœ์ข… ๊ฒ€์ฆ ์‹คํŒจ: dcm analyze error ${finalDcmErrors.length}๊ฑด`);
  throw new Error(`Final DCM lint gate blocked: ${finalDcmErrors.length} error issues remaining`);
}

console.log(`โœ… Step 8.5 complete โ€” dart analyze 0๊ฑด, dcm analyze error 0๊ฑด`);

Step 8.7: Code Review Gate (gstack pattern)#

Agent Teams Parallel Mode (auto-detected)

When Agent Teams are available, 8 review categories are distributed across 3 teams for parallel execution. (Agent Teams availability is already checked before Step 7 start)

Agent Teams ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์‹œ:
  โ”œโ”€ Teammate 1: ๋ณด์•ˆ + ์„ฑ๋Šฅ (Critical Focus)
  โ”‚   โ”œโ”€ ๋ณด์•ˆ ์ทจ์•ฝ์  (injection, XSS, ์ธ์ฆ ์šฐํšŒ)
  โ”‚   โ”œโ”€ ๋ฐ์ดํ„ฐ ์•ˆ์ „์„ฑ (null safety, race condition)
  โ”‚   โ””โ”€ ์„ฑ๋Šฅ (N+1, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜, ๋ถˆํ•„์š”ํ•œ rebuild)
  โ”‚
  โ”œโ”€ Teammate 2: ์•„ํ‚คํ…์ฒ˜ + ์ƒํƒœ๊ด€๋ฆฌ
  โ”‚   โ”œโ”€ Clean Architecture ์ค€์ˆ˜ (๋ ˆ์ด์–ด ์˜์กด์„ฑ)
  โ”‚   โ”œโ”€ BLoC ํŒจํ„ด (์ƒํƒœ ์ „์ด, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ)
  โ”‚   โ””โ”€ DI / Repository ์ธํ„ฐํŽ˜์ด์Šค ์ค€์ˆ˜
  โ”‚
  โ””โ”€ Teammate 3: ๊ฐ€๋…์„ฑ + i18n + ์ ‘๊ทผ์„ฑ (Informational)
      โ”œโ”€ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ (๋„ค์ด๋ฐ, ๊ตฌ์กฐ, ๋ณต์žก๋„)
      โ”œโ”€ i18n (ํ•˜๋“œ์ฝ”๋”ฉ ๋ฌธ์ž์—ด, ๋ฒˆ์—ญ ํ‚ค)
      โ””โ”€ ์ ‘๊ทผ์„ฑ (semanticLabel, ํ„ฐ์น˜ ํƒ€๊ฒŸ)

  โ†’ Lead๊ฐ€ ๊ฒฐ๊ณผ ๋ณ‘ํ•ฉ:
    - Critical ์ด์Šˆ (Teammate 1, 2) โ†’ Gate ์ฐจ๋‹จ ํŒ์ •
    - Informational (Teammate 3) โ†’ PR body์— ํฌํ•จ
    - Critical ๋ฐœ๊ฒฌ ์‹œ ์ž๋™ ์ˆ˜์ • ์‹œ๋„ (์ตœ๋Œ€ 2ํšŒ)

Fallback (์ˆœ์ฐจ):
  8๊ฐœ ์นดํ…Œ๊ณ ๋ฆฌ ์ˆœ์ฐจ ๊ฒ€์‚ฌ

Sequential Execution Flow (default / Fallback)

if (!options.skipReview) {
  // Pass 1: Critical ์ด์Šˆ ๊ฒ€์‚ฌ
  const reviewResult = await Skill({
    skill:  " code-review " ,
    args:  " --quick --gate-mode " ,
  });

  const criticalIssues = reviewResult.issues.filter(i = >   i.severity ===  " critical " );
  const informationalIssues = reviewResult.issues.filter(i = >   i.severity !==  " critical " );

  if (criticalIssues.length  >   0) {
    // ์ž๋™ ์ˆ˜์ • ์‹œ๋„ (์ตœ๋Œ€ 2ํšŒ)
    for (let attempt = 0; attempt  <   2; attempt++) {
      await autoFixCriticalIssues(criticalIssues);
      const recheck = await Skill({ skill:  " code-review " , args:  " --quick --gate-mode "   });
      if (recheck.criticalCount === 0) break;
    }

    // ์žฌ๊ฒ€์ฆ ํ›„์—๋„ Critical ๋‚จ์•„์žˆ์œผ๋ฉด ์ฐจ๋‹จ
    if (finalCheck.criticalCount  >   0) {
      console.error(`โŒ Code Review Gate ์‹คํŒจ: ${finalCheck.criticalCount}๊ฑด์˜ Critical ์ด์Šˆ`);
      console.error( "     --skip-review ์˜ต์…˜์œผ๋กœ ์šฐํšŒํ•˜๊ฑฐ๋‚˜, ์ˆ˜๋™ ์ˆ˜์ • ํ›„ ์žฌ์‹œ๋„ํ•˜์„ธ์š” " );
      throw new Error( " Code Review Gate blocked " );
    }
  }

  // Pass 2: Informational ํ•ญ๋ชฉ์€ PR body์— ํฌํ•จํ•  ๋ฐ์ดํ„ฐ๋กœ ์ €์žฅ
  prBodyExtras.reviewFindings = informationalIssues;
} else {
  console.warn( " โš ๏ธ Code Review Gate๋ฅผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค (--skip-review) " );
  console.warn( "     ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ „ ๋ฐ˜๋“œ์‹œ /code-review๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š” " );
}

Step 9-10: PR Creation & Move to Review/QA (hierarchical merge)#

// PR base ๋ธŒ๋žœ์น˜ ๊ฒฐ์ • (๊ณ„์ธต ๋ธŒ๋žœ์น˜ ์ „๋žต)
// baseBranch๋Š” Step 4์—์„œ ๊ฒฐ์ •๋œ ๊ฐ’ ์‚ฌ์šฉ
const prBaseBranch = baseBranch; // epic/xxx, feature/xxx, ๋˜๋Š” development

// PR ์ƒ์„ฑ
await Bash(`
  gh pr create --base  " ${prBaseBranch} "   \
    --title  " ${gitmoji} ${analysis.scope}: ${workContent} "   \
    --body  " $(cat  < < ' EOF ' 
 ## Summary
- ${workContent}

## Test Plan
${prBodyExtras.testPlanResults?.map(t = >   {
  const check = t.testPass === true ?  ' x '   : (t.testPass === false ?  '   '   :  ' ~ ' );
  const status = t.analyzePass
    ? (t.testPass === true ?  ' โœ… '   : (t.testPass === false ?  ' โŒ '   :  ' โš ๏ธ ๋ถ„์„๋งŒ ํ†ต๊ณผ ' ))
    :  ' โŒ ๋ถ„์„ ์‹คํŒจ ' ;
  return `- [${check}] ${t.item} (${status})`;
}).join( ' \n ' ) ?? `
- [ ] UseCase ๋‹จ์œ„ tests passed
- [ ] BLoC ๋‹จ์œ„ tests passed
${hasBackendChanges ?  ' - [ ] ๋ฐฑ์—”๋“œ ์—”๋“œํฌ์ธํŠธ ํ†ตํ•ฉ tests passed '   :  ' ' }
${analysis.requiresBdd ?  ' - [ ] BDD ์‹œ๋‚˜๋ฆฌ์˜ค ํ†ต๊ณผ '   :  ' ' }
`}
${prBodyExtras.testSummary ? `
 >   ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ: ${prBodyExtras.testSummary.totalPassed}๊ฑด ํ†ต๊ณผ` +
  (prBodyExtras.testSummary.totalFailed  >   0 ? `, ${prBodyExtras.testSummary.totalFailed}๊ฑด ์‹คํŒจ` :  ' ' ) +
  (prBodyExtras.testSummary.analyzeErrors  >   0 ? ` | ์ •์  ๋ถ„์„ ์—๋Ÿฌ: ${prBodyExtras.testSummary.analyzeErrors}๊ฑด` :  '   | ์ •์  ๋ถ„์„: โœ… ' )
:  ' ' }

Closes #${issue.number}

${prBodyExtras.dcmFindings?.length  >   0 ? `
## DCM Quality Report
${prBodyExtras.dcmFindings.map(f = >   `- **[${f.severity}]** ${f.rule}: ${f.message} (${f.file}:${f.line})`).join( ' \n ' )}
` :  ' ' }
${prBodyExtras.reviewFindings?.length  >   0 ? `
## Review Findings (Informational)
${prBodyExtras.reviewFindings.map(f = >   `- **[${f.category}]** ${f.message} (${f.file}:${f.line})`).join( ' \n ' )}
` :  ' ' }
๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code)
EOF
) " 
 `);

// Review/QA ์ด๋™
await mcp__zenhub__moveIssueToPipeline({
  issueId: issue.id,
  pipelineId: reviewQaPipelineId,
});

Step 11: Apply Additional Review Feedback#

// Step 8.7์—์„œ ์ž๋™ ์ฝ”๋“œ review complete๋จ
// Step 11์€ PR ์ƒ์„ฑ ํ›„ ์ถ”๊ฐ€ ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜ ๋‹จ๊ณ„
if (!options.skipReview) {
  // PR ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ ํ™•์ธ ๋ฐ ์ถ”๊ฐ€ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜
  await Skill({ skill:  " code-review "   });

  // ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜ (์ž๋™ ๊ฐ€๋Šฅํ•œ ๊ฒƒ๋งŒ)
  await Bash(`melos run format`);       // dcm format
  await Bash(`dart fix --apply`);
  await Bash(`melos run analyze:dart`);
  await Bash(`melos run analyze:dcm`);

  // /checklist:feature-complete ์‹คํ–‰
  await Skill({ skill:  " checklist:feature-complete "   });
}

Step 12: Wait for Merge Approval#

// ์ตœ์ข… ์ƒํƒœ ์š”์•ฝ
displayMergeSummary(issue, pr, testResults, reviewResults);

// user approval ์š”์ฒญ
const approval = await AskUserQuestion({
  questions: [{
    header:  " ๋จธ์ง€ " ,
    question:  " PR์„ ๋จธ์ง€ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? " ,
    options: [
      { label:  " ๋จธ์ง€ ์Šน์ธ " , description:  " ์Šค์ฟผ์‹œ ๋จธ์ง€ ํ›„ ์ด์Šˆ ํด๋กœ์ฆˆ "   },
      { label:  " ์ˆ˜์ • ํ•„์š” " , description:  " Step 7๋กœ ๋Œ์•„๊ฐ€์„œ ์ˆ˜์ • "   },
      { label:  " ์ทจ์†Œ " , description:  " ํ˜„์žฌ ์ƒํƒœ ์œ ์ง€ "   },
    ],
    multiSelect: false,
  }],
});

if (approval ===  " ๋จธ์ง€ ์Šน์ธ " ) {
  // ์Šค์ฟผ์‹œ ๋จธ์ง€ โ†’ GitHub  " Closes # "   ํ‚ค์›Œ๋“œ๋กœ ์ด์Šˆ ์ž๋™ Close
  // Done ํŒŒ์ดํ”„๋ผ์ธ ์ด๋™ ๋ถˆํ•„์š” (๋จธ์ง€ = ์™„๋ฃŒ)
  await Bash(`gh pr merge --squash --delete-branch`);

  // ๊ณ„์ธต ๋ธŒ๋žœ์น˜: ๋ถ€๋ชจ ๋ธŒ๋žœ์น˜๊ฐ€ Epic์ด๊ณ  ๋ชจ๋“  Story๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์•ˆ๋‚ด
  if (parentIssue  & &   parentIssue.issueType ===  " Epic " ) {
    const siblings = await mcp__zenhub__searchLatestIssues({
      query: `parent:${parentIssue.id}`,
    });
    const openSiblings = siblings.filter(s = >   s.state ===  " open " );
    if (openSiblings.length === 0) {
      console.log(`\n๐ŸŽ‰ Epic #${parentIssue.number}์˜ ๋ชจ๋“  Story๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`);
      console.log(`   Epic ๋ธŒ๋žœ์น˜๋ฅผ development์— ๋จธ์ง€ํ•˜์„ธ์š”:`);
      console.log(`   /dev:run ${parentIssue.number}`);
    } else {
      console.log(`\nโ„น๏ธ Epic #${parentIssue.number}: ${openSiblings.length}๊ฐœ Story ๋‚จ์Œ`);
    }
  }
}

Output Format#

Progress Display#

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘  /dev:run Progress                                            โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘                                                                โ•‘
โ•‘  [โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘] 50% - Step 6/12                       โ•‘
โ•‘                                                                โ•‘
โ•‘  โœ… Step 1: ์ž‘์—… ๋‚ด์šฉ ๋ถ„์„ ์™„๋ฃŒ (screen feature ๊ฐ์ง€: List)          โ•‘
โ•‘  โœ… Step 2: ์ด์Šˆ #1810 ์ƒ์„ฑ ์™„๋ฃŒ                                โ•‘
โ•‘  โœ… Step 3: Product Backlog ์ด๋™                               โ•‘
โ•‘  โœ… Step 4: ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ์™„๋ฃŒ                                   โ•‘
โ•‘  โœ… Step 5: In Progress ์ด๋™                                   โ•‘
โ•‘  ๐Ÿ”„ Step 6: BDD ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ ์ค‘...                            โ•‘
โ•‘  โณ Step 7: ๊ตฌํ˜„ ์ž‘์—… ๋Œ€๊ธฐ                                     โ•‘
โ•‘  โณ Step 8: ํ…Œ์ŠคํŠธ ์ž‘์„ฑ/์‹คํ–‰ ๋Œ€๊ธฐ                               โ•‘
โ•‘  โณ Step 9: PR ์ƒ์„ฑ ๋Œ€๊ธฐ                                       โ•‘
โ•‘  โณ Step 10: Review/QA ์ด๋™ ๋Œ€๊ธฐ                               โ•‘
โ•‘  โณ Step 11: ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋Œ€๊ธฐ                                    โ•‘
โ•‘  โณ Step 12: ๋จธ์ง€ ์Šน์ธ ๋Œ€๊ธฐ                                    โ•‘
โ•‘                                                                โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

On Completion#

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘  Workflow Complete: #1810                                      โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘                                                                โ•‘
โ•‘  ๐Ÿ“‹ Issue: #1810 - ์ €์ž ๋ชฉ๋ก ํ™”๋ฉด ์ถ”๊ฐ€                          โ•‘
โ•‘  ๐Ÿ”€ PR: #1815                                                  โ•‘
โ•‘  ๐ŸŒฟ Branch: feature/1810-author-list (deleted)                 โ•‘
โ•‘                                                                โ•‘
โ•‘  ๐Ÿ“ Changes:                                                   โ•‘
โ•‘    - 12 files changed                                         โ•‘
โ•‘    - +520 / -30 lines                                         โ•‘
โ•‘                                                                โ•‘
โ•‘  โœ… Tests: 35/35 passed                                        โ•‘
โ•‘    - UseCase Unit: 10/10                                      โ•‘
โ•‘    - BLoC Unit: 8/8                                           โ•‘
โ•‘    - Backend Unit: 6/6 (endpoint: 3, service: 3)              โ•‘
โ•‘    - Backend Integration: 4/4                                 โ•‘
โ•‘    - BDD: 7/7 scenarios                                       โ•‘
โ•‘                                                                โ•‘
โ•‘  โœ… Review: All issues resolved                                โ•‘
โ•‘  โœ… Checklist: 11/11 passed                                   โ•‘
โ•‘  โœ… CI: All checks passed                                      โ•‘
โ•‘                                                                โ•‘
โ•‘  ๐Ÿ“Š Duration: 22m 15s                                          โ•‘
โ•‘  ๐Ÿ Final State: CLOSED (by merge)                             โ•‘
โ•‘                                                                โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

TodoWrite Integration (Required)#

Rule: Immediately update TodoWrite on each step start/completion

Initialization (On Step 1 Start)#

TodoWrite([
  { content:  " Step 1: ์ž‘์—… ๋‚ด์šฉ ๋ถ„์„ " , status:  " in_progress " , activeForm:  " ์ž‘์—… ๋‚ด์šฉ ๋ถ„์„ ์ค‘ "   },
  { content:  " Step 2: ZenHub ์ด์Šˆ ์ƒ์„ฑ " , status:  " pending " , activeForm:  " ์ด์Šˆ ์ƒ์„ฑ ๋Œ€๊ธฐ "   },
  { content:  " Step 3: Product Backlog ์ด๋™ " , status:  " pending " , activeForm:  " Pipeline ์ด๋™ ๋Œ€๊ธฐ "   },
  { content:  " Step 4: ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ " , status:  " pending " , activeForm:  " ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ๋Œ€๊ธฐ "   },
  { content:  " Step 5: In Progress ์ด๋™ " , status:  " pending " , activeForm:  " Pipeline ์ด๋™ ๋Œ€๊ธฐ "   },
  { content:  " Step 6: BDD ์‹œ๋‚˜๋ฆฌ์˜ค " , status:  " pending " , activeForm:  " BDD ์ž‘์„ฑ ๋Œ€๊ธฐ "   },
  { content:  " Step 7: ๊ตฌํ˜„ ์ž‘์—… " , status:  " pending " , activeForm:  " ๊ตฌํ˜„ ๋Œ€๊ธฐ "   },
  { content:  " Step 7.5: Backend ์ฝ”๋“œ ์ƒ์„ฑ " , status:  " pending " , activeForm:  " Backend ์ƒ์„ฑ ๋Œ€๊ธฐ "   },
  { content:  " Step 8: ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐ ๊ฒ€์ฆ (ํ•„์ˆ˜ ๊ฒŒ์ดํŠธ) " , status:  " pending " , activeForm:  " ํ…Œ์ŠคํŠธ ๋Œ€๊ธฐ "   },
  { content:  " Step 8.3: BDD Coverage Gate " , status:  " pending " , activeForm:  " BDD ์ปค๋ฒ„๋ฆฌ์ง€ ๊ฒ€์ฆ ๋Œ€๊ธฐ "   },
  { content:  " Step 8.5: Pre-push ๊ฒ€์ฆ + ๋ฆฐํŠธ 0๊ฑด + DCM ํ’ˆ์งˆ ๊ฐœ์„  " , status:  " pending " , activeForm:  " ๊ฒ€์ฆ ๋Œ€๊ธฐ "   },
  { content:  " Step 8.7: Code Review Gate " , status:  " pending " , activeForm:  " ๋ฆฌ๋ทฐ ๊ฒŒ์ดํŠธ ๋Œ€๊ธฐ "   },
  { content:  " Step 9: PR ์ƒ์„ฑ " , status:  " pending " , activeForm:  " PR ์ƒ์„ฑ ๋Œ€๊ธฐ "   },
  { content:  " Step 10-12: ๋ฆฌ๋ทฐ/๋จธ์ง€ " , status:  " pending " , activeForm:  " ๋ฆฌ๋ทฐ ๋Œ€๊ธฐ "   },
]);

Update Immediately on Step Completion#

// Step 4 complete ํ›„ ์˜ˆ์‹œ
TodoWrite([
  { content:  " Step 1: ์ž‘์—… ๋‚ด์šฉ ๋ถ„์„ " , status:  " completed " , activeForm:  " ์ž‘์—… ๋ถ„์„ ์™„๋ฃŒ "   },
  { content:  " Step 2: ZenHub ์ด์Šˆ ์ƒ์„ฑ " , status:  " completed " , activeForm:  " ์ด์Šˆ ์ƒ์„ฑ ์™„๋ฃŒ "   },
  { content:  " Step 3: Product Backlog ์ด๋™ " , status:  " completed " , activeForm:  " Pipeline ์ด๋™ ์™„๋ฃŒ "   },
  { content:  " Step 4: ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ " , status:  " completed " , activeForm:  " ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ์™„๋ฃŒ "   },
  { content:  " Step 5: In Progress ์ด๋™ " , status:  " in_progress " , activeForm:  " Pipeline ์ด๋™ ์ค‘ "   },
  // ... ๋‚˜๋จธ์ง€ pending ์œ ์ง€
]);

State Tracking Rules#

RuleDescription
Only 1 in_progressOnly 1 in_progress state allowed at a time
Immediate update Change to completed immediately on step completion
Skip markingAdd "(skip)" to content for N/A steps
Keep on failureKeep failed step as in_progress

Auto-Inference Details#

Type Inference Examples#

/dev:run  " ์ €์ž ๋ชฉ๋ก ํ™”๋ฉด ์ถ”๊ฐ€ " 
 โ†’ ํ‚ค์›Œ๋“œ  " ์ถ”๊ฐ€ " ,  " ํ™”๋ฉด "   ๊ฐ์ง€ โ†’ feat

/dev:run  " ๋กœ๊ทธ์ธ ๋ฒ„๊ทธ ์ˆ˜์ • " 
 โ†’ ํ‚ค์›Œ๋“œ  " ๋ฒ„๊ทธ " ,  " ์ˆ˜์ • "   ๊ฐ์ง€ โ†’ fix

/dev:run  " API ์‘๋‹ต ์บ์‹ฑ ๊ฐœ์„  " 
 โ†’ ํ‚ค์›Œ๋“œ  " ๊ฐœ์„  "   ๊ฐ์ง€ โ†’ refactor

Screen Type Detection Examples#

/dev:run  " ์ €์ž ๋ชฉ๋ก ํ™”๋ฉด ์ถ”๊ฐ€ " 
 โ†’ ํ‚ค์›Œ๋“œ  " ๋ชฉ๋ก "   ๊ฐ์ง€ โ†’ List โ†’ BDD ์ž๋™ ์ƒ์„ฑ

/dev:run  " ๋„์„œ ์ƒ์„ธ ํ™”๋ฉด ๊ตฌํ˜„ " 
 โ†’ ํ‚ค์›Œ๋“œ  " ์ƒ์„ธ "   ๊ฐ์ง€ โ†’ Detail โ†’ BDD ์ž๋™ ์ƒ์„ฑ

/dev:run  " ์ €์ž ๋“ฑ๋ก ํผ ์ถ”๊ฐ€ " 
 โ†’ ํ‚ค์›Œ๋“œ  " ๋“ฑ๋ก "   ๊ฐ์ง€ โ†’ Form โ†’ BDD ์ž๋™ ์ƒ์„ฑ

/dev:run  " API ์‘๋‹ต ์บ์‹ฑ ์ถ”๊ฐ€ " 
 โ†’ ํ™”๋ฉด ํ‚ค์›Œ๋“œ ์—†์Œ โ†’ BDD ์Šคํ‚ต

Error Handling#

Step-by-Step Recovery Strategy#

Failed StepStateRecovery Method
Issue creationNo changesRetry
Branch creationIssue existsRetry
BDD scenarioBranch exists--skip-bdd or manual writing
ImplementationBranch existsContinue work
TestsCode complete--skip-tests or manual fix
Dart lint gate Code complete dart fix --apply + melos run format (dcm format) + manual fix (up to 2 times) โ†’ 0 issues required
DCM quality gate Code complete melos run fix:dcm auto-fix โ†’ melos run analyze:dcm โ†’ manually fix remaining errors
Code Review GateCode complete--skip-review or manual fix
PR creationCode completeRun gh pr create manually
Code reviewPR exists--skip-review or manual application
MergePR existsWait for CI pass then manual merge

  • /dev:issue {number} - Progress cycle with existing issue
  • /dev:bugfix - Bug fix dedicated cycle
  • /bug-report - Bug report creation
  • /code-review - Run code review
  • /dcm:quality - DCM code quality analysis and auto-fix
  • /checklist:feature-complete - Completion checklist
  • issue-branch-agent - Branch creation
  • issue-state-agent - Issue state management
  • bdd-scenario-agent - BDD scenario generation
  • implementation-agent - Code implementation
  • test-runner-agent - Test execution
  • pr-lifecycle-agent - PR management