# 작업 보고: stale-pr-ciwatch (묵은 PR CI 감시·머지)

- 팀: dev2-team (오딘)
- 근거 명세: `/home/jay/workspace/memory/events/stale-pr.ci-watch-handoff.json` (ANU, 2026-08-21T05:50+09:00)
- 대상: InsuRo PR #207, #217
- 종단 상태: **#207 = MERGE 완료 / #217 = CHAIR_REQUIRED (머지 보류)**

---

## S (상황)

8~12일 방치된 InsuRo PR 2건에 대해 ANU 가 CI_WATCH_HANDOFF 를 발행했다. update-branch 직후 CI 재실행 중이었고, 전부 pass + `expected_files` 일치 시 squash 머지하라는 한정 위임이다. `#215`·`#202` 는 명시적 범위 밖.

## C (복잡성)

메모리 프리플라이트에서 **핸드오프 명세와 정면 충돌하는 선행 판단**이 나왔다.

- 같은 날 **05:01** ANU 기록: 「묵은 PR #207 — **머지하면 안 됩니다**」. 삭제 대상 3개 Edge Function 이 `src/components/crm/AudioRecorder.tsx`, `CallLogTab.tsx`, `KakaoAnalysis.tsx`, `CrmCustomerDetail.tsx`, `server/main.py` 에서 **참조된다**는 이유. CRM 은 최근 30일 신규 고객 6명으로 실사용 중.
- 핸드오프 명세는 **05:50** 자로 「호출 0건·자체 백엔드 이관 완료」라고 정반대 결론.

49분 간격으로 결론이 뒤집혔으므로, 명세를 그대로 신뢰하지 않고 **레포지토리 실측으로 독립 재검증**했다.

## Q (질문)

1. #207 삭제 대상이 정말 죽은 코드인가, 아니면 05:01 판단대로 살아있는 참조가 있는가?
2. 각 PR 의 변경 파일이 `expected_files` 와 일치하는가?

## A (답변·조치)

### 1. #207 — 05:01 우려는 **이름 충돌 오탐**이었음을 실증

프론트가 참조하는 것은 Edge Function 이 아니라 **자체 백엔드 REST 경로**다. 경로 세그먼트가 함수명과 같아서 단순 grep 이 오탐했다.

```
src/components/crm/AudioRecorder.tsx:116
  `${INSURO_API_BASE}/api/insuro/transcribe-call`   ← 백엔드 FastAPI 라우트
server/main.py:7664
  @app.post("/api/insuro/transcribe-call")          ← 실제 구현체
```

Edge Function 실호출 경로를 전수 조사한 결과:

- `supabase.functions.invoke(...)` 잔존 호출 = `crawl-metrics`, `get-vapid-key`, `send-push` **3건뿐** → 삭제 대상 3개에 대한 invoke **0건**
- `/functions/v1/{analyze-customer,transcribe-call,evaluate-consultation}` 직접 URL 호출 **0건**
- `supabase/config.toml` diff = 해당 3개 stanza 제거만 (다른 함수 무접촉)

**삭제되는 테스트 2건의 커버리지 손실도 없음**을 확인했다. `pii-ai-provider.test.ts` 는 헤더 주석대로 삭제 대상 함수의 소스 텍스트를 정적 검증하는 가드(task-2933)이므로 함수가 사라지면 대상 자체가 소멸한다. 동등한 보증은 백엔드로 승계되어 있다 — `server/tests/test_anu_provider.py`(provider 가드), `server/tests/test_edge_to_anu.py`(이관 엔드포인트 401/422 회귀).

→ 이관 완료가 사실로 확인되어 **05:50 핸드오프 결론이 옳고, 05:01 보류 사유는 해소**.

### 2. #217 — `expected_files` 불일치로 **머지하지 않음**

CI 는 GREEN 이지만 명세 목록과 실제 변경이 어긋난다.

```
명세 expected_files : 4건
실제 changed_files  : 6건
초과 2건:
  docs/silson-dispute-case-law-reference-for-agents.md        (added +217/-0)
  server/silson/data/sources/case_law/FSS_20250310_보도자료.md (added +444/-0)
```

규칙 4(“expected_files 밖 변경이 보이면 머지하지 말고 즉시 ANU 보고”)에 따라 **머지를 중단**했다.

다만 판단 근거로 덧붙이면, 이 2건은 **PR 의 범위 이탈이 아니라 명세의 목록 누락**일 가능성이 높다. dev2 자체 task-2956 기록(2026-08-15)이 산출물을 6건으로 명시하고 있고, 초과 2건이 그 목록과 정확히 일치한다. 둘 다 순수 추가(+0 삭제)이며 `forbidden_paths` 무침범이다. **그럼에도 자가 판단으로 명세를 넓히지 않았다** — 목록 확장 권한은 ANU 에 있다.

### 3. 범위 준수

`#215`·`#202` 는 조회조차 상태 확인 1회로 제한했고 어떤 변경도 가하지 않았다(둘 다 open 유지, `updated_at` 불변).

---

## 검증 상태

| 검증 항목 | 대상 | 방법 | 결과 | status |
|---|---|---|---|---|
| CI 전체 통과 | PR #207 | check-runs 폴링 (2분 간격) | 11/11 success · 0 fail · 0 pending | verified |
| CI 전체 통과 | PR #217 | check-runs 폴링 (2분 간격) | 11/11 success · 0 fail · 0 pending | verified |
| expected_files 일치 | PR #207 | 명세 대 pulls/files 집합 대조 | extra=0 · missing=0 (6/6 정확 일치) | verified |
| expected_files 일치 | PR #217 | 명세 대 pulls/files 집합 대조 | **extra=2 · missing=0 → 머지 차단** | verified |
| forbidden_paths 무침범 | #207 · #217 | 5개 금지 glob 매칭 | 양쪽 0건 | verified |
| Edge Function 실호출 0건 | PR #207 | invoke 전수 + /functions/v1 URL 전수 | 0건 (잔존 invoke 3건은 무관 함수) | verified |
| 백엔드 이관 완료 | PR #207 | server/main.py 라우트 존재 확인 | 3/3 라우트 생존 (auth·rate-limit 포함) | verified |
| 테스트 커버리지 승계 | PR #207 | 삭제 테스트 import 범위 + 백엔드 테스트 존재 | 손실 0 (test_anu_provider.py 등 승계) | verified |
| 머지 반영 (blob 동일성) | PR #207 | squash 후 origin/main 트리 실측 | 함수 3개·tests 디렉터리 제거 · stanza 0 · 백엔드 3/3 생존 | verified |
| 비대상 PR 무접촉 | #215 · #202 | state·updated_at 대조 | 양쪽 open 유지 · 변경 0 | verified |

## 머지 결과

| PR | head | merge_commit_sha | 방식 | 결과 |
|---|---|---|---|---|
| #207 | `c074f13` | `eadd0c9780b180c86a7554045be2d5c5c96751ff` | squash | **merged** |
| #217 | `1dcbaf5` | — | — | **보류 (CHAIR_REQUIRED)** |

`origin/main` = `eadd0c9 chore: 미사용 CRM Edge Function 3개 제거 (#207)`

## Why 분석 — #217 이 막힌 근본 원인

- **1st Why**: 왜 #217 을 머지하지 못했나 → 실제 변경 6건이 명세 `expected_files` 4건을 초과했다.
- **2nd Why**: 왜 초과했나 → PR 이 범위를 벗어난 게 아니라, 핸드오프 명세를 작성할 때 산출물 6건 중 문서·원자료 2건이 목록에서 누락됐다.
- **3rd Why**: 왜 누락됐나 → `expected_files` 를 PR 의 실제 파일 목록(`pulls/{n}/files`)에서 기계적으로 생성하지 않고 사람이 코드 파일 위주로 옮겨 적었다. 문서·데이터 산출물이 "코드가 아니다"라는 이유로 시야에서 빠졌다.

**교훈**: `expected_files` 는 손으로 적지 말고 발행 시점의 `gh api pulls/{n}/files` 스냅샷으로 생성해야 한다. 그래야 감시 봇의 범위 검사가 명세 오류가 아닌 실제 범위 이탈만 잡는다.

## ANU 판단 요청 (2건)

1. **#217 머지 승인 여부** — `expected_files` 를 실제 6건으로 정정하면 즉시 머지 가능한 상태다(CI 11/11, 초과분 2건 모두 순수 추가·forbidden 무침범). 명세 정정 후 재위임을 요청한다. 아울러 dev2 메모리에는 #217 이 **머지 HOLD** 및 티눈제거술 판례(2023다241421) 실손 축 제외 건이 **회장 결정 대기**로 기록돼 있어, 이 HOLD 가 해소된 것인지 확인이 필요하다.
2. **#207 후속 위생 작업** — `docs/d4-production-checklist.md:32` 의 Edge Function 목록에 삭제된 3개가 아직 남아 있다. 문서 전용 정리 건이며 이번 범위 밖이라 손대지 않았다.

## 비고

- 자동수정·코드 수정 **0줄**. 명세의 `auto_remediation_policy` 준수.
- 감시 소요: 약 12분 (예산 45분, LOOP_BOUNDARY 미도달).
- 본 작업은 dispatch 경유가 아닌 스케줄 실행이라 dispatch 가 부여한 task_id·타이머 항목이 없다. 고스트 태스크 생성을 피하기 위해 `task-timer.py start` 를 임의 호출하지 않았고, 따라서 대응하는 `end` 도 없다.
