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,229 @@
|
|
|
1
|
+
# 6단계: Atomic Commit (Publisher 직접 실행)
|
|
2
|
+
|
|
3
|
+
**목적**: 변경을 논리적 단위로 쪼개 커밋한다. **1 파일 = 1 commit** 원칙을 절대적으로 준수한다.
|
|
4
|
+
**진입 게이트**: `verify.sh <이슈키> 3_delivery.commit` (단위·통합 테스트가 둘 다 **pass 또는 skip**이어야 함. 하나라도 **fail**이면 4단계로 복귀). major 이슈는 변경 보고서를 자동 생성하고 승인 없이 진행하며, HITL opt-in(`.policy.auto_approve."3_delivery.commit" == false`)인 경우에만 사람 승인이 추가로 요구된다 (§6-0).
|
|
5
|
+
> **PUBLISHER 전용 단계.** publisher 가 worktree 에서 **직접 `git add` / `git commit`** 을 실행한다. 부장님(team-leader) 은 git 명령 permission 이 deny 되어 있으므로 실행할 수 없다. publisher 는 permission 으로 `git commit*` / `git add*` 가 allow 되어 있으며, 훅이 발동해 state.json 자동 기록도 정상 수행된다.
|
|
6
|
+
|
|
7
|
+
## 6-0. 변경 보고서 생성 (major 이슈) + 사람 승인 (HITL opt-in 전용)
|
|
8
|
+
|
|
9
|
+
진입 조건에 따라 동작이 다르다. 두 조건 모두 해당 없으면(minor + auto_approve=true) 본 절을 건너뛰고 6-1로 직행한다.
|
|
10
|
+
|
|
11
|
+
- **major 이슈** (`.policy.category == "major"`): 변경 보고서를 아티팩트로 자동 생성. 사용자 승인 게이트 없이 §6-1로 자동 진행한다.
|
|
12
|
+
- **HITL opt-in** (`.policy.auto_approve."3_delivery.commit" == false`): 보고서 생성 후 사용자 명시적 승인이 추가로 필요하다.
|
|
13
|
+
|
|
14
|
+
> **역할 분담**: 보고서 작성은 **publisher(1차 dispatch)**가 수행하고, 사용자에게 제시·승인 수령·마커 기록은 **부장님(PRIMARY)**이 수행한다. 부장님은 Write 툴이 없으므로 보고서를 직접 작성하지 않는다.
|
|
15
|
+
>
|
|
16
|
+
> 흐름: `auto_advance_stage` → `needs_report:true` → 부장님이 `dispatch_stage(3_delivery.commit)` 호출 → publisher §1-0이 보고서 작성 + `verification_pending=true` 마킹 → 부장님이 보고서 제시 → 사용자 승인 → 부장님이 `approved_by_user=true` + `verification_pending=false` 마킹 → `auto_advance_stage` 재호출 → 게이트 통과 → `dispatch_stage` 재호출(2차) → publisher 가 §6-1 부터 직접 실행
|
|
17
|
+
|
|
18
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
19
|
+
|
|
20
|
+
### 6-0-1. 변경 보고서 작성 (publisher §1-0이 수행)
|
|
21
|
+
|
|
22
|
+
`git diff`(working tree, 아직 미커밋)와 5단계 테스트 결과로 보고서를 작성해 **다음 표준 경로**에 저장한다 (게이트가 이 경로의 파일 존재를 검사한다):
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
<worktree>/.makdoong2-team/<이슈키>/change-report.md # 물리 파일 생성 위치 (publisher 는 worktree cwd 실행)
|
|
26
|
+
.makdoong2-team/<이슈키>/change-report.md # state.json 에 기록할 상대경로
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
보고서 필수 섹션 (한글):
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
# 변경 보고서 — <이슈키> (HITL opt-in)
|
|
33
|
+
|
|
34
|
+
## 요구사항 요약
|
|
35
|
+
- <2단계 요구사항 명세 핵심 — 무엇을, 왜>
|
|
36
|
+
|
|
37
|
+
## 변경 내용
|
|
38
|
+
- <기능 단위별 변경 요지> # 파일 나열이 아니라 기능 단위로
|
|
39
|
+
- 변경 파일 통계: `git diff --stat` 요약
|
|
40
|
+
|
|
41
|
+
## 테스트 결과
|
|
42
|
+
- 단위: <pass|skip> / 통합: <pass|skip> / 커버리지: <pct>% (<pass|exempt>)
|
|
43
|
+
|
|
44
|
+
## 위험 · 영향 범위
|
|
45
|
+
- criticality 근거(critical 사유) / 영향 모듈·하위 시스템
|
|
46
|
+
- 롤백 가능성 · 데이터 마이그레이션 여부
|
|
47
|
+
|
|
48
|
+
## 커밋 계획
|
|
49
|
+
- 1. <atomic 커밋 단위1> 2. <단위2> ... # 6-3에서 그대로 실행
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
작성 후 경로와 검증-대기 마커를 기록한다 — **반드시 상대경로만 저장한다** (절대경로 저장 시 다른 cwd 에서 Read hang 유발):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> \
|
|
56
|
+
'.stages."3_delivery".substages."commit".report_path' '".makdoong2-team/<이슈키>/change-report.md"'
|
|
57
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".verification_pending' 'true'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 6-0-2. 사람에게 보고 + 승인 수령 (HITL opt-in 전용, 부장님이 수행)
|
|
61
|
+
|
|
62
|
+
> **major 이슈는 이 섹션 건너뜀**: publisher §1-0이 보고서를 아티팩트로 생성한 뒤 사용자 승인 없이 §6-1로 자동 진행한다. 아래 절차는 `auto_approve."3_delivery.commit" == false` 인 HITL opt-in 케이스에만 적용.
|
|
63
|
+
|
|
64
|
+
publisher §1-0의 결과로 받은 `change_report_path`를 읽어 보고서 전문(또는 핵심 요약 + 파일 경로)을 사용자에게 제시하고 **명시적 커밋 승인**을 받는다.
|
|
65
|
+
|
|
66
|
+
- 승인("이대로 커밋하세요" 등) → 6-1로 진행하며 아래 마커 기록.
|
|
67
|
+
- 보류·수정 요청 → 해당 단계(요구사항/범위/구현)로 복귀. **커밋하지 않는다.**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".approved_by_user' 'true'
|
|
71
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".approved_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
72
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".verification_pending' 'false'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> HITL opt-in에서 보고서 미작성 또는 미승인 상태로 커밋을 시도하면 `verify.sh 6_commit`(stage6-commit-verify.sh)이 차단한다. `change-report.md` 존재 **+** `approved_by_user == true` **+** `verification_pending != true` 셋을 모두 만족해야 통과한다.
|
|
76
|
+
|
|
77
|
+
## 6-1. base_sha 기록 (첫 커밋 전 필수 — publisher 가 실행)
|
|
78
|
+
|
|
79
|
+
publisher 가 worktree cd 로 진입한 뒤 **첫 커밋 전** base_sha 를 반드시 기록한다. 이후 atomicity 검증과 rollback 의 기준점이 된다.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
cd <worktree 절대경로>
|
|
83
|
+
BASE_SHA=$(git rev-parse HEAD)
|
|
84
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".base_sha' "\"$BASE_SHA\""
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 6-2. 커밋 계획 수립 (1 파일 = 1 commit 원칙)
|
|
88
|
+
|
|
89
|
+
**절대 규칙**: 한 commit 에는 **정확히 1개 파일**만 포함한다. 예외 없음.
|
|
90
|
+
|
|
91
|
+
- 여러 파일이 논리적으로 하나의 변경이라도 각 파일마다 개별 커밋을 만든다.
|
|
92
|
+
- 커밋 순서는 의존성 (base → dependent) 을 고려해 정한다. 예: 새 함수 정의 → 그 함수 사용처.
|
|
93
|
+
- 결합어(`and`, `&`, `+`, `및`, `그리고`) 를 제목에 사용하면 post-commit 게이트가 REJECT.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
CHANGED_FILES=$(git diff --name-only)
|
|
97
|
+
STAGED_FILES=$(git diff --cached --name-only)
|
|
98
|
+
ALL_FILES=$(printf '%s\n%s\n' "$CHANGED_FILES" "$STAGED_FILES" | sort -u | grep -v '^$')
|
|
99
|
+
echo "$ALL_FILES" | wc -l # 총 파일 수 = 만들어야 할 commit 수
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 6-3. 커밋 메시지 규약 (`references/commit-convention.md` 전문 참조)
|
|
103
|
+
|
|
104
|
+
**언어**: 한글, 제목 명령조도 한글.
|
|
105
|
+
**포맷**:
|
|
106
|
+
```
|
|
107
|
+
<Type>: <이슈키> - <명령조 요약>
|
|
108
|
+
|
|
109
|
+
[본문: 왜·무엇 (선택)]
|
|
110
|
+
|
|
111
|
+
[RV] <이슈키>
|
|
112
|
+
[AI] 100%
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- **Type** (허용값): `Feat`, `Fix`, `Chore`, `Refactor`, `Docs`, `Style`, `Test`, `Perf`, `Ci`, `Build`, `Revert`
|
|
116
|
+
- **제목**: 대문자로 시작, 50자 이내 (한글 25자 내외), 마침표 금지, 명령조 (한글도 "추가" 형태 유지), 결합어(`and`/`&`/`+`/`및`/`그리고`) 금지
|
|
117
|
+
- **빈 줄**: 제목과 본문 사이 반드시 빈 줄 1개
|
|
118
|
+
- **본문** (선택): "어떻게" 보다 "무엇을·왜" 중심. 한글 줄폭 ~40자
|
|
119
|
+
- **이슈 참조 마커**: `[RV] <이슈키>` — 이슈 번호 연결. 본문이 있을 때 필수
|
|
120
|
+
- **AI 기여도 마커**: `[AI] 100%` — AI 작성 비율 표기
|
|
121
|
+
|
|
122
|
+
**예시**:
|
|
123
|
+
```
|
|
124
|
+
Feat: PROJ-123 - 상품 캐시 조회 메서드 추가
|
|
125
|
+
|
|
126
|
+
기존에는 요청마다 DB 를 조회해 지연이 컸다.
|
|
127
|
+
캐시 계층을 도입해 응답 시간을 단축한다.
|
|
128
|
+
|
|
129
|
+
[RV] PROJ-123
|
|
130
|
+
[AI] 100%
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 6-4. 커밋 실행 (publisher 가 파일별 1개씩)
|
|
134
|
+
|
|
135
|
+
- **git command line 만** 사용 (GUI/IDE 단축키 금지).
|
|
136
|
+
- 매 커밋 전 `git diff --cached --name-only` 로 stage 된 파일이 정확히 1개인지 확인.
|
|
137
|
+
- **`git add .` / `git add -A` / `git add -u` 금지** — 여러 파일이 한꺼번에 stage 된다.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
cd <worktree>
|
|
141
|
+
for FILE in $ALL_FILES; do
|
|
142
|
+
git add -- "$FILE" # 정확히 1개 파일만 stage
|
|
143
|
+
STAGED=$(git diff --cached --name-only | wc -l)
|
|
144
|
+
[ "$STAGED" -eq 1 ] || { echo "❌ stage 파일 수=$STAGED (기대: 1). abort"; exit 1; }
|
|
145
|
+
git commit -m "<Type>: <이슈키> - <요약>" -m "<본문 (선택)>
|
|
146
|
+
|
|
147
|
+
[RV] <이슈키>
|
|
148
|
+
[AI] 100%"
|
|
149
|
+
done
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**untracked 파일 취급**: 3_delivery.commit / 3_delivery.pr 게이트는 worktree 의 untracked 파일을 **자동으로 커밋 대상에서 제외**하고 진행한다. 사용자 확인 프롬프트를 띄우지 않는다. untracked 파일이 커밋에 필요하면 engineer 가 `2_implementation.dev` 단계에서 명시적으로 `git add` 했어야 한다.
|
|
153
|
+
|
|
154
|
+
## 6-5. Atomicity 자체 검토 및 기록
|
|
155
|
+
|
|
156
|
+
모든 커밋이 끝났으면 각 커밋을 다시 한 번 검토해 1 파일 = 1 commit 인지 자체 확인한다.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
BASE=$(bash <SCRIPTS_DIR>/state.sh get <이슈키> '.stages."3_delivery".substages."commit".base_sha' | tr -d '"')
|
|
160
|
+
git log --format='%h %s' $BASE..HEAD # 이번 단계 커밋 목록
|
|
161
|
+
N=$(git rev-list --count $BASE..HEAD)
|
|
162
|
+
|
|
163
|
+
BAD=0
|
|
164
|
+
for SHA in $(git rev-list "$BASE..HEAD"); do
|
|
165
|
+
NF=$(git show --name-only --pretty="" "$SHA" | grep -c .)
|
|
166
|
+
if [ "$NF" -ne 1 ]; then
|
|
167
|
+
SUBJ=$(git log -1 --format='%s' "$SHA")
|
|
168
|
+
echo "❌ commit ${SHA:0:7} '$SUBJ' 파일 수=$NF (기대: 1)"
|
|
169
|
+
BAD=$((BAD+1))
|
|
170
|
+
fi
|
|
171
|
+
done
|
|
172
|
+
[ "$BAD" -eq 0 ] || { echo "1 파일/commit 위반 $BAD 건. 재커밋 필요"; exit 1; }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
각 커밋이 단일 변경임을 확인했으면 그 사실을 기록한다 (자체 attestation):
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
HEAD_SHA=$(git rev-parse HEAD)
|
|
179
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".head_sha' "\"$HEAD_SHA\""
|
|
180
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".atomic_review' \
|
|
181
|
+
"{\"all_atomic\": true, \"count_commits\": $N, \"one_file_per_commit\": true}"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 6-6. 최종 자가 검증 (Pre-Completion Checklist)
|
|
185
|
+
|
|
186
|
+
`verify.sh 3_delivery.commit_post` 호출 전 자체 5체크. 하나라도 false 면 게이트 호출 금지 — 미충족 항목을 먼저 해소한다.
|
|
187
|
+
|
|
188
|
+
| 항목 | 확인 |
|
|
189
|
+
|---|---|
|
|
190
|
+
| 1 | `base_sha` 가 첫 커밋 전에 정확히 기록되었다 |
|
|
191
|
+
| 2 | 각 커밋이 정확히 1개 파일만 포함, 결합어(`and`/`&`/`+`/`및`/`그리고`) 없음 |
|
|
192
|
+
| 3 | 커밋 메시지가 `<Type>: <이슈키> - <요약>` + 한글 명령조 + 제목 50자 이내 + 마침표 없음 컨벤션 준수 |
|
|
193
|
+
| 4 | 매 커밋 전 `git diff --cached --name-only` 로 stage 파일 수 = 1 확인 |
|
|
194
|
+
| 5 | `.env` / secrets / API 키가 커밋 디프에 포함되지 않았다 (`git log -p $BASE..HEAD \| grep -iE '(secret\|password\|api[_-]?key\|token)'` 0건) |
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".self_check' \
|
|
198
|
+
'{"base_sha_recorded": true, "atomic_commits": true, "msg_convention": true, "one_file_per_commit": true, "no_secrets_in_diff": true}'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 6-7. 검증 게이트 + 실패 시 rollback
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
bash <SCRIPTS_DIR>/../gates/verify.sh <이슈키> 3_delivery.commit_post
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 통과 (exit 0)
|
|
208
|
+
6_commit 완료를 기록한다.
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."commit".done' 'true'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 차단 (exit 2) — 6단계 commit 작업을 모두 rollback 하고 다시 진행
|
|
215
|
+
|
|
216
|
+
verify 가 BLOCKED 를 출력하면, 다음 스크립트로 **이번 단계에서 만든 모든 커밋을 취소** 한다.
|
|
217
|
+
soft reset 이라 working tree·index 의 변경 내용은 그대로 보존되므로, 동일 변경을
|
|
218
|
+
1 파일 = 1 commit 에 맞게 다시 쪼개 재커밋할 수 있다. **rollback 은 publisher 가 직접 수행한다** — 부장님(team-leader) 은 git 명령 permission 이 deny 이므로 rollback 을 대신 하지 않는다.
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
bash <SCRIPTS_DIR>/rollback-commits.sh <이슈키>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
이후 **6-2 부터 다시 진행한다** (base_sha 는 보존되어 동일 기준점으로 재커밋된다).
|
|
225
|
+
검증이 통과할 때까지 위 과정을 반복한다.
|
|
226
|
+
|
|
227
|
+
### REJECTED verdict 재작업 진입 시 (dispatch_stage 재-attempt)
|
|
228
|
+
|
|
229
|
+
dispatch_verifier 가 REJECTED 를 반환하면 부장님이 dispatch_stage 를 재호출하고, dispatch_stage 는 프롬프트에 `=== 이전 검증 실패 사유 (재작업 시 참고) ===` 블록을 자동 주입한다. 이 블록이 존재한 상태로 3_delivery.commit 재진입한 publisher 는 위 §6-7 rollback 을 **다른 어떤 작업보다 먼저** 실행해야 한다 (자세한 절차는 publisher.md 의 "이전 검증 실패 사유 재주입" §2 참조).
|
package/stages/08-pr.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 7단계: Pull Request 생성 (Publisher 직접 실행)
|
|
2
|
+
|
|
3
|
+
**목적**: 리뷰 가능한 PR 을 만든다.
|
|
4
|
+
**진입 게이트**: `verify.sh <이슈키> 3_delivery.pr` — **전제조건만** 검사한다. 6단계 커밋 완료 + worktree clean + 현재 브랜치 확인 가능. 원격 push 존재 여부는 본 단계의 **완료 조건**이므로 진입 게이트가 아니라 §완료 후 검증(`verify.sh 3_delivery.pr_post`)에서 확인한다. remote push · createPullRequest 는 본 단계에서 publisher 가 수행한다.
|
|
5
|
+
> `git push` 자체도 PreToolUse 훅이 동일 게이트 (`3_delivery.commit.done == true`) 로 검증하므로, 전제 미충족 시 push 가 차단된다. push 가 통과하면 게이트도 통과한다.
|
|
6
|
+
> **PUBLISHER 전용 단계.** `git push` 및 Bitbucket MCP `createPullRequest` 는 publisher 가 worktree 에서 직접 실행한다. 부장님(team-leader) 은 git 명령 permission 이 deny 되어 있어 실행할 수 없다.
|
|
7
|
+
|
|
8
|
+
## 7-1. 사전 확인
|
|
9
|
+
|
|
10
|
+
게이트가 자동 검증하지만 의미상 다음이 모두 true여야 한다: 단위·통합 테스트가 둘 다 pass 또는 skip, 모든 커밋 완료, `git status` clean, remote push 완료. 하나라도 false면 해당 단계로 복귀.
|
|
11
|
+
|
|
12
|
+
## 7-2. PR 본문 (`references/pr-template.md` 참조)
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
#### 목표
|
|
16
|
+
- <이슈 최종 목적>
|
|
17
|
+
#### 구현내용
|
|
18
|
+
- <실제 구현한 기능 단위> # 파일 단위로 쓰지 않는다
|
|
19
|
+
#### Test
|
|
20
|
+
- "<테스트 시나리오 한글 문장>"
|
|
21
|
+
```
|
|
22
|
+
- **목표**: Jira acceptance criteria를 자연어로.
|
|
23
|
+
- **구현내용**: 추가·수정한 **기능 단위**로 나열.
|
|
24
|
+
- **Test**: 실제 시나리오를 큰따옴표 한글 문장으로.
|
|
25
|
+
|
|
26
|
+
## 7-3. PR 본문 검증 (생성 전 필수)
|
|
27
|
+
|
|
28
|
+
7-2에서 작성한 PR 본문을 임시 파일(예: `/tmp/pr-body.md`)에 저장한 뒤,
|
|
29
|
+
**PR 생성 전에 다음 세 가지를 모두 통과시킨다.** 하나라도 통과 못 하면 본문을 고치고
|
|
30
|
+
다시 검증한다. **통과 전엔 PR을 생성하지 않는다.**
|
|
31
|
+
|
|
32
|
+
### ① 테스트 코드 없는 시나리오 금지
|
|
33
|
+
|
|
34
|
+
`#### Test` 섹션의 각 시나리오 문장은, 이 브랜치에 추가/수정된 **실제 테스트 코드**로 1:1
|
|
35
|
+
매핑되어야 한다(시나리오 하나당 그것을 검증하는 테스트 메서드/케이스 하나).
|
|
36
|
+
|
|
37
|
+
이번 브랜치의 변경된 테스트 파일 확인:
|
|
38
|
+
```bash
|
|
39
|
+
git diff origin/main...HEAD --name-only -- \
|
|
40
|
+
'*Test*.scala' '*Spec*.scala' '*Test*.java' '*.spec.ts' '*_test.go' 'test_*.py'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
각 시나리오를 위 파일들 중 어떤 테스트가 검증하는지 스스로 확인한다. 매핑되지 않는
|
|
44
|
+
시나리오가 하나라도 있으면 → 시나리오를 제거하거나 누락 테스트를 작성. 매핑 0개인
|
|
45
|
+
"테스트 시나리오로만 존재하는" 항목은 PR 본문에 남기지 않는다.
|
|
46
|
+
|
|
47
|
+
### ② 템플릿 markdown 형식 준수
|
|
48
|
+
|
|
49
|
+
PR 본문은 `references/pr-template.md`가 정의한 `####` 헤딩 셋을 **정확히 그 순서로** 가진다.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
grep -E '^#### ' /tmp/pr-body.md
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> `<SCRIPTS_DIR>`는 부장님이 dispatch_stage 프롬프트로 주입한 절대경로다. 이 값을 그대로 대입하여 실행한다.
|
|
56
|
+
출력이 **정확히** 다음과 같아야 한다(추가도, 누락도, 순서 어긋남도 금지):
|
|
57
|
+
```
|
|
58
|
+
#### 목표
|
|
59
|
+
#### 구현내용
|
|
60
|
+
#### Test
|
|
61
|
+
```
|
|
62
|
+
- 헤딩 누락 → 추가.
|
|
63
|
+
- 임의 추가(예: `#### 비고`, `#### 참고`, `#### 영향도`) → 제거 또는 다른 섹션으로 흡수.
|
|
64
|
+
- 순서 다름 → 재정렬.
|
|
65
|
+
|
|
66
|
+
### ③ 항목 내용 적합성
|
|
67
|
+
|
|
68
|
+
각 섹션 내용이 그 섹션 성격에만 맞는지 자기검열:
|
|
69
|
+
|
|
70
|
+
- `#### 목표`: 이슈의 최종 목적(자연어 1~2문장). 구현 세부·테스트 시나리오 혼입 금지.
|
|
71
|
+
- `#### 구현내용`: 추가·수정한 **기능 단위** 나열. 파일 단위 나열 금지, 시나리오 문장 금지.
|
|
72
|
+
- `#### Test`: 큰따옴표 한글 시나리오 문장만. 코드 인용·구현 세부 금지.
|
|
73
|
+
|
|
74
|
+
빈 섹션(placeholder만 남음) 금지 — 해당 사항이 정말 없으면 누락 사유를 해소한다.
|
|
75
|
+
|
|
76
|
+
### 검증 결과 기록 (셋 다 통과 후에만)
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".body_validation' \
|
|
80
|
+
'{"no_orphan_scenarios": true, "template_match": true, "section_content_match": true}'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> 8단계 진입 게이트가 위 세 플래그를 모두 `true`로 검증한다. 하나라도 false/누락이면
|
|
84
|
+
> 차단되어 다시 7-3을 통과해야 한다.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## 7-4. 생성 실행 (`bitbucket-research`의 PR 작성 규칙)
|
|
89
|
+
|
|
90
|
+
### 토큰 소유자 식별 (리뷰어 추가용)
|
|
91
|
+
|
|
92
|
+
API 호출로 `X-AUSERNAME` 응답 헤더를 확인하여 토큰 소유자의 username을 식별한다:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
TOKEN=$(jq -r '.secrets.BITBUCKET_API_TOKEN' ~/.config/opencode/makdoong2-team.json)
|
|
96
|
+
BB_BASE=$(jq -r '.hosts.BITBUCKET_API_BASE_PATH' ~/.config/opencode/makdoong2-team.json)
|
|
97
|
+
USERNAME=$(curl -sI -H "Authorization: Bearer $TOKEN" \
|
|
98
|
+
"$BB_BASE/api/latest/application-properties" \
|
|
99
|
+
| grep -i '^X-AUSERNAME:' | awk '{print $2}' | tr -d '\r')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### PR 생성 규칙
|
|
103
|
+
|
|
104
|
+
- 반드시 **Draft로 생성** (`draft=true`).
|
|
105
|
+
- **토큰 소유자를 리뷰어로 자동 추가** (`reviewers=["$USERNAME"]`).
|
|
106
|
+
- 제목: `[이슈키] 짧은 요약` (예: `[PROJ-12345] 상품 캐시 조회 API 구현`).
|
|
107
|
+
|
|
108
|
+
`bitbucket_createPullRequest` 호출 시 위에서 식별한 `USERNAME`을 reviewers 파라미터에 포함한다.
|
|
109
|
+
|
|
110
|
+
> **자기 리뷰어 예외**: Bitbucket DC는 PR 작성자 자신을 reviewer로 추가하는 것을 허용하지 않는다. `bitbucket_getPullRequest` 재조회 후 `reviewers` 배열이 비어 있고, 토큰 소유자(`$USERNAME`)가 PR 작성자(`author.user.name`)와 동일한 경우, 이를 정상 상태로 처리하고 아래 완료 기록에서 `reviewer_self_skipped=true`를 사용한다.
|
|
111
|
+
|
|
112
|
+
## 7-5. 최종 자가 검증 (Pre-Completion Checklist)
|
|
113
|
+
|
|
114
|
+
PR 생성 직전 추가 5체크. 7-3 PR 본문 검증과 별개로, 단계 종료 자체에 대한 자체 점검.
|
|
115
|
+
하나라도 false면 PR 생성·완료 기록 금지.
|
|
116
|
+
|
|
117
|
+
| 항목 | 확인 |
|
|
118
|
+
|---|---|
|
|
119
|
+
| 1 | PR 본문이 `####` 헤딩 3개(목표/구현내용/Test)를 정확한 순서로 가진다 (7-3 ② 통과) |
|
|
120
|
+
| 2 | `#### Test` 시나리오 ↔ 실제 테스트 코드의 1:1 매핑이 확인되었다 (7-3 ① 통과) |
|
|
121
|
+
| 3 | 각 섹션 내용이 그 섹션 성격에 맞고, 빈 섹션이 없다 (7-3 ③ 통과) |
|
|
122
|
+
| 4 | Draft로 생성되며 리뷰어를 추가했거나(`reviewer_added=true`), 토큰 소유자 = PR 작성자이어서 skip했다(`reviewer_self_skipped=true`) |
|
|
123
|
+
| 5 | PR 제목이 `[이슈키] 짧은 요약` 형식이다 |
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".self_check' \
|
|
127
|
+
'{"template_match": true, "scenario_test_paired": true, "section_content_match": true, "draft_with_reviewer": true, "title_format": true}'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 완료 기록
|
|
131
|
+
|
|
132
|
+
PR 생성 직후, `bitbucket_getPullRequest`로 PR 상세를 재조회하여 `reviewers` 배열을 확인한다.
|
|
133
|
+
|
|
134
|
+
- **리뷰어가 있는 경우**: `reviewer_added=true` 기록.
|
|
135
|
+
- **리뷰어 배열이 비어 있는 경우**:
|
|
136
|
+
- 토큰 소유자(`$USERNAME`) == PR 작성자(`author.user.name`)이면 → **자기 리뷰어 예외**: `reviewer_self_skipped=true` 기록. `reviewer_added`는 기록하지 않는다.
|
|
137
|
+
- 그 외 → `bitbucket_updatePullRequest`로 reviewer를 추가한 뒤 재확인 후 `reviewer_added=true` 기록.
|
|
138
|
+
|
|
139
|
+
**두 마커 중 하나도 기록하지 않고 완료 선언 금지.**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".draft_url' '"<생성된 PR URL>"'
|
|
143
|
+
# 아래 두 줄 중 실제 상황에 맞는 하나만 기록한다
|
|
144
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".reviewer_added' 'true' # 리뷰어 추가 성공
|
|
145
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".reviewer_self_skipped' 'true' # 자기 자신이 PR 작성자여서 skip
|
|
146
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".done_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
147
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".verification_pending' 'true'
|
|
148
|
+
# 사용자가 Draft PR을 검토하고 8단계 진행을 승인한 직후에만:
|
|
149
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".approved_by_user' 'true'
|
|
150
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".approved_at' "\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
|
|
151
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".verification_pending' 'false'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 완료 후 검증 (post-verify · 필수)
|
|
155
|
+
|
|
156
|
+
publisher 는 `.done=true` 를 기록하기 **직전** 완료 조건 재검증을 실행한다. 실패 시 exit 2 로 재작업 loop 를 트리거한다.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
bash <SCRIPTS_DIR>/state.sh set <이슈키> '.stages."3_delivery".substages."pr".done' 'true'
|
|
160
|
+
bash <SCRIPTS_DIR>/../gates/stage7-post-pr-verify.sh <이슈키>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
검사 대상 (모두 통과해야 done 유지):
|
|
164
|
+
- `origin/<current-branch>` 원격 브랜치 존재 (git push 성공)
|
|
165
|
+
- `.draft_url` 이 HTTPS URL 문자열
|
|
166
|
+
- `body_validation` 3항목 모두 true
|
|
167
|
+
- reviewer 마커 상호 배타 (reviewer_added=true XOR reviewer_self_skipped=true)
|
|
168
|
+
- `.done == true`
|
|
169
|
+
|
|
170
|
+
post-verify 실패 시:
|
|
171
|
+
1. stderr 의 `MAKDOONG2-POSTGATE BLOCKED` 사유를 읽는다
|
|
172
|
+
2. 해당 조건을 충족시키는 조치 수행 (예: git push 재시도, reviewer 재추가, draft_url 재기록)
|
|
173
|
+
3. `.done` 을 다시 `true` 로 설정하고 post-verify 재실행
|
|
174
|
+
4. 통과할 때까지 반복. 통과 후 부장님에게 결과 요약 출력
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|