---
task_id: task-2486
type: plan
scope: task
created: 2026-05-08
updated: 2026-05-08
status: completed
---

# 계획서: task-2486 — CI pull_request SHA payload fallback fix

**task**: task-2486
**목표**: `.github/workflows/ci.yml`의 `gemini-review-gate` / `phase3-merge-gate` job이 `pull_request` 이벤트에서 head SHA를 안정적으로 추출하도록 fallback chain을 도입하여, PR #47 / PR #42 차단을 해소한다.
**승인**: 회장 — 2026-05-08 "stale evidence가 아니라 workflow SHA 추출 로직 결함이다. task-2486으로 위임."
**근거**: `memory/events/task-2485.code-pass-merge-pending` (재시도 5회 동일 FAIL `missing pull_request payload (SHA= PR=47)`)

---

## 목표

1. PR #47의 `gemini-review-gate` / `phase3-merge-gate`가 자동 PASS 되도록 ci.yml 의 SHA/PR 추출 로직을 fallback 체인으로 교체.
2. 동일 결함 가능성이 있는 `guard.yml` 도 점검.
3. fallback 동작을 회귀 테스트 + dry-run 스크립트로 박제.
4. fallback audit log를 `memory/orchestration-audit/workflow-sha-fallback.jsonl` 에 남겨 향후 재발 시 진단 가능하도록 한다.

## 범위

### 포함
- `scripts/verify_workflow_sha_payload.py` 신설 — 두 모드 지원:
  - `--mode resolve`: workflow runtime 추출용. fallback 체인 + canonical 검증 + `$GITHUB_STEP_SUMMARY` audit
  - `--mode dry-run`: fixture 기반 자체 테스트. exit 0 = PASS
  - allowed_resources.paths에 `scripts/verify_workflow_sha_payload*.py` 로 명시되어 있어 범위 내
- `.github/workflows/ci.yml` 의 `gemini-review-gate`, `phase3-merge-gate` step에서 위 스크립트 `--mode resolve` 호출
- `tests/regression/test_workflow_sha_payload.py` 신설 (4 케이스 + canonical mismatch 케이스)
- `tests/regression/fixtures/` 4종 fixture (정상/SHA 누락/PR 누락/모두 누락)
- `guard.yml` 점검 결과: SHA 미사용 surface 없음 → **변경 대상 제외**

### 제외 (다음 페이즈 이후)
- PR #47 머지 자체 — 본 task 머지 후 자동 재실행 (회장 명시 후속 chain)
- PR #42 / task-2472+1 처리 — 본 task 영향만 검증, 머지는 별도 자동화
- task-2483 finish-task 재실행 — 후속 chain
- gemini_review_gate.py 의 SHA 인자 처리 보강 — 현재는 SHA를 외부에서 받기만 하므로 미터치

## 위임 계획

- Phase 1 (설계 + Codex 게이트): **헤르메스 (팀장)**
- Phase 2 (구현: verify_workflow_sha_payload.py 통합 모드 + ci.yml 수정 + fixtures): **불칸 (백엔드)** — Sonnet
- Phase 3 (회귀 테스트 작성): **아르고스 (테스터)** — Sonnet
- Phase 4 (검증 + PR + Gemini 리뷰 대응): **헤르메스 (팀장)**

## 검증 기준

- `python3 scripts/verify_workflow_sha_payload.py` exit 0
- `pytest tests/regression/test_workflow_sha_payload.py` PASS
- worktree에서 `python3 scripts/verify_workflow_sha_payload.py --mode resolve --event-path tests/regression/fixtures/pr_event_normal.json` SHA + PR 출력
- PR #47 statusCheckRollup에서 `gemini-review-gate` / `phase3-merge-gate` `conclusion=SUCCESS` (본 task 머지 후 1차 검증)

## fallback 체인 (회장 명시 순서)

### SHA
1. `event.pull_request.head.sha` — primary (정상 케이스 즉시 채택, 추가 검증 생략)
2. `event.after`
3. `github.sha` (env: `GITHUB_SHA`)
4. `gh pr view <PR> --json headRefOid` — **canonical source**

### PR
1. `event.pull_request.number`
2. `event.number`
3. `gh pr list --head $BRANCH --base main --state open --json number,headRefName,headRepositoryOwner` (base/state 좁히기 + 단건 검증, 다건이면 abort)

### canonical 검증 (fallback 단계에서만 적용)
- 1단계 SHA가 비어 있어 2~3단계 fallback을 사용한 경우, canonical(`gh pr view --json headRefOid`)과 비교
- mismatch 시: canonical 값으로 교체 + step summary 에 mismatch 기록
- 1단계가 정상 채워진 경우: canonical 검증 생략 (정상 케이스 latency 보존)

### 실패 처리
- 모든 후보 빈 값 (canonical 포함) → exit 1 (`required CI fail`)
- step summary (`$GITHUB_STEP_SUMMARY`) 에 후보별 시도 결과 markdown 기록
