"Wrong game" re-searches on the spot; resolve explains what it won't do
Eric pressed wrong-game on both rows, ran resolve, and resolve truthfully found "nothing to match" — unmatched is a human-owned state it refuses to touch, but the button's name promised a re-match and the pipeline was the natural place to seek one. reopen_match now clears the match AND re-searches immediately (merged depunct search, sibling editions included, stats attached), returning the row as an ambiguous ballot on the very card the button lives on; if BGG is unreachable it reopens bare with a visible warning, and re-search/manual-id remain. run_resolve's summary now says out loud that unmatched rows wait for the human — it never overrides a decision, including "this is wrong." Data: the two stranded WIZ-WAR rows re-searched into ballots — both cards now offer all three lineages, awaiting Eric's picks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
1dd72d2688
commit
481fa63488
+2
-2
@@ -83,7 +83,7 @@ Poetry for Neanderthals,312786,Poetry for Neanderthals,2020,boardgame,auto,,,ver
|
|||||||
Elite Sportz Equipment Table Top Curling,,,,,local,,,,[],[],IMG_4526.jpeg,,
|
Elite Sportz Equipment Table Top Curling,,,,,local,,,,[],[],IMG_4526.jpeg,,
|
||||||
Simon's Cat Card Game,188614,Simon's Cat Card Game,2016,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 188614, ""name"": ""Simon's Cat Card Game"", ""year"": 2016, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 1429, ""rank"": 12119}, {""bgg_id"": 330317, ""name"": ""NOM: Simon's Cat Card Game"", ""year"": 2021, ""type"": ""boardgame"", ""exact"": false, ""fuzzy"": 91.3, ""owned"": 70, ""rank"": null}]","[{""version_id"": 292307, ""name"": ""English edition, first printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 779792, ""name"": ""English edition, second printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4526.jpeg,,
|
Simon's Cat Card Game,188614,Simon's Cat Card Game,2016,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 188614, ""name"": ""Simon's Cat Card Game"", ""year"": 2016, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 1429, ""rank"": 12119}, {""bgg_id"": 330317, ""name"": ""NOM: Simon's Cat Card Game"", ""year"": 2021, ""type"": ""boardgame"", ""exact"": false, ""fuzzy"": 91.3, ""owned"": 70, ""rank"": null}]","[{""version_id"": 292307, ""name"": ""English edition, first printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 779792, ""name"": ""English edition, second printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4526.jpeg,,
|
||||||
The Red Dragon Inn: Smorgasbox,273240,The Red Dragon Inn Smorgasbox,2019,boardgame,auto,446069,Kickstarter edition,version_approved,"[{""bgg_id"": 273240, ""name"": ""The Red Dragon Inn Smorgasbox"", ""year"": 2019, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 446786, ""name"": ""Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446788, ""name"": ""Eco-Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446787, ""name"": ""Eco-Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446069, ""name"": ""Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4527.jpeg,,
|
The Red Dragon Inn: Smorgasbox,273240,The Red Dragon Inn Smorgasbox,2019,boardgame,auto,446069,Kickstarter edition,version_approved,"[{""bgg_id"": 273240, ""name"": ""The Red Dragon Inn Smorgasbox"", ""year"": 2019, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 446786, ""name"": ""Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446788, ""name"": ""Eco-Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446787, ""name"": ""Eco-Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446069, ""name"": ""Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4527.jpeg,,
|
||||||
WIZ-WAR,589,Wiz-War,1983,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 360420, ""name"": ""Third edition"", ""year"": 1986, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 29214, ""name"": ""Fourth edition"", ""year"": 1987, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26114, ""name"": ""Fifth edition"", ""year"": 1991, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 188937, ""name"": ""First edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360421, ""name"": ""Second edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 27352, ""name"": ""Chessex sixth edition"", ""year"": 1993, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 28612, ""name"": ""Chessex classic edition 1997"", ""year"": 1997, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}]",IMG_4528.jpeg,,
|
WIZ-WAR,,,,,ambiguous,,,,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 2076, ""rank"": 3049}, {""bgg_id"": 324937, ""name"": ""Wiz-War (9th Edition)"", ""year"": 2023, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 53.8, ""owned"": 482, ""rank"": 11443}, {""bgg_id"": 104710, ""name"": ""Wiz-War (Eighth Edition)"", ""year"": 2012, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 48.3, ""owned"": 7742, ""rank"": 1266}]",[],IMG_4528.jpeg,,
|
||||||
RISK THE LORD OF THE RINGS: The Middle-earth Conquest Game,4324,Risk: The Lord of the Rings,2002,boardgame,auto,26859,English edition 2002,version_approved,"[{""bgg_id"": 4324, ""name"": ""Risk: The Lord of the Rings"", ""year"": 2002, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 57.1, ""owned"": null, ""rank"": null}]","[{""version_id"": 33264, ""name"": ""English (UK) edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26859, ""name"": ""English edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26863, ""name"": ""English/French edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""English"", ""French""], ""score"": 3}, {""version_id"": 26865, ""name"": ""Danish edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Danish""], ""score"": 2}, {""version_id"": 26861, ""name"": ""Dutch edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Dutch""], ""score"": 2}, {""version_id"": 77144, ""name"": ""French edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""French""], ""score"": 2}, {""version_id"": 26862, ""name"": ""German edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 75135, ""name"": ""Norwegian edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Norwegian""], ""score"": 2}]",IMG_4529.jpeg,,
|
RISK THE LORD OF THE RINGS: The Middle-earth Conquest Game,4324,Risk: The Lord of the Rings,2002,boardgame,auto,26859,English edition 2002,version_approved,"[{""bgg_id"": 4324, ""name"": ""Risk: The Lord of the Rings"", ""year"": 2002, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 57.1, ""owned"": null, ""rank"": null}]","[{""version_id"": 33264, ""name"": ""English (UK) edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26859, ""name"": ""English edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26863, ""name"": ""English/French edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""English"", ""French""], ""score"": 3}, {""version_id"": 26865, ""name"": ""Danish edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Danish""], ""score"": 2}, {""version_id"": 26861, ""name"": ""Dutch edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Dutch""], ""score"": 2}, {""version_id"": 77144, ""name"": ""French edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""French""], ""score"": 2}, {""version_id"": 26862, ""name"": ""German edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 75135, ""name"": ""Norwegian edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Norwegian""], ""score"": 2}]",IMG_4529.jpeg,,
|
||||||
Ouija,,,,,local,,,,[],[],IMG_4529.jpeg,,
|
Ouija,,,,,local,,,,[],[],IMG_4529.jpeg,,
|
||||||
Munchkin Big Box,419687,Munchkin Big Box,2025,boardgame,auto,711400,English edition,version_auto,"[{""bgg_id"": 419687, ""name"": ""Munchkin Big Box"", ""year"": 2025, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 711400, ""name"": ""English edition"", ""year"": 2025, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 777457, ""name"": ""Russian edition"", ""year"": 2025, ""publishers"": [""Hobby World"", ""Steve Jackson Games""], ""languages"": [""Russian""], ""score"": 2}]",IMG_4530.jpeg,,
|
Munchkin Big Box,419687,Munchkin Big Box,2025,boardgame,auto,711400,English edition,version_auto,"[{""bgg_id"": 419687, ""name"": ""Munchkin Big Box"", ""year"": 2025, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 711400, ""name"": ""English edition"", ""year"": 2025, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 777457, ""name"": ""Russian edition"", ""year"": 2025, ""publishers"": [""Hobby World"", ""Steve Jackson Games""], ""languages"": [""Russian""], ""score"": 2}]",IMG_4530.jpeg,,
|
||||||
@@ -134,4 +134,4 @@ BOTANY: PERILOUS PERFUMES,417064,Botany: Perilous Perfumes,2024,boardgameexpansi
|
|||||||
Civilization: West Extension Map,2058,Civilization: West Extension Map,1986,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 2058, ""name"": ""Civilization: West Extension Map"", ""year"": 1986, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
Civilization: West Extension Map,2058,Civilization: West Extension Map,1986,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 2058, ""name"": ""Civilization: West Extension Map"", ""year"": 1986, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
||||||
Artistry: Delightful Doorways Mini Expansion,452833,Artistry: Delightful Doorways Mini Expansion,2025,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 452833, ""name"": ""Artistry: Delightful Doorways Mini Expansion"", ""year"": 2025, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
Artistry: Delightful Doorways Mini Expansion,452833,Artistry: Delightful Doorways Mini Expansion,2025,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 452833, ""name"": ""Artistry: Delightful Doorways Mini Expansion"", ""year"": 2025, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
||||||
castle panic wizard's tower,104590,Castle Panic: The Wizard's Tower,2011,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 104590, ""name"": ""Castle Panic: The Wizard's Tower"", ""year"": 2011, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
castle panic wizard's tower,104590,Castle Panic: The Wizard's Tower,2011,boardgameexpansion,auto,,,version_unknown,"[{""bgg_id"": 104590, ""name"": ""Castle Panic: The Wizard's Tower"", ""year"": 2011, ""type"": ""boardgameexpansion"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],,,
|
||||||
WIZ-WAR,589,Wiz-War,1983,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 188937, ""name"": ""First edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360421, ""name"": ""Second edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360420, ""name"": ""Third edition"", ""year"": 1986, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 29214, ""name"": ""Fourth edition"", ""year"": 1987, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 26114, ""name"": ""Fifth edition"", ""year"": 1991, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 27352, ""name"": ""Chessex sixth edition"", ""year"": 1993, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 28612, ""name"": ""Chessex classic edition 1997"", ""year"": 1997, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}]",IMG_4504.jpeg,,
|
WIZ-WAR,,,,,ambiguous,,,,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 2076, ""rank"": 3049}, {""bgg_id"": 324937, ""name"": ""Wiz-War (9th Edition)"", ""year"": 2023, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 53.8, ""owned"": 482, ""rank"": 11443}, {""bgg_id"": 104710, ""name"": ""Wiz-War (Eighth Edition)"", ""year"": 2012, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 48.3, ""owned"": 7742, ""rank"": 1266}]",[],IMG_4504.jpeg,,
|
||||||
|
|||||||
|
@@ -717,6 +717,13 @@ def run_resolve(
|
|||||||
f"Resolved {len(new_rows)} title(s) ({summary or 'nothing new'}); "
|
f"Resolved {len(new_rows)} title(s) ({summary or 'nothing new'}); "
|
||||||
f"skipped {skipped} already in {cfg.matches_path}."
|
f"skipped {skipped} already in {cfg.matches_path}."
|
||||||
)
|
)
|
||||||
|
waiting = sum(1 for r in all_rows if r.get("match_status") == "unmatched")
|
||||||
|
if waiting:
|
||||||
|
typer.echo(
|
||||||
|
f" {waiting} unmatched row(s) wait for YOUR call in review "
|
||||||
|
"(re-search or manual id) — resolve never overrides a human "
|
||||||
|
"decision, including 'this match is wrong'"
|
||||||
|
)
|
||||||
if blocked:
|
if blocked:
|
||||||
typer.echo(
|
typer.echo(
|
||||||
f"\n{len(blocked)} title(s) are waiting on the BGG API "
|
f"\n{len(blocked)} title(s) are waiting on the BGG API "
|
||||||
|
|||||||
+32
-4
@@ -32,6 +32,7 @@ from bggpipe.normalize import normalize_title
|
|||||||
from bggpipe.resolve import (
|
from bggpipe.resolve import (
|
||||||
MatchRow,
|
MatchRow,
|
||||||
TitleEntry,
|
TitleEntry,
|
||||||
|
_merged_candidates,
|
||||||
_score_version,
|
_score_version,
|
||||||
load_titles,
|
load_titles,
|
||||||
read_matches,
|
read_matches,
|
||||||
@@ -369,10 +370,12 @@ class ReviewSession:
|
|||||||
self._save(row)
|
self._save(row)
|
||||||
|
|
||||||
def reopen_match(self, row: dict) -> None:
|
def reopen_match(self, row: dict) -> None:
|
||||||
"""The human says a matched row is the WRONG game: back to the
|
"""The human says a matched row is the WRONG game: clear the match
|
||||||
unmatched queue with a clean slate — manual id and re-search live
|
and immediately re-search so the card comes back as a ballot — the
|
||||||
there. (The .dungeon case: an exact-normalized impostor wins when
|
machine re-OFFERS, only the human re-decides (run_resolve never
|
||||||
the real game never surfaced in the search.)"""
|
touches unmatched rows, so without this the row would just sit).
|
||||||
|
If BGG is unreachable the row still reopens, bare: re-search and
|
||||||
|
manual id remain available on the card."""
|
||||||
row["match_status"] = "unmatched"
|
row["match_status"] = "unmatched"
|
||||||
row["bgg_id"] = ""
|
row["bgg_id"] = ""
|
||||||
row["bgg_name"] = ""
|
row["bgg_name"] = ""
|
||||||
@@ -383,6 +386,31 @@ class ReviewSession:
|
|||||||
row["version_id"] = ""
|
row["version_id"] = ""
|
||||||
row["version_name"] = ""
|
row["version_name"] = ""
|
||||||
row["version_candidates_json"] = "[]"
|
row["version_candidates_json"] = "[]"
|
||||||
|
entry = self.cues_for(row["title_raw"], row["source_photos"]) or TitleEntry(
|
||||||
|
title_raw=row["title_raw"],
|
||||||
|
title_normalized=normalize_title(row["title_raw"]),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
cands = _merged_candidates(self.client, entry, row["title_raw"])[:8]
|
||||||
|
if cands:
|
||||||
|
stats = {
|
||||||
|
t.bgg_id: t
|
||||||
|
for t in self.client.things([c.bgg_id for c in cands], stats=True)
|
||||||
|
}
|
||||||
|
for c in cands:
|
||||||
|
if c.bgg_id in stats:
|
||||||
|
c.owned = stats[c.bgg_id].owned
|
||||||
|
c.rank = stats[c.bgg_id].rank
|
||||||
|
c.publishers = list(stats[c.bgg_id].publishers)
|
||||||
|
row["match_status"] = "ambiguous"
|
||||||
|
row["candidates_json"] = json.dumps(
|
||||||
|
[c.as_json() for c in cands], ensure_ascii=False
|
||||||
|
)
|
||||||
|
except _BGG_ERRORS as err:
|
||||||
|
self._warn(
|
||||||
|
f"re-search unavailable ({err}) — the row is reopened; use "
|
||||||
|
"(f) re-search or (m) manual id on its card"
|
||||||
|
)
|
||||||
self._save(row)
|
self._save(row)
|
||||||
|
|
||||||
def open_version_ballot(self, row: dict) -> int:
|
def open_version_ballot(self, row: dict) -> int:
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<p><b>edit</b> — fix a misread title or add cues you already know (publisher, edition, year, language). A corrected misspelling automatically merges with a correctly-read sighting of the same game from another photo. If the line already had a BGG match, saving re-queues it so resolve searches again with the corrected data.</p>
|
<p><b>edit</b> — fix a misread title or add cues you already know (publisher, edition, year, language). A corrected misspelling automatically merges with a correctly-read sighting of the same game from another photo. If the line already had a BGG match, saving re-queues it so resolve searches again with the corrected data.</p>
|
||||||
<p><b>split into copies</b> — one line, several physical boxes? Splitting makes each photo its own copy, and each copy picks its own edition afterward. Appears on any line whose title was seen in more than one photo. Splitting one game never affects a same-named different edition.</p>
|
<p><b>split into copies</b> — one line, several physical boxes? Splitting makes each photo its own copy, and each copy picks its own edition afterward. Appears on any line whose title was seen in more than one photo. Splitting one game never affects a same-named different edition.</p>
|
||||||
<p><b>pick edition</b> — a matched game with no legible edition cues stays version-less by design (never guess) — but you know which printing your box is. This fetches the game's complete version list into a Review ballot; pick yours there.</p>
|
<p><b>pick edition</b> — a matched game with no legible edition cues stays version-less by design (never guess) — but you know which printing your box is. This fetches the game's complete version list into a Review ballot; pick yours there.</p>
|
||||||
<p><b>wrong match</b> (inside the edit panel) — an auto-match landed on the wrong game (same-name impostors happen). This clears the match and returns the title to Review's unmatched queue, where re-search and manual-id live. Note BGG sometimes splits one game's lineage across entries — Wiz-War's early editions and its FFG remake are separate games — so a copy whose edition isn't on the ballot may belong to the sibling entry.</p>
|
<p><b>wrong match</b> (inside the edit panel) — an auto-match landed on the wrong game (same-name impostors happen). This clears the match, re-searches immediately, and returns the title to Review as a fresh ballot of candidates (including same-named sibling editions); manual-id entry is there too for games BGG's search can't find. Note BGG sometimes splits one game's lineage across entries — Wiz-War's early editions and its FFG remake are separate games — so a copy whose edition isn't on the ballot may belong to the sibling entry.</p>
|
||||||
<p><b>add a game</b> (top of the Titles page) — a game no photo shows: an expansion stored inside a base box, a game away from the shelves. It joins the list like any read (BGG wants base game and expansion as separate collection entries, so boxes that hold both need this for the hidden half), and if a later photo shows it, the sighting merges instead of duplicating.</p>
|
<p><b>add a game</b> (top of the Titles page) — a game no photo shows: an expansion stored inside a base box, a game away from the shelves. It joins the list like any read (BGG wants base game and expansion as separate collection entries, so boxes that hold both need this for the hidden half), and if a later photo shows it, the sighting merges instead of duplicating.</p>
|
||||||
<p><b>remove</b> (inside the edit panel) — for lines that shouldn't exist at all: a book read as a game, box art misread as a title. The line and its matches are discarded and stay gone. This is different from <i>reject</i> on the Review page, which keeps the line visible as "no BGG match" — right for real games BGG doesn't know.</p>
|
<p><b>remove</b> (inside the edit panel) — for lines that shouldn't exist at all: a book read as a game, box art misread as a title. The line and its matches are discarded and stay gone. This is different from <i>reject</i> on the Review page, which keeps the line visible as "no BGG match" — right for real games BGG doesn't know.</p>
|
||||||
<p>Undo: each decision is one record in <code>data/title_edits.json</code>, <code>data/title_splits.json</code>, or <code>data/title_removals.json</code> — delete the record and the next rebuild restores the old state.</p>
|
<p>Undo: each decision is one record in <code>data/title_edits.json</code>, <code>data/title_splits.json</code>, or <code>data/title_removals.json</code> — delete the record and the next rebuild restores the old state.</p>
|
||||||
|
|||||||
@@ -605,3 +605,45 @@ def test_local_decision_keeps_a_real_game_off_bgg(tmp_path):
|
|||||||
(row,) = read_matches(cfg.matches_path)
|
(row,) = read_matches(cfg.matches_path)
|
||||||
assert row["match_status"] == "local"
|
assert row["match_status"] == "local"
|
||||||
assert row["bgg_id"] == "" # a local citizen carries no BGG identity
|
assert row["bgg_id"] == "" # a local citizen carries no BGG identity
|
||||||
|
|
||||||
|
|
||||||
|
def test_reopen_match_returns_a_fresh_ballot(tmp_path):
|
||||||
|
""" "Wrong game" must not strand the row: it re-searches immediately
|
||||||
|
and comes back ambiguous with the candidates on the card — resolve
|
||||||
|
(which never touches unmatched rows) is not part of this loop."""
|
||||||
|
cfg = _setup(
|
||||||
|
tmp_path,
|
||||||
|
[
|
||||||
|
_row(
|
||||||
|
title_raw="WIZ-WAR",
|
||||||
|
match_status="auto",
|
||||||
|
bgg_id="589",
|
||||||
|
bgg_name="Wiz-War",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
session = ReviewSession(
|
||||||
|
cfg, console=quiet_console(), input_fn=scripted(), client=fixture_client()
|
||||||
|
)
|
||||||
|
row = session.rows[0]
|
||||||
|
session.reopen_match(row)
|
||||||
|
assert row["match_status"] == "ambiguous"
|
||||||
|
names = {c["name"] for c in json.loads(row["candidates_json"])}
|
||||||
|
assert "Wiz-War" in names
|
||||||
|
assert any("Eighth Edition" in n for n in names) # the lineages surface
|
||||||
|
# BGG unreachable: the row still reopens, bare but actionable
|
||||||
|
dead = ReviewSession(
|
||||||
|
cfg,
|
||||||
|
console=quiet_console(),
|
||||||
|
input_fn=scripted(),
|
||||||
|
client=BGGClient(
|
||||||
|
cache_dir=tmp_path / "empty",
|
||||||
|
transport=httpx.MockTransport(
|
||||||
|
lambda req: httpx.Response(401, text="Unauthorized")
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
row2 = dead.rows[0]
|
||||||
|
dead.reopen_match(row2)
|
||||||
|
assert row2["match_status"] == "unmatched"
|
||||||
|
assert dead.warnings # the degradation is visible
|
||||||
|
|||||||
Reference in New Issue
Block a user