# task-2149: ci_preflight.sh 신규 생성 — 멀티 러너 CI 게이트

## ★ 프로젝트: `/home/jay/workspace/`

## 3문서 참조 (필독)
- 프로젝트 계획서: `/home/jay/workspace/memory/plans/system/dispatch-quality-gates/plan.md` — 컴포넌트 2번
- 미팅 기록: `/home/jay/workspace/memory/meetings/2026-04-24-dispatch-quality-automation.md` (Cycle 2 비슈누/엔키 의견)

## 문제
finish-task.sh의 test_runner가 `--check-files` 기반 부분 테스트만 실행하여, 한 스택(pytest)은 통과해도 다른 스택(tsc/vitest)에서 실패하는 연쇄 이슈를 사전 감지 못함.
실제 사례: task-2143(Vitest supabaseUrl) → task-2144(pytest doc_parser) 연쇄 발생.

## 구현

### 파일: `/home/jay/workspace/scripts/ci_preflight.sh` (신규, ~80줄)

#### CLI
```bash
bash ci_preflight.sh <project_root> [--affected-only <commit_count>]
```

#### 로직
1. 프로젝트 루트에서 tech stack 자동 감지:
   - `pyproject.toml` OR `setup.py` OR `requirements.txt` → pytest
   - `tsconfig.json` → tsc --noEmit
   - `vitest.config.*` → vitest run
   - `jest.config.*` → jest --ci
2. 감지된 스택 순차 실행 (각 runner timeout 120초)
3. --affected-only: git diff → test_X.py / X.test.ts / X.spec.ts 패턴 매칭
4. 결과 수집 + 출력

#### 출력
```
[CI-PREFLIGHT] runner=pytest exit=0 time=12s
[CI-PREFLIGHT] runner=tsc exit=0 time=45s
[CI-PREFLIGHT] runner=vitest exit=1 time=30s
[CI-PREFLIGHT] overall=FAIL
```
- exit code: 0=전체 PASS, 1=하나 이상 FAIL
- 타임아웃: exit 0 + `[CI-PREFLIGHT] runner=tsc exit=TIMEOUT time=120s` + `overall=WARN`

## ★ 먼저 읽을 파일
- `/home/jay/workspace/scripts/finish-task.sh` — 기존 test_runner 호출 방식 참조
- `/home/jay/workspace/scripts/` — 기존 스크립트 구조

## 검증 시나리오

### 시나리오 1: 멀티 스택 프로젝트
InsuRo(pytest + tsc + vitest) → 3개 러너 순차 실행 → 전체 PASS/FAIL

### 시나리오 2: Python 전용 프로젝트
workspace(pytest만) → pytest만 실행 → PASS/FAIL

### 시나리오 3: 타임아웃
tsc가 120초 초과 → TIMEOUT 표시 + overall=WARN (FAIL 아님)

### 시나리오 4: --affected-only
commit 2건 → git diff → test_feature_gate.py만 실행

### 시나리오 5: tech stack 없는 프로젝트
감지된 러너 0개 → overall=PASS (테스트 대상 없음)

## 완료 시그니처
- 4개 tech stack 감지 동작
- 러너당 120초 타임아웃 동작
- --affected-only 모드 동작
- 단위 테스트 3건+ PASS
- exit code 0/1 정상

## 레벨
- critical

## 프로젝트
- dev-system
