makdoong2-team 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/agents/makdoong2-analyzer.md +135 -0
- package/agents/makdoong2-engineer.md +165 -0
- package/agents/makdoong2-planner.md +267 -0
- package/agents/makdoong2-publisher.md +481 -0
- package/agents/makdoong2-team-leader.md +249 -0
- package/agents/makdoong2-verifier.md +353 -0
- package/assets/makdoong2-team.default.json +46 -0
- package/assets/makdoong2-team.schema.json +357 -0
- package/bin/cli.js +404 -0
- package/dist/agent-stage-config.d.ts +15 -0
- package/dist/agent-stage-config.js +119 -0
- package/dist/config.d.ts +79 -0
- package/dist/config.js +96 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.js +131 -0
- package/dist/mcp-secret-injector.d.ts +56 -0
- package/dist/mcp-secret-injector.js +89 -0
- package/dist/model-chain-cli.d.ts +1 -0
- package/dist/model-chain-cli.js +21 -0
- package/dist/model-fallback-policy.d.ts +69 -0
- package/dist/model-fallback-policy.js +211 -0
- package/dist/opencode-plugin.d.ts +8 -0
- package/dist/opencode-plugin.js +2457 -0
- package/dist/poll-sub-session.d.ts +139 -0
- package/dist/poll-sub-session.js +494 -0
- package/dist/redact-secrets.d.ts +3 -0
- package/dist/redact-secrets.js +68 -0
- package/dist/session-index.d.ts +11 -0
- package/dist/session-index.js +71 -0
- package/dist/skill-mcp-registry.d.ts +59 -0
- package/dist/skill-mcp-registry.js +178 -0
- package/dist/stall-escalation.d.ts +1 -0
- package/dist/stall-escalation.js +22 -0
- package/dist/tmux-monitor.d.ts +193 -0
- package/dist/tmux-monitor.js +694 -0
- package/dist/verdict-hash.d.ts +1 -0
- package/dist/verdict-hash.js +62 -0
- package/gates/stage-analysis-verify.sh +84 -0
- package/gates/stage2-requirements-verify.sh +13 -0
- package/gates/stage3-scope-verify.sh +45 -0
- package/gates/stage4-dev-post-verify.sh +64 -0
- package/gates/stage4-dev-verify.sh +36 -0
- package/gates/stage5-coverage-verify.sh +36 -0
- package/gates/stage5-test-verify.sh +24 -0
- package/gates/stage6-commit-verify.sh +41 -0
- package/gates/stage6-post-commit-verify.sh +131 -0
- package/gates/stage7-post-pr-verify.sh +53 -0
- package/gates/stage7-pr-verify.sh +48 -0
- package/gates/stage8-post-review-verify.sh +84 -0
- package/gates/stage8-review-verify.sh +45 -0
- package/gates/verify.sh +44 -0
- package/opencode.json.example +40 -0
- package/package.json +84 -0
- package/postinstall.mjs +56 -0
- package/references/commit-convention.md +130 -0
- package/references/jira-issue-templates.md +203 -0
- package/references/pr-template.md +381 -0
- package/scripts/config.sh +46 -0
- package/scripts/coverage-record.sh +67 -0
- package/scripts/gate-policy-test.sh +152 -0
- package/scripts/install-lib.mjs +1029 -0
- package/scripts/lint-agent-prompts.sh +74 -0
- package/scripts/log-event.sh +44 -0
- package/scripts/model-policy.mjs +183 -0
- package/scripts/publish-if-changed.sh +207 -0
- package/scripts/release.sh +276 -0
- package/scripts/rollback-commits.sh +35 -0
- package/scripts/smoke-test.mjs +194 -0
- package/scripts/state.sh +192 -0
- package/scripts/test-postinstall.mjs +141 -0
- package/scripts/with-fallback.sh +56 -0
- package/scripts/wt-sync-ignored.sh +193 -0
- package/skills/_lib/load-secret.sh +149 -0
- package/skills/bamboo-ci/SKILL.md +81 -0
- package/skills/bamboo-ci/run-bamboo.sh +23 -0
- package/skills/bitbucket-research/SKILL.md +87 -0
- package/skills/bitbucket-research/run-repos.sh +23 -0
- package/skills/confluence-research/SKILL.md +75 -0
- package/skills/confluence-research/run-docs.sh +23 -0
- package/skills/github-oss-research/SKILL.md +59 -0
- package/skills/jira-research/SKILL.md +75 -0
- package/skills/jira-research/run-works.sh +23 -0
- package/src/hooks/guard-bash.sh +67 -0
- package/src/hooks/session-start.sh +96 -0
- package/src/hooks/sync-state.sh +47 -0
- package/stages/01-jira.md +43 -0
- package/stages/01-planning.md +229 -0
- package/stages/02-requirements.md +298 -0
- package/stages/03-scope.md +81 -0
- package/stages/04-analysis.md +281 -0
- package/stages/05-worktree-dev.md +124 -0
- package/stages/06-test.md +161 -0
- package/stages/07-commit.md +229 -0
- package/stages/08-pr.md +177 -0
- package/stages/09-review-comments.md +277 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# 4단계: Workspace 분석 (Analysis)
|
|
2
|
+
|
|
3
|
+
**목적**: 개발 진입 전에 workspace 구조·의존성·관례·통합 지점을 결정론적으로 분석하고, 그 결과를 고정 JSON schema로 산출한다. 로컬 LLM 계열이 분석을 건너뛰고 코드 생성으로 직행하는 문제를 harness 레벨에서 차단하는 phase gating 이다.
|
|
4
|
+
|
|
5
|
+
**진입 게이트**: `verify.sh <이슈키> 2_implementation.analysis` (3단계 scope 완료 필요).
|
|
6
|
+
|
|
7
|
+
> 게이트가 build tool 마커 파일 부재를 감지하면 자동 스킵 처리한다 (`skipped=true`, `done=true` 마킹 후 dispatch 없이 dev substage 로 진행). 본 명세는 게이트를 통과하여 dispatch 된 경우에만 실행된다.
|
|
8
|
+
|
|
9
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
10
|
+
|
|
11
|
+
## 4-0. 사전 확인 (재개 판정)
|
|
12
|
+
|
|
13
|
+
이미 완료된 재실행을 방지한다.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."2_implementation".substages."analysis"' 2>/dev/null
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- `.done == true` → 재실행 금지. 부장님에게 "이미 완료" 회신 후 종료.
|
|
20
|
+
- `.skipped == true` → 게이트가 이미 SKIP 처리한 상태. dispatch 자체가 발생하지 않았어야 하므로 상태 이상. 부장님에게 보고.
|
|
21
|
+
- 그 외 → 다음 절차로 진행.
|
|
22
|
+
|
|
23
|
+
## 4-1. Workspace 스캔 (Read-Only)
|
|
24
|
+
|
|
25
|
+
프로젝트 루트의 파일 시스템을 read-only 로 스캔한다. **Edit / Patch / MultiEdit 툴 사용 금지 (프론트매터에서 차단)**. `glob`, `grep`, `read`, read-only `bash` (`ls`, `find`, `cat`, `jq`, `grep` 등) 만 사용.
|
|
26
|
+
|
|
27
|
+
### 4-1-1. Build tool 및 프로젝트 형태 확인
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# 프로젝트 루트에서 build tool 마커 파일 확인
|
|
31
|
+
cd <worktree>
|
|
32
|
+
ls -la package.json build.gradle build.gradle.kts pom.xml Cargo.toml go.mod \
|
|
33
|
+
pyproject.toml setup.py requirements.txt Gemfile mix.exs build.sbt \
|
|
34
|
+
composer.json Package.swift Makefile CMakeLists.txt 2>/dev/null || true
|
|
35
|
+
|
|
36
|
+
# .csproj 는 glob 필요
|
|
37
|
+
ls -la *.csproj 2>/dev/null || true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
식별된 build tool 을 기반으로 `project_structure.build_tool` 필드 값을 확정한다 (`npm`|`gradle`|`maven`|`cargo`|`go`|`pip`|`bundler`|`mix`|`sbt`|`composer`|`swiftpm`|`make`|`cmake`|`dotnet` 등). 여러 마커가 있으면 primary 를 선택 (예: gradle wrapper + Makefile → gradle).
|
|
41
|
+
|
|
42
|
+
### 4-1-2. Source tree 파악
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 디렉토리 구조 (max depth 3, 빌드 산출물 제외)
|
|
46
|
+
find . -maxdepth 3 -type d \
|
|
47
|
+
-not -path '*/node_modules*' -not -path '*/.git*' -not -path '*/build*' \
|
|
48
|
+
-not -path '*/dist*' -not -path '*/target*' -not -path '*/.gradle*' \
|
|
49
|
+
-not -path '*/out*' -not -path '*/.venv*' -not -path '*/__pycache__*' | sort
|
|
50
|
+
|
|
51
|
+
# 주요 확장자별 파일 카운트 (분석 참고용)
|
|
52
|
+
for ext in java kt scala py js ts go rs rb cs cpp c h swift; do
|
|
53
|
+
cnt=$(find . -maxdepth 5 -type f -name "*.$ext" \
|
|
54
|
+
-not -path '*/node_modules*' -not -path '*/.git*' \
|
|
55
|
+
-not -path '*/build*' -not -path '*/target*' 2>/dev/null | wc -l)
|
|
56
|
+
[ "$cnt" -gt 0 ] && echo " .$ext: $cnt"
|
|
57
|
+
done
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`project_structure.tree` 필드에 간략화된 tree 를 문자열로 기록 (최대 100 줄 이내). `project_structure.modules` 배열에는 최상위 모듈/패키지 명을 기록 (예: gradle multi-module 이면 settings.gradle 파싱, npm workspace 이면 package.json workspaces 파싱).
|
|
61
|
+
|
|
62
|
+
### 4-1-3. Dependency 선언 조사
|
|
63
|
+
|
|
64
|
+
Build tool 별 대응:
|
|
65
|
+
|
|
66
|
+
| Build tool | 조사 명령 |
|
|
67
|
+
|---|---|
|
|
68
|
+
| npm | `jq '.dependencies, .devDependencies' package.json` |
|
|
69
|
+
| gradle | `grep -E '(implementation\|api\|testImplementation\|compileOnly)\s+' build.gradle*` |
|
|
70
|
+
| maven | `grep -A2 '<dependency>' pom.xml` |
|
|
71
|
+
| cargo | `awk '/^\[dependencies\]/{f=1} /^\[/&&!/^\[dependencies\]/{f=0} f' Cargo.toml` |
|
|
72
|
+
| go | `cat go.mod` |
|
|
73
|
+
| pip | `cat requirements.txt` 또는 `grep -A5 dependencies pyproject.toml` |
|
|
74
|
+
| sbt | `cat build.sbt` |
|
|
75
|
+
| composer | `jq '.require, .["require-dev"]' composer.json` |
|
|
76
|
+
|
|
77
|
+
- `dependencies.internal`: 프로젝트 내부 모듈 참조 (multi-module 또는 workspace 형태의 경우).
|
|
78
|
+
- `dependencies.external`: 외부 패키지. 각 항목은 `{name, version}` 형태.
|
|
79
|
+
|
|
80
|
+
버전을 확정할 수 없는 경우 `version: null`.
|
|
81
|
+
|
|
82
|
+
### 4-1-4. Task-relevant files 파악
|
|
83
|
+
|
|
84
|
+
3단계 scope substage 에서 확정한 수정 대상 파일 목록을 state.json 에서 조회한다.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."1_planning".substages."scope"' 2>/dev/null
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
scope 결과의 각 파일에 대해 실제 파일을 read + grep 하여:
|
|
91
|
+
|
|
92
|
+
- `path`: repo root 기준 상대 경로
|
|
93
|
+
- `role`: `target` | `reference` | `test` | `integration_point` 중 하나
|
|
94
|
+
- `reason`: 이 파일이 왜 관련되는지 200자 이내 서술
|
|
95
|
+
|
|
96
|
+
**`task_relevant_files` 배열은 반드시 1개 이상의 요소를 가져야 한다.** (verifier 필수 요건)
|
|
97
|
+
|
|
98
|
+
### 4-1-5. Conventions 조사
|
|
99
|
+
|
|
100
|
+
수정 대상 파일 및 그 이웃 파일들에서 명명 규칙·패턴·유사 구현체를 파악한다.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# naming 예시 확인 (수정 대상 파일에서)
|
|
104
|
+
grep -hE '(public|private|def|fn|func)\s+[a-zA-Z_]+' <target-file> | head -20
|
|
105
|
+
|
|
106
|
+
# 아키텍처 패턴 파악 (Repository/Service/Controller/Handler 계열)
|
|
107
|
+
grep -rE 'class\s+\w+(Service|Repository|Controller|Handler|Manager|Facade)' \
|
|
108
|
+
<source-root>/ 2>/dev/null | head -10
|
|
109
|
+
|
|
110
|
+
# 유사 기능 구현체 검색 (수정 대상과 유사 심볼)
|
|
111
|
+
grep -rl '<유사 심볼 패턴>' <source-root>/ 2>/dev/null | head -5
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- `conventions.naming`: 짧은 요약 (예: "camelCase for methods, PascalCase for classes")
|
|
115
|
+
- `conventions.patterns`: 문자열 배열 (예: `["3-tier Repository/Service/Controller", "@Transactional on service methods"]`)
|
|
116
|
+
- `conventions.similar_impl`: 유사 구현체 파일 경로 배열
|
|
117
|
+
|
|
118
|
+
### 4-1-6. Test conventions 조사
|
|
119
|
+
|
|
120
|
+
기존 테스트 코드의 구조·프레임워크·패턴을 파악한다. engineer 가 테스트 코드를 새로 작성할 때 이 정보를 기반으로 기존 패턴과 일관성을 유지하도록 강제한다.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cd <worktree>
|
|
124
|
+
|
|
125
|
+
# 테스트 루트 디렉토리 탐색
|
|
126
|
+
find . -maxdepth 4 -type d \
|
|
127
|
+
\( -name "test" -o -name "tests" -o -name "__tests__" -o -name "spec" \) \
|
|
128
|
+
-not -path '*/.git*' -not -path '*/node_modules*' -not -path '*/target*' \
|
|
129
|
+
-not -path '*/build*' 2>/dev/null | sort
|
|
130
|
+
|
|
131
|
+
# build tool 별 표준 테스트 루트 확인
|
|
132
|
+
ls -d src/test/scala src/test/java src/test/kotlin \
|
|
133
|
+
test/ tests/ __tests__/ spec/ 2>/dev/null || true
|
|
134
|
+
|
|
135
|
+
# 언어별 테스트 파일 탐색 (프레임워크 식별용)
|
|
136
|
+
find . -maxdepth 6 -type f \
|
|
137
|
+
\( -name "*Spec.scala" -o -name "*Test.scala" -o -name "*Suite.scala" \
|
|
138
|
+
-o -name "*Test.java" -o -name "*Tests.java" \
|
|
139
|
+
-o -name "*Test.kt" -o -name "*Spec.kt" \
|
|
140
|
+
-o -name "*.test.ts" -o -name "*.spec.ts" \
|
|
141
|
+
-o -name "*.test.js" -o -name "*.spec.js" \
|
|
142
|
+
-o -name "test_*.py" -o -name "*_test.py" \
|
|
143
|
+
-o -name "*_test.go" \) \
|
|
144
|
+
-not -path '*/.git*' -not -path '*/node_modules*' \
|
|
145
|
+
-not -path '*/target*' -not -path '*/build*' 2>/dev/null | head -20
|
|
146
|
+
|
|
147
|
+
# 테스트 프레임워크 의존성 확인 (build tool 별)
|
|
148
|
+
# SBT:
|
|
149
|
+
grep -E '(ScalaTest|specs2|munit|scalacheck|mockito|scalamock)' build.sbt 2>/dev/null || true
|
|
150
|
+
# Gradle:
|
|
151
|
+
grep -E '(junit|testng|mockito|assertj|kotest)' build.gradle build.gradle.kts 2>/dev/null || true
|
|
152
|
+
# Maven:
|
|
153
|
+
grep -B1 -A1 'junit\|testng\|mockito\|assertj' pom.xml 2>/dev/null | head -20 || true
|
|
154
|
+
# npm:
|
|
155
|
+
jq '.devDependencies | to_entries[] | select(.key | test("jest|mocha|vitest|jasmine|chai|sinon"))' \
|
|
156
|
+
package.json 2>/dev/null || true
|
|
157
|
+
|
|
158
|
+
# 대표 테스트 파일 2-3개 내용 확인 (패턴 파악)
|
|
159
|
+
find . -maxdepth 6 -type f \
|
|
160
|
+
\( -name "*Spec.scala" -o -name "*Test.java" -o -name "*.test.ts" -o -name "test_*.py" \) \
|
|
161
|
+
-not -path '*/target*' -not -path '*/build*' -not -path '*/node_modules*' \
|
|
162
|
+
2>/dev/null | head -3 | while read -r f; do
|
|
163
|
+
echo "=== $f ==="
|
|
164
|
+
head -40 "$f"
|
|
165
|
+
echo "---"
|
|
166
|
+
done
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
수집 항목:
|
|
170
|
+
- `framework`: 테스트 프레임워크 명 (예: `ScalaTest`, `JUnit5`, `Jest`, `pytest`, `Go test`)
|
|
171
|
+
- `style`: 테스트 스타일 (예: `FlatSpec with Matchers`, `@Test + AssertJ`, `describe-it`, `FunSuite`)
|
|
172
|
+
- `test_roots`: 테스트 루트 디렉토리 배열 (예: `["src/test/scala"]`)
|
|
173
|
+
- `naming_pattern`: 테스트 파일 네이밍 규칙 (예: `*Spec`, `*Test`, `test_*`, `*.test.ts`)
|
|
174
|
+
- `sample_files`: 대표 테스트 파일 경로 2-3개 (repo root 기준 상대 경로)
|
|
175
|
+
- `mock_library`: Mock 라이브러리 (예: `Mockito`, `ScalaMock`, `jest.mock`, `unittest.mock`, `null`)
|
|
176
|
+
- `patterns`: 관찰된 테스트 패턴 문자열 배열 (예: `["given-when-then", "MockitoSugar trait", "fixture setup in beforeEach"]`)
|
|
177
|
+
|
|
178
|
+
테스트 파일이 전혀 없는 경우: `framework: "none"`, 나머지 필드 빈 배열/null.
|
|
179
|
+
|
|
180
|
+
### 4-1-7. Integration points 결정
|
|
181
|
+
|
|
182
|
+
수정 대상 파일 각각에 대해 신규 코드 삽입 위치를 명시한다.
|
|
183
|
+
|
|
184
|
+
- `file`: repo root 기준 상대 경로
|
|
185
|
+
- `symbol`: 삽입 대상 심볼 (예: `com.example.UserService.createUser`, `src/api/routes/auth.ts::loginHandler`)
|
|
186
|
+
- `how`: 삽입 방식 서술 (100자 이내, 예: "메서드 시작부에 validation 호출 추가", "새 case 절을 switch 문에 추가")
|
|
187
|
+
|
|
188
|
+
**`integration_points` 배열은 반드시 1개 이상의 요소를 가져야 한다.** (verifier 필수 요건)
|
|
189
|
+
|
|
190
|
+
## 4-2. 분석 산출물 파일 생성
|
|
191
|
+
|
|
192
|
+
**경로 (repo/worktree root 기준 상대경로)**: `.makdoong2-team/<이슈키>/workspace-analysis.json`
|
|
193
|
+
**물리 파일 생성 위치**: analyzer 는 worktree cwd 에서 실행되므로 `<worktree>/.makdoong2-team/<이슈키>/workspace-analysis.json` 에 물리 파일이 생성된다.
|
|
194
|
+
**형식**: 아래 스키마 엄수. **파일 하나만 생성 허용**. 그 외 파일은 생성·수정 절대 금지.
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"project_structure": {
|
|
199
|
+
"tree": "<간략 tree, 최대 100줄, 문자열>",
|
|
200
|
+
"build_tool": "<npm|gradle|maven|cargo|go|pip|bundler|mix|sbt|composer|swiftpm|make|cmake|dotnet|other>",
|
|
201
|
+
"modules": ["<모듈명 문자열 배열>"]
|
|
202
|
+
},
|
|
203
|
+
"dependencies": {
|
|
204
|
+
"internal": ["<internal module refs>"],
|
|
205
|
+
"external": [
|
|
206
|
+
{"name": "<pkg name>", "version": "<version or null>"}
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
"task_relevant_files": [
|
|
210
|
+
{
|
|
211
|
+
"path": "<relative path from repo root>",
|
|
212
|
+
"role": "<target|reference|test|integration_point>",
|
|
213
|
+
"reason": "<200자 이내>"
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"conventions": {
|
|
217
|
+
"naming": "<naming convention 요약>",
|
|
218
|
+
"patterns": ["<pattern 명 배열>"],
|
|
219
|
+
"similar_impl": ["<유사 구현체 경로 배열>"]
|
|
220
|
+
},
|
|
221
|
+
"integration_points": [
|
|
222
|
+
{
|
|
223
|
+
"file": "<relative path>",
|
|
224
|
+
"symbol": "<class.method 또는 모듈 심볼>",
|
|
225
|
+
"how": "<100자 이내>"
|
|
226
|
+
}
|
|
227
|
+
],
|
|
228
|
+
"test_conventions": {
|
|
229
|
+
"framework": "<ScalaTest|JUnit5|Jest|pytest|Go test|none|other>",
|
|
230
|
+
"style": "<FlatSpec with Matchers|@Test + AssertJ|describe-it|FunSuite|etc>",
|
|
231
|
+
"test_roots": ["<relative path to test root dirs>"],
|
|
232
|
+
"naming_pattern": "<*Spec|*Test|test_*|*.test.ts|etc>",
|
|
233
|
+
"sample_files": ["<2-3 existing test file paths, repo-root relative>"],
|
|
234
|
+
"mock_library": "<Mockito|ScalaMock|jest.mock|unittest.mock|null>",
|
|
235
|
+
"patterns": ["<observed pattern 1>", "<observed pattern 2>"]
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
생성 방식: `Write` 툴을 사용해 위 경로에 파일을 저장한다. `bash` heredoc 리디렉션 (`cat > file <<'JSON' ...`) 은 파일 쓰기 우회로 간주되어 훅에서 차단될 수 있으므로 사용하지 않는다.
|
|
241
|
+
|
|
242
|
+
## 4-3. State.json 마커 기록
|
|
243
|
+
|
|
244
|
+
`state.sh set` 만 사용한다. state.json 직접 편집 금지 (하드룰).
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
# artifact 경로 기록 — 반드시 상대경로만 저장한다 (절대경로 저장 시 다른 cwd 에서 Read hang 유발).
|
|
248
|
+
# 소비 측(dev/test substage, verifier)은 state.sh root() 로 절대경로 해석한다.
|
|
249
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> \
|
|
250
|
+
'.stages."2_implementation".substages."analysis".artifact_path' \
|
|
251
|
+
'".makdoong2-team/<이슈키>/workspace-analysis.json"'
|
|
252
|
+
|
|
253
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> \
|
|
254
|
+
'.stages."2_implementation".substages."analysis".self_check' \
|
|
255
|
+
'{"has_project_structure": true, "has_dependencies": true, "has_task_relevant_files": true, "has_conventions": true, "has_integration_points": true, "has_test_conventions": true, "json_schema_valid": true}'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 4-4. 자가검증 (Pre-Completion Checklist)
|
|
259
|
+
|
|
260
|
+
`done=true` 직전, 아래 7체크를 자가검증한다. 하나라도 false 면 완료 기록 금지 — 미충족 항목을 먼저 해소한다.
|
|
261
|
+
|
|
262
|
+
| 항목 | 확인 |
|
|
263
|
+
|---|---|
|
|
264
|
+
| 1 | `workspace-analysis.json` 이 지정 경로에 생성되었다 (파일 존재) |
|
|
265
|
+
| 2 | JSON parse 성공 (`jq . workspace-analysis.json` 통과) |
|
|
266
|
+
| 3 | 6개 필수 필드 (`project_structure`, `dependencies`, `task_relevant_files`, `conventions`, `integration_points`, `test_conventions`) 모두 존재한다 |
|
|
267
|
+
| 4 | `task_relevant_files` 배열이 비어있지 않다 (>= 1) |
|
|
268
|
+
| 5 | `integration_points` 배열이 비어있지 않다 (>= 1) |
|
|
269
|
+
| 6 | `test_conventions.framework` 가 명시되었다 (테스트 파일 없으면 `"none"`) |
|
|
270
|
+
| 7 | `workspace-analysis.json` 외 파일을 생성·수정하지 않았다 (`git status` 로 확인 — untracked/modified 없음) |
|
|
271
|
+
|
|
272
|
+
## 완료 기록
|
|
273
|
+
|
|
274
|
+
self_check 7개 모두 true 이며 `workspace-analysis.json` 이 유효하면 `done=true` 를 마킹한다.
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> \
|
|
278
|
+
'.stages."2_implementation".substages."analysis".done' 'true'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
> 5단계 진입 시 `verify.sh <이슈키> 2_implementation.dev` 는 `.stages."2_implementation".substages."analysis".done == true` 를 요구한다 (`skipped=true` 인 경우에도 `done=true` 로 처리됨). verifier 는 산출물 파일 존재 + JSON 스키마 정합 + self_check 3중 검증한다.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# 4단계: 격리된 Worktree에서 개발
|
|
2
|
+
|
|
3
|
+
**목적**: 부장님이 준비한 격리된 작업 공간에서 개발한다.
|
|
4
|
+
**진입 게이트**: `verify.sh <이슈키> 2_implementation.dev` (3단계 완료 + 사용자 승인 필요).
|
|
5
|
+
**중요**: Worktree는 **부장님(team-leader)이 자동 생성**했다. Engineer는 이미 준비된 환경에서 작업만 수행한다.
|
|
6
|
+
|
|
7
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
8
|
+
|
|
9
|
+
## 4-0. Analysis 결과 읽기 (필수 — 개발 시작 전)
|
|
10
|
+
|
|
11
|
+
analysis substage 가 산출한 `workspace-analysis.json` 을 읽어 구현 방향을 확정한다. **이 단계를 건너뛰면 기존 코드 패턴과 불일치한 구현이 발생할 수 있으므로 반드시 수행한다.**
|
|
12
|
+
|
|
13
|
+
`artifact_path` 는 상대경로 저장 원칙 (`repo/worktree root` 기준) 을 따르므로 반드시 `state.sh root()` 로 절대경로 해석한다. 절대경로 legacy 값도 함께 수용한다:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ART_REL="$(bash <SCRIPTS_DIR>/state.sh get <이슈키> \
|
|
17
|
+
'.stages."2_implementation".substages."analysis".artifact_path' | tr -d '"')"
|
|
18
|
+
|
|
19
|
+
if [ -z "$ART_REL" ] || [ "$ART_REL" = "null" ]; then
|
|
20
|
+
echo "WARNING: workspace-analysis.json 없음 (analysis 스킵된 경우)"
|
|
21
|
+
elif [[ "$ART_REL" == /* ]]; then
|
|
22
|
+
ANALYSIS_PATH="$ART_REL" # legacy 절대경로 수용
|
|
23
|
+
else
|
|
24
|
+
ANALYSIS_PATH="$(bash <SCRIPTS_DIR>/state.sh root)/$ART_REL"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if [ -n "${ANALYSIS_PATH:-}" ] && [ -f "$ANALYSIS_PATH" ]; then
|
|
28
|
+
jq '{conventions, integration_points, task_relevant_files}' "$ANALYSIS_PATH"
|
|
29
|
+
fi
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
확인 후 아래 항목을 구현 전에 반드시 파악한다:
|
|
33
|
+
|
|
34
|
+
| 항목 | 출처 | 활용 |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `conventions.patterns` | workspace-analysis.json | 아키텍처 패턴 (Repository/Service/Controller 등) — 동일 패턴으로 구현 |
|
|
37
|
+
| `conventions.naming` | workspace-analysis.json | 명명 규칙 — 새 심볼 네이밍에 적용 |
|
|
38
|
+
| `conventions.similar_impl` | workspace-analysis.json | **유사 구현체 파일** — `Read` 로 내용 확인 후 같은 방식으로 구현 |
|
|
39
|
+
| `integration_points[].symbol` | workspace-analysis.json | 코드 삽입 대상 심볼 |
|
|
40
|
+
| `integration_points[].how` | workspace-analysis.json | 삽입 방식 — 이 지시를 그대로 따름 |
|
|
41
|
+
| `task_relevant_files` | workspace-analysis.json | 수정 대상·참조 파일 역할 분류 |
|
|
42
|
+
|
|
43
|
+
**`conventions.similar_impl` 파일이 존재하면**: `Read` 툴로 내용을 실제로 읽고, 해당 구현 방식을 그대로 복제하여 일관성을 유지한다. 유사 구현체를 읽지 않고 독자적으로 구현하는 것을 금지한다.
|
|
44
|
+
|
|
45
|
+
## 4-1. Worktree 환경 확인
|
|
46
|
+
|
|
47
|
+
부장님이 준비한 worktree 경로를 확인한다:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
WT=$(bash <SCRIPTS_DIR>/state.sh get <이슈키> '.worktree' | tr -d '"')
|
|
51
|
+
echo "Working in: $WT"
|
|
52
|
+
pwd # 현재 위치가 $WT인지 확인
|
|
53
|
+
git branch --show-current # feature/<이슈키>인지 확인
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**예상되는 환경**:
|
|
57
|
+
- 경로: `<메인 repo 부모>/<메인 repo명>-<이슈키>` (메인 repo의 형제 디렉토리)
|
|
58
|
+
- 브랜치: `feature/<이슈키>`
|
|
59
|
+
- 로컬 셋업 파일: `.env`, `.idea/` 등이 이미 동기화되어 있음
|
|
60
|
+
|
|
61
|
+
**환경 불일치 시**:
|
|
62
|
+
- 현재 경로 ≠ state.json의 worktree → 사용자에게 보고 후 종료 (부장님이 해결)
|
|
63
|
+
- 브랜치 ≠ `feature/<이슈키>` → 경고 출력 후 계속 (부장님에게 보고 권장)
|
|
64
|
+
|
|
65
|
+
## 4-2. 로컬 셋업 파일 상태 확인
|
|
66
|
+
|
|
67
|
+
`auto_advance_stage` 플러그인이 dev 진입 게이트 직전 `wt-sync-ignored.sh`를 자동 실행했으므로, **추가 작업 불필요**.
|
|
68
|
+
|
|
69
|
+
필요시 확인 사항:
|
|
70
|
+
- `.env`, `.idea/`, IDE 설정 파일들이 존재하는지 확인
|
|
71
|
+
- 빌드 도구 캐시(`.gradle/`, `node_modules/` 등)는 **복사되지 않음** — 첫 빌드 시 자동 생성됨
|
|
72
|
+
|
|
73
|
+
**재동기화가 필요한 경우** (메인 repo의 로컬 파일이 업데이트됨):
|
|
74
|
+
```bash
|
|
75
|
+
bash <SCRIPTS_DIR>/wt-sync-ignored.sh "$WT" "<이슈키>"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> `auto_advance_stage` 플러그인이 gate 진입 직전 이미 실행했으므로 대부분 불필요.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
## 4-3. 개발 진행
|
|
82
|
+
|
|
83
|
+
- 모든 파일 편집을 worktree 절대경로 하위에서만 수행한다.
|
|
84
|
+
- **outer-world 에이전트 위임 금지** — engineer 프론트매터에 `Task` 툴이 없으므로 물리적으로 스폰 불가. 구현·조사·리팩토링 모두 본 에이전트가 직접 수행한다. 조사가 필요하면 `skill_mcp` 로 makdoong2 스킬(`bitbucket-research` 등)만 사용.
|
|
85
|
+
- 3단계 작업 단위 순서대로 구현한다. 한 단위가 끝나면 커밋 가능 상태로 만들어 둔다(실제 커밋은 6단계).
|
|
86
|
+
|
|
87
|
+
## 4-4. 최종 자가 검증 (Pre-Completion Checklist)
|
|
88
|
+
|
|
89
|
+
`done=true` 직전, 아래 6체크를 자가 검증한다.
|
|
90
|
+
하나라도 false면 완료 기록 금지 — 미충족 항목을 먼저 해소한다.
|
|
91
|
+
|
|
92
|
+
| 항목 | 확인 |
|
|
93
|
+
|---|---|
|
|
94
|
+
| 1 | 3단계에서 합의한 모든 수정/추가 파일이 구현되었다 (스코프 100% 충족) |
|
|
95
|
+
| 2 | 기존 테스트(`sbt test` / `./gradlew test` / `mvn test` 등)가 모두 통과한다 |
|
|
96
|
+
| 3 | 새 기능·버그 수정에 대한 테스트가 함께 추가되었다 (테스트 동반 원칙) |
|
|
97
|
+
| 4 | 타입/린트/컴파일 에러가 0이다 |
|
|
98
|
+
| 5 | `.env` / secrets / API 키 / 하드코딩된 비밀이 코드·테스트·로그에 노출되지 않았다 |
|
|
99
|
+
| 6 | `write`/`edit`/`patch`/`multiedit` 로 편집한 모든 파일이 staging area 에 반영되었다 (`git ls-files --others --exclude-standard` 결과 0) |
|
|
100
|
+
|
|
101
|
+
> 항목 6은 `tool.execute.after` 훅이 매 write 완료 시 자동으로 `git add`를 수행하므로 기본적으로 자동 충족된다. 훅 실패로 untracked 가 남으면 §4-5 exit gate 가 BLOCK 하여 재작업을 요구한다.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."dev".self_check' \
|
|
105
|
+
'{"scope_met": true, "existing_tests_pass": true, "new_tests_added": true, "type_lint_clean": true, "no_secrets": true, "all_writes_staged": true}'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 4-5. Exit Gate 실행 (staging 강제)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
bash <SCRIPTS_DIR>/../gates/verify.sh <이슈키> 2_implementation.dev_post
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- exit 0: 통과 — 완료 기록 진행
|
|
115
|
+
- exit 2 (BLOCKED): 출력된 파일 목록을 확인하고 각각 `git add -- <파일>` 실행 후 재실행
|
|
116
|
+
|
|
117
|
+
## 완료 기록
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."dev".done' 'true'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> 5단계 진입 시 `verify.sh <이슈키> 2_implementation.test`가 worktree가 메인 repo의 형제 디렉토리인지
|
|
124
|
+
> 자동 검증한다. 비규약 경로(예: 메인 repo 안)에 만들었다면 거기서 차단된다.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# 5단계: 테스트 (단위 + 통합) — `2_implementation.test` substage
|
|
2
|
+
|
|
3
|
+
**목적**: 코드 변경의 정확성을 단위 테스트와 통합 테스트로 검증한다(로컬 실행).
|
|
4
|
+
**진입 게이트**: `verify.sh <이슈키> 2_implementation.test` (`2_implementation.dev` 완료 + worktree 형제 검증).
|
|
5
|
+
|
|
6
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
7
|
+
|
|
8
|
+
## 5-0. Analysis 결과 읽기 (필수 — 테스트 코드 작성 전)
|
|
9
|
+
|
|
10
|
+
테스트를 작성하기 전에 `workspace-analysis.json` 의 `test_conventions` 를 읽어 기존 테스트 패턴을 파악한다. **새 테스트 코드는 반드시 이 패턴을 따라야 한다. 독자적인 스타일로 작성하는 것을 금지한다.**
|
|
11
|
+
|
|
12
|
+
`artifact_path` 는 상대경로 저장 원칙을 따르므로 반드시 `state.sh root()` 로 절대경로 해석한다 (legacy 절대경로도 수용):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
ART_REL="$(bash <SCRIPTS_DIR>/state.sh get <이슈키> \
|
|
16
|
+
'.stages."2_implementation".substages."analysis".artifact_path' | tr -d '"')"
|
|
17
|
+
|
|
18
|
+
if [ -n "$ART_REL" ] && [ "$ART_REL" != "null" ]; then
|
|
19
|
+
if [[ "$ART_REL" == /* ]]; then
|
|
20
|
+
ANALYSIS_PATH="$ART_REL" # legacy 절대경로 수용
|
|
21
|
+
else
|
|
22
|
+
ANALYSIS_PATH="$(bash <SCRIPTS_DIR>/state.sh root)/$ART_REL"
|
|
23
|
+
fi
|
|
24
|
+
[ -f "$ANALYSIS_PATH" ] && jq '.test_conventions' "$ANALYSIS_PATH"
|
|
25
|
+
fi
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
확인 후 아래 항목을 테스트 코드 작성 전에 반드시 파악한다:
|
|
29
|
+
|
|
30
|
+
| 항목 | 활용 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `test_conventions.framework` | 테스트 프레임워크 — 동일 프레임워크 사용 (`framework: "none"` 이면 도입 불필요) |
|
|
33
|
+
| `test_conventions.style` | 테스트 스타일 — 동일 스타일 적용 (예: FlatSpec, @Test+AssertJ) |
|
|
34
|
+
| `test_conventions.test_roots` | 테스트 파일 생성 위치 |
|
|
35
|
+
| `test_conventions.naming_pattern` | 테스트 파일/클래스 네이밍 |
|
|
36
|
+
| `test_conventions.mock_library` | Mock 라이브러리 — 기존과 동일하게 사용 |
|
|
37
|
+
| `test_conventions.patterns` | 관찰된 패턴 (given-when-then, fixture 설정 방식 등) |
|
|
38
|
+
| `test_conventions.sample_files` | **대표 샘플 파일** — `Read` 툴로 반드시 내용 확인 후 동일 방식으로 작성 |
|
|
39
|
+
|
|
40
|
+
**`test_conventions.sample_files` 가 존재하면**: `Read` 툴로 각 파일을 실제로 읽어 구조·import·assertion 방식을 파악한 뒤, 그 패턴을 새 테스트에 그대로 적용한다.
|
|
41
|
+
|
|
42
|
+
## 5-1. 빌드 시스템 식별
|
|
43
|
+
|
|
44
|
+
- `build.sbt` → **SBT** (이 워크플로의 1순위 대상)
|
|
45
|
+
- `build.gradle` / `build.gradle.kts` → Gradle
|
|
46
|
+
- `pom.xml` → Maven
|
|
47
|
+
|
|
48
|
+
빌드 시스템마다 테스트 유형별 명령이 다르다(아래 표 참조).
|
|
49
|
+
|
|
50
|
+
## 5-2. 단위 테스트
|
|
51
|
+
|
|
52
|
+
| 빌드 시스템 | 명령 |
|
|
53
|
+
|---|---|
|
|
54
|
+
| SBT | `sbt test` |
|
|
55
|
+
| Gradle | `./gradlew test` |
|
|
56
|
+
| Maven | `mvn test` |
|
|
57
|
+
|
|
58
|
+
실행 후 결과를 셋 중 하나로 분류한다:
|
|
59
|
+
|
|
60
|
+
- **pass** — 테스트가 실제로 실행되어 모두 통과.
|
|
61
|
+
- **fail** — 테스트가 실행되었고 실패한 케이스 존재.
|
|
62
|
+
- **skip** — **테스트가 존재하지 않거나 정의되지 않음.** 예:
|
|
63
|
+
- SBT: `No tests to run` / `tests found: 0` / `[info] No tests were executed`
|
|
64
|
+
- Gradle: `No tests found for given includes` / 모듈에 test task 자체가 없음
|
|
65
|
+
- Maven: `No tests to run`
|
|
66
|
+
- 명령 자체가 missing task로 실패: `Unknown task '...'` 등
|
|
67
|
+
- **테스트 부재로 인한 실패는 fail이 아니라 skip이다.**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."test".unit' '"pass"' # | "fail" | "skip"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 5-3. 통합 테스트
|
|
74
|
+
|
|
75
|
+
| 빌드 시스템 | 명령 |
|
|
76
|
+
|---|---|
|
|
77
|
+
| SBT | `sbt IntegrationTest/test` (SBT 0.13.x: `sbt it:test`) |
|
|
78
|
+
| Gradle | `./gradlew integrationTest` (프로젝트 task명에 맞춤) |
|
|
79
|
+
| Maven | `mvn verify` 또는 `mvn failsafe:integration-test` |
|
|
80
|
+
|
|
81
|
+
결과 분류는 5-2와 동일(pass / fail / skip).
|
|
82
|
+
|
|
83
|
+
특히 SBT에서 `IntegrationTest` config가 정의되지 않아 `Reference to undefined setting` 등으로
|
|
84
|
+
명령이 실패하는 경우는 **skip**으로 처리한다(통합 테스트 설정 부재 = 통합 테스트 없음).
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."test".integration' '"skip"' # | "pass" | "fail"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 5-4. 커버리지 검증
|
|
91
|
+
|
|
92
|
+
단위·통합 테스트 결과 중 하나라도 `pass`이면 반드시 수행한다. 둘 다 `skip`이면 `"exempt"` 기록 후 완료 기록으로 진행.
|
|
93
|
+
|
|
94
|
+
**임계값**: makdoong2-team.json 의 `coverage.threshold` (기본: **95%**).
|
|
95
|
+
직접 확인: `bash gates/stage5-coverage-verify.sh <이슈키>`
|
|
96
|
+
|
|
97
|
+
### 커버리지 측정 명령
|
|
98
|
+
|
|
99
|
+
| 빌드 시스템 | 커버리지 측정 명령 |
|
|
100
|
+
|---|---|
|
|
101
|
+
| SBT | `sbt coverage test coverageReport` |
|
|
102
|
+
| Gradle | `./gradlew jacocoTestReport` |
|
|
103
|
+
| Maven | `mvn jacoco:prepare-agent test jacoco:report` |
|
|
104
|
+
| npm/Jest | `npm test -- --coverage --coverageReporters=text` |
|
|
105
|
+
| Go | `go test -cover ./...` |
|
|
106
|
+
|
|
107
|
+
수정된 파일의 **라인 커버리지(line coverage)** 기준으로 판단한다.
|
|
108
|
+
|
|
109
|
+
### 커버리지 루프 (최대 2라운드)
|
|
110
|
+
|
|
111
|
+
| 라운드 | 커버리지 | 행동 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| 1 | ≥ 임계값 | `pass` 기록 → 완료 기록으로 진행 |
|
|
114
|
+
| 1 | < 임계값 | 미커버 구간 분석 → 새 테스트 코드 생성 → 재측정 |
|
|
115
|
+
| 2 | ≥ 임계값 | `pass` 기록 → 완료 기록으로 진행 |
|
|
116
|
+
| 2 | < 임계값 | `fail` 기록 → 6단계 게이트가 차단함. 사용자에게 상세 보고 |
|
|
117
|
+
|
|
118
|
+
**테스트 생성 불가 판단 기준** (사용자에게 `exempt` 승인 요청):
|
|
119
|
+
- 레거시 코드로 모킹이 불가능한 구조
|
|
120
|
+
- 외부 시스템 의존으로 단위 테스트 환경 구성 불가
|
|
121
|
+
- → 사용자 명시 승인 시에만 `"exempt"` 기록
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# 라운드 1: 커버리지 측정 후 숫자(<측정된_pct>)를 추출해서 스크립트에 전달
|
|
125
|
+
# coverage-record.sh 가 config.coverage.threshold 와 비교하고 pass/fail 을 state.json 에 기록한다
|
|
126
|
+
bash <SCRIPTS_DIR>/coverage-record.sh <이슈키> <측정된_pct> 1
|
|
127
|
+
# 종료코드 0 → pass, 1 → fail
|
|
128
|
+
|
|
129
|
+
# 라운드 2: 라운드 1 이 fail 인 경우에만 실행 (미커버 구간 분석 + 새 테스트 작성 후)
|
|
130
|
+
bash <SCRIPTS_DIR>/coverage-record.sh <이슈키> <측정된_pct> 2
|
|
131
|
+
# 종료코드 0 → pass, 1 → fail → 6단계 게이트가 차단 + 사용자에게 보고
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 5-5. 최종 자가 검증 (Pre-Completion Checklist)
|
|
135
|
+
|
|
136
|
+
`done=true` 직전, 다음 5항목을 자체 확인하고 state.json에 결과를 기록한다.
|
|
137
|
+
하나라도 false면 완료 기록 금지.
|
|
138
|
+
|
|
139
|
+
| 항목 | 확인 |
|
|
140
|
+
|---|---|
|
|
141
|
+
| 1 | 단위·통합 결과(pass/fail/skip)가 명시적으로 state.json에 기록되었다 (none 잔존 X) |
|
|
142
|
+
| 2 | 커버리지 측정 명령이 실제 빌드 시스템(SBT/Gradle/Maven/Jest/Go)에 맞게 사용되었다 |
|
|
143
|
+
| 3 | `coverage_attempt`가 1 또는 2로 정확히 기록되었다 (race condition 방지) |
|
|
144
|
+
| 4 | `exempt` 처리 시 사용자 명시 승인을 받았다 (legacy/외부 의존 사유) |
|
|
145
|
+
| 5 | 라운드 2 fail 또는 단위·통합 fail 시 4단계 복귀와 함께 사용자에게 상세 보고했다 |
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."test".self_check' \
|
|
149
|
+
'{"results_recorded": true, "coverage_cmd_correct": true, "attempt_tracked": true, "exempt_user_approved": true, "fail_reported": true}'
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 완료 기록
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."2_implementation".substages."test".done' 'true'
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
> `3_delivery.commit` 진입 시 `verify.sh <이슈키> 3_delivery.commit`이 단위·통합·커버리지 결과를 함께 검사한다.
|
|
159
|
+
> 단위·통합은 **pass 또는 skip**, 커버리지는 **pass 또는 exempt**이어야 통과한다.
|
|
160
|
+
> 하나라도 `fail`이면 `2_implementation.dev` substage로 복귀해 수정한다.
|
|
161
|
+
> 기본 흐름에서는 `.policy.category` 가 `minor`이든 `major`이든 테스트 완료 후 `3_delivery.commit` 로 무인 자동 진행한다. `.policy.auto_approve."3_delivery.commit"` 가 명시적으로 `false` 로 opt-in 된 경우에만 부장님이 변경 보고서(6단계 §6-0의 `change-report.md`)를 작성하고 사람의 커밋 승인을 받는다.
|