leechard / scripts /check_summary_report_status.py
nenae18's picture
Deploy LeeChard
5d3c2a9 verified
Raw
History Blame Contribute Delete
7.21 kB
"""Status-only checker for the evidence summary_report.md.
Read-only: does NOT modify the summary and never marks anything PASS. It reads
the file (and, when available, checks whether the Gemini output image exists on
disk) and reports a lifecycle-aware status:
summary_status_check: OK | WARN | WARN_WITH_FAILURE_EVIDENCE | FAIL
Accepted (non-fatal) Gemini real-call states, all with Pilot Ready NOT CONFIRMED:
- gemini_real_call: NOT RUN (pre-call; human QA PENDING)
- gemini_real_call: RUN_FAILED - ... (attempted+failed) -> WARN_WITH_FAILURE_EVIDENCE
- gemini_real_call: RUN - output generated (success; output image must exist)
FAIL (unsafe / inconsistent):
- Pilot Ready: CONFIRMED
- single-device smoke: PASS
- human QA PASS while real call is NOT RUN or RUN_FAILED
- gemini_real_call RUN but output image missing
- gemini_output_image PRESENT but the actual file is missing
- "actual Gemini result verified" claimed but no output image
- an API-key-like string exposed in the summary
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
DEFAULT_SUMMARY = Path(
r"C:\Users\Admin\Documents\헤어\field-test-evidence"
r"\v0.1.0-staging\2026-05-31-single-device-smoke-01\summary_report.md"
)
_SEVERITY = {"OK": 0, "WARN": 1, "WARN_WITH_FAILURE_EVIDENCE": 2, "FAIL": 3}
_API_KEY_RE = re.compile(r"AIza[0-9A-Za-z_\-]{20,}")
def _worst(a: str, b: str) -> str:
return a if _SEVERITY[a] >= _SEVERITY[b] else b
def _values(text: str, key: str) -> list[str]:
prefix = key.lower() + ":"
out = []
for line in text.splitlines():
stripped = line.strip().lstrip("-* ").strip()
if stripped.lower().startswith(prefix):
out.append(stripped.split(":", 1)[1].strip())
return out
def _first(text: str, key: str) -> str | None:
vals = _values(text, key)
return vals[0] if vals else None
def _find_api_key_like(text: str) -> str | None:
return "AIza...(redacted)" if _API_KEY_RE.search(text) else None
def _output_png_exists(summary_path: Path) -> bool:
out = summary_path.parent / "gemini-smoke" / "output"
return out.exists() and any(out.glob("gemini-output-*.png"))
def check_summary(path: Path | str = DEFAULT_SUMMARY) -> dict:
path = Path(path)
if not path.exists():
return {"result": "FAIL", "reasons": [f"FAIL: summary not found: {path}"], "observed": {}}
text = path.read_text(encoding="utf-8", errors="replace")
output_png_exists = _output_png_exists(path)
result = "OK"
reasons: list[str] = []
real_call = _first(text, "gemini_real_call")
human_qa = _first(text, "gemini_human_visual_qa")
output_line = _first(text, "gemini_output_image")
local_storage = _first(text, "localStorage_check")
rc = (real_call or "").strip().upper()
hq = (human_qa or "").strip().upper()
oi = (output_line or "").strip().upper()
is_not_run = rc.startswith("NOT RUN")
is_run_failed = rc.startswith("RUN_FAILED")
is_run = rc.startswith("RUN") and not is_run_failed
hq_pass = hq.startswith("PASS") or "CONFIRMED" in hq
output_present_claim = oi.startswith("PRESENT")
output_missing_claim = oi.startswith("MISSING")
# --- always-FAIL danger rules -------------------------------------
pilot = _values(text, "Pilot Ready")
if not pilot:
result = _worst(result, "WARN")
reasons.append("WARN: Pilot Ready line not found")
for val in pilot:
u = val.upper()
if "CONFIRMED" in u and "NOT CONFIRMED" not in u:
result = _worst(result, "FAIL")
reasons.append(f"FAIL: Pilot Ready is '{val}' (must be NOT CONFIRMED)")
for val in _values(text, "single-device smoke"):
if val.upper().startswith("PASS"):
result = _worst(result, "FAIL")
reasons.append("FAIL: single-device smoke is marked PASS")
if _find_api_key_like(text):
result = _worst(result, "FAIL")
reasons.append("FAIL: possible API key value exposed in summary: AIza...(redacted)")
if output_present_claim and not output_png_exists:
result = _worst(result, "FAIL")
reasons.append("FAIL: gemini_output_image PRESENT but no output file found on disk")
if "actual gemini result verified" in text.lower() and not output_png_exists:
result = _worst(result, "FAIL")
reasons.append("FAIL: 'actual Gemini result verified' claimed but no output image")
# --- gemini_real_call lifecycle -----------------------------------
if real_call is None:
result = _worst(result, "WARN")
reasons.append("WARN: gemini_real_call line not found")
elif is_not_run:
if hq_pass:
result = _worst(result, "FAIL")
reasons.append("FAIL: human QA PASS while gemini_real_call is NOT RUN")
elif is_run_failed:
if hq_pass:
result = _worst(result, "FAIL")
reasons.append("FAIL: human QA PASS while gemini_real_call is RUN_FAILED")
else:
result = _worst(result, "WARN_WITH_FAILURE_EVIDENCE")
reasons.append("INFO: gemini_real_call RUN_FAILED - failure evidence recorded (not a safety violation)")
elif is_run:
if output_missing_claim or not output_png_exists:
result = _worst(result, "FAIL")
reasons.append("FAIL: gemini_real_call RUN but output image is missing")
else:
result = _worst(result, "WARN")
reasons.append(f"WARN: unrecognized gemini_real_call value '{real_call}'")
if human_qa is None:
result = _worst(result, "WARN")
reasons.append("WARN: gemini_human_visual_qa line not found")
if local_storage is None:
result = _worst(result, "WARN")
reasons.append("WARN: localStorage_check line not found")
elif not local_storage.upper().startswith("PASS"):
result = _worst(result, "WARN")
reasons.append(f"WARN: localStorage_check is '{local_storage}' (expected PASS)")
observed = {
"gemini_real_call": real_call,
"gemini_human_visual_qa": human_qa,
"gemini_output_image": output_line,
"output_png_on_disk": output_png_exists,
"localStorage_check": local_storage,
"pilot_ready": pilot[0] if pilot else None,
}
return {"result": result, "reasons": reasons, "observed": observed}
def main(argv: list[str] | None = None) -> int:
argv = list(sys.argv[1:] if argv is None else argv)
path = argv[0] if argv else DEFAULT_SUMMARY
report = check_summary(path)
print(f"summary: {path}")
if report["observed"]:
print("observed:")
for k, v in report["observed"].items():
print(f" {k}: {v}")
if report["reasons"]:
print("notes:")
for r in report["reasons"]:
print(f" - {r}")
print(f"summary_status_check: {report['result']}")
return 1 if report["result"] == "FAIL" else 0
if __name__ == "__main__":
sys.exit(main())