Skip to content

Commit 280debf

Browse files
illenne77Copilot
andcommitted
fix(ci): 회귀 floor 검증 — collected(passed+skipped) vs total + skip_tolerance
문제: CI run #3 실패 — Linux CI에서 test_ports_smoke의 2개 테스트가 KIS parquet cache 부재로 합법적 skip. baseline.json의 pass=46만 비교하니 44 < 46으로 회귀 오판정. 해결: - pass만 비교 -> collected(passed+skipped+failed) vs baseline.test.total - skipped <= baseline.test.skip_tolerance 추가 확인 - failed > 0이면 즉시 실패 이제 환경별 합법적 skip은 허용하되 테스트 유실(collection 감소)은 차단. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent aeff4d3 commit 280debf

1 file changed

Lines changed: 24 additions & 14 deletions

File tree

.github/workflows/ci.yml

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,39 @@ jobs:
5050
-m "not integration"
5151
5252
- name: Enforce baseline.json regression floor
53-
# baseline.json의 test.pass를 회귀 차단 floor로 사용한다.
54-
# 통과 테스트 수가 baseline보다 적으면 CI 실패.
53+
# baseline.json의 test.total을 회귀 차단 floor로 사용한다.
54+
# 수집된 테스트(passed + skipped)가 total 미만이면 실패 (테스트 유실 회귀).
55+
# skip은 skip_tolerance 이내까지 허용 (예: KIS cache 부재로 인한 합법적 skip).
5556
run: |
5657
python - <<'PY'
5758
import json, subprocess, sys, re
5859
baseline = json.load(open(".claude/baseline.json"))
59-
floor = baseline["test"]["pass"]
60-
# pytest를 다시 quiet 모드로 실행하여 결과 카운트만 추출
60+
total_floor = baseline["test"]["total"]
61+
skip_tol = baseline["test"].get("skip_tolerance", 0)
6162
result = subprocess.run(
6263
["pytest", "tests/", "-q", "-m", "not integration", "--no-header"],
6364
capture_output=True, text=True
6465
)
6566
output = result.stdout + result.stderr
66-
# 예: "46 passed in 1.23s" 패턴 매칭
67-
match = re.search(r"(\d+) passed", output)
68-
if not match:
69-
print("CANNOT parse pytest output:")
70-
print(output)
71-
sys.exit(1)
72-
passed = int(match.group(1))
73-
print(f"baseline.json floor = {floor}, current pass = {passed}")
74-
if passed < floor:
75-
print(f"::error::Regression: {passed} < baseline {floor}")
67+
passed = int(re.search(r"(\d+) passed", output).group(1)) if re.search(r"(\d+) passed", output) else 0
68+
skipped_m = re.search(r"(\d+) skipped", output)
69+
skipped = int(skipped_m.group(1)) if skipped_m else 0
70+
failed_m = re.search(r"(\d+) failed", output)
71+
failed = int(failed_m.group(1)) if failed_m else 0
72+
collected = passed + skipped + failed
73+
print(f"baseline: total={total_floor}, skip_tol={skip_tol}")
74+
print(f"current : passed={passed}, skipped={skipped}, failed={failed}, collected={collected}")
75+
ok = True
76+
if failed > 0:
77+
print(f"::error::Test failures: {failed}")
78+
ok = False
79+
if collected < total_floor:
80+
print(f"::error::Regression: collected {collected} < baseline total {total_floor} (테스트 유실)")
81+
ok = False
82+
if skipped > skip_tol:
83+
print(f"::error::Too many skips: {skipped} > tolerance {skip_tol}")
84+
ok = False
85+
if not ok:
7686
sys.exit(1)
7787
print("OK: at or above baseline floor.")
7888
PY

0 commit comments

Comments
 (0)