# task-2495 — PR #42 / task-2472+1 recovery read-only analysis

- **작업 유형**: read-only 분석 (Lv.1)
- **담당**: dev1-team (헤르메스)
- **일시**: 2026-05-08
- **산출물 경로**: `memory/reports/task-2495.md`, `memory/events/task-2495.pr42-recovery-readonly-analysis`
- **준수 사항**: 회장 명시 17 공통 금지 — 코드/테스트/PR/branch 변경 0건, update-branch 미실행, admin override 미사용

---

## SCQA 요약

- **Situation**: PR #42 (task-2472+1, head `2c603d27`)는 task-2485+1 머지 후 BLOCKED → BEHIND로 전환. mergeable=true이지만 taskctl-state-guard 2건이 동일 사유로 FAIL을 반복 중.
- **Complication**: anu가 직전에 `gh pr update-branch 42`로 main의 regex fix(PR #46, ff330711)를 PR branch에 흡수했음에도 B-3 stage에서 `task scope 밖 파일 1건: utils/g3_fail_classifier.py`로 차단된다.
- **Question**: (1) 단순 update-branch 재실행으로 해소되는가? (2) taskctl-state-guard 잔존 fail의 진짜 원인은? (3) 후속으로 무엇을 발행해야 하는가?
- **Answer**: 단순 update-branch 재실행만으로는 **해소 불가**. 진짜 원인은 PR branch에 capability snapshot이 누락되어 폴백된 task 파일 YAML(`## 3. allowed_resources`)에 `utils/g3_fail_classifier.py`가 빠져 있는 것. 후속 액션은 회장 결정으로 별도 task 발행 권고.

---

## 회장 명시 6항목 보고

### 1. 현재 PR #42 상태

| 항목 | 값 |
|---|---|
| state | OPEN |
| mergeStateStatus | **BEHIND** (이전: BLOCKED) |
| mergeable | MERGEABLE (충돌 없음) |
| baseRefName | main |
| headRefName | task/task-2472+1-dev2 |
| headRefOid | `2c603d2739c7d452b39d73849326dcc6ab3eceaf` |
| 머지 여부 | 미머지 |
| BEHIND 깊이 | main 대비 약 5 commit 뒤 (task-2485+1 PR #47 등 머지 이후) |

> **BLOCKED → BEHIND 전환 원인**: task-2485+1 PR #47(`be8dcd21`) 등이 main에 머지되면서 PR #42가 단순 "behind" 상태가 됐다. 즉 branch protection이 요구하는 `up-to-date` 조건만 미충족인 상태.

### 2. failing checks (현재)

| Check | Run ID | Job ID | 결론 | 단계 | 메시지 |
|---|---|---|---|---|---|
| taskctl-state-guard | 25502797215 | 74840099829 | FAILURE | B-3 task scope 일치 | `task scope 밖 파일 1건: utils/g3_fail_classifier.py` |
| taskctl-state-guard | 25502793315 | 74840086070 | FAILURE | B-3 task scope 일치 | `task scope 밖 파일 1건: utils/g3_fail_classifier.py` |

PASS: cancel-kill-switch / qc-check / hidden-path-audit / lock-in-check / merge-safety-check / gemini-review-gate / phase3-merge-gate / ci/guard / guard (총 9/11)

> **2건 fail 사유**: `guard.yml`이 `pull_request: branches=[main]` + `push: branches-ignore=[main]` 양쪽 트리거를 켜고 있어, update-branch 시 PR sync + push가 동시에 발생하면서 동일 job이 두 번 실행되는 구조. **본질 원인이 아닌 트리거 중복**.

### 3. taskctl-state-guard fail 원인 (root cause)

**1줄 결론**: PR branch에 capability snapshot이 없어 task 파일 YAML로 폴백되는데, PR branch의 task 파일에는 `utils/g3_fail_classifier.py`가 allowed_resources에 누락되어 있어 B-3 task scope 검사에서 차단된다.

**상세 인과 사슬**:

1. PR #42 head_diff 10 파일 중 `utils/g3_fail_classifier.py`는 실제로 커밋되어 있다.
2. CI는 `scripts/pre_push_guard.py`의 `_resolve_allowed_resources(task-2472+1)` 호출.
3. 이 resolver는 `memory/capabilities/task-2472+1.json` 우선 시도 → **PR branch에 미존재** (`memory/capabilities/`는 git-tracked이지만 task-2472+1.json은 PR head 트리에 없음).
4. 폴백으로 PR branch의 `memory/tasks/task-2472+1.md` ## allowed_resources 블록을 파싱.
5. PR branch의 task 파일은 원본 spec 형태(`## 3. allowed_resources`)만 보유하며, 그 paths에 **`utils/g3_fail_classifier.py`가 없다**.
   - 로컬 워크스페이스의 task 파일은 상단에 추가된 `## allowed_resources`(번호 없음)에 해당 경로가 명시돼 있지만, 이는 commit/push되지 않은 로컬 메타 갱신.
6. `check_b3_task_scope`가 head_diff의 `utils/g3_fail_classifier.py`를 forbidden, system-ignore, allowed_paths 모두에서 매칭 실패 → out_of_scope 1건 → FAIL.
7. workflow regex fix(PR #46)는 task_id 추출 단계만 고친다. B-3 단계의 task scope 매칭에는 영향이 없으므로 **regex fix는 진단했어도 본 fail은 해결 못 함** (재실행 evidence가 동일 진단).

**증거 매트릭스**

| 자료 | 위치 | g3_fail_classifier.py 포함? |
|---|---|---|
| 로컬 capability snapshot | `memory/capabilities/task-2472+1.json` (워크스페이스) | ✅ |
| 로컬 task 파일 `## allowed_resources` (라인 3) | `memory/tasks/task-2472+1.md` (워크스페이스) | ✅ |
| **PR branch capability snapshot** | `(2c603d27 트리에 없음)` | **N/A — 누락** |
| **PR branch task 파일 `## 3. allowed_resources`** | `2c603d27:memory/tasks/task-2472+1.md` | **❌** |
| PR head_diff | `git diff origin/main...2c603d27` | 포함 (변경 대상) |

### 4. update-branch 가능성

| 차원 | 판정 |
|---|---|
| 기술적 가능성 | **가능** (mergeable=MERGEABLE, 5 commit 뒤지만 충돌 0) |
| 권고 여부 | **비권고 (futile)** |
| 사유 | update-branch는 main의 변경을 PR branch에 흡수하지만, B-3 fail 원인이 PR branch의 **task 파일 자체** 또는 **capability snapshot 부재**이므로 main에서 가져올 수 있는 변경분으로는 해소되지 않는다. 재실행 evidence(`task-2472+1.merge-pending-rerun-evidence`)에 이미 동일 결과가 입증돼 있다. |
| 부작용 | 동일 trigger 2중 발화로 fail이 2건 더 누적, retry 카운터 잠재 증가, 봇 흐름에 noise 가중 |

### 5. 충돌 위험 (conflict risk)

main이 `2c603d27` 이후 추가 변경한 파일 목록(23건):

```
.github/workflows/ci.yml
memory/plans/tasks/task-2485/{checklist,context-notes,plan}.md
memory/reports/task-2485.md
scripts/verify_task_id_hardening.py
scripts/verify_workflow_sha_payload.py
teams/shared/verifiers/{browser_verify,git_evidence}.py
tests/regression/fixtures/workflow_sha_payload/* (7건)
tests/regression/test_browser_verify_hardening.py
tests/regression/test_git_evidence_hardening.py
tests/regression/test_task_id_parser_hardening.py
tests/regression/test_workflow_sha_payload.py
tests/regression/test_workflow_taskid_regex_hardening.py
utils/task_id_parser.py
```

PR #42가 변경하는 10 파일(`scripts/taskctl.py`, `utils/g3_fail_classifier.py`, `utils/state_repair.py`, tests/regression/test_g3_fail_classification.py, test_taskctl_reconcile.py, plans/tasks/task-2472+1/*, reports/task-2472+1.md, tasks/task-2472+1.md)과 **겹치는 경로 0건** → 머지 충돌 위험 없음. mergeable=true와 일치.

> **주의**: 충돌이 없다고 해서 **CI 통과를 의미하지 않는다**. B-3 fail은 PR branch 내용 문제이지 main과의 충돌이 아니다.

### 6. 추천 후속 액션 (실행 금지 — 분석/제안만)

회장 결정 후 별도 task로 발행 권고. 우선순위 순서:

| 안 | 작업 범위 | 위험 | 비용 | 비고 |
|---|---|---|---|---|
| **A. PR #42 branch에 capability snapshot 커밋** | `memory/capabilities/task-2472+1.json` 1파일 add | 낮음 (snapshot은 메타데이터) | 작음 | snapshot 자체에 `g3_fail_classifier.py` 명시되어 있어 B-3 PASS 즉시 가능. dev2-team(오딘) 또는 한정승인 봇이 PR head에 push. **단, snapshot이 본질 코드는 아니므로 "task-2472+1 본질 코드 추가 수정 금지" 원칙과 충돌 가능 여부는 회장 판단 필요** |
| **B. PR #42 branch task 파일의 `## 3. allowed_resources`에 `utils/g3_fail_classifier.py` 1줄 추가** | task 파일 1줄 patch | 중간 — task 파일 surface 수정 | 작음 | 가장 가시적인 해결. 단 회장 명시 "task-2472+1 본질 코드 추가 수정 금지"의 문언적 해석에 걸림. spec/메타에 한정한 1줄 보강이라는 사유로 한정승인 필요 |
| **C. pre_push_guard.py를 main 기반 snapshot도 조회하도록 hardening** | `scripts/pre_push_guard.py` _resolve_allowed_resources에 `origin/main` 폴백 분기 추가 + 회귀 테스트 | 중간 — guard 코어 변경 | 중간 | 별도 task(예: task-2497) 발행. 본질적 hardening이지만 PR #42 외 다른 PR에도 영향 → 회귀 위험 큼 |
| **D. workflow trigger 중복 정리 (선택)** | `.github/workflows/guard.yml`의 push trigger 제거 또는 paths-ignore | 낮음 | 작음 | fail 2건이 1건으로 줄어드는 노이즈 정리만, 본질 fail은 그대로. 별도 운영 개선으로 분리 |
| **E. admin override / force merge** | — | **금지** | — | 회장 명시 위반. 절대 비권고 |

**개인 권고**: **안 A 우선** (snapshot 커밋이 본질 코드를 건드리지 않고 결정적 해소). 안 A가 회장 해석상 막히면 안 B(1줄 patch). 안 C는 hardening track으로 병행 검토하되 PR #42 unblock 경로로는 비권고 (큰 변경, 회귀 risk).

---

## 발견 이슈 및 해결

| 이슈 | 상태 | 비고 |
|---|---|---|
| PR branch와 로컬 워크스페이스 사이의 task 파일 불일치 | **확인됨, 미해결** (read-only 작업이므로 의도적으로 미수정) | 로컬은 `## allowed_resources`(번호 없음, g3_fail_classifier.py 포함) + `## 3. allowed_resources`(원본) 이중 블록. PR branch는 `## 3.`만 보유. _parse_allowed_resources_yaml 정규식이 `## allowed_resources` 매칭이라 로컬 환경에서는 첫 매치(상단 블록)를 잡지만, PR branch에서는 `## 3.`을 잡음 |
| guard.yml 트리거 중복(pull_request + push) | **확인됨** | 동일 fail 2회 보고. 본 분석 범위 외, 별도 운영 개선 항목 |
| capability snapshot의 git tracking 정책 모호 | **확인됨** | `memory/capabilities/`는 git-tracked이나 task-2472+1.json은 미커밋. dispatch 흐름이 push 전 snapshot을 자동 커밋하는지/아닌지 명확화 필요 (시스템 hardening 후보) |

---

## 모델 사용 기록

- 본 작업은 read-only 분석 + 보고서 작성. 별도 팀원 위임 없이 팀장(Opus, claude-opus-4-7)이 직접 수행.
  - 사유: Lv.1 분석/문서화 작업, 분해 가능한 코딩 서브태스크 부재. 팀원 위임 시 컨텍스트 전달 비용이 직접 수행 비용을 초과.
  - 작업 부하: PR 상태 1회 조회 + git diff/show 5회 + workflow/guard 코드 4개 파일 read + 보고서 1건 작성.

---

## L1 스모크테스트 결과

본 task는 read-only 분석으로 코드/테스트/PR/branch 변경 0건. 따라서:
- 서버 재시작: 해당없음
- API 응답 확인: PR #42 상태 조회 1회 (`gh pr view 42 --json ...`) — 정상 200 응답, JSON parse 성공
- 스크린샷: 해당없음 (UI 변경 없음)

추가 검증으로 다음 read-only 명령을 실행:
- `git ls-tree -r 2c603d27` → PR head 트리 정상 조회
- `git show 2c603d27:memory/tasks/task-2472+1.md` → PR branch 파일 정상 조회
- `git diff --name-only origin/main...2c603d27` → 10 파일 정상 출력
- `git diff --name-only 2c603d27...origin/main` → 23 파일 정상 출력

L1 통과: read-only API 호출 + git 트리 조회가 모두 기대 동작. 코드 path가 변경되지 않았으므로 추가 동작 검증 불필요.

---

## 산출물

- `memory/reports/task-2495.md` (본 보고서)
- `memory/events/task-2495.pr42-recovery-readonly-analysis` (이벤트 마커, 별도 작성)

## 게이트 결과 (Lv.1)

- **G1 설계 게이트**: 본 작업의 affected_files=0 (read-only). 다른 팀과 충돌 없음. PASS
- **G2 구현 게이트**: 구현 변경 없음. 분석/문서만. PASS (해당 없음)
- **G3 머지 게이트**: 머지 대상 없음. 보고서만 제출. 해당 없음

## 회장 명시 7 공통 완료 조건 충족 확인

- ✅ 코드 변경 0건
- ✅ 테스트 변경 0건
- ✅ PR 변경 0건
- ✅ branch 변경 0건
- ✅ 오딘 task-2487+1 비개입 (해당 task 영역 일체 미접근)
- ✅ 산출물 문서 경로 제출 (보고서 + 이벤트)
- ✅ 후속 작업 제안만 (실행 0건)

## 세션 통계
- 총 도구 호출: 0회

