# task-2348 — finish-task.sh + qc_verify.py 무한 루프 구조 개선

- 작업 ID: task-2348
- 팀: dev7-team (이참나 팀장)
- 작업 레벨: Lv.2 (인프라 안정성)
- 프로젝트: 시스템 작업 (workspace 자체)
- 작업일: 2026-05-02

## SCQA

### S(상황)
2026-05-02 task-2344(dev1) + task-2345(dev5) 연속 escalate. 보고서에 "## 세션 통계" 섹션이 각각 11개씩 누적되어 있고, finish-task.sh가 9~13회 retry 후 .escalate. 운영물은 완료됐는데 .done이 안 만들어져 task가 영구 escalate.

### C(복잡 요인)
1. **세션 통계 누적**: 코드에 자동 추가 로직은 없으나 봇(LLM)이 retry마다 보고서 끝에 "## 세션 통계" 섹션을 매번 추가 → workspace의 `memory/reports/`가 unstaged 상태가 되어 git_evidence FAIL → 봇이 다시 commit → 또 추가의 무한 루프.
2. **git_evidence 워크트리 외부 검사**: `_find_project_root(workspace_root)`가 `cwd=/home/jay/workspace`에서 `git rev-parse --show-toplevel`을 실행 → workspace를 git root로 반환. 워크트리(`/home/jay/projects/InsuRo/.worktrees/...`)에서 작업해도 workspace 검사. 봇이 우회로 workspace에 보고서 commit하는 hack 발생.
3. **디자인 QC 가드 false positive**: finish-task.sh 0번/0b번 단계가 본문 키워드(`디자인|배너|이미지|...`) 한 번만 매칭. UI 코드 작업 본문에 "이미지" 단어 우연 포함 시 발동. SKIP_LOKI_CHECK=1 우회 시 retry 카운트만 증가.
4. **retry escalate 조건 부족**: task 단위 3회 retry로 escalate하지만, 같은 verifier가 매번 같은 사유로 FAIL하는 헛수고에는 무방비.

### Q(질문)
세션 통계 정리, 워크트리 인식, 디자인 가드 강화, 같은 사유 즉시 escalate를 모두 적용하여 escalate 사이클을 끊을 수 있는가?

### A(답변)
4가지 수정안 모두 적용. 12개 pytest + 3개 L1 통합 시나리오 통과.
- (A) finish-task.sh가 보고서 진입 시 "## 세션 통계" 섹션이 2개 이상이면 마지막 1개만 남기고 모두 제거 (idempotent).
- (B) git_evidence가 환경변수(`PROJECT_PATH`/`WORKTREE_PATH`) → task-timers.json `worktree_path` → task 파일 "워크트리 경로:" → workspace 폴백 순서로 프로젝트 디렉토리 자동 탐지.
- (C) 디자인 작업 판별을 (1) affected_files에 이미지/에셋 패턴, (2) 명시적 `## 디자인 작업: yes` 또는 `design_task: true` 플래그, (3) 본문 키워드 AND 제목에도 디자인 키워드 — 셋 중 하나 충족 시에만 발동으로 강화.
- (D) qc_verify.py가 `{task_id}.fail_history.jsonl`에 매 FAIL의 verifier 이름 조합을 기록, 같은 조합이 3회 등장하면 task 단위 retry_count와 무관하게 즉시 escalate.

## 수정 파일 목록

### 인프라 (쿠쿨칸 — 백엔드)
| 파일 | 변경 | 커밋 |
| --- | --- | --- |
| `scripts/finish-task.sh` | "## 세션 통계" idempotent 정리 함수 추가 (Step 0 직전) | 296abbaf |
| `scripts/finish-task.sh` | IS_DESIGN_TASK 변수 도입, 0번/0b번 단계의 키워드 매칭을 강화된 3중 조건으로 교체 | af5e76b3 |
| `scripts/finish-task.sh` | PROJECT_PATH가 빈 값일 때 task-timers.json `worktree_path` 자동 인식 | 63a4cdaf |

### QC 검증 (카마소츠 — 테스터)
| 파일 | 변경 | 커밋 |
| --- | --- | --- |
| `teams/shared/verifiers/git_evidence.py` | `_resolve_project_dir()` 추가 (env→timers.json→task파일→폴백) | eedc3222 |
| `teams/shared/qc_verify.py` | `_get_failed_check_history`/`_record_failed_checks` 추가, `_handle_gate` FAIL 분기에 동일 verifier 3회 즉시 escalate | d5811924 |
| `teams/dev7/qc/tests/test_finish_loop_fix.py` | 5회 시뮬레이션 + 12개 pytest 신규 작성 | d07d65c2, 29ee4fc5 |

> `teams/dev*/qc/qc_verify.py`는 모두 `teams/shared/qc_verify.py` 심볼릭 링크 → 한 곳만 수정해도 8팀 전체 적용.

## 모델 사용 기록
- 이참나(팀장): claude-opus-4-7 (1M context) — 진단/분배/검증/통합
- 쿠쿨칸(백엔드): sonnet — MT-1~3 (finish-task.sh)
- 카마소츠(테스터): sonnet — MT-1~4 (verifiers + pytest)
- haiku 사용 없음
- 인프라 파일 수정으로 정확도가 중요해 sonnet 이상 사용

## 발견 이슈 및 해결

| # | 이슈 | 해결/조치 |
| --- | --- | --- |
| 1 | task-2344/2345 보고서에 "## 세션 통계" 11개 누적 (이미 발생한 데이터) | 신규 finish-task.sh 적용 후 자동 정리됨. 과거 보고서는 이미 escalate 처리되어 별도 정리 불필요 |
| 2 | dev1~dev8 qc_verify.py 동기화 필요 → 모두 `teams/shared/qc_verify.py` 심볼릭 링크임을 확인 | cp 동기화 불필요. 단일 위치 수정으로 자동 반영 |
| 3 | pytest test 파일에 미사용 변수 (`importlib`, `history_file`, `result`) | 팀장 직접 정리 후 commit (29ee4fc5) |
| 4 | Pyright `verifiers`/`qc_verify` import 미해결 경고 | sys.path 동적 추가 패턴의 정적 분석 한계. 런타임 동작 정상(pytest 통과) |

## L1 스모크테스트 결과

- **서버 재시작**: 해당없음 (인프라 스크립트 수정, 서버 미관여)
- **API 응답 확인**: 해당없음
- **스크린샷**: 해당없음 (CLI 인프라 작업)

### 통합 시나리오 검증
1. **세션 통계 idempotent**: task-2344 보고서(11개 ## 세션 통계) 임시 복사본을 정리 함수에 통과 → 1개만 잔존. **PASS**
2. **디자인 QC 가드 false positive 방어**:
   - 비-디자인 task (본문에 "이미지" 단어만, 제목 fix) → IS_DESIGN_TASK=0 ✅
   - 디자인 task (affected_files에 .png, .jpg) → IS_DESIGN_TASK=1 ✅
   - **PASS**
3. **git_evidence PROJECT_PATH 인식**: 환경변수 설정 후 `_resolve_project_dir` 호출 → 환경변수 경로 반환. **PASS**
4. **자기 참조 안전성**: task-2348 자체에 대해 IS_DESIGN_TASK=0 확인 (제목·affected_files에 디자인 키워드 없음). **PASS**

### pytest 결과
```
============== 12 passed in 0.13s ==============
teams/dev7/qc/tests/test_finish_loop_fix.py
- test_env_var_project_path_takes_priority
- test_env_var_worktree_path_takes_priority
- test_task_timers_json_fallback
- test_task_file_fallback
- test_workspace_fallback
- test_same_verifier_3_times_escalate
- test_5_simulations_escalate_at_3rd[1..5]
- test_git_evidence_uses_env_project_path
```

### bash 문법 검증
- `bash -n /home/jay/workspace/scripts/finish-task.sh` → syntax OK

## 검증 시나리오 결과 (task 문서 기준)
1. ✅ **세션 통계 idempotent**: 5회 연속 적용 → 1개만 존재 (정리 함수 단위 테스트)
2. ✅ **워크트리 인식**: PROJECT_PATH 환경변수 + 실제 .git 디렉토리 → 그 경로 반환
3. ✅ **escalate 조건**: 같은 verifier 3회 FAIL → 3번째에 즉시 escalate (5회 시뮬레이션 모두 정상)
4. ✅ **디자인 QC false positive**: 본문 키워드만 있고 제목/affected_files에 없는 task → IS_DESIGN_TASK=0

## 머지 판단
- **머지 필요**: 시스템 작업 (workspace main 브랜치 직접 작업, worktree 미사용)
- **브랜치**: main (직접 작업)
- **워크트리 경로**: 해당없음
- **머지 의견**:
  - 변경은 모두 추가 동작(idempotent 정리, 강화된 가드, escalate 보강)이며 기존 통과 경로는 유지. 회귀 위험 낮음.
  - 8팀 모두 동일 심볼릭 링크 → 자동 반영. 별도 동기화 불필요.
  - task-2348 자체에도 IS_DESIGN_TASK=0이 적용되어 자기 참조 안전성 확보.

## 향후 재발 방지 모니터링 방안
1. **세션 통계 누적 모니터링**: `find memory/reports -name "*.md" -exec grep -c "^## 세션 통계" {} +` 정기 점검. 2개 이상 검출 시 finish-task.sh가 미실행된 것
2. **fail_history.jsonl 모니터링**: `memory/logs/retry-counters/*.fail_history.jsonl`에 동일 verifier 3회 기록되면 즉시 escalate. 대시보드에 카운터 추가 권장
3. **워크트리 경로 검증 로그**: git_evidence가 어느 경로를 검사했는지 details에 기록하므로, FAIL 시 경로 mismatch 즉시 진단 가능
4. **디자인 가드 회귀 방지**: pytest에 IS_DESIGN_TASK 단위 테스트 추가 권장 (현재 이 task에서는 통합 시뮬레이션으로 검증)
