PR Preflight โ ๋ณ๊ฒฝ ํจํค์ง ๋ฒ์ 3-๋ ์ด์ด ํ ์คํธ ๊ฒ์ดํธ#
ํ๋ง๋๋ก (๋น๊ฐ๋ฐ์์ฉ)#
์ฝ๋๋ฅผ ํ์ ํฉ์น๊ธฐ ์ , ์ด๋ฒ์ ๋ฐ๋ ๋ถ๋ถ๋ง ๊ณจ๋ผ์ ์๋์ผ๋ก ๊ฒ์ฌํด ์ฃผ๋ "์ถ๊ณ ์ ํ์ง ๊ฒ์ฌ๋"์ ๋๋ค. ๋นํ๊ธฐ๊ฐ ์ด๋ฅ ์ ์ ์ ๊ฒ ๋ชฉ๋ก(pre-flight check)์ ํ์ธํ๋ฏ, ๋ฌธ์ ๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ํฉ์น๋ ์์ ์์ฒด๋ฅผ ๋ง์ ์ค๋๋ค. ๊ฒ์ฌ๋ฅผ ํต๊ณผํด์ผ๋ง ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ ์ ์์ด, ๋ง๊ฐ์ง ์ฝ๋๊ฐ ์ฌ์ฉ ๋ค์ด๊ฐ๋ ๊ฒ์ ์ฌ์ ์ ์ฐจ๋จํฉ๋๋ค.
๋ฌด์์ยท์ธ์ (๋น๊ฐ๋ฐ์์ฉ)#
-
๋ฌด์์ ํด ์ฃผ๋์
- ์ด๋ฒ์ ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ๋๋ํ๊ฒ ๊ณจ๋ผ ๊ฒ์ฌํฉ๋๋ค. ๋ฐ๋์ง ์์ ๊ณณ๊น์ง ์ ๋ถ ๋๋ฆฌ์ง ์์ ์๊ฐ์ ์๋๋๋ค.
- ์ธ ๋จ๊ณ ๊ฒ์ฌ(์์ ๋จ์ โ ํ๋ฉด โ ์ค์ ๋์)๋ฅผ ์์๋๋ก ๋๋ฆฌ๊ณ , ํ๋๋ผ๋ ์คํจํ๋ฉด ์ฆ์ ๋ฉ์ถ๊ณ ๋ณด๊ณ ์๋ฅผ ๋ณด์ฌ ์ค๋๋ค.
- ๊ฒ์ฌ๋ฅผ ๊ฑด๋๋ฐ๋ ค๋ฉด ๋ฐ๋์ ๋ช ์์ ์ผ๋ก ์ฌ์ ๋ฅผ ๋จ๊ฒจ์ผ ํ๋ฉฐ, ๊ธฐ๋ก์ด ๋จ์ ๋์ค์ ํ์ธํ ์ ์์ต๋๋ค.
-
์ธ์ ์๋ํ๋์
- ๋ณ๊ฒฝ ์ฌํญ์ ํ์ ํฉ์น์๊ณ ์์ฒญ(PR)ํ๊ธฐ ์ง์ ์ ์๋์ผ๋ก ์ผ์ง๋๋ค.
- "PR ์ฌ๋ฆฌ๊ธฐ ์ ์ ํ ์คํธ", "pre-flight check", "๋ณ๊ฒฝ ํจํค์ง ํ ์คํธ" ๊ฐ์ ์์ฒญ์ ํ ๋.
- ์๋ ๊ฐ๋ฐ ํ๋ฆ(
/dev:run)์ ๋ง์ง๋ง ์ ๊ฒ ๋จ๊ณ์์๋ ์๋์ผ๋ก ๋ถ๋ ค ์ต๋๋ค.
ํต์ฌ ์ฉ์ด (๋น๊ฐ๋ฐ์์ฉ)#
| ์ฉ์ด | ์ฌ์ด ์ค๋ช |
|---|---|
| PR (Pull Request) | ๋ด๊ฐ ๋ง๋ ๋ณ๊ฒฝ์ ํ์ ๊ณต์ ์ฝ๋์ ํฉ์ณ ๋ฌ๋ผ๊ณ ๋ณด๋ด๋ ์์ฒญ์ |
| Preflight | ์ด๋ฅ ์ ์ ๊ฒ์ฒ๋ผ, PR์ ๋ณด๋ด๊ธฐ ์ง์ ์ ๋ฏธ๋ฆฌ ๋๋ฆฌ๋ ๊ฒ์ฌ |
| Unit ํ ์คํธ | ๊ฐ์ฅ ์์ ๋ถํ ํ๋ํ๋๊ฐ ์ ๋๋ก ๋์ํ๋์ง ๋ณด๋ ๊ฒ์ฌ |
| Widget ํ ์คํธ | ํ๋ฉด์ ๋ณด์ด๋ ์์(๋ฒํผยท๋ชฉ๋ก ๋ฑ)๊ฐ ์ ๊ทธ๋ ค์ง๋์ง ๋ณด๋ ๊ฒ์ฌ |
| Integration ํ ์คํธ | ์ฌ๋ฌ ๋ถ๋ถ์ ์ด์ด ๋ถ์ฌ ์ค์ ์ฌ์ฉ์ฒ๋ผ ๋๊น์ง ๋์๊ฐ๋์ง ๋ณด๋ ๊ฒ์ฌ |
| ํจํค์ง(package) | ๊ธฐ๋ฅ๋ณ๋ก ๋ฌถ์ธ ์ฝ๋ ๊พธ๋ฌ๋ฏธ. ๋ณ๊ฒฝ๋ ๊พธ๋ฌ๋ฏธ๋ง ๊ฒ์ฌ ๋์์ด ๋จ |
| Base ๋ธ๋์น | ๋ด ๋ณ๊ฒฝ์ ํฉ์น ๊ธฐ์ค์ด ๋๋ ์๋ณธ ์ฝ๋ ์ค๊ธฐ |
| Regression | ๋ฉ์ฉกํ๋ ๊ธฐ๋ฅ์ด ์ ๋ณ๊ฒฝ ๋๋ฌธ์ ๋ค์ ๋ง๊ฐ์ง๋ ํ์ |
| CI | ์ฝ๋๊ฐ ํฉ์ณ์ง ๋ ์๋ฒ๊ฐ ์๋์ผ๋ก ์ ์ฒด ๊ฒ์ฌ๋ฅผ ๋๋ ค ์ฃผ๋ ์์คํ |
| Skip | ํน์ ๊ฒ์ฌ๋ฅผ ์๋์ ์ผ๋ก ๊ฑด๋๋ฐ๋ ๊ฒ (์ฌ์ ๊ธฐ๋ก ํ์) |
| hotfix | ์ด์ ์ค์ธ ์๋น์ค์ ๊ธด๊ธ ์ฅ์ ๋ฅผ ๊ธํ ๊ณ ์น๋ ์์ |
| ๊ฒ์ดํธ(gate) | ํต๊ณผํด์ผ๋ง ๋ค์์ผ๋ก ๋์ด๊ฐ ์ ์๋ ๊ด๋ฌธ |
๋ชจ๋ PR ์ ๋ณธ ์คํฌ PASS ์์ด ์์ฑ ๊ธ์ง ์ ๋๋ค.
/pr:preflight์ปค๋งจ๋ ๋๋/dev:runStep 8 ์๋ ํธ์ถ๋ก ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
์ ํ์ํ๊ฐ#
- ์ ์ฒด ๋ ํฌ ํ ์คํธ๋ ๋๋ฆฌ๋ค โ ๋ณ๊ฒฝ ์๋ ํจํค์ง๊น์ง ๋๋ฆฌ๋ฉด ์ ๋ถ ๋ญ๋น
- Regression ์ ์ฆ์ ๋ฐ๊ฒฌ โ PR ์ฌ๋ฆฐ ๋ค CI ์์ ๋ฐ๊ฒฌํ๋ฉด feedback loop ์ด ๊ธธ์ด์ง
- 3 ๋ ์ด์ด ์ผ๊ด ๋ณด์ฅ โ unit ๋ง ๋๋ฆฌ๊ณ widget ์ ๊ฑด๋๋ฐ๋ ๊ฐ๋ฐ์ ์ต๊ด ์ฐจ๋จ
-
์ ์ธ์ ์ ์ฑ
โ ์คํต ์กฐ๊ฑด์ด ๋ช
์์ (
--skip-tests,--skip-integration)์ด์ด์ผ ๊ฐ์ฌ ๊ฐ๋ฅ
ํธ๋ฆฌ๊ฑฐ#
/pr:preflight์ปค๋งจ๋/dev:runStep 8 ์๋ ํธ์ถ/e2e:kick-off์๋ฃ ํ ๋ค์ ๋จ๊ณ ์ ์- ์ฌ์ฉ์ ์์ฒญ: "PR ์ฌ๋ฆฌ๊ธฐ ์ ์ ํ ์คํธ", "pre-flight check", "๋ณ๊ฒฝ ํจํค์ง ํ ์คํธ"
์ ์ #
- ํ๋ก์ ํธ๊ฐ melos ๋ชจ๋ ธ๋ ํฌ (kobic/good-teacher ํ์ค)
- ๊ฐ ํจํค์ง์
pubspec.yaml+ (ํด๋น๋๋ฉด)test/๋๋ ํ ๋ฆฌ flutter_test,bloc_test,mocktail๋ฑ ์์กด์ฑ ์ค์ - BDD dual ์ฌ์ฉ ์
bdd_test_gen์์ฑ๋ฌผ์ด ์ต์ ์ํ (dart run build_runner build)
๋์#
1. Base ๋ธ๋์น ๊ฒฐ์ #
์ฐ์ ์์:
--base์ต์ ๋ช ์ ๊ฐ- ํ์ฌ ๋ธ๋์น์ upstream (
git rev-parse --abbrev-ref '@{u}') development(์กฐ์ง ๊ธฐ๋ณธ base)main(fallback)
2. ๋ณ๊ฒฝ ํจํค์ง ์๋ ๊ฐ์ง#
# 1) ๋ณ๊ฒฝ ํ์ผ ๋ชฉ๋ก
git diff --name-only " $BASE " ..HEAD
# 2) ๊ฐ ํ์ผ ๊ฒฝ๋ก๋ฅผ ์๋ก ์ฌ๋ผ๊ฐ๋ฉฐ pubspec.yaml ์ ๋ง๋๋ ์ฒซ ๋๋ ํ ๋ฆฌ = ํจํค์ง ๋ฃจํธ
# 3) pubspec.yaml ์ name ํ๋ โ melos scope ์ด๋ฆ
์กฐ์ง ๋ชจ๋ ธ๋ ํฌ ๊ฒฝ๋ก ๋งค์นญ ํํธ:
| ๊ฒฝ๋ก ํจํด | ํด์ |
|---|---|
app/{name}/ | ์ฑ ํจํค์ง (integration_test ์คํ ํ๋ณด) |
feature/{type}/{name}/ | feature ํจํค์ง (unit + widget + bdd_test_gen) |
package/{name}/ | ๊ณต์ฉ ํจํค์ง (unit ๋ง ํ์ํ ๊ฒฝ์ฐ ๅค) |
backend/{name}/ | ์๋ฒํ ํจํค์ง (serverpod-test-agent ์์) |
shared/{name}/ | ๊ณต์ ์ค์ โ ํ
์คํธ ๋์์์ ์ ์ธ (๋๋ --include-shared) |
๋ณ๊ฒฝ ์์ โ ์กฐ๊ธฐ ์ข ๋ฃ (PR ์ ์ฝ๋ ๋ณ๊ฒฝ์ด ์๋ค๋ ๋ป, ๊ฒ์ดํธ skip).
3. ๋ ์ด์ด๋ณ ์คํ ๋งคํธ๋ฆญ์ค#
| ๋ ์ด์ด | ๋์ ํ์ผ | ์คํ ๋ช ๋ น | ๋๋ฐ์ด์ค | ๊ธฐ๋ณธ ์คํ ์ฌ๋ถ |
|---|---|---|---|---|
| Unit | test/src/domain/, test/src/data/, test/src/presentation/bloc/ |
melos exec --scope="$SCOPES" --dir-exists=test -- flutter test --exclude-tags=integration
|
โ ๋ถํ์ | โ ํ์ |
| Widget | test/src/presentation/widget/, test/src/bdd/*.widget_test.dart |
flutter test(์์ ํตํฉ) + BDD widget ์๋ ํฌํจ |
โ ๋ถํ์ | โ ํ์ |
| Integration (BDD patrol) | test/src/bdd/*.patrol_test.dart |
patrol test --target=feature/.../*.patrol_test.dart --flavor=staging |
โ ์ค ๋๋ฐ์ด์ค/์๋ฎฌ | โ ๏ธ ์กฐ๊ฑด๋ถ |
| Integration (app E2E) | app/*/integration_test/features/*.feature |
patrol test --target=integration_test/features/<@smoke ์๋๋ฆฌ์ค> |
โ ์ค ๋๋ฐ์ด์ค/์๋ฎฌ | โ ๏ธ ์กฐ๊ฑด๋ถ |
Integration ์กฐ๊ฑด๋ถ ์คํ ๊ท์น:
--with-integrationํ๋๊ทธ โ ๋ณ๊ฒฝ ํจํค์ง์ ๋ชจ๋ integration ์คํ--with-integration=smoke(๊ธฐ๋ณธ) โ@smokeํ๊ทธ ์๋๋ฆฌ์ค๋ง ์คํ- ๋ณ๊ฒฝ ํจํค์ง์
integration_test๋๋*.patrol_test.dart๊ฐ ์์ โ integration skip - ๋๋ฐ์ด์ค ์์ (
flutter devices๊ฒฐ๊ณผ 0) โ integration skip + ๊ฒฝ๊ณ - ์ ๋ integration ์ CI ์ฑ ์ (PR ๋จธ์ง ์ CI ๊ฐ ์คํ)
4. ์คํ ์์#
1. Unit (๋น ๋ฅธ ์คํจ ํ์ง)
โโ FAIL โ ์ฆ์ ์ค๋จ, ๋ ์ด์ด ๊ฒฐ๊ณผ ๋ฆฌํฌํธ, PR ์ฐจ๋จ
โโ PASS โ ๋ค์
2. Widget (BDD widget_test ํฌํจ)
โโ FAIL โ ์ค๋จ, ๋ฆฌํฌํธ, PR ์ฐจ๋จ
โโ PASS โ ๋ค์
3. Integration (์กฐ๊ฑด๋ถ)
โโ SKIP (์กฐ๊ฑด ๋ฏธ์ถฉ์กฑ) โ ๋ค์
โโ FAIL โ ์ค๋จ, ๋ฆฌํฌํธ, PR ์ฐจ๋จ
โโ PASS โ ๋ค์
4. ์ง๊ณ + ๋ฆฌํฌํธ + PR ์งํ ํ์ฉ
5. ์คํ ์ธ๋ถ ๋ช ๋ น ์์#
# ๋ณ๊ฒฝ ํจํค์ง scope ๋ฌธ์์ด ๋น๋
SCOPES= " feature_sign_in,feature_store,kobic "
# Unit + Widget (๋์ผ ๋ช
๋ น์ผ๋ก ์ปค๋ฒ)
melos exec --scope= " $SCOPES " --dir-exists=test -- flutter test \
--coverage --exclude-tags=integration
# BDD dual ์ด๋ฉด build_runner ๊ฐ ์ต์ ์ธ์ง ํ์ธ
melos exec --scope= " $SCOPES " --depends-on= " bdd_test_gen " \
-- dart run build_runner build --delete-conflicting-outputs
# Integration @smoke (์ ํ)
cd app/kobic
patrol test \
--target integration_test/features/smoke.feature \
--flavor staging
6. ์ง๊ณ ๋ฆฌํฌํธ ํฌ๋งท#
๐งช PR Preflight Report (base: development โ feature/1234-sign-in)
๐ฆ ๋ณ๊ฒฝ ํจํค์ง (3)
- feature_common_auth
- feature_application_store
- kobic (app)
๐ฌ Unit
โ
42 passed / 0 failed feature_common_auth
โ
18 passed / 0 failed feature_application_store
โ
5 passed / 0 failed kobic
๐จ Widget
โ
12 passed / 0 failed feature_common_auth (BDD widget_test ํฌํจ)
โ
8 passed / 0 failed feature_application_store
๐ฑ Integration (@smoke)
โ
3 passed / 0 failed kobic / integration_test/features/smoke.feature
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
ALL LAYERS PASSED โ PR ์์ฑ ํ์ฉ
๋ค์ ๋จ๊ณ: gh pr create --base development
์คํจ ์:
โ WIDGET LAYER FAILED
๐ฆ feature_common_auth
โ test/src/bdd/sign_in.widget_test.dart
- " Successful login with valid email " FAILED
expected: K.storeScreen visible
actual: timeout after 5s
๐ซ PR ์์ฑ ์ฐจ๋จ. ์กฐ์น:
1. ์คํจ ์์ธ ํ์ธ: flutter test feature/common/auth/test/src/bdd/sign_in.widget_test.dart --name " Successful login "
2. TestDriver step ๊ฒํ : feature/common/auth/test/src/bdd/step/*.dart
3. ์์ ํ /pr:preflight ์ฌ์คํ
7. Skip ์ ์ฑ (์ฌ์ฉ์ ๋ช ์ ํ์)#
| ์ต์ | ํ์ฉ ์กฐ๊ฑด | ๊ฐ์ฌ ๊ธฐ๋ก |
|---|---|---|
--skip-unit | ์์ โ ํญ์ ๊ฑฐ๋ถ | โ |
--skip-widget | ์์ โ ํญ์ ๊ฑฐ๋ถ | โ |
--skip-integration | ๊ธฐ๋ณธ๊ฐ (๋ก์ปฌ ์ฑ๋ฅ) | ์ ์ |
--skip-all |
hotfix ์ ์ฉ + ๋ช ์ ์ฌ์ ํ์ | .claude/preflight-skip.log ์ ๊ธฐ๋ก |
--skip-all ํ์ฉ ์กฐ๊ฑด:
- Urgent hotfix (ํ๋ก๋์ ์ฅ์ ๋์)
- ์ปค๋ฐ ๋ฉ์์ง์
hotfix:๋๋fix!:์ ๋์ฌ - ์ฌ์ฉ์๊ฐ ํ๋กฌํํธ์ ์ด์ ๋ช ์
๊ฐ์ฌ ๋ก๊ทธ ํ์:
[2026-04-23T12:34:56Z] user=dongwoo branch=hotfix/payment-crash
reason= " ํ๋ก๋์
๊ฒฐ์ ํฌ๋์ ์๊ธ ํจ์น, CI ์์ ์ ๋ ๊ฒ์ฆ "
8. lefthook ํตํฉ (์ ํ)#
ํ๋ก์ ํธ lefthook.yml ์ pre-push ์ ์์ wrapper ์ถ๊ฐ ๊ถ์ฅ:
pre-push:
parallel: false
commands:
preflight-unit:
tags: test
run: |
# ๋ณ๊ฒฝ ํจํค์ง์ unit/widget ๋ง ๋น ๋ฅด๊ฒ
# --skip-integration ๋ default
claude-code-cli run /pr:preflight --from-hook || exit 1
์ฃผ์: integration ์ hook ์ ๋์ง ๋ง ๊ฒ (push ์๋ ์ ํ). /pr:preflight ๋ก ๊ฐ๋ฐ์๊ฐ ๋ช
์ ์คํ.
9. CI ์ฐ๊ณ#
CI ๋ preflight ์ ๋ณ๋๋ก ์ ๋ ํ ์คํธ ๋ฅผ ์คํ:
- PR ๋งคํธ๋ฆญ์ค: ๋ณ๊ฒฝ ํจํค์ง์ unit + widget + ์ ์ฒด integration
- Nightly: ์ ์ฒด ๋ ํฌ unit + widget + integration
.claude/preflight-skip.log๊ฐ์ง ์ CI ๊ฐ ๊ฐํ ๊ฒ์ดํธ๋ก ๋์
์ถ๋ ฅ#
- ์คํ ๋ฆฌํฌํธ (stdout)
.claude/preflight-report-{timestamp}.json(์ ํ,--save-report).claude/preflight-skip.log(skip ์๋ง)- ์คํจ ์ exit code โ 0 (์๋ํ ์ฐ๊ณ์ฉ)
๊ธ์ง ์ฌํญ#
- โ
--skip-unit/--skip-widget์ ์ ์ฑ ๋ณ๊ฒฝ ์์ด ํ์ฉ - โ base ๋ธ๋์น ๊ฐ์ง ์คํจ ์ ๋ก์ปฌ ์ ์ฒด ๋ธ๋์น๋ก fallback (์๋ชป๋ diff)
- โ ๋ณ๊ฒฝ ์๋ ํจํค์ง๋ฅผ scope ์ ํฌํจ (์ ์ฒด ํ ์คํธ ์คํ)
- โ ๋๋ฐ์ด์ค ์์ ์ํ์์ integration ์ ๊ฐ์ ์คํํ์ฌ false positive ์์ฑ
-
โ ์๋ ์์ฑ ํ์ผ(
.g.dart,.freezed.dart,.widget_test.dart,.patrol_test.dart) ์ ์ํ ๋ณ๊ฒฝ์ "๋ณ๊ฒฝ ํจํค์ง" ๋ก ์ค์ธ โ ์ด๋ค์ source ๋ณ๊ฒฝ์ ๋ฐ๋ผ๊ฐ ๊ฒฐ๊ณผ์ด๋ฏ๋ก ์์ฒ ์์ค ํจํค์ง ๊ธฐ์ค์ผ๋ก ๋งค์นญ
์๋ ์์ฑ ํ์ผ ํํฐ#
๋ณ๊ฒฝ ํ์ผ ๋ชฉ๋ก์์ ๋ค์์ ํจํค์ง scope ํ์ ์ ๋ถ์์ ์ผ๋ก๋ง ๋ฐ์:
-
**/*.g.dart,**/*.freezed.dart,**/*.gr.dart,**/*.config.dart,**/*.gen.dart,**/*.mocks.dart **/*.widget_test.dart,**/*.patrol_test.dart(bdd_test_gen ์ฐ์ถ๋ฌผ)
์ด๋ค์ด ์ ์ผํ ๋ณ๊ฒฝ์ด๋ฉด scope ์ถ๊ฐํ์ง ์์ (์ฝ๋ ์์ฑ ์ฌ์คํ์ผ ๊ฐ๋ฅ์ฑ).
๋ค๋ฅธ ์คํฌ/์์ด์ ํธ์์ ๊ด๊ณ#
| ํญ๋ชฉ | ๊ด๊ณ |
|---|---|
cc-uiux:unit-testing | Unit ๋ ์ด์ด ์์ (ํ ์คํธ ๋ด์ฉ ํ์ค) |
cc-uiux:widget-testing | Widget ๋ ์ด์ด ์์ |
cc-uiux:bdd-testing | BDD dual ์์ฑ๋ฌผ ํฌํจ ์คํ |
cc-uiux:integration-testing | Patrol integration ์คํ ๋ช ๋ น |
cc-flutter-dev:test (์์ด์ ํธ) | ์คํจ ์ ์์ ์์ ์์ |
cc-e2e-authoring:feature-test-bundle | kick-off ํ preflight ์ฐ๊ณ |
cc-e2e-authoring:scenario-lock | lock ๋์ ์๋๋ฆฌ์ค๋ preflight ์ ๋ฐ๋์ ํฌํจ |
cc-dev-cycle:dev:run | Step 8 ์์ ๋ณธ ์คํฌ ์๋ ํธ์ถ |
์คํจ ์ผ์ด์ค#
| ์์ธ | ๋์ |
|---|---|
| melos ์์ | flutter test + ๋๋ ํ ๋ฆฌ ์ค์บ ํด๋ฐฑ |
bdd_test_gen ์์ฑ๋ฌผ ๋๋ฝ |
dart run build_runner build ์๋ ์คํ ํ ์ฌ์๋ |
| Integration ๋๋ฐ์ด์ค ์์ | skip + ๊ฒฝ๊ณ , CI ์ฑ ์์ผ๋ก ์ด๊ด |
๋ณ๊ฒฝ ํ์ผ ์ค .gitignore ๋ ๊ฒฝ๋ก | skip (๋ ธ์ด์ฆ ์ ๊ฑฐ) |
์ ์ฒด ํ
์คํธ ์คํ ์์ฒญ (--full) | ํ์ฉํ๋ ๋ฆฌํฌํธ์ "Full scope" ๋ช ์ |
์ฐธ๊ณ #
- ์ ์ฑ
:
rules/pr-preflight-policy.md - ์ปค๋งจ๋:
commands/pr/preflight.md - ๊ธฐ์กด
/dev:runStep 8 ์ test-runner-agent ๋ ๋ณธ ์คํฌ ๋ด๋ถ์์ ํธ์ถ๋จ