# task-2549 — scripts/ci.sh worktree exclude fix

**레벨**: Lv.2 (normal, single file fix)
**팀**: dev2 오딘
**브랜치**: `task/task-2549-dev2`

---

## 본질 (요약)

매일 9시 자동 실행되는 `scripts/ci.sh`가 5/8 (20분), 5/9 (54분), 5/10 (173분), 5/11 (67분) 동안 stuck. 근본 원인: 1단계 (syntax check)의 `find "$WORKSPACE" -name "*.py"`가 누적된 80개의 `.worktrees/*` 디렉토리를 전체 스캔하여 워크스페이스 내 .py 파일 **442,775개**를 수집 → `py_compile` 루프 시간 폭증.

마지막 성공: 2026-05-02 (24분). 이후 .worktrees 누적으로 매일 점진적으로 악화.

---

## 적용한 fix (단일 파일)

### `scripts/ci.sh` 1단계 find 명령 — vendor 디렉토리 6종 prune

**Before**:
```bash
done < <(find "$WORKSPACE" -name "*.py" -print0 2>/dev/null)
```

**After** (Gemini 리뷰 반영 — `-not -path` → `-prune` 으로 65× 가속):
```bash
done < <(find "$WORKSPACE" \
    \( -path "*/.worktrees" -o -path "*/.venv" -o -path "*/venv" \
       -o -path "*/.codegraph-venv" -o -path "*/node_modules" -o -path "*/.git" \) \
    -prune -o -name "*.py" -print0 2>/dev/null)
```

`-not -path` 는 vendor 디렉토리 트리를 모두 traverse 한 뒤 출력에서만
제외하므로 수십만 파일이 있을 때 여전히 느리다. `-prune` 은 트리 자체를
탐색하지 않아 압도적으로 빠르다 (실측 6.5s → 0.11s).

### 스펙 대비 확장 사유

스펙의 prescribed "After" 코드는 `$WORKSPACE/.../*` (top-level only) 패턴으로 4종 (`.worktrees`, `.venv`, `node_modules`, `.git`) 만 exclude. 실 워크스페이스 확인 결과:

1. `tools/ai-image-gen/jaaz-app/server/venv/` — **중첩** venv (top-level 패턴으로 못 잡음, 이름도 `.venv`가 아니라 `venv`)
2. `scripts/.codegraph-venv/` — 5,243 tracked 파일, pyvenv.cfg 있음 (실질적 venv)

두 디렉토리만으로 ~10,000개의 .py 파일이 스캔되어 5분 타깃 미달. 스펙의 intent ("정상 워크스페이스 .py 파일만 스캔")를 보존하려면 (a) recursive 패턴 (`*/.../*`) + (b) `venv` (dot 없음) + (c) `.codegraph-venv` 추가가 필요. 6종 모두 vendor/non-source 디렉토리로 스펙 list와 본질적으로 동일 부류.

### 효과 (실측)

| 측정 | Before | After (full fix) |
|---|---|---|
| `find` 발견 .py 파일 수 | 442,775 | 1,436 (**308× 감소**) |
| 1단계 (syntax check) 시간 | 173분+ stuck | ~수십 초 (전체 75초 안에 포함) |
| 전체 ci.sh 시간 | timeout | **75초 (1분 15초)** |
| `verdict` | TIMEOUT | **PASS** |

---

## expected_files (3개)

1. **`scripts/ci.sh`** — find 명령에 vendor exclude 6종 추가 (단일 file fix)
2. **`tests/regression/test_ci_sh_worktree_exclude_2549.py`** — 회귀 테스트 14개 (source/behavior/nested 검증)
3. **`memory/reports/task-2549.md`** — 본 보고서

---

## 회귀 테스트 (14개 모두 PASS)

```
$ pytest tests/regression/test_ci_sh_worktree_exclude_2549.py -v
...
============================== 14 passed in 0.24s ==============================
```

내역:
- Source 검증 (8개): ci.sh 존재, `*.py` 패턴 유지, 6종 vendor 패턴 박제 (parametrize), recursive 패턴 사용 검증
- Behavior 검증 (4개): fake workspace 드라이런 — vendor 누설 0, 정상 .py 정확 수집, ≥4× 감소 비율
- Nested 검증 (2개): 중첩 venv / 중첩 node_modules 누설 0

---

## self-test (실 워크스페이스)

명령:
```bash
cd /home/jay/workspace/.worktrees/task-2549-dev2-ci-fix
bash scripts/ci.sh
```

결과 (`memory/logs/ci-latest.json`):
```json
{
  "timestamp": "2026-05-11T02:19:02",
  "duration_seconds": 75,
  "stages": {
    "syntax_check":  {"status": "pass", "detail": "1436 files checked"},
    "pytest":        {"status": "pass", "detail": "..."},
    "coverage":      {"status": "pass", "detail": "coverage: unknown"},
    "pip_audit":     {"status": "pass", "detail": "no vulnerabilities found"},
    "run_tests":     {"status": "pass", "detail": "4 passed, 0 failed"},
    "health_check":  {"status": "pass", "detail": "6 checks passed"},
    "npm_audit":     {"status": "pass", "detail": "no HIGH+ vulnerabilities"}
  },
  "verdict": "PASS",
  "exit_code": 0
}
```

| 지표 | 타깃 | 실측 |
|---|---|---|
| 1단계 syntax check | ≤ 5분 | ~수십 초 (전체 75초 안 포함, py_compile 1436건) |
| 전체 ci.sh | ≤ 30분 | **75초** |
| verdict | PASS | **PASS** |
| 정상 .py 파일 수 | — | **1,436** |

---

## pyright

```
$ pyright tests/regression/test_ci_sh_worktree_exclude_2549.py
0 errors, 0 warnings, 0 informations
```

---

## forbidden paths 준수

- `.worktrees/*` — 변경 없음 (worktree 내부 작업만, 다른 worktree 미접근)
- 다른 `scripts/*` — `scripts/ci.sh`만 수정 (1 file)
- `anu_v2/`, `dispatch/`, `prompts/team_prompts.py` — 변경 없음
- 매일 9시 ci cron — 재등록 없음 (회장 별도 승인 대기)

---

## 후속 작업

1. 본 PR MERGED 후 → 회장 별도 승인 시 매일 9시 ci cron 재등록 (이전 ID `ED57088F` 삭제됨)
2. **task-2550** (worktree 정리): 80개 `.worktrees/*` 디렉토리 정리
3. (선택) `scripts/.codegraph-venv/` 정리: 5,243 tracked venv 파일이 git에 누적된 상태 — 별도 task로 정리 권고 (.gitignore 추가 + git rm -r)
4. (선택) ci.sh 2단계 pytest exit code 검사 로직 보강: 현재 `|| true` 로 exit code가 항상 0 처리되어 pytest 실패가 status에 반영되지 않음 (본 task scope 밖)

---

## 결론

본 task의 **★ 핵심 criterion** "self-test 1단계 5분 이내 + 전체 30분 이내 PASS" 충족:
- 1단계: ✓ (1,436 files, 5분 한참 아래)
- 전체: ✓ (75초, 30분 한참 아래)
- verdict: ✓ PASS

`find` exclude pattern 확장 (top-level → recursive + `venv` + `.codegraph-venv` 추가)으로 442,775 → 1,436 (308× 감소) 달성. 5/8 이후 stuck 패턴 근본 해소.
