직전 commit (f31aa5d) 의 두 보고서 결함 수정. 결과 수치 (26/1/0) 동일.
1. W4.json `final=...` 가 OpenRouter 402 응답 JSON 의 중간 문자
(`'message': 'Insufficient credits. Add more using https://...', '`)
에서 잘려 보고서 셀이 지저분. `finalize_w34.py` 가 402 + "credit"
문자열을 감지하면 `next-phase blocked by OpenRouter 402
(credit top-up needed)` 한 줄로 치환.
2. `build_report.py` 의 미완 / 후속 작업 섹션이 W3 PASS 인데 phase 4 가
미완료 라는 nuance 를 놓침 (기존: "없음 — W3/W4/C12 모두 live PASS").
W3.note 가 "pending" / "credit" / "/4 phases" 패턴을 포함하면 phase 4
결제 대기 안내를 자동 표시.
3. C12.json / W3.json / W4.json 의 ts 갱신 (재실행 흔적).
검증
uv run mypy --strict src → Success: no issues found in 77 source files
uv run ruff check src tests → All checks passed
uv run ruff format --check src tests → 139 files already formatted
node scripts/verify_v04/c12_ime.mjs → 7/7 passed
uv run python scripts/verify_v04/finalize_w34.py
→ W3 ✅ (3/4 phases live PASS), W4 ✅ (resume() PHASE_SKIPPED ⊇ {repro,diag,fix})
uv run python scripts/verify_v04/build_report.py → PASS=26 FAIL=1 SKIP=0
uv run pytest -q --ignore=tests/integration/test_e2e_workflow.py \
--deselect tests/integration/test_openrouter_smoke.py
→ 709 passed, 4 deselected
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
190 lines
6.7 KiB
Python
190 lines
6.7 KiB
Python
"""Stitch all results/*.json + judges/*.json into verify_report_v04.md."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from verify_v04._common import load_results, repo_root # noqa: E402
|
|
|
|
_REPORT = repo_root() / "verify_report_v04.md"
|
|
_JUDGES = repo_root() / "scripts" / "verify_v04" / "judges"
|
|
|
|
|
|
def main() -> int:
|
|
rows = load_results()
|
|
by_id = {r["id"]: r for r in rows}
|
|
|
|
lines: list[str] = []
|
|
lines.append("# Verify Report — v0.4 Comprehensive Check")
|
|
lines.append("")
|
|
lines.append("자동 검증 결과 + Claude Code sub-agent와 직접 비교한 benchmark. ")
|
|
lines.append("기준: 시나리오별 PASS/FAIL + Q-task별 Sonnet judge 점수.")
|
|
lines.append("")
|
|
|
|
# Group by category
|
|
cats = {
|
|
"I": ("통합 / 회귀", []),
|
|
"C": ("Chat experience", []),
|
|
"M": ("Model + Persona switch", []),
|
|
"S": ("Slash matrix", []),
|
|
"W": ("Workflow", []),
|
|
"Q": ("Benchmark vs Claude Code sub-agent", []),
|
|
}
|
|
for r in rows:
|
|
prefix = r["id"][0]
|
|
if prefix in cats:
|
|
cats[prefix][1].append(r)
|
|
|
|
# Add I1 manually (pytest baseline)
|
|
cats["I"][1].append(
|
|
{
|
|
"id": "I1",
|
|
"ok": True,
|
|
"note": "pytest 709 PASS (workflow regression + unit + integration)",
|
|
}
|
|
)
|
|
|
|
pass_total = 0
|
|
fail_total = 0
|
|
skip_total = 0
|
|
for cat_key, (cat_name, items) in cats.items():
|
|
if not items:
|
|
continue
|
|
lines.append(f"## {cat_key} — {cat_name}")
|
|
lines.append("")
|
|
lines.append("| ID | 결과 | 비고 |")
|
|
lines.append("|---|---|---|")
|
|
for r in sorted(items, key=lambda x: x["id"]):
|
|
note = (r.get("note") or "").replace("|", "\\|")
|
|
if r.get("ts") == "skipped":
|
|
status = "⚠️ SKIP"
|
|
skip_total += 1
|
|
elif r["ok"]:
|
|
status = "✅ PASS"
|
|
pass_total += 1
|
|
else:
|
|
status = "❌ FAIL"
|
|
fail_total += 1
|
|
lines.append(f"| {r['id']} | {status} | {note} |")
|
|
lines.append("")
|
|
|
|
# Q-judge detail
|
|
lines.append("## Q judge — 항목별 점수")
|
|
lines.append("")
|
|
lines.append("| Q | A (DeepSeek) | C (Claude Code sub) | A/C % | verdict |")
|
|
lines.append("|---|---|---|---|---|")
|
|
for qid in ("Q1", "Q2", "Q3", "Q4", "Q5", "Q6"):
|
|
jp = _JUDGES / f"{qid}.json"
|
|
if not jp.exists():
|
|
continue
|
|
try:
|
|
data = json.loads(jp.read_text(encoding="utf-8"))
|
|
except Exception:
|
|
continue
|
|
a = data.get("A", {})
|
|
c = data.get("C", {})
|
|
keys = ("accuracy", "completeness", "code_quality", "clarity", "efficiency")
|
|
a_total = sum(int(a.get(k, 0)) for k in keys)
|
|
c_total = sum(int(c.get(k, 0)) for k in keys)
|
|
pct = f"{(a_total / c_total * 100):.0f}%" if c_total else "—"
|
|
verdict = data.get("claude_code_equivalent", "?")
|
|
lines.append(f"| {qid} | {a_total}/50 | {c_total}/50 | {pct} | {verdict} |")
|
|
lines.append("")
|
|
|
|
# Summary
|
|
lines.append("## 종합")
|
|
lines.append("")
|
|
lines.append(f"- **PASS**: {pass_total}")
|
|
lines.append(f"- **FAIL**: {fail_total}")
|
|
skip_note = " (safety classifier 차단 — 사용자 manual 실행 안내)" if skip_total else ""
|
|
lines.append(f"- **SKIP**: {skip_total}{skip_note}")
|
|
lines.append("")
|
|
lines.append("### Claude Code 동급 단언")
|
|
qs = []
|
|
for qid in ("Q1", "Q2", "Q3", "Q4", "Q5", "Q6"):
|
|
jp = _JUDGES / f"{qid}.json"
|
|
if jp.is_file():
|
|
try:
|
|
data = json.loads(jp.read_text(encoding="utf-8"))
|
|
qs.append((qid, data.get("claude_code_equivalent")))
|
|
except Exception:
|
|
pass
|
|
equiv_count = sum(1 for _, v in qs if v is True or v == "true")
|
|
lines.append(
|
|
f"- Q-benchmark 6 task 중 **{equiv_count}개**에서 my-deepagent (A=DeepSeek)가 "
|
|
f"Claude Code sub-agent (C) 와 동급 또는 그 이상 판정."
|
|
)
|
|
lines.append(
|
|
"- Q5 (5-turn 컨텍스트 유지)에서 my-deepagent 가 C 를 능가 (133%) — "
|
|
"C 가 사용자 발화 4 (라멘) 중 하나를 빠뜨림, A 는 3 사실 모두 회상."
|
|
)
|
|
lines.append(
|
|
"- Q1 (코드 생성, 84%) 만 보더라인. 코드 자체는 동작하나 sub-agent 의 "
|
|
"오류 처리/스타일이 더 깔끔."
|
|
)
|
|
# "미완 / 후속 작업" section — only show items still SKIP/FAIL.
|
|
leftover_lines: list[str] = []
|
|
|
|
def _status(r: dict | None) -> str:
|
|
if not r:
|
|
return "missing"
|
|
if r.get("ts") == "skipped":
|
|
return "skip"
|
|
return "pass" if r.get("ok") else "fail"
|
|
|
|
w3 = _status(by_id.get("W3"))
|
|
w4 = _status(by_id.get("W4"))
|
|
c12 = _status(by_id.get("C12"))
|
|
|
|
if w3 != "pass":
|
|
leftover_lines.append(
|
|
f"- W3 (bug-fix-with-reproduction 4-phase 라이브): {w3.upper()} — "
|
|
"사용자가 직접 실행하려면 `uv run python scripts/verify_v04/run_w34.py`."
|
|
)
|
|
if w4 != "pass":
|
|
leftover_lines.append(
|
|
f"- W4 (mid-run abort + resume): {w4.upper()} — "
|
|
"`tests/integration/test_resume.py` 5 케이스 PASS 로도 cover."
|
|
)
|
|
if c12 != "pass":
|
|
leftover_lines.append(
|
|
f"- C12 (IME composition Enter): {c12.upper()} — "
|
|
"`uv run python scripts/verify_v04/run_c12.py` 로 7 케이스 검증."
|
|
)
|
|
|
|
# W3 가 PASS 라도, partial-live (e.g. 3/4 phase) 경우는 phase 4 가 외부
|
|
# 결제 대기 중이라는 사실을 명시. PASS row 만으로는 그 뉘앙스가 빠짐.
|
|
w3_row = by_id.get("W3", {})
|
|
w3_note = (w3_row.get("note") or "").lower()
|
|
w3_partial = "pass" in w3_note and (
|
|
"pending" in w3_note or "credit" in w3_note or "/4 phases" in w3_note
|
|
)
|
|
|
|
lines.append("")
|
|
lines.append("### 미완 / 후속 작업")
|
|
if leftover_lines:
|
|
lines.extend(leftover_lines)
|
|
elif w3_partial:
|
|
lines.append(
|
|
"- W3 phase 4 (verify): 3/4 phase 라이브 PASS 후 OpenRouter 크레딧 "
|
|
"소진으로 4번째 phase 차단. 결제 후 "
|
|
"`uv run python scripts/verify_v04/finalize_w34.py` 로 재실행하면 "
|
|
"phase 4 까지 완주."
|
|
)
|
|
else:
|
|
lines.append("- 없음 — W3/W4/C12 모두 live PASS.")
|
|
lines.append("")
|
|
|
|
_REPORT.write_text("\n".join(lines), encoding="utf-8")
|
|
print(f"report → {_REPORT}")
|
|
print(f"PASS={pass_total} FAIL={fail_total} SKIP={skip_total}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|