문서 목차
이 페이지에서목차

PR Preflight Policy — 사전 테스트 게이트 정책

기능 작업의 작성·소유·등재·증거 정본은

모든 PR 은 변경된 패키지 범위에서 unit + widget + integration 테스트가 PASS 한 뒤에만 생성될 수 있다. 이 문서는 구속력 있는 정책 이며, 스킬/커맨드/훅이 모두 이를 준수한다.

1. 원칙#

기능 작업의 작성·소유·등재·증거 정본은 feature-verification이다. 모든 UI feature는 unit, widget, golden, Widgetbook, BDD 5종을 작성·배선한다. 일반 테스트 PASS만으로 나머지를 통과시키지 않고 변경 기능과 관련 조립에 대해 golden compare·gallery 입력, 카탈로그 생성/렌더·Knob, AC↔BDD 모드별 실행을 확인한다. UI 없는 역할의 N/A는 근거를 기록한다. 승인된 skip는 DEFERRED이며 완료/PASS가 아니다.

  1. 모든 PR 은 /cc-dev:pr:preflight PASS 필수 — 자동(/cc-dev:run) 또는 수동 실행
  2. Unit + 적용 가능한 Widget 레이어는 항상 실행 — skip 금지. 순수 headless 역할의 UI N/A는 소스 근거로 판정하며 --skip-widget 면제와 구분한다.
  3. Integration 레이어는 조건부 실행 가능
    • 로컬: @smoke 또는 명시 요청
    • CI: 전량
  4. 변경된 패키지만 대상 — 전체 레포 강제 실행 금지 (속도 저하)
  5. Skip 사용은 감사 기록 — .claude/preflight-skip.log

2. 레이어별 실행 정책#

레이어로컬CISkip 정책
Unit✅ 필수✅ 전량절대 불가
Widget✅ 필수✅ 전량절대 불가
Golden capture·같은 OS의 compare 또는 명시적 CI 대기 동일 Linux 이미지 compare 필수 capture/skip를 compare PASS로 보고 금지
Widgetbook 기능 등록·생성·렌더/Knob smoke 조립·렌더·웹 빌드 및 등록 대조 카탈로그 앱 존재만으로 feature 등재 판정 금지
BDD 실제 co_bdd 위젯/legacy 러너·step/assertion 검사 선언된 실행 대상 필수 디바이스 부재는 BLOCKED/CI 대기, 작성은 필수
Integration (@smoke) ⚠️ 권장 (디바이스 있을 때) ✅ 필수 디바이스 없음 시 자동 skip
Integration (full) ⚠️ 선택 (--with-integration=full) ✅ 필수 로컬 skip 허용

3. 변경 패키지 감지 규칙#

포함 대상#

  • feature/*/ — feature 모듈
  • app/*/ — 앱 패키지
  • package/*/ — 공용 패키지 (단, 테스트 파일 있을 때만)
  • backend/*/ — 서버팟 패키지 (serverpod-test-agent 위임 범위)
  • 기능 test/src/golden·test/src/bdd·독립 widgetbook/ 패키지와 역의존 gallery/catalog 조립

부수 변경 (단독이면 scope 미추가)#

  • **/*.g.dart, **/*.freezed.dart, **/*.gr.dart, **/*.config.dart, **/*.gen.dart, **/*.mocks.dart

⛔ **/*.patrol_test.dart 는 이 목록에서 빠졌습니다. 코드 생성기가 없으므로 이제 손으로 쓴 테스트 소스입니다 — 다른 실제 소스 변경과 똑같이 scope 에 포함해야 합니다. 자동 생성물 취급하면 scenarios/*_test.dart 만 바뀐 PR 이 Integration 레이어를 건너뛰게 됩니다.

제외 대상#

  • shared/*/ 중 순수 설정 — --include-shared 없으면 제외
  • docs/, *.md, .github/, .claude/, .cursor/, README.md, CHANGELOG.md
  • i18n/*.json (언어 리소스만 변경 시 테스트 불필요, 다만 .dart 생성물 변경 시는 포함)

4. Skip 예외 규정#

정책상 거부 옵션#

  • --skip-unit → 항상 거부 (exit code 2)
  • --skip-widget → 항상 거부 (exit code 2)

조건부 허용#

  • --skip-integration → 로컬 기본값 (감사 기록 불필요)
  • --skip-all → hotfix 전용, 다음 조건 모두 만족
    1. --reason 사유 명시
    2. 커밋 메시지에 hotfix:, fix!:, revert: 접두사 중 하나
    3. 감사 로그 기록

감사 로그 포맷 (.claude/preflight-skip.log)#

2026-04-23T12:34:56Z | user=dongwoo | branch=hotfix/payment-crash | base=development | skip=all | reason="프로덕션 결제 크래시 응급 패치"
  • 이 파일은 커밋 대상 (감사 추적)
  • CI 가 파일 존재 시 강한 게이트로 대체 실행 (전량 unit + widget + integration)

5. /cc-dev:run 과의 통합#

/cc-dev:run 의 Step 8 (테스트 작성 및 검증) 은 본 정책의 구현체:

Step 8: 테스트 작성 및 검증 (필수 게이트) ⚠️
  ├── [테스트 코드 작성]  ← cc-flutter:test 에이전트
  ├── [PR Preflight 실행]  ← /cc-dev:pr:preflight --auto-scope
  │     ├── Unit (변경 패키지)
  │     ├── Widget (변경 패키지)
   │     ├── Golden compare·gallery 수집 증거
   │     ├── Widgetbook 생성·등록·렌더/Knob
   │     ├── BDD 모드별 실제 실행/단언
   │     └── Integration @smoke (조건부; 미실행 상태 별도)
  └── ⚠️ 실패 시 Step 9 (PR 생성) 진행 불가

/cc-dev:run --skip-tests 는 본 정책의 --skip-all 과 동일하게 취급 (사유 필수).

6. lefthook 훅 통합 (프로젝트 레포)#

프로젝트 lefthook.yml 의 pre-push 에 권장 블록:

pre-push:
  parallel: false
  commands:
    # 기존: format-check, analyze

    # 추가: preflight (unit + widget 만 — integration 은 /cc-dev:pr:preflight 로 수동)
    preflight-fast:
      tags: test
      run: |
        if [ "$LEFTHOOK_SKIP_PREFLIGHT" = "1" ]; then
          echo "⚠️  LEFTHOOK_SKIP_PREFLIGHT=1 감지 — preflight 건너뜀"
          exit 0
        fi
        # 환경에 claude-code-cli 가 있으면 /cc-dev:pr:preflight, 없으면 melos 직접
        if command -v claude-code-cli >/dev/null; then
          claude-code-cli run /cc-dev:pr:preflight --from-hook --skip-integration
        else
          # 폴백
          BASE=$(git rev-parse --abbrev-ref '@{u}' 2>/dev/null | sed 's|.*/||')
          BASE=${BASE:-development}
          CHANGED=$(git diff --name-only "$BASE"..HEAD | grep -E '^(feature|app|package|backend)/' | cut -d/ -f1-3 | sort -u)
          if [ -n "$CHANGED" ]; then
            # pubspec.yaml name 추출 후 melos scope 실행
            melos run test --scope="..."
          fi
        fi

주의: integration 은 hook 에 두지 않음 (push 속도 저하). 개발자가 /cc-dev:pr:preflight --with-integration 명시 실행.

7. CI 연계#

CI 워크플로우 요구사항:

  1. 준비 완료 PR(초안 아님) 트리거 시 전량 unit + widget + integration 실행 (변경 패키지 한정 아님 — CI 는 방어선). 초안 PR 은 가벼운 층(포맷 · 분석 · 변경 패키지 단위)만 돈다 — 로컬 preflight 가 이미 같은 범위를 돌았다. 같은 git 트리를 이미 검증한 기록이 있으면(머지 뒤 push · 승격 PR) 다시 돌지 않는다 (ci-receipts — 검증 기록 · 2층 CI)
  2. .claude/preflight-skip.log 최근 엔트리 감지 시 강한 게이트:
    • 전체 레포 unit + widget + integration 실행
    • 실패 시 머지 차단
  3. Nightly 는 skip 로그 · 검증 기록을 무시하고 전량 실행(트리 밖 입력의 드리프트를 잡는다)

예시 .github/workflows/preflight-gate.yml:

name: preflight-gate
on:
  pull_request:
    branches: [development, main]
    # 초안 → 준비 완료(ready_for_review) 때 무거운 층이 돈다. types 를 적으면 기본 셋이 사라지므로 함께 적는다
    types: [opened, synchronize, reopened, ready_for_review]
jobs:
  unit-widget:
    # 초안에서는 로컬 preflight 가 같은 범위를 이미 돌았다 — 준비 완료부터 전량
    if: ${{ !github.event.pull_request.draft }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: melos bootstrap
      - run: melos run test
  integration-smoke:
    if: ${{ !github.event.pull_request.draft }}
    runs-on: macos-latest
    steps:
      # Patrol 시뮬레이터 실행

8. 실패 시 조치#

Unit FAIL#

  1. flutter test <실패 파일> 재실행
  2. cc-flutter:test 에이전트 위임
  3. 수정 → 재커밋 → /cc-dev:pr:preflight 재실행

Widget FAIL#

  1. flutter test <실패 파일> 재실행
  2. Mock 설정 재검토
  3. cc-flutter:test 에이전트 위임

Integration FAIL (Patrol)#

  1. scenarios/*_test.dart 는 손으로 쓴 파일이다 — 코드 생성기가 없으므로 .feature 를 고쳤으면 scenarios/*_test.dart 도 직접 고쳤는지 먼저 확인(dart analyze 로 step 이름 불일치 검출)
  2. patrol develop + patrol_mcp run/screenshot/native-tree 로 원인 분석
  3. TestDriver step 검토: K 상수 적용 여부 (BDD 는 PatrolTestDriver 로만 실행)
  4. cc-e2e:step-implement 재진입
  5. staging 서버 상태 확인 (네트워크/데이터 의존)

9. 금지 사항#

  • ❌ Unit/Widget skip 허용
  • ❌ 전체 레포 전량 실행 기본화 (--full 은 명시 요청 시만)
  • ❌ 감사 로그(preflight-skip.log)를 .gitignore
  • ❌ hook 안에서 integration 자동 실행 (push 속도 저하)
  • ❌ 변경 없는 패키지를 scope 에 포함

10. 관련 문서#

  • 스킬 본체: cc-dev/skills/pr/SKILL.md
  • 커맨드: cc-dev/commands/pr/preflight.md
  • 개발 사이클: cc-dev/commands/run.md (Step 8)
  • E2E 저작: cc-e2e/skills/feature-test-bundle, scenario-lock
  • 테스트 표준:
    • cc-flutter/skills/unit-testing/SKILL.md
    • cc-flutter/skills/widget-testing/SKILL.md
    • cc-flutter/skills/bdd-testing/SKILL.md
    • cc-flutter/skills/integration-testing/SKILL.md
    • cc-flutter/rules/bdd-test-patterns.md

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기