Post-resolve dedupe: duplicate reads merge, review can veto
Rows resolving to the same (bgg_id, version_id — or both version-
unknown) are the same physical game read twice unless their extraction
cues conflict (two editions stay separate). The survivor is the read
whose transcription matches the BGG name; losers are marked
match_status=merged with a new merged_into column — no row is ever
deleted, and older matches.csv files without the column still read.
Downstream: diff skips merged rows but folds their photos into the
survivor's to_add provenance; enrich and the review passes ignore them.
The web UI gains a Merges section ("Jokin Ha... merged into Joking
Hazard") with a veto (v key) that restores the row as a distinct
approved match, plus a merged catalog chip and header tally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -286,3 +286,41 @@ def test_catalog_and_unresolved_backlog_are_visible(tmp_path):
|
||||
by_title = {c["title_raw"]: c for c in state["catalog"]}
|
||||
assert by_title["Fresh Off The Shelf"]["status"] == "awaiting_resolve"
|
||||
assert by_title["Citadels"]["status"] == "ambiguous"
|
||||
|
||||
|
||||
def test_merge_veto_roundtrip(tmp_path):
|
||||
cfg = make_cfg(tmp_path)
|
||||
rows = read_matches(cfg.matches_path)
|
||||
rows.append(
|
||||
_row(
|
||||
title_raw="Jokin Ha...",
|
||||
match_status="merged",
|
||||
bgg_id="193621",
|
||||
bgg_name="Joking Hazard",
|
||||
source_photos="shelf.jpg",
|
||||
)
|
||||
)
|
||||
rows[-1]["merged_into"] = "Joking Hazard"
|
||||
write_matches(cfg.matches_path, rows)
|
||||
web = TestClient(create_app(cfg, client=unauthorized_client(tmp_path)))
|
||||
|
||||
state = web.get("/api/state").json()
|
||||
(merge,) = state["merges"]
|
||||
assert merge["title_raw"] == "Jokin Ha..."
|
||||
assert merge["merged_into"] == "Joking Hazard"
|
||||
|
||||
state = web.post(
|
||||
"/api/veto-merge",
|
||||
json={"title_raw": "Jokin Ha...", "source_photos": "shelf.jpg"},
|
||||
).json()
|
||||
assert state["merges"] == []
|
||||
saved = {r["title_raw"]: r for r in read_matches(cfg.matches_path)}
|
||||
assert saved["Jokin Ha..."]["match_status"] == "approved"
|
||||
assert saved["Jokin Ha..."]["merged_into"] == ""
|
||||
|
||||
# veto on a non-merged row is refused
|
||||
bad = web.post(
|
||||
"/api/veto-merge",
|
||||
json={"title_raw": "Jokin Ha...", "source_photos": "shelf.jpg"},
|
||||
)
|
||||
assert bad.status_code == 400
|
||||
|
||||
Reference in New Issue
Block a user