# 완전자동 머지 시스템 — 강제 실행형 (코드/설정만 인정, 문서 무력화 방지) ★ Lv.4

## ★★★ 본 task 절대 원칙 (회장 직접 명시 2026-05-04 격상)

> **"문서를 삭제해도 시스템은 그대로 동작해야 한다."**
> **"설명 금지, 코드/설정/실행 결과만 인정."**
> **"규칙 위반 시 '실패'가 아니라 '불가능' 상태가 되도록 한다."**
> **"task.md/MD 파일만 생성 시 즉시 FAIL."**

본 task는 단일 payload. dispatch 후 어떤 task.md 수정도 무효 — 봇은 본 파일만 실행. **모든 검증은 GitHub 원본 기준 (gh api / branch protection rule / check run / merge queue settings).**

## 작업 레벨: Lv.4 (시스템 인프라 — GitHub 보호 규칙 + Required Checks + Gemini Gate + Merge Queue)

## 위임 배경

task-2439는 **9단계 + Lock-in + 침투/Race/CI 모두 PASS**. 다만 회장 추가 진단:
> "task-2439 가드는 '코드/스크립트 차원'에서 PASS. 그러나 **GitHub 보호 규칙 차원에서 강제되어야** 진짜 'cancel된 작업이 main에 절대 들어가지 못함'이 영구적 보장."

→ **본 task에서 GitHub repo 보호 규칙 + Required Checks + Gemini Gate + Merge Queue를 모두 코드/설정으로 강제**.

## 핵심 합격 기준 (한 줄)

> **"문서를 삭제해도 시스템은 그대로 동작한다."**

GitHub 원본 데이터 (gh api) 응답으로만 합격 판단. task.md/MD 파일은 즉시 FAIL.

---

## [1] main 보호 — GitHub 보호 규칙 강제

### 작업
다음을 GitHub `repos/JonghyukJeon/dev_workspace/branches/main/protection` API 또는 `gh api` PUT으로 설정:

```bash
gh api -X PUT repos/JonghyukJeon/dev_workspace/branches/main/protection \
  -F required_status_checks[strict]=true \
  -F required_status_checks[contexts][]=ci/guard \
  -F required_status_checks[contexts][]=cancel-kill-switch \
  -F required_status_checks[contexts][]=qc-check \
  -F required_status_checks[contexts][]=hidden-path-audit \
  -F required_status_checks[contexts][]=lock-in-check \
  -F required_status_checks[contexts][]=merge-safety-check \
  -F required_status_checks[contexts][]=gemini-review-gate \
  -F enforce_admins=true \
  -F required_pull_request_reviews[required_approving_review_count]=1 \
  -F required_pull_request_reviews[dismiss_stale_reviews]=true \
  -F restrictions=null \
  -F allow_force_pushes=false \
  -F allow_deletions=false \
  -F required_conversation_resolution=true \
  -F required_linear_history=true
```

### Merge Queue 활성화 (별도 호출 또는 GraphQL):
```bash
gh api graphql -f query='mutation { 
  enableRepositoryMergeQueue(input: {
    repositoryId: "<REPO_ID>",
    branchPattern: "main",
    mergeMethod: MERGE,
    minimumGroupSize: 1,
    maximumGroupSize: 5
  })
}'
```

### 산출물 (GitHub 원본 검증)
- `gh api repos/JonghyukJeon/dev_workspace/branches/main/protection` 응답 JSON 캡처 (`memory/reports/task-XXXX-enforce/01-branch-protection.json`)
- enforce_admins=true / allow_force_pushes=false / required_status_checks 7종 모두 contexts에 포함

---

## [2] Required Checks 강제 등록 (CI workflow 신규/확장)

### 작업
`.github/workflows/ci.yml` 확장 — 7개 step을 분리해서 **각각 독립 status check name**으로 등록:

```yaml
name: CI
on:
  pull_request: { branches: [main] }
  merge_group:
jobs:
  cancel-kill-switch:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run cancel kill-switch
        run: |
          TASK_ID=$(echo "${{ github.head_ref }}${{ github.ref }}" | grep -oE 'task-[0-9]+' | head -n1 || true)
          if [[ -n "$TASK_ID" && -f "memory/events/${TASK_ID}.cancelled" ]]; then
            echo "::error::Cancelled task — CI FAIL ($TASK_ID)"
            exit 1
          fi
  qc-check:
    needs: cancel-kill-switch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: bash scripts/guard.sh qc-check "$(echo $GITHUB_HEAD_REF | grep -oE 'task-[0-9]+' | head -n1)" || exit 1
  hidden-path-audit:
    needs: cancel-kill-switch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          UNGUARDED=$(grep -rn "gh pr merge\|git push.*origin main\|worktree_manager.*finish" --include='*.py' --include='*.sh' scripts/ | grep -v "guard\|cancelled\|docstring\|comment" | wc -l)
          if [[ "$UNGUARDED" -gt 0 ]]; then echo "::error::Unguarded merge call detected"; exit 1; fi
  lock-in-check:
    needs: cancel-kill-switch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          # Lock-in 1: 가드가 함수 첫 statement인지 grep
          python3 scripts/lock_in_verify.py
  merge-safety-check:
    needs: [qc-check, hidden-path-audit, lock-in-check]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: bash scripts/guard.sh pre-push "$(echo $GITHUB_HEAD_REF | grep -oE 'task-[0-9]+' | head -n1)" || exit 1
  gemini-review-gate:
    needs: [merge-safety-check]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Gemini review request
        env:
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          python3 scripts/gemini_review_gate.py \
            --pr-number ${{ github.event.pull_request.number || 0 }} \
            --commit-sha ${{ github.sha }} \
            --status pending
          # ... Gemini 호출 + comment parsing + status 업데이트
          python3 scripts/gemini_review_gate.py \
            --pr-number ${{ github.event.pull_request.number || 0 }} \
            --commit-sha ${{ github.sha }} \
            --status success-or-failure-based-on-result
```

### 산출물
- 확장된 `.github/workflows/ci.yml`
- `scripts/lock_in_verify.py` 신규 (Lock-in 1 First-line 자동 검증)
- `scripts/gemini_review_gate.py` 신규 (아래 [3]에서 상세)

---

## [3] Gemini Review Gate — 실제 차단 게이트 구현

### 신규 파일: `scripts/gemini_review_gate.py`

#### 기능
1. PR HEAD 커밋의 diff를 Gemini API에 전달
2. Gemini 응답에서 다음 패턴 detect:
   - "blocking" / "critical issue" / "must fix" / "request changes"
   - 한국어: "차단" / "필수 수정" / "심각" / "blocker"
3. detection 결과에 따라 GitHub commit status 또는 check run 생성:
   ```bash
   gh api -X POST repos/.../check-runs \
     -F name="gemini-review-gate" \
     -F head_sha="<sha>" \
     -F status="completed" \
     -F conclusion="failure"  # 또는 success
   ```
4. status는 항상 다음 중 하나:
   - `pending` — 리뷰 진행 중
   - `success` — Gemini blocking 0건
   - `failure` — Gemini blocking 1건 이상

#### 실행 순서 강제
- PR 생성 → cancel-kill-switch → qc-check + hidden-path-audit + lock-in-check 병렬 → merge-safety-check → gemini-review-gate
- gemini-review-gate가 success일 때만 Required checks rollup이 success
- merge queue 진입 조건: 모든 Required checks success

#### Gemini 피드백 루프
신규 파일: `scripts/gemini_feedback_loop.py`
- Gemini failure 시 봇이 review comment를 파싱
- 자동 수정 가능 항목 (linter / typo / 단순 refactor) 적용
- commit + push (force-with-lease 금지, 새 commit only)
- gemini-review-gate를 pending으로 reset
- CI 재실행 트리거
- **루프 횟수 카운트** (`memory/events/<task-id>.gemini-loop-count`)
- 3회 초과 시:
  - PR에 `human_review_required` label 부착 (gh api `--method POST /issues/<num>/labels`)
  - queue 등록 차단
  - PR comment "@회장 review 필요"

#### Rate Limit / 비용 방지
```python
# scripts/gemini_review_gate.py 안에 강제
import time, json, hashlib
def should_call_gemini(pr_number, commit_sha):
    # 1. CI status 확인 — 실패 PR은 호출 금지
    ci_status = gh_api(f"commits/{commit_sha}/status")
    if ci_status["state"] != "success": return False, "CI failed"
    # 2. 같은 SHA 중복 호출 금지
    cache_key = hashlib.sha1(commit_sha.encode()).hexdigest()
    cache_path = f"memory/cache/gemini-{cache_key}.json"
    if Path(cache_path).exists(): return False, "duplicate SHA"
    # 3. debounce 2~5분
    last = Path(f"memory/cache/gemini-pr-{pr_number}.lasttime").read_text() if ... else "0"
    if time.time() - float(last) < 120: return False, "debounce"
    return True, "OK"
```

#### Gemini 호출 로그 + 토큰 카운트
- `memory/logs/gemini-calls.jsonl` append-only
- 각 호출마다: `{timestamp, pr_number, commit_sha, tokens_in, tokens_out, status, latency_ms}`

### 산출물
- `scripts/gemini_review_gate.py` 신규
- `scripts/gemini_feedback_loop.py` 신규
- `scripts/lock_in_verify.py` 신규
- 회귀 테스트 `tests/scripts/test_gemini_review_gate.py` (mock Gemini API)

### 검증 (강제 — GitHub 원본)
**case_id: gemini-block-real**
1. test PR 생성 (cancelled marker 없음, 정상 task)
2. Gemini failure mock으로 `gemini-review-gate` check run = failure
3. `gh pr merge <PR>` 시도
4. **GitHub 원본**: `gh api repos/.../pulls/<num>` → mergeable_state: blocked + 거부 응답
5. exit_code != 0 + stderr 캡처

---

## [4] 문서 무력화 방지 (enforcement-check 3종)

### case_id: enforcement-check-1 (Required Checks 실 enforced)
```bash
gh api repos/JonghyukJeon/dev_workspace/branches/main/protection | python3 -c "
import json,sys
d=json.load(sys.stdin)
required=set(d['required_status_checks']['contexts'])
expected={'cancel-kill-switch','qc-check','hidden-path-audit','lock-in-check','merge-safety-check','gemini-review-gate'}
missing=expected-required
assert not missing, f'MISSING: {missing}'
print('PASS: all required checks enforced')
"
```
조건: missing 0건 → PASS / 1건 이상 → FAIL

### case_id: enforcement-check-2 (체크 skip 시 merge 차단)
```bash
# 의도적으로 1개 check skip한 PR 만들기 (workflow_dispatch 강제 fail)
gh pr create --title "[task-test] skip check" ...
gh pr merge <num>
```
GitHub 원본 응답: 거부 (mergeable_state: blocked)

### case_id: enforcement-check-3 (gemini-review-gate 제거 시도 시 merge 불가)
```bash
# branch protection에서 임시로 gemini-review-gate context 제거
# merge 시도 → 차단되거나 (admin 권한 없으면) protection rule이 enforce_admins로 막음
```

### 산출물
- 3 케이스 raw GitHub API 응답 (`memory/reports/task-XXXX-enforce/04-enforcement-check.txt`)
- 모든 결과 GitHub 원본 응답 캡처

---

## [5] 봇 권한 차단 (물리적)

### 검증 케이스
**case_id: physical-1 (main direct push 불가)**
```bash
git push origin HEAD:main 2>&1
# 기대: GitHub 거부 (branch protection: required_pull_request_reviews + required_status_checks)
```

**case_id: physical-2 (gh pr merge 직접 호출 차단)**
```bash
gh pr merge <PR> --merge 2>&1
# 기대: 거부 ("required status checks failing" 또는 "merge queue required")
```

**case_id: physical-3 (admin bypass 불가)**
```bash
gh pr merge <PR> --admin 2>&1
# 기대: 거부 (enforce_admins=true)
```

각 케이스 exit_code != 0 + stderr 캡처 + GitHub API 응답 인용.

---

## [6] Merge Queue 강제

### case_id: queue-enforcement-1 (direct merge 비활성화)
```bash
gh pr merge <PR>  # without --auto / queue
# 기대: 거부 또는 "Merge queue required"
```

### case_id: queue-flow-3 (3 PR 순차 처리)
1. 동시에 3개 PR 만들기 (다른 task ID)
2. 각 PR queue 추가 (`gh pr merge <PR> --auto`)
3. queue가 1, 2, 3 순서로 순차 처리되는 로그 캡처
4. 각 PR `gh api repos/.../pulls/<num>` → merged_at timestamp 차이 (sequential 증명)

### 산출물
- `memory/reports/task-XXXX-enforce/06-queue-flow.json` (3 PR merged_at + duration)

---

## [7] Gemini 피드백 루프 강제

### case_id: gemini-loop-3
1. 의도적 lint 오류 PR 생성
2. CI success 후 Gemini failure (lint 오류 detect)
3. 봇 자동 수정 + 재push
4. CI + Gemini 재호출
5. 3회 반복 후 success 시 queue 등록 가능
6. 3회 초과 시 `human_review_required` 라벨 자동 부착

### 산출물
- 루프 카운트 로그 (`memory/events/<task-id>.gemini-loop-count`)
- `human_review_required` 라벨 부착 GitHub API 응답 캡처

---

## [8] Cancel Kill-Switch 전구간 강제

### case_id: cancel-mid-queue
1. PR을 queue에 등록
2. queue 대기 중에 task `.cancelled` 마커 생성
3. **자동 시퀀스**:
   - cancel-kill-switch CI step → fail
   - gemini-review-gate → failure로 reset
   - queue에서 자동 제거
   - PR auto-close + branch delete
4. **GitHub 원본 검증**:
   - `gh pr view <num>` → state=closed, merged=false
   - `gh api repos/.../actions/runs/<run-id>` → conclusion=cancelled or failure
   - `git ls-remote origin <branch>` = 0
   - `gh api search/commits?q=task-XXXX` = 0

---

## [9] True Race 강제 검증

### case_id: race-true-merge
```bash
# 동일 PR에 동시 merge 시도
(gh pr merge <PR> --merge) &
(gh pr merge <PR> --merge) &
wait
```
조건:
- 둘 다 exit != 0
- main 반영 0건
- merged_at = null

---

## [10] MD 파일 무력화 테스트 (★ 핵심)

### case_id: md-bypass-test
1. **모든 MD/문서 임시 삭제**:
   ```bash
   git rm $(git ls-files '*.md')
   git commit -m "[md-bypass-test] all MD removed"
   git push origin task-md-bypass-test
   ```
2. cancelled task PR 생성 시도
3. **시스템 그대로 동작해야 함**:
   - branch protection: 그대로 enforce
   - required checks: 그대로 enforce
   - gemini-review-gate: 그대로 동작
   - merge queue: 그대로 동작
4. **GitHub 원본 검증**:
   - `gh api repos/.../branches/main/protection` 응답 = 변경 없음
   - `gh pr merge` 시도 결과 = 거부
5. cleanup: MD 파일 복원 (revert)

---

## [11] 합격 조건 (★ 회장 직접 명시)

다음이 **모두 GitHub 원본 기준**으로 증명될 때만 PASS:

| # | 조건 | 검증 명령 |
|---|---|---|
| A | required checks 실제 enforced | gh api branches/main/protection → 7개 contexts 확인 |
| B | Gemini failure → merge 불가 | gemini-review-gate=failure 시 mergeable_state=blocked |
| C | cancel → 모든 경로 차단 | case_id: cancel-mid-queue 통과 |
| D | direct push 불가 | git push origin main → 거부 |
| E | merge queue 강제 | gh pr merge (without queue) → 거부 |
| F | race 0건 반영 | 동시 merge 후 main grep task-XXXX = 0 |
| G | MD 삭제 후 동작 | case_id: md-bypass-test 통과 |

**한 가지라도 FAIL = task FAIL.**

---

## 산출물 (의무)

봇 .done 발급 시 첨부:

### 신규 코드/설정
- `.github/workflows/ci.yml` (확장)
- `scripts/gemini_review_gate.py`
- `scripts/gemini_feedback_loop.py`
- `scripts/lock_in_verify.py`
- 회귀 테스트 3종 (`tests/scripts/test_gemini_review_gate.py` etc.)

### GitHub 원본 응답 캡처 (모든 케이스)
- `memory/reports/task-XXXX-enforce/01-branch-protection.json` — gh api 원본 응답
- `memory/reports/task-XXXX-enforce/02-required-checks.json`
- `memory/reports/task-XXXX-enforce/03-gemini-block-real.json`
- `memory/reports/task-XXXX-enforce/04-enforcement-check-{1,2,3}.txt`
- `memory/reports/task-XXXX-enforce/05-physical-{1,2,3}.txt`
- `memory/reports/task-XXXX-enforce/06-queue-{enforcement,flow}.json`
- `memory/reports/task-XXXX-enforce/07-gemini-loop-3.json`
- `memory/reports/task-XXXX-enforce/08-cancel-mid-queue.json`
- `memory/reports/task-XXXX-enforce/09-race-true-merge.txt`
- `memory/reports/task-XXXX-enforce/10-md-bypass-test.json`

### SCQA 보고서 (`memory/reports/task-XXXX.md`) — **단, 본 보고서가 없어도 합격은 GitHub 원본 기준**

---

## 금지 (회장 직접)

- "구현 예정" / "설계 완료" / "문서 작성" / "PASS 판단" → **즉시 FAIL**
- task.md / MD 파일만 생성 → 즉시 FAIL
- `.done` 발급 시 GitHub 원본 응답 첨부 없음 → 즉시 FAIL

---

## 작업 원칙

1. **GitHub 보호 규칙 = 강제 규칙**: 봇이 admin 권한으로 설정. 설정 안 되면 회장 직접 설정 요청
2. **코드/설정만 인정**: 모든 검증은 gh api / GitHub UI / 실 명령 결과
3. **MD 무력화 보증**: 시스템이 코드/설정에 박혀있어야 함. MD 의존 0
4. **Lock-in 1 First-line 영구 강제**: lock_in_verify.py가 CI에서 실 검증
5. **Gemini Gate가 진짜 게이트**: optional 리뷰 X. failure면 merge 불가

---

## affected_files

### 수정
- `.github/workflows/ci.yml` (확장 — 7개 step 분리 + Gemini Gate)
- `scripts/finish-task.sh` (cancel-mid-queue 처리 보강)
- `scripts/auto_merge.py` (queue 경유 강제)

### 신규
- `scripts/gemini_review_gate.py`
- `scripts/gemini_feedback_loop.py`
- `scripts/lock_in_verify.py`
- `tests/scripts/test_gemini_review_gate.py`
- `tests/scripts/test_gemini_feedback_loop.py`
- `tests/scripts/test_lock_in_verify.py`
- `memory/reports/task-XXXX-enforce/` 폴더 (10종 GitHub 원본 응답)
- `memory/reports/task-XXXX.md`

### 변경 금지 (forbidden — task-2434/2439 산출물 keep)
- `scripts/task_scope.py`
- `scripts/pre_push_guard.py`
- `scripts/qc_report_guard.py`
- `scripts/guard.sh`
- `scripts/anu_confirm_bot/main.py` (task-2439 First-line 가드 보존)
- `scripts/git-hooks/pre-push` (task-2439 보존)
- `tests/scripts/test_*` (기존 회귀 보존)
- `dispatch.py`
- `dashboard/**`
- `teams/shared/**`
- `CLAUDE.md`

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "/home/jay/workspace/.github/workflows/**"
    - "/home/jay/workspace/scripts/gemini_review_gate.py"
    - "/home/jay/workspace/scripts/gemini_feedback_loop.py"
    - "/home/jay/workspace/scripts/lock_in_verify.py"
    - "/home/jay/workspace/scripts/finish-task.sh"
    - "/home/jay/workspace/scripts/auto_merge.py"
    - "/home/jay/workspace/tests/scripts/test_gemini_*.py"
    - "/home/jay/workspace/tests/scripts/test_lock_in_*.py"
    - "/home/jay/workspace/memory/reports/task-XXXX*/**"
    - "/home/jay/workspace/memory/reports/task-XXXX.md"
    - "/home/jay/workspace/memory/cache/gemini-*"
    - "/home/jay/workspace/memory/logs/gemini-calls.jsonl"
  forbidden_paths:
    - "/home/jay/workspace/scripts/task_scope.py"
    - "/home/jay/workspace/scripts/pre_push_guard.py"
    - "/home/jay/workspace/scripts/qc_report_guard.py"
    - "/home/jay/workspace/scripts/guard.sh"
    - "/home/jay/workspace/scripts/anu_confirm_bot/main.py"
    - "/home/jay/workspace/scripts/git-hooks/pre-push"
    - "/home/jay/workspace/dispatch.py"
    - "/home/jay/workspace/dashboard/**"
    - "/home/jay/workspace/teams/shared/**"
    - "/home/jay/workspace/CLAUDE.md"
  commands:
    - "gh api"
    - "gh pr"
    - "gh run"
    - "git push"
    - "git status"
    - "git log"
    - "git diff"
    - "git config"
    - "python3 -m py_compile"
    - "pytest"
    - "bash scripts/guard.sh"
    - "node --check"
  merge_policy: "manual_after_full_enforcement"
  ttl_hours: 12
```

## 운영
- ★ Lv.4 (시스템 인프라 — GitHub 보호 규칙 + Required Checks + Gemini Gate + Merge Queue)
- TTL 12h (대형 작업)
- 위임: dev1-team (헤르메스) — task-2439 1차 컨텍스트 보유
- 본 task의 머지 = anu_confirm_bot/finish-task.sh 추가 수정 + ci.yml 확장 + 신규 script 3개. **수동 검증** 후에만
- 회장 게이트키퍼 [11] 합격 조건 7항 모두 GitHub 원본으로 증명될 때만 .done.acked

## 참조
- task-2439 보고서 + 증거: `/home/jay/workspace/memory/reports/task-2439.md` + `/task-2439-pentest-evidence/` + `/task-2439-anu-verification/`
- task-2434 1차 가드 산출물: `scripts/{task_scope,pre_push_guard,qc_report_guard}.py` + `scripts/guard.sh`
- 회장 거버넌스 9원칙 + 3경로 동일 가드: `system_governance_4layer.md`
- 회장 격상 메모리: `feedback_dispatch_no_mid_correction.md` (위임 후 정정 100% 무효)
- 좀비 봇 PR #101 사고: `bug_zombie_bot_pr_101.md`

---

## ★ 한 줄 절대 기준 (재고정)
> **"문서를 삭제해도 시스템은 그대로 동작해야 한다."**
> **"GitHub 원본 응답으로만 합격 판단."**