Audit round 2: aspect measured the case too; defensive image decode; own-key state reset

4. aspect_profile had the same root cause as edges/centering but no guard.
   On the cased photo it reported 5.8% off standard -- the CASE's
   proportions -- and the UI would surface that as a trimming hint about a
   card it never measured. This one is more directly load-bearing than the
   other two, since the measurement IS the detected box. Now refuses, with
   both consumers (prompt block and UI hint) checking reliable.

5. _decode_images could KeyError/raise out of a plain read on a malformed
   row, and separately b64decode returns b'' rather than raising on some
   corrupt input -- which would have fed a zero-byte 'photo' into grading
   to fail confusingly deep in the pipeline. Both now degrade to the
   existing re-pick path.

6. _last_used_own_key is instance state on a handler that serves every
   request on a keep-alive connection, so it outlives the request that set
   it. Currently safe (every logging path assigns first), but a future path
   that logged without reaching the assignment would bill the previous
   request's payer. Cleared up-front now.

Full regression suite re-run: die-cut exclusion, uniform cards, centering,
aspect, cased-photo refusals, and the store layer all still behave.
This commit is contained in:
Barely Removable 2026-08-25 08:05:33 -07:00
parent 6c612c1f4a
commit 0cbeb26665
5 changed files with 39 additions and 4 deletions

View file

@ -939,6 +939,16 @@ def aspect_profile(image_bytes):
bw, bh = box[2] - box[0], box[3] - box[1]
if bw < 40 or bh < 40:
return None
# This measurement IS the detected box, so a box that didn't find
# the card's real boundary doesn't produce an approximate ratio —
# it produces the ratio of something else entirely. On a cased card
# it reported 5.8% off standard, which is the CASE's proportions;
# the UI would then show a trimming hint about a card it never
# measured. Same guard as edge/centering, and more directly
# load-bearing here than for either of those.
margin_reason = _box_margin_reason(box, img.size)
if margin_reason:
return {"reliable": False, "reason": margin_reason}
ratio = min(bw, bh) / float(max(bw, bh))
against_standards = {
@ -951,6 +961,7 @@ def aspect_profile(image_bytes):
best_name = min(against_standards, key=lambda n: against_standards[n]["deviation_percent"])
return {
"reliable": True,
"measured_ratio": round(ratio, 4),
"width_px": bw,
"height_px": bh,