LogoSkills

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

1. **모든 PR 은 `/pr:preflight` PASS 필수** — 자동(`/dev:run`) 또는 수동 실행

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

1. 원칙#

  1. 모든 PR 은 /pr:preflight PASS 필수 — 자동(/dev:run) 또는 수동 실행
  2. Unit + Widget 레이어는 항상 실행 — skip 금지
  3. Integration 레이어는 조건부 실행 가능
    • 로컬: @smoke 또는 명시 요청
    • CI: 전량
  4. 변경된 패키지만 대상 — 전체 레포 강제 실행 금지 (속도 저하)
  5. Skip 사용은 감사 기록.claude/preflight-skip.log

2. 레이어별 실행 정책#

레이어로컬CISkip 정책
Unit✅ 필수✅ 전량절대 불가
Widget✅ 필수✅ 전량절대 불가
Integration (@smoke) ⚠️ 권장 (디바이스 있을 때) ✅ 필수 디바이스 없음 시 자동 skip
Integration (full) ⚠️ 선택 (--with-integration=full) ✅ 필수 로컬 skip 허용

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

포함 대상#

  • feature/*/ — feature 모듈
  • app/*/ — 앱 패키지
  • package/*/ — 공용 패키지 (단, 테스트 파일 있을 때만)
  • backend/*/ — 서버팟 패키지 (serverpod-test-agent 위임 범위)

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

  • **/*.g.dart, **/*.freezed.dart, **/*.gr.dart, **/*.config.dart, **/*.gen.dart, **/*.mocks.dart
  • **/*.widget_test.dart, **/*.patrol_test.dart (bdd_test_gen 산출물)

제외 대상#

  • 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-allhotfix 전용, 다음 조건 모두 만족
    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. /dev:run 과의 통합#

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

Step 8: 테스트 작성 및 검증 (필수 게이트) ⚠️
  ├── [테스트 코드 작성]  ← cc-flutter-dev:test 에이전트
  ├── [PR Preflight 실행]/pr:preflight --auto-scope
  │     ├── Unit (변경 패키지)
  │     ├── Widget (변경 패키지)
  │     └── Integration @smoke (조건부)
  └── ⚠️ 실패 시 Step 9 (PR 생성) 진행 불가

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

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

프로젝트 lefthook.ymlpre-push 에 권장 블록:

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

    # 추가: preflight (unit + widget 만 — integration 은 /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 가 있으면 /pr:preflight, 없으면 melos 직접
        if command -v claude-code-cli  > /dev/null; then
          claude-code-cli run /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 속도 저하). 개발자가 /pr:preflight --with-integration 명시 실행.

7. CI 연계#

CI 워크플로우 요구사항:

  1. PR 트리거 시 전량 unit + widget + integration 실행 (변경 패키지 한정 아님 — 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]
jobs:
  unit-widget:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: melos bootstrap
      - run: melos run test
  integration-smoke:
    runs-on: macos-latest
    steps:
      # Patrol 시뮬레이터 실행

8. 실패 시 조치#

Unit FAIL#

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

Widget FAIL (BDD widget_test 포함)#

  1. bdd_test_gen 최신 확인: dart run build_runner build --delete-conflicting-outputs
  2. TestDriver step 검토: K 상수 적용 여부
  3. Mock 설정 재검토

Integration FAIL (Patrol)#

  1. patrol develop + patrol_mcp run/screenshot/native-tree 로 원인 분석
  2. cc-e2e-authoring:step-implement 재진입
  3. staging 서버 상태 확인 (네트워크/데이터 의존)

9. 금지 사항#

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

10. 관련 문서#

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