"""What the falsely-accepted crops actually read, and what the text lane scores. The advisory says crops 82-97 are Kewpie Mayonnaise 450g - a product the catalog does not hold - and that no catalog row can therefore win the text ranking, so the veto at DecisionPolicy.decide never fires. This prints the reads and the scores that claim depends on. """ import csv import sys import cv2 import numpy as np sys.path.insert(0, "code") from identity_lanes import TextLane, carries_identity # noqa: E402 from ocr import build_ocr_engine # noqa: E402 INDICES = [73, 82, 83, 84, 86, 94, 95, 96, 97] rows = [] with open("stock-lopia-clean/stock.csv", encoding="utf-8") as handle: for record in csv.reader(handle): if len(record) >= 2 and record[0].startswith("sku_"): rows.append({"sku_id": record[0], "product_name": record[1]}) engine = build_ocr_engine("vision") lane = TextLane.from_catalog(rows, "stock-lopia-clean", ocr_engine=engine) labels = {f["index"]: f for f in __import__("json").load(open("eval/labels/image6.json"))["facings"]} image = cv2.imread("add/image6.jpg") tiles = [] for index in INDICES: facing = labels[index] x1, y1, x2, y2 = facing["box"] crop = image[y1:y2, x1:x2] read = lane.read(crop) scores = lane.scores_from_text(read) top = sorted(scores.items(), key=lambda kv: -kv[1])[:3] print(f"#{index:>3} truth={facing['label']:<9} carries={carries_identity(read)}") print(f" read: {read[:110]}") print(f" text top: {[(s, round(v, 3)) for s, v in top]}") height, width = crop.shape[:2] scale = 260.0 / max(1, height) resized = cv2.resize(crop, (max(1, int(width * scale)), 260), interpolation=cv2.INTER_CUBIC) canvas = np.full((300, 220, 3), 255, np.uint8) canvas[30:290, : min(resized.shape[1], 220)] = resized[:, :220] cv2.putText(canvas, str(index), (6, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) tiles.append(canvas) grid = np.vstack([np.hstack(tiles[:5]), np.hstack(tiles[5:])]) cv2.imwrite("data/evaluations/2026-09-29-session/scratch/fa_tiles.jpg", grid) print("tile:", grid.shape)