review(shot): finding A1 [adversary] — blank-retry overwrites unconditionally, can REGRESS a larger frame (9999B->4801B) to a worse one; LOW/non-blocking (R7 holds, visual M2 check is backstop); trivial max(first,retry) guard suggested. Independent cold probe, 9/9 R7 checks otherwise pass.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
autonomic-bot
2026-06-11 06:20:08 +00:00
parent 80e5713c5c
commit ea0e3e9d2f

View File

@ -75,4 +75,19 @@ PNG-size note: 4801/4802 B at 1280×800 is a byte-stable blank-frame fingerprint
## Adversary findings
(Adversary-owned section.)
### [adversary] A1 — blank-retry can REGRESS a larger frame to a worse one (LOW, non-blocking) — OPEN
**Where:** `runner/harness/screenshot.py` `_snap_with_blank_retry` (ce50f64).
**What:** the retry overwrites `out_path` *unconditionally* with the second screenshot. The code/comment
claim "the retry only ever replaces a tiny frame with a later one" — but *later ≠ better*. If the first
frame is e.g. 9999 B (a partial render, just under `BLANK_SIZE_BYTES=10000`) and the page regresses in the
extra 4 s settle (redirect, session-timeout splash, error overlay), the retry can yield a 4801 B blank that
**overwrites the better 9999 B frame**. The Builder's unit test only covers blank→blank (4801→4802); the
bigger→smaller regression is untested.
**Repro (cold, my independent probe, not the Builder's test file):** fake page returning sizes
`[9999, 4801]``_snap_with_blank_retry` keeps **4801** (the worse frame).
**Severity:** LOW. R7 holds (cosmetic only, never affects verdict); my M2 per-PNG visual check is the
backstop — any actually-blank final PNG will FAIL that recipe regardless. Filed for hardening, not a veto.
**Suggested guard (trivial, strictly safer):** keep the larger frame — only overwrite if
`getsize(retry) >= getsize(first)` (or snap retry to a temp path and pick `max`). Then extend the unit
test with a bigger→smaller case asserting the larger frame survives.
**Closes:** only I close this, after re-test. Non-blocking for an M2 claim, but I will re-check at M2.