Catalog pairs same-title rows by photos, not csv position

The Wiz-War lines were displaying each other's rows: an edit re-queue
recreates its row at the END of matches.csv, and the catalog's
positional per-title pairing then crossed the wires — the 4504 line
wore 4528's open ballot while 4528's line offered 4504's pick-edition
button (whose click re-targeted by photos and safely hit the other
row, deepening the confusion). Pairing now matches run_resolve's rule:
exact photo set, then overlap, then positional fallback, with
unclaimed rows appended as their own lines. Plus a regression test
with deliberately reversed csv order, and the open-ballot marker
restyled as a quiet dotted link instead of a mis-wrapped button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-05 21:32:46 -04:00
co-authored by Claude Fable 5
parent c94e8bc695
commit 3e61a03686
5 changed files with 80 additions and 17 deletions
+41
View File
@@ -1202,3 +1202,44 @@ def test_version_cards_carry_their_photos(tmp_path):
(card,) = web.get("/api/state").json()["versions"]
assert card["title_raw"] == "Dungeon!"
assert card["photos"] == ["shelf.jpg"] # same-title copies stay tellable
def test_same_title_lines_pair_rows_by_photos_not_csv_order(tmp_path):
cfg = make_cfg(tmp_path)
titles = json.loads(cfg.titles_path.read_text())
titles += [
{"title_raw": "WIZ-WAR", "confidence": "high", "source_photos": ["a.jpg"]},
{"title_raw": "WIZ-WAR", "confidence": "high", "source_photos": ["b.jpg"]},
]
cfg.titles_path.write_text(json.dumps(titles))
rows = read_matches(cfg.matches_path)
# csv order REVERSED vs entry order: b's row first (an edit re-queue
# recreates a row at the file's end)
rows.append(
_row(
title_raw="WIZ-WAR",
match_status="auto",
bgg_id="589",
source_photos="b.jpg",
version_status="version_ambiguous",
version_candidates_json=VERSION_CANDIDATES,
)
)
rows.append(
_row(
title_raw="WIZ-WAR",
match_status="auto",
bgg_id="589",
source_photos="a.jpg",
version_status="version_unknown",
)
)
write_matches(cfg.matches_path, rows)
web = TestClient(create_app(cfg, client=unauthorized_client(tmp_path)))
lines = {
tuple(c["photos"]): c
for c in web.get("/api/state").json()["catalog"]
if c["title_raw"] == "WIZ-WAR"
}
assert lines[("a.jpg",)]["version_status"] == "version_unknown"
assert lines[("b.jpg",)]["version_status"] == "version_ambiguous"