test-runner-agent — 테스트 자동 검사관#
| 항목 | 내용 |
|---|---|
| 모델 | sonnet |
한마디로#
새 기능을 PR로 올리기 전에 "이거 진짜 잘 돌아가나?" 자동으로 점검해 주는 품질 검사관입니다. 공장에서 제품을 출하하기 전 마지막 검수대를 통과시키는 것과 같아요. 검수를 통과하지 못하면 출하(PR 생성)를 막습니다.
누가·언제 쓰나요#
- 새 기능 개발을 마치고 PR(코드 병합 요청)을 올리기 직전, 자동 개발 흐름이 이 검사관을 호출합니다.
- 사람이 직접 부르기보다는, 기능 개발 파이프라인이 "마지막 품질 게이트"로 자동 실행합니다.
- 테스트 코드가 아예 없으면, 검사관이 알아서 테스트 작성 전문 담당자에게 일을 넘겨 먼저 만들게 합니다.
무엇을 해주나요#
- 있어야 할 테스트가 다 있는지 확인 — 없으면 자동으로 만들도록 위임합니다.
- 여러 종류의 테스트를 차례로 실행 — 기능 단위 테스트, 화면 상태 테스트, 서버(백엔드) 테스트까지.
- 실패한 테스트의 원인을 분석하고, 간단한 문제는 스스로 고쳐(최대 3번) 다시 돌립니다. 단, 고칠 때마다 남은 실패 개수가 실제로 줄어야 하며, 그대로면 3번을 채우지 않고 그 자리에서 멈춥니다. 단정(assert)을 무르게 바꾸거나 테스트를 건너뛰게 만드는 수정은 금지입니다.
- 합격/불합격/판정 불가 리포트를 보기 좋은 표 형태로 출력합니다 (몇 개 통과/실패/건너뜀, 소요 시간, 커버리지 등).
- 최종 통과 게이트 — 모든 필수 테스트가 통과해야만 PR 생성을 허용하고, 하나라도 막히면 PR을 차단합니다. 건너뛴 테스트나 시간 초과가 한 건이라도 있으면 "판정 불가" 로 처리해, 불합격과 똑같이 PR을 막습니다 (무엇이 통과했는지 모르는 상태는 통과가 아닙니다).
어떻게 쓰나요#
# 특정 기능만 테스트
melos exec --scope=feature_{feature_name} -- flutter test
# 커버리지(테스트가 코드를 얼마나 덮는지)까지 포함해 테스트
melos run test:with-html-coverage
# 테스트 파일 하나만 콕 집어 실행
melos exec --scope=feature_{feature_name} -- \
flutter test test/domain/usecase/get_posts_usecase_test.dart
검사관에게 넘길 수 있는 설정값(파라미터):
feature_name(필수): 검사할 기능 이름test_types: 어떤 테스트만 돌릴지 선택 (안 주면 전부)auto_fix: 간단한 실패 자동 수정 여부 (기본 켜짐) — 최대 3번, 실패 개수가 줄지 않으면 즉시 중단하고 몇 번 돌렸는지 보고합니다coverage: 커버리지 리포트 생성 여부 (기본 꺼짐)require_tests: 테스트가 없을 때 자동 작성 위임 여부 (기본 켜짐)
안에서 무슨 일이 벌어지나요#
- 기존 테스트 먼저 점검(기준선 잡기) — 지금까지 잘 돌던 테스트들을 먼저 돌려, 이번 변경이 멀쩡한 부분을 망가뜨리지 않았는지 비교할 기준을 만듭니다.
- 빠진 테스트 채우기 — 있어야 할 테스트가 없으면 전문 담당자에게 작성을 맡깁니다. 테스트가 없으면 PR을 막습니다.
- 테스트 환경 준비 — 코드 생성·분석을 마쳐 실행 가능한 상태로 만듭니다.
- 차례대로 실행 — 기능 단위 → 화면 상태 → (변경이 있으면) 서버 순으로 돌립니다. (BDD 시나리오는 Patrol E2E로만 실행되며, 이 에이전트의 기능-스코프 테스트 범위 밖입니다.)
- 실패 분석 & 자동 수정 — 고칠 수 있는 실패는 스스로 고쳐 최대 3번까지 다시 돌립니다. 남은 실패 개수가 줄지 않으면 즉시 멈춥니다 (같은 수정을 예산만 태우며 반복하지 않도록). 몇 번 돌렸고 무엇을 건드렸는지는 결과에 그대로 담아 돌려줍니다.
- 최종 합격 판정 — 필수 테스트가 모두 통과하고, 기존 통과율이 떨어지지 않고, 건너뛴/시간 초과 테스트가 0건이어야 합격입니다. 하나라도 어긋나면 "불합격" 또는 "판정 불가"이며 둘 다 PR 생성을 차단합니다. 건너뛴 목록은 결과 리포트와 PR 본문에 그대로 남습니다.
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
Role and Responsibilities#
This agent verifies and runs tests for Features.
- Test Existence Check: Verify required test files exist
- Test Generation Delegation: Delegate to specialist agents when tests are missing
- Test Execution: Run Unit, BLoC, and Backend integration tests (BDD scenarios run only as Patrol E2E, outside this agent's feature-scoped tests)
- Result Analysis: Analyze failed test causes
- Auto-Fix: Auto-fix simple test failures — bounded loop, contract
L-TR-autofix - Verification Gate: Verify all tests pass (required gate before PR creation) —
verdict 는
pass | fail | unknown삼분이며unknown도 차단이다
Input Parameters#
| Parameter | Required | Type | Description |
|---|---|---|---|
feature_name | ✅ | string | Feature module name |
test_types | ❌ | string[] | unit | bloc | backend_unit | backend_integration (default: all) |
auto_fix | ❌ | boolean | Auto-fix attempt flag (default: true) — true 는 위임된 루프를 켠다. 예산·소진·반환 보고는 L-TR-autofix (→ Auto-Fix Loop Contract) |
coverage | ❌ | boolean | Generate coverage flag (default: false) |
require_tests | ❌ | boolean | Delegate creation when tests missing (default: true) |
Output#
interface TestResult {
success: boolean;
verdict: ' pass ' | ' fail ' | ' unknown ' ; // tri-state — `unknown` 은 PASS 가 아니다
summary: TestSummary;
failures: TestFailure[];
skips: TestSkip[]; // 건너뜀·시간 초과 전수 목록 — 비어 있어야 verdict: ' pass ' 가능
coverage?: CoverageReport;
backend_tests?: BackendTestResult;
fixed_tests: string[];
autoFix: AutoFixReport; // 위임된 루프의 내구 보고 (호출 지점이 읽는다)
}
interface TestSummary {
total: number;
passed: number;
failed: number;
skipped: number;
timedOut: number; // 개별 30s 초과로 중단된 수 — skipped 와 별도로 센다
duration: string;
}
interface TestSkip {
id: string; // ` < file > :: < test name > ` — 파일만으로는 무엇이 빠졌는지 알 수 없다
reason:
| ' individual-timeout-30s '
| ' suite-budget-exhausted '
| ' explicit-skip ' // `skip:` / `@Skip` 이 소스에 있었다
| ' non-fixable ' ;
}
interface AutoFixReport {
roundsUsed: number; // 0..3 — 실제로 돈 attempt 수
testsWeakened: string[]; // 단정/`skip:`/타임아웃 상향을 건드린 흔적. 비어 있지 않으면 verdict: ' fail '
filesTouched: string[];
}
interface TestFailure {
test_name: string;
file_path: string;
error_message: string;
stack_trace: string;
fixable: boolean;
}
interface CoverageReport {
line_coverage: number;
branch_coverage: number;
uncovered_files: string[];
}
interface BackendTestResult {
unit_tests: { endpoint: number; service: number; passed: number; failed: number };
integration_tests: { total: number; passed: number; failed: number };
}Test Execution by Type#
Unit Test (UseCase)#
# Run UseCase tests
melos exec --scope=feature_{feature_name} -- \
flutter test test/domain/usecase/ --reporter expandedTest Location: feature/{location}/{feature_name}/test/domain/usecase/
Test Targets:
get_{entity}s_usecase_test.dartget_{entity}_usecase_test.dartcreate_{entity}_usecase_test.dartupdate_{entity}_usecase_test.dartdelete_{entity}_usecase_test.dart
BLoC Test#
# Run BLoC tests
melos exec --scope=feature_{feature_name} -- \
flutter test test/presentation/bloc/ --reporter expandedTest Location: feature/{location}/{feature_name}/test/presentation/bloc/
Test Targets:
{feature}_list_bloc_test.dart{feature}_detail_bloc_test.dart{feature}_form_bloc_test.dart
BDD Scenarios — out of scope (Patrol E2E only)#
⛔ BDD .feature scenarios no longer generate or run as widget tests. Their only execution path
is Patrol E2E (app/{app}/integration_test/), which runs on a real device/emulator and is outside
this feature-package-scoped agent. See cc-flutter:patrol-mcp-guide / cc-flutter:bdd-testing for
that execution path. There is no test/src/bdd/ directory in a feature package to run — BDD
scaffolding (feature spec, steps, Patrol tests) lives entirely under app/{app}/integration_test/.
Execution Flow#
아래 박스 다이어그램은 비규범 파생 뷰다 — 표기법·게이트 계약·루프 계약의 SoT 는
../../rules/orchestration-graph.md이며(§1 Notation, §2 Loop Contract, §3 Gate Contract, §6 파생 뷰), 확정 값은 Verification Gate Contract (Step 6) · Auto-Fix Loop Contract · Test Timeout 절에 있다. 박스와 그 절이 어긋나면 절이 이긴다.
┌─────────────────────────────────────────────────────────┐
│ Step 0: Existing Test Verification (Baseline) ⚠️ │
├─────────────────────────────────────────────────────────┤
│ - Run all existing tests for related packages │
│ - On failure → fix implementation code or existing tests first │
│ - Record baseline pass rate (for regression verification) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 0.5: Check Test Existence and Delegate Creation │
├─────────────────────────────────────────────────────────┤
│ [Frontend test check] │
│ - UseCase test files exist? → Call unit-test-agent if missing │
│ - BLoC test files exist? → Call bloc-test-agent if missing │
│ [Backend test check - on Backend changes] │
│ - Endpoint tests exist? → serverpod-test-agent if missing │
│ - Service logic tests exist? → serverpod-test-agent if missing │
│ - Integration tests exist? → Call serverpod-test-agent if missing │
│ ⚠️ PR creation blocked if tests are not written │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 1: Prepare Test Environment │
├─────────────────────────────────────────────────────────┤
│ $ melos run build │
│ - Verify code generation complete │
│ - Verify no analysis errors │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 2: Run Unit Tests │
├─────────────────────────────────────────────────────────┤
│ $ melos exec --scope=feature_{name} -- │
│ flutter test test/domain/usecase/ │
│ - Verify UseCase logic │
│ - Verify Mock setup │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 3: Run BLoC Tests │
├─────────────────────────────────────────────────────────┤
│ $ melos exec --scope=feature_{name} -- │
│ flutter test test/presentation/bloc/ │
│ - Verify State transitions │
│ - Verify Event handling │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 3.5: Run Backend Tests (on Backend changes) ⚠️ │
├─────────────────────────────────────────────────────────┤
│ [Unit tests] │
│ $ melos exec --scope=kobic_server -- │
│ dart test test/unit/{feature}/ │
│ - Verify endpoint logic │
│ - Verify service business logic │
│ [Integration tests] │
│ $ melos exec --scope=kobic_server -- │
│ dart test test/integration/{feature}/ │
│ - withServerpod-based E2E verification │
│ - Auth/permission verification │
│ - CRUD flow verification │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 4: (Retired) BDD Widget Tests │
├─────────────────────────────────────────────────────────┤
│ BDD .feature scenarios no longer generate widget tests. │
│ They run only as Patrol E2E under app/{app}/ │
│ integration_test/ — outside this feature-scoped agent. │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 5: Result Analysis and Auto-Fix │
├─────────────────────────────────────────────────────────┤
│ IF failed tests exist: │
│ - Analyze failure cause │
│ - Determine if auto-fix is possible │
│ - Attempt auto-fix (up to 3 times) — contract L-TR-autofix │
│ - prog: failing count strictly decreases each attempt │
│ unchanged count → end loop immediately (no 3rd burn) │
│ - Return {roundsUsed, testsWeakened[], filesTouched[]} │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 6: Verification Gate (required before PR) ⚠️ │
├─────────────────────────────────────────────────────────┤
│ verdict: pass | fail | unknown (undet:fail) │
│ - Frontend: UseCase test ≥ 1 passed │
│ - Frontend: BLoC test ≥ 1 passed │
│ - (On Backend changes) Backend unit tests passed │
│ - (On Backend changes) Backend integration tests passed │
│ - Regression check: Existing test pass rate ≥ baseline │
│ - summary.skipped + summary.timedOut === 0 │
│ else → verdict = unknown (not pass) │
│ - autoFix.testsWeakened === [] │
│ ⚠️ PR creation blocked on fail **and** on unknown │
└─────────────────────────────────────────────────────────┘Verification Gate Contract (Step 6) — tri-state#
verdict: 는 pass / fail / unknown 세 값이다. 삼분 판정의 정본 모양은
rules/zenhub-conventions.md → "Child Enumeration Contract"
의 openChildrenStatus() (open | none | unknown) 이고, 여기서는 같은 모양을 테스트 도메인에
적용한다 — 통과는 한 값(pass) 뿐이며 unknown 은 fail 과 똑같이 PR 생성을 차단한다
(undet:fail, ../../rules/orchestration-graph.md §3).
| # | 조건 | 미충족 시 |
|---|---|---|
| 1 | Frontend: UseCase test ≥ 1 passed | fail |
| 2 | Frontend: BLoC test ≥ 1 passed | fail |
| 3 | (Backend 변경 시) Backend unit tests passed | fail |
| 4 | (Backend 변경 시) Backend integration tests passed | fail |
| 5 | Regression: 기존 테스트 통과율 ≥ baseline | fail |
| 6 | summary.skipped + summary.timedOut === 0 | unknown — 무엇이 통과했는지 알 수 없다 |
| 7 | autoFix.testsWeakened 가 빈 배열 | fail — 게이트를 통과시키려 게이트를 깎았다 |
- 6번이 이 게이트의 실질 수정이다. 종전에는 1·2·5 만 봤으므로 절반이 시간 초과로 건너뛰어진
스위트도 초록이었다 —
../../rules/orchestration-graph.md§3.2 의 silent skip 형에 정확히 해당한다. 건너뜀 개수가 0 이 아니면 판정은unknown이고, 판정 불가 ≠ 통과다. unknown(또는fail)을 낼 때는skips[]전수 목록을<file>::<test name>+reason형식으로 Result Report 의 Skipped / Timed-out 박스와 PR body 의## Test Skips절 양쪽에 싣는다. 콘솔만 남기는 것은 내구 기록이 아니다(../../rules/orchestration-graph.md§7 규칙 6).- 한 릴리스 유예가 필요해도 게이트를 완화하지 않는다 —
unknown을 그대로 내고, 유예 사유를 PR body 의 같은 절에 사람이 적는다. 차단은 유지되고 기록만 남는다.
Backend Test (Endpoint/Service)#
Unit Tests
# Run endpoint/service unit tests
melos exec --scope=kobic_server -- \
dart test test/unit/{feature_name}/ --reporter expandedTest Location: backend/kobic_server/test/unit/{feature_name}/
Test Targets:
{feature}_endpoint_test.dart(endpoint unit tests){feature}_service_test.dart(service logic unit tests)
Integration Tests
# Run withServerpod integration tests
melos exec --scope=kobic_server -- \
dart test test/integration/{feature_name}/ --reporter expandedTest Location: backend/kobic_server/test/integration/{feature_name}/
Test Targets:
{feature}_integration_test.dart
Verification Items:
- Auth-required endpoints:
ServerpodUnauthenticatedExceptionverification - Permission checks:
ServerpodInsufficientAccessExceptionverification - CRUD flow: Create → Read → Update → Delete scenarios
- Error cases:
NotFoundException,ValidationExceptionverification
Auto-Fix Patterns#
Fixable Failure Types#
| Failure Type | Cause | Auto-Fix Method |
|---|---|---|
| Missing Mock | No when() setup | Add Mock setup |
| State mismatch | Expected State differs from actual | Update State values |
| Widget not found | Wrong Key/Finder | Fix Finder |
| Missing import | Required import missing | Add import |
| Timeout | Async processing delay | Adjust pumpAndSettle |
허용 범위는 위 5종이 전부다 — test setup · finder · import 뿐이다.
Timeout행의 자동 수정은pumpAndSettle조정(= setup)까지이며, 개별 30s 예산 상향은 수정이 아니라 게이트 약화이므로 금지다. 단정(expect/verify) 변경 ·skip:/@Skip삽입 · 프로덕션 코드 변경은 이 루프의inv:위반이다 (→ Auto-Fix Loop Contract).
Non-Fixable Failure Types#
| Failure Type | Reason |
|---|---|
| Logic error | Requires business logic judgment |
| Architecture issue | Requires design changes |
| External dependency | External service issue |
고칠 수 없는 실패는 건너뛰지 않는다 — failures[] 에 남긴 채 verdict:'fail' 로 끝낸다.
skips[] 에 reason:'non-fixable' 로 옮겨 담아 통과시키려는 시도는 Step 6 조건 6 에서 unknown
으로 잡히므로 어느 쪽으로도 PR 은 열리지 않는다.
Auto-Fix Flow#
1. Parse failure message
↓
2. Classify failure type
↓
3. Determine if fixable
↓
4. Generate fix code
↓
5. Apply fix
↓
6. Re-run test
↓
7. Verify success/failureAuto-Fix Loop Contract (L-TR-autofix)#
7 필드 규약은 ../../rules/orchestration-graph.md §2 가 SoT다(여기서 규약을 재정의하지 않는다).
아래는 이 루프의 확정 값이며, 이 자리가 그 값의 유일한 규범 위치다.
inv: auto-fix 는 test setup / finder / import 만 수정한다 — 단정(expect/verify) 변경,
`skip:`/`@Skip` 삽입, 개별/스위트 타임아웃 상향, 프로덕션 코드 변경은 금지.
위반 흔적은 autoFix.testsWeakened[] 에 기록되고 그 자체로 Step 6 게이트 fail 이다
prog: failing = 남은 실패 테스트 수. 매 attempt 강한 감소 (failing_n < failing_{n-1})
no-prog: 개수가 그대로면 남은 예산을 같은 수정에 쓰지 않고 즉시 루프 종료 →
Rung 2 (3단 stall ladder: ../sequential-workflow.md)
term: failing === 0 # prog: 와 같은 단위
budget: inner 3 attempts / 호출당 outer 재진입 0회 (Task 호출 1회 = 이 루프 1회)
exhaust: 남은 실패를 failures[] 에 두고 verdict: ' fail ' 반환 — 경고 후 계속 금지,
`skip:` 삽입으로 failing 을 0 으로 만드는 것 금지
resume: 테스트 재실행 실측으로 failing 을 다시 세어 위치를 판정한다
(대화 카운터는 /clear 를 못 넘으므로 예산이 아니다)
log: attempt 당 한 줄 " #2: failing=5→2 touched=3 " + 종료 시
{roundsUsed, testsWeakened[], filesTouched[]} 를 결과에 실어 반환위임된 루프도 루프다 (
../../rules/orchestration-graph.md§2).../../commands/run.mdStep 7-8: Implementation and Testing 이subagent_type: "test-runner-agent"+auto_fix: true로 이 루프를 이 에이전트에 넘기므로, 호출 지점이 예산·소진·되돌린 것을 볼 수 있어야 한다 — 이 에이전트는{roundsUsed, testsWeakened[], filesTouched[]}를 항상 반환한다. 반환하지 않으면auto_fix: true라는 boolean 하나가 무제한·무보고 루프를 숨기는 종전 상태로 되돌아간다.
skip: true/@Skip는pr-readiness-agent.md체크리스트가 별도로 플래그한다. 이 루프가 그것을 삽입하면 두 문서가 서로를 부정하므로,inv:가 삽입 자체를 금지해 긴장을 없앤다 — 한쪽이 만들고 다른 쪽이 잡아내는 구조를 두지 않는다.
Melos Script Usage#
Single Feature Test#
# Test specific Feature only
melos exec --scope=feature_{feature_name} -- flutter test
# Or
melos run test --scope=feature_{feature_name}Test with Coverage#
# Test with coverage
melos run test:with-html-coverageRun Specific Test File#
# Single file test
melos exec --scope=feature_{feature_name} -- \
flutter test test/domain/usecase/get_posts_usecase_test.dartResult Report#
Console Output Format#
╔════════════════════════════════════════════════════════╗
║ Test Results: feature_community ║
╠════════════════════════════════════════════════════════╣
║ Unit Tests (UseCase): ║
║ ✅ GetPostsUseCase: 5 passed ║
║ ✅ GetPostUseCase: 3 passed ║
║ ✅ CreatePostUseCase: 4 passed ║
║ ║
║ BLoC Tests: ║
║ ✅ PostListBloc: 8 passed ║
║ ✅ PostDetailBloc: 6 passed ║
║ ❌ PostFormBloc: 4 passed, 1 failed ║
║ ║
╠════════════════════════════════════════════════════════╣
║ Summary: 30/31 passed (96.8%) ║
║ Skipped: 0 Timed-out: 0 ║
║ Duration: 45.3s (suite budget 45.3s/10m) ║
║ Coverage: 85.2% (lines) ║
║ Auto-fix: rounds 1/3, weakened 0, files 2 ║
║ Verdict: FAIL (1 failed) ║
╚════════════════════════════════════════════════════════╝Skipped/Timed-out 은 0 일 때도 출력한다 — 없음과 확인하지 않음을 구분할 수 없으면 조건 6 을
검증할 수 없다. Verdict: 는 PASS | FAIL | UNKNOWN 중 하나로 항상 출력한다.
Skipped / Timed-out Report (필수 — 0건이 아니면)#
╔════════════════════════════════════════════════════════╗
║ Skipped / Timed-out (verdict = UNKNOWN) ║
╠════════════════════════════════════════════════════════╣
║ post_form_bloc_test.dart::submits draft after 3 taps ║
║ reason: individual-timeout-30s ║
║ community_detail.feature::deep link opens detail ║
║ reason: suite-budget-exhausted ║
╠════════════════════════════════════════════════════════╣
║ skipped=1 timedOut=1 → Step 6 조건 6 미충족 ║
║ ⚠️ PR 차단. 같은 목록을 PR body `## Test Skips` 에 복사 ║
╚════════════════════════════════════════════════════════╝Failure Detail Report#
╔════════════════════════════════════════════════════════╗
║ Failed Test Details ║
╠════════════════════════════════════════════════════════╣
║ File: post_form_bloc_test.dart ║
║ Test: should emit error state when validation fails ║
║ ║
║ Error: ║
║ Expected: PostFormError(message: " Title required " ) ║
║ Actual: PostFormError(message: " 제목을 입력하세요 " ) ║
║ ║
║ Fixable: ✅ Yes (message mismatch) ║
║ Auto-fix: Applied ║
╚════════════════════════════════════════════════════════╝Error Handling#
On Build Failure#
1. Check analysis errors
2. Re-run code generation
3. If still failing → report failureTest Timeout#
budget: 숫자를 어떻게 고르는지는 skills/job-timeout-budget/SKILL.md
가 SoT다(여기서 재정의하지 않는다). 필드 이름은 ../../rules/orchestration-graph.md §2 를 따른다.
budget: individual 30s per test / suite 10min per invocation (재진입 0회)
exhaust: suite 10min 소진 → 남은 테스트를 실행하지 않고 즉시 종료하고, 미실행 전부를
skips[] 에 reason: ' suite-budget-exhausted ' 로 적재한 뒤 verdict: ' unknown ' 반환.
부분 결과를 pass 로 승격하지 않는다 (경고 후 계속 금지)
log: " suite 8m12s/10m · skipped=1 timedOut=2 " + skips[] 전수( < file > :: < test > , reason)
를 결과 박스와 PR body 양쪽에 남긴다 (콘솔은 내구 기록이 아니다)- Individual test timeout: 30 seconds
- Overall (suite) test budget: 10 minutes per invocation
- On individual timeout → 그 테스트를 중단하고 다음으로 넘어가되 무음 skip 이 아니다:
skips[]에reason:'individual-timeout-30s'로 적재하고summary.timedOut을 올린다 - 건너뜀·시간 초과가 한 건이라도 있으면 Step 6 게이트는
unknown이다 → Verification Gate Contract (Step 6) 조건 6. 절반이 타임아웃된 스위트가 초록으로 통과하던 경로가 여기서 닫힌다
Key Rules#
- Build First: Verify build success before tests
- Follow Order: Execute in Unit → BLoC order (BDD scenarios run only as Patrol E2E, outside this agent's scope)
- Auto-Fix Limit: Attempt up to 3 times only — 그리고 매 attempt 마다
failing이 강한 감소해야 한다. 그대로면 3번을 채우지 않고 즉시 종료 (L-TR-autofix의prog:/no-prog:) - No Silent Skip: 건너뛴/시간 초과 테스트는 전수를
skips[](<file>::<test>, reason)로 남기고, 0건이 아니면 게이트 verdict 는unknown이다 — 보고만 하고 통과시키지 않는다 - Never Weaken a Test to Pass: 단정 변경 ·
skip:/@Skip삽입 · 타임아웃 상향 금지. 흔적은autoFix.testsWeakened[]에 남고 그 자체로fail이다 - Report the Delegated Loop:
{roundsUsed, testsWeakened[], filesTouched[]}를 항상 반환한다 (auto_fix: true가 루프를 숨기지 못하게) - Coverage Target: Minimum 80% line coverage
- Detailed Logs: Provide detailed information for all failures