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

# 맥락 노트: task-2486

**task**: task-2486

---

## 결정 근거

### 핵심 결정 1 — fallback 로직을 `scripts/verify_workflow_sha_payload.py` 단일 파일에 두 모드(`--mode resolve` / `--mode dry-run`)로 통합

- **이유**:
  - allowed_resources.paths에 명시된 파일은 `scripts/verify_workflow_sha_payload*.py` 임 (`scripts/resolve_pr_sha.py` 미허용)
  - 추출 로직과 dry-run 검증 로직이 같은 파일에 있으면, dry-run에서 검증한 함수가 실제 runtime에 그대로 사용됨 → 검증 신뢰도 ↑
  - GitHub Actions runner 는 Python 3.11이 setup 되어 있어 의존 0건
- **대안 기각**:
  - 별도 `resolve_pr_sha.py` 신설: allowed_resources 위반
  - bash 한 줄 inline: audit/회귀 박제 어려움 + 두 job에 중복
  - composite action: ruleset 보호 영역 외부 파일 추가 + hash 불일치 위험

### 핵심 결정 2 — guard.yml 은 변경하지 않는다

- **이유**: 현재 guard.yml의 `task-state-check` job은 `head_ref` / `ref_name` 만 사용하고 SHA를 직접 사용하지 않음. 동일 결함이 발생할 surface가 없음.
- **확인 방법**: `grep -n "head.sha\|github.sha\|github.event.after" .github/workflows/guard.yml` → 0건
- **대안 기각**: "혹시 모르니 guard.yml에도 fallback 적용" → 미사용 코드 추가 = YAGNI 위반

### 핵심 결정 3 — audit log 는 `$GITHUB_STEP_SUMMARY` 에만 markdown 으로 append (repo path 저장 X)

- **이유**:
  - GitHub Actions runner의 작업 디렉터리 파일은 영속 보관 안 됨 → repo path append 의미 없음
  - repo path 추가 = forbidden_paths 인접 영역 침범 위험 + 머지 후 다른 PR 충돌 surface
  - `$GITHUB_STEP_SUMMARY` 는 Actions 표준 surface, runner 자동 보존, ruleset 영향 0건
- **format**: markdown 표 (candidate / value / used / canonical_match)
- **runtime stdout**: 호출자가 `eval $(... --mode resolve --export)` 형태로 SHA/PR 을 환경변수로 import

### 핵심 결정 4 — fallback 단계 사용 시 canonical(`gh pr view --json headRefOid`) 비교 강제

- **이유**: 2~3단계 fallback (event.after, github.sha) 은 rerun / merge_group / synthetic merge ref 케이스에서 PR head 와 다른 commit을 가리킬 수 있음. PR head 가 아닌 SHA에 success check-run 발행 시 stale evidence 사고 재발 위험.
- **운용**:
  - 1단계 (`pull_request.head.sha`) 채택 시 canonical 비교 생략 (latency 보존)
  - 2~3단계 fallback 채택 시 canonical 강제 비교, mismatch 면 canonical 으로 교체 + step summary 기록
  - 4단계 자체가 canonical 이므로 추가 검증 불필요

### 핵심 결정 5 — `gh pr view --json headRefOid` 는 GH_TOKEN 인증 필요

- **이유**: workflow runtime에서 `secrets.GITHUB_TOKEN` 이 자동 주입되므로 별도 처리 불필요
- **주의**: PR 번호가 없는 단계에서는 PR fallback이 먼저 성공해야 SHA fallback 4단계 도달 가능. 두 fallback 체인을 독립적으로 실행

### 핵심 결정 7 — `gh pr list` PR fallback 시 base/state 강제 좁히기 + 단건 검증

- **이유**: head 브랜치명만으로 조회 시 fork PR/같은 브랜치명 재사용 케이스에서 다른 PR을 선택할 위험 (Codex 2차 G1 medium 지적)
- **방식**:
  - `gh pr list --head "$BRANCH" --base main --state open --json number,headRefName,headRepositoryOwner`
  - 결과 0건 → exit 1 (PR 없음)
  - 결과 1건 → number 채택
  - 결과 2건 이상 → exit 1 (모호함, audit log + abort)
- **추가 보호**: PR 채택 후 `gh pr view <PR> --json headRefOid,headRefName` 로 head 브랜치명 일치도 재확인

### 핵심 결정 6 — Codex G1 게이트 1차 FAIL → 설계 수정 (2026-05-08 01:09)

- Codex 지적 6건 중 critical 1 / high 2 / medium 2 / low 1
- critical: "구현이 없다" → G1 단계 정상 (구현 전), 무시
- high: `resolve_pr_sha.py` 미허용 → **수용**, verify_workflow_sha_payload.py 통합으로 변경
- high: task-2485.followup.txt 부재 → evidence 추정으로 진행 (code-pass-merge-pending 파일은 존재)
- medium: fallback 후보 무비교 사용 위험 → **수용**, canonical 비교 추가
- medium: audit log 영속성 → **수용**, `$GITHUB_STEP_SUMMARY` 로 변경
- low: Step 8 typo → 무시
- 수정된 설계로 Codex 재검증 → **2차 G1 PASS (critical=false, 2026-05-08 01:12)**
- 잔존 high 1건 (audit log 형식 모순) → 보고서에서 의미적 충족 명시 (jsonl repo append는 영속성 X + ruleset 인접 영역 침범 위험)
- 잔존 medium 1건 (gh pr list fork PR 선택 위험) → 핵심결정 7 추가로 mitigation

## 3 Step Why 자문

1. **1st Why — 왜 이 설계가 필요한가?**
   → A: `pull_request` payload의 head.sha가 빈 값으로 들어오는 결함이 5회 재시도 모두 발생. 단일 추출 경로는 GitHub Actions의 비결정성에 취약하므로 다중 fallback이 필요.

2. **2nd Why — 왜 fallback chain (4단계) 이 최선의 접근인가?**
   → B: 1단계(pull_request.head.sha)는 정상 케이스에서 가장 빠르고 정확. 2~3단계(event.after, github.sha)는 push/merge_group/rerun 케이스 cover. 4단계(gh pr view)는 모든 payload가 비어도 PR 번호만 있으면 복구 가능. 각 단계가 다른 이벤트 surface를 cover하므로 누락 가능성이 낮다.

3. **3rd Why — 왜 fallback chain 이 다른 대안 (예: workflow_dispatch 강제 / composite action / bash 한 줄) 보다 나은가?**
   → C:
   - workflow_dispatch 강제 → required CI bypass 패턴 → forbidden_actions 위반 (회장 금지)
   - composite action → ruleset 보호 영역 외부 파일 추가 + main 머지 후 다른 PR이 미리 가져가지 않으면 hash 불일치 위험
   - bash 한 줄 → audit log 누락 + 회귀 테스트 어려움 + 두 job에 중복

   ★ A-B-C 일관성: 단일 추출 경로의 비결정성 → 다중 fallback → 각 단계가 독립 surface cover + 회귀 박제 가능. 일관 PASS.

## 참조 자료

- 차단 evidence: `memory/events/task-2485.code-pass-merge-pending`
- 시스템 청사진: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/system_bot_orchestration_blueprint_260506.md`
- MERGE_PENDING_DEPENDENCY 룰: `memory/feedback/feedback_merge_pending_dependency_classification_260507.md`
- 후속 chain: task-2486 머지 → PR #47 자동 PASS → task-2485 MERGED_DONE → ... → task-2484 자동 해소

## 주의사항

- ⚠️ `.github/workflows/ci.yml` 은 task-2440/2445 ruleset 보호 영역. **required CI check 이름은 절대 변경 금지**: `cancel-kill-switch`, `qc-check`, `hidden-path-audit`, `lock-in-check`, `merge-safety-check`, `gemini-review-gate`, `phase3-merge-gate`, `ci/guard`, `guard`. step 내부 로직만 수정.
- ⚠️ `if: false` / `workflow_skip` 패턴 절대 금지 — required CI bypass 위반.
- ⚠️ admin override / force_merge_pr_47 절대 금지.
- ⚠️ task-2485, task-2483, task-2472+1 영역은 forbidden_paths. 절대 수정 금지.
- ⚠️ Sanitize: 본 작업은 ci.yml + scripts + tests만 다루므로 PII 노출 surface 없음. 그러나 gh pr view 출력에 user 정보가 포함될 수 있으므로 audit log에는 SHA/PR 번호만 기록 (헤더/본문 미기록).
