The retry badge stops offering jobs the human retired

Marking the D&D blue box "local" removed its job from the queue — but
the badge still counted its old failure and the checkbox still offered
to retry it, because the count read only upload_log.csv. A failure is
retryable only if the job is still queued AND still endorsed by
matches.csv; on Eric's data that's the difference between 2 and 1.

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 23:06:40 -04:00
co-authored by Claude Fable 5
parent 99c1fbf02d
commit 74ecd5059b
5 changed files with 73 additions and 9 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ Walk the Plank!,35505,Walk the Plank!,2013,boardgame,auto,781669,English MDG-431
AGRICOLA,31260,Agricola,2007,boardgame,auto,297589,Z-Man Games English fifth edition,version_auto,"[{""bgg_id"": 31260, ""name"": ""Agricola"", ""year"": 2007, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 297589, ""name"": ""Z-Man Games English fifth edition"", ""year"": 2013, ""publishers"": [""Filosofia Éditions"", ""Lookout Games"", ""Z-Man Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 165308, ""name"": ""999 Games Dutch second edition 2011"", ""year"": 2011, ""publishers"": [""999 Games"", ""Lookout Games""], ""languages"": [""Dutch""], ""score"": 2}, {""version_id"": 266028, ""name"": ""Hobby World Russian first edition"", ""year"": 2013, ""publishers"": [""Hobby World"", ""Lookout Games""], ""languages"": [""Russian""], ""score"": 2}, {""version_id"": 22673, ""name"": ""Lookout Games German first edition"", ""year"": 2007, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 64715, ""name"": ""Lookout Games German second edition 2008 with animeeples"", ""year"": 2008, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 219203, ""name"": ""Lookout Games German seventh edition 2012 with DSP and SdJ"", ""year"": 2012, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 64718, ""name"": ""Lookout Games German third edition 2009 with DSP and SdJ"", ""year"": 2009, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 113858, ""name"": ""Lookout Games Russian first edition 2011"", ""year"": 2011, ""publishers"": [""Lookout Games"", ""Smart Ltd""], ""languages"": [""Russian""], ""score"": 2}]",IMG_4518.jpeg,, AGRICOLA,31260,Agricola,2007,boardgame,auto,297589,Z-Man Games English fifth edition,version_auto,"[{""bgg_id"": 31260, ""name"": ""Agricola"", ""year"": 2007, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 297589, ""name"": ""Z-Man Games English fifth edition"", ""year"": 2013, ""publishers"": [""Filosofia Éditions"", ""Lookout Games"", ""Z-Man Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 165308, ""name"": ""999 Games Dutch second edition 2011"", ""year"": 2011, ""publishers"": [""999 Games"", ""Lookout Games""], ""languages"": [""Dutch""], ""score"": 2}, {""version_id"": 266028, ""name"": ""Hobby World Russian first edition"", ""year"": 2013, ""publishers"": [""Hobby World"", ""Lookout Games""], ""languages"": [""Russian""], ""score"": 2}, {""version_id"": 22673, ""name"": ""Lookout Games German first edition"", ""year"": 2007, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 64715, ""name"": ""Lookout Games German second edition 2008 with animeeples"", ""year"": 2008, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 219203, ""name"": ""Lookout Games German seventh edition 2012 with DSP and SdJ"", ""year"": 2012, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 64718, ""name"": ""Lookout Games German third edition 2009 with DSP and SdJ"", ""year"": 2009, ""publishers"": [""Lookout Games""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 113858, ""name"": ""Lookout Games Russian first edition 2011"", ""year"": 2011, ""publishers"": [""Lookout Games"", ""Smart Ltd""], ""languages"": [""Russian""], ""score"": 2}]",IMG_4518.jpeg,,
METEOR,166109,Meteor,2014,boardgame,auto,,,version_unknown,"[{""bgg_id"": 25172, ""name"": ""Meteor"", ""year"": 1975, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 56, ""rank"": null}, {""bgg_id"": 166109, ""name"": ""Meteor"", ""year"": 2014, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 1396, ""rank"": 10371}, {""bgg_id"": 246740, ""name"": ""Meteors"", ""year"": 2018, ""type"": ""boardgame"", ""exact"": false, ""fuzzy"": 92.3, ""owned"": 71, ""rank"": 25541}]",[],IMG_4518.jpeg,, METEOR,166109,Meteor,2014,boardgame,auto,,,version_unknown,"[{""bgg_id"": 25172, ""name"": ""Meteor"", ""year"": 1975, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 56, ""rank"": null}, {""bgg_id"": 166109, ""name"": ""Meteor"", ""year"": 2014, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 1396, ""rank"": 10371}, {""bgg_id"": 246740, ""name"": ""Meteors"", ""year"": 2018, ""type"": ""boardgame"", ""exact"": false, ""fuzzy"": 92.3, ""owned"": 71, ""rank"": 25541}]",[],IMG_4518.jpeg,,
DOCTOR WHO THE card GAME,125675,Doctor Who: The Card Game,2012,boardgame,auto,,,version_unknown,"[{""bgg_id"": 125675, ""name"": ""Doctor Who: The Card Game"", ""year"": 2012, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4518.jpeg,, DOCTOR WHO THE card GAME,125675,Doctor Who: The Card Game,2012,boardgame,auto,,,version_unknown,"[{""bgg_id"": 125675, ""name"": ""Doctor Who: The Card Game"", ""year"": 2012, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4518.jpeg,,
DUNGEONS & DRAGONS,140509,Dungeons & Dragons,1985,boardgame,auto,,,version_unknown,"[{""bgg_id"": 140509, ""name"": ""Dungeons & Dragons"", ""year"": 1985, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4519.jpeg,, DUNGEONS & DRAGONS,,,,,local,,,,"[{""bgg_id"": 140509, ""name"": ""Dungeons & Dragons"", ""year"": 1985, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 65, ""rank"": null}]",[],IMG_4519.jpeg,,
DUNGEONS & DRAGONS FANTASY GAME RULES,,,,,local,,,,[],[],IMG_4519.jpeg,, DUNGEONS & DRAGONS FANTASY GAME RULES,,,,,local,,,,[],[],IMG_4519.jpeg,,
"Before I Kill You, Mister Bond...",164,"Before I Kill You, Mister Bond",1996,boardgame,auto,28465,"Cheapass black and white ""Better Edition"" edition",version_auto,"[{""bgg_id"": 164, ""name"": ""Before I Kill You, Mister Bond"", ""year"": 1996, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 28465, ""name"": ""Cheapass black and white \""Better Edition\"" edition"", ""year"": 2001, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 5}, {""version_id"": 291316, ""name"": ""English edition 2016"", ""year"": 2016, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 520361, ""name"": ""English second edition"", ""year"": 1997, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 28459, ""name"": ""First \""Renamed\"" edition, First color edition"", ""year"": 2004, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 180392, ""name"": ""First black and white envelope edition"", ""year"": 1996, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 28462, ""name"": ""Third black and white edition"", ""year"": 1998, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4519.jpeg;IMG_4554.jpeg,, "Before I Kill You, Mister Bond...",164,"Before I Kill You, Mister Bond",1996,boardgame,auto,28465,"Cheapass black and white ""Better Edition"" edition",version_auto,"[{""bgg_id"": 164, ""name"": ""Before I Kill You, Mister Bond"", ""year"": 1996, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 28465, ""name"": ""Cheapass black and white \""Better Edition\"" edition"", ""year"": 2001, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 5}, {""version_id"": 291316, ""name"": ""English edition 2016"", ""year"": 2016, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 520361, ""name"": ""English second edition"", ""year"": 1997, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 28459, ""name"": ""First \""Renamed\"" edition, First color edition"", ""year"": 2004, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 180392, ""name"": ""First black and white envelope edition"", ""year"": 1996, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 28462, ""name"": ""Third black and white edition"", ""year"": 1998, ""publishers"": [""Cheapass Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4519.jpeg;IMG_4554.jpeg,,
MYSTERIUM,181304,Mysterium,2015,boardgame,auto,536289,English edition 2018-2,version_approved,"[{""bgg_id"": 181304, ""name"": ""Mysterium"", ""year"": 2015, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 85034, ""rank"": 454}, {""bgg_id"": 113997, ""name"": ""Mysterium"", ""year"": 2013, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 5494, ""rank"": 1143}]","[{""version_id"": 781306, ""name"": ""English 2025 Refresh Edition"", ""year"": 2025, ""publishers"": [""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 280251, ""name"": ""English edition 2015-1"", ""year"": 2015, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 493543, ""name"": ""English edition 2015-2"", ""year"": 2015, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 475162, ""name"": ""English edition 2016-1"", ""year"": 2016, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 351093, ""name"": ""English edition 2017-1"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 467608, ""name"": ""English edition 2017-2"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 404443, ""name"": ""English edition 2017-3"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 536289, ""name"": ""English edition 2018-2"", ""year"": 2018, ""publishers"": [""Libellud""], ""languages"": [""English""], ""score"": 3}]",IMG_4520.jpeg,, MYSTERIUM,181304,Mysterium,2015,boardgame,auto,536289,English edition 2018-2,version_approved,"[{""bgg_id"": 181304, ""name"": ""Mysterium"", ""year"": 2015, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 85034, ""rank"": 454}, {""bgg_id"": 113997, ""name"": ""Mysterium"", ""year"": 2013, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 5494, ""rank"": 1143}]","[{""version_id"": 781306, ""name"": ""English 2025 Refresh Edition"", ""year"": 2025, ""publishers"": [""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 280251, ""name"": ""English edition 2015-1"", ""year"": 2015, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 493543, ""name"": ""English edition 2015-2"", ""year"": 2015, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 475162, ""name"": ""English edition 2016-1"", ""year"": 2016, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 351093, ""name"": ""English edition 2017-1"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 467608, ""name"": ""English edition 2017-2"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 404443, ""name"": ""English edition 2017-3"", ""year"": 2017, ""publishers"": [""Esdevium"", ""Libellud""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 536289, ""name"": ""English edition 2018-2"", ""year"": 2018, ""publishers"": [""Libellud""], ""languages"": [""English""], ""score"": 3}]",IMG_4520.jpeg,,
1 title_raw bgg_id bgg_name year type match_status version_id version_name version_status candidates_json version_candidates_json source_photos merged_into dedupe_veto
63 AGRICOLA 31260 Agricola 2007 boardgame auto 297589 Z-Man Games English fifth edition version_auto [{"bgg_id": 31260, "name": "Agricola", "year": 2007, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": null, "rank": null}] [{"version_id": 297589, "name": "Z-Man Games English fifth edition", "year": 2013, "publishers": ["Filosofia Éditions", "Lookout Games", "Z-Man Games"], "languages": ["English"], "score": 3}, {"version_id": 165308, "name": "999 Games Dutch second edition 2011", "year": 2011, "publishers": ["999 Games", "Lookout Games"], "languages": ["Dutch"], "score": 2}, {"version_id": 266028, "name": "Hobby World Russian first edition", "year": 2013, "publishers": ["Hobby World", "Lookout Games"], "languages": ["Russian"], "score": 2}, {"version_id": 22673, "name": "Lookout Games German first edition", "year": 2007, "publishers": ["Lookout Games"], "languages": ["German"], "score": 2}, {"version_id": 64715, "name": "Lookout Games German second edition 2008 with animeeples", "year": 2008, "publishers": ["Lookout Games"], "languages": ["German"], "score": 2}, {"version_id": 219203, "name": "Lookout Games German seventh edition 2012 with DSP and SdJ", "year": 2012, "publishers": ["Lookout Games"], "languages": ["German"], "score": 2}, {"version_id": 64718, "name": "Lookout Games German third edition 2009 with DSP and SdJ", "year": 2009, "publishers": ["Lookout Games"], "languages": ["German"], "score": 2}, {"version_id": 113858, "name": "Lookout Games Russian first edition 2011", "year": 2011, "publishers": ["Lookout Games", "Smart Ltd"], "languages": ["Russian"], "score": 2}] IMG_4518.jpeg
64 METEOR 166109 Meteor 2014 boardgame auto version_unknown [{"bgg_id": 25172, "name": "Meteor", "year": 1975, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": 56, "rank": null}, {"bgg_id": 166109, "name": "Meteor", "year": 2014, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": 1396, "rank": 10371}, {"bgg_id": 246740, "name": "Meteors", "year": 2018, "type": "boardgame", "exact": false, "fuzzy": 92.3, "owned": 71, "rank": 25541}] [] IMG_4518.jpeg
65 DOCTOR WHO THE card GAME 125675 Doctor Who: The Card Game 2012 boardgame auto version_unknown [{"bgg_id": 125675, "name": "Doctor Who: The Card Game", "year": 2012, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": null, "rank": null}] [] IMG_4518.jpeg
66 DUNGEONS & DRAGONS 140509 Dungeons & Dragons 1985 boardgame auto local version_unknown [{"bgg_id": 140509, "name": "Dungeons & Dragons", "year": 1985, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": null, "rank": null}] [{"bgg_id": 140509, "name": "Dungeons & Dragons", "year": 1985, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": 65, "rank": null}] [] IMG_4519.jpeg
67 DUNGEONS & DRAGONS FANTASY GAME RULES local [] [] IMG_4519.jpeg
68 Before I Kill You, Mister Bond... 164 Before I Kill You, Mister Bond 1996 boardgame auto 28465 Cheapass black and white "Better Edition" edition version_auto [{"bgg_id": 164, "name": "Before I Kill You, Mister Bond", "year": 1996, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": null, "rank": null}] [{"version_id": 28465, "name": "Cheapass black and white \"Better Edition\" edition", "year": 2001, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 5}, {"version_id": 291316, "name": "English edition 2016", "year": 2016, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 3}, {"version_id": 520361, "name": "English second edition", "year": 1997, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 3}, {"version_id": 28459, "name": "First \"Renamed\" edition, First color edition", "year": 2004, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 3}, {"version_id": 180392, "name": "First black and white envelope edition", "year": 1996, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 3}, {"version_id": 28462, "name": "Third black and white edition", "year": 1998, "publishers": ["Cheapass Games"], "languages": ["English"], "score": 3}] IMG_4519.jpeg;IMG_4554.jpeg
69 MYSTERIUM 181304 Mysterium 2015 boardgame auto 536289 English edition 2018-2 version_approved [{"bgg_id": 181304, "name": "Mysterium", "year": 2015, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": 85034, "rank": 454}, {"bgg_id": 113997, "name": "Mysterium", "year": 2013, "type": "boardgame", "exact": true, "fuzzy": 100.0, "owned": 5494, "rank": 1143}] [{"version_id": 781306, "name": "English 2025 Refresh Edition", "year": 2025, "publishers": ["Libellud"], "languages": ["English"], "score": 3}, {"version_id": 280251, "name": "English edition 2015-1", "year": 2015, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 493543, "name": "English edition 2015-2", "year": 2015, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 475162, "name": "English edition 2016-1", "year": 2016, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 351093, "name": "English edition 2017-1", "year": 2017, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 467608, "name": "English edition 2017-2", "year": 2017, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 404443, "name": "English edition 2017-3", "year": 2017, "publishers": ["Esdevium", "Libellud"], "languages": ["English"], "score": 3}, {"version_id": 536289, "name": "English edition 2018-2", "year": 2018, "publishers": ["Libellud"], "languages": ["English"], "score": 3}] IMG_4520.jpeg
+8
View File
@@ -65,3 +65,11 @@ add,291457,,Gloomhaven: Jaws of the Lion,,,added,2026-08-06T02:59:12+00:00,
add,150925,,Hold Your Breath!,,,added,2026-08-06T02:59:18+00:00, add,150925,,Hold Your Breath!,,,added,2026-08-06T02:59:18+00:00,
add,2980,,The Simpsons Trivia Game,,,added,2026-08-06T02:59:23+00:00, add,2980,,The Simpsons Trivia Game,,,added,2026-08-06T02:59:23+00:00,
add,1197,,Blink,,,added,2026-08-06T02:59:29+00:00, add,1197,,Blink,,,added,2026-08-06T02:59:29+00:00,
add,140509,,Dungeons & Dragons,,,failed,2026-08-06T03:05:04+00:00,"TimeoutError: Locator.wait_for: Timeout 15000ms exceeded. Call log: - waiting for get_by_role(""dialog"").get_by_role(""heading"", name=re.compile(r""Dungeons\ \&\ Dragons"", re.IGNORECASE)) to be visible"
add,352819,,The Office Trivia Game,,,added,2026-08-06T03:05:09+00:00,
add,163412,,Patchwork,,,added,2026-08-06T03:05:14+00:00,
add,291847,,Mantis Falls,,,added,2026-08-06T03:05:19+00:00,
add,2058,,Civilization: West Extension Map,,,added,2026-08-06T03:05:24+00:00,
add,452833,,Artistry: Delightful Doorways Mini Expansion,,,added,2026-08-06T03:05:31+00:00,
update,240,53429559,Britannia,24621,,failed,2026-08-06T03:06:04+00:00,"TimeoutError: Locator.click: Timeout 30000ms exceeded. Call log: - waiting for get_by_role(""row"").filter(has_text=re.compile(r""Britannia"", re.IGNORECASE)).first.get_by_role(""link"", name=re.compile(r""own"", re.IGNORECASE)).first"
update,71,53429530,Civilization,24006,,failed,2026-08-06T03:06:39+00:00,"TimeoutError: Locator.click: Timeout 30000ms exceeded. Call log: - waiting for get_by_role(""row"").filter(has_text=re.compile(r""Civilization"", re.IGNORECASE)).first.get_by_role(""link"", name=re.compile(r""own"", re.IGNORECASE)).first"
1 action bgg_id collid name version_id second_copy status timestamp error
65 add 150925 Hold Your Breath! added 2026-08-06T02:59:18+00:00
66 add 2980 The Simpsons Trivia Game added 2026-08-06T02:59:23+00:00
67 add 1197 Blink added 2026-08-06T02:59:29+00:00
68 add 140509 Dungeons & Dragons failed 2026-08-06T03:05:04+00:00 TimeoutError: Locator.wait_for: Timeout 15000ms exceeded. Call log: - waiting for get_by_role("dialog").get_by_role("heading", name=re.compile(r"Dungeons\ \&\ Dragons", re.IGNORECASE)) to be visible
69 add 352819 The Office Trivia Game added 2026-08-06T03:05:09+00:00
70 add 163412 Patchwork added 2026-08-06T03:05:14+00:00
71 add 291847 Mantis Falls added 2026-08-06T03:05:19+00:00
72 add 2058 Civilization: West Extension Map added 2026-08-06T03:05:24+00:00
73 add 452833 Artistry: Delightful Doorways Mini Expansion added 2026-08-06T03:05:31+00:00
74 update 240 53429559 Britannia 24621 failed 2026-08-06T03:06:04+00:00 TimeoutError: Locator.click: Timeout 30000ms exceeded. Call log: - waiting for get_by_role("row").filter(has_text=re.compile(r"Britannia", re.IGNORECASE)).first.get_by_role("link", name=re.compile(r"own", re.IGNORECASE)).first
75 update 71 53429530 Civilization 24006 failed 2026-08-06T03:06:39+00:00 TimeoutError: Locator.click: Timeout 30000ms exceeded. Call log: - waiting for get_by_role("row").filter(has_text=re.compile(r"Civilization", re.IGNORECASE)).first.get_by_role("link", name=re.compile(r"own", re.IGNORECASE)).first
+22 -7
View File
@@ -117,14 +117,29 @@ def stale_jobs(queue_rows: list[dict], match_rows: list[dict]) -> dict[str, str]
return stale return stale
def outstanding_failures(log_rows: list[dict]) -> int: def outstanding_failures(
"""Jobs whose LATEST attempt failed. upload_log.csv is an append-only log_rows: list[dict],
audit trail, so counting every 'failed' row ever written would keep queue_rows: list[dict] | None = None,
growing after a successful retry.""" match_rows: list[dict] | None = None,
last: dict[tuple[str, str, str], str] = {} ) -> int:
"""Failures still worth retrying: the job's LATEST attempt failed AND
it is still queued and still endorsed by matches.csv.
Two ways to over-count. upload_log.csv is append-only, so a successful
retry leaves its old 'failed' line behind; and a failed job whose
review decision has since changed (marked local, rejected) is not
pending work at all — it will never run again, so offering to retry it
is a lie."""
last: dict[tuple[str, str, str], tuple[str, str]] = {}
for row in log_rows: for row in log_rows:
last[_job_key(row)] = row["status"] last[_job_key(row)] = (row["status"], row.get("bgg_id", ""))
return sum(1 for status in last.values() if status == "failed") failed = [bgg_id for status, bgg_id in last.values() if status == "failed"]
if queue_rows is None:
return len(failed)
live = {r.get("bgg_id", "") for r in queue_rows} - set(
stale_jobs(queue_rows, match_rows or [])
)
return sum(1 for bgg_id in failed if bgg_id in live)
def _read_csv(path: Path) -> list[dict]: def _read_csv(path: Path) -> list[dict]:
+12 -1
View File
@@ -793,7 +793,18 @@ def create_app(
with log_path.open(newline="") as f: with log_path.open(newline="") as f:
log_rows = list(csv.DictReader(f)) log_rows = list(csv.DictReader(f))
log_counts = Counter(row["status"] for row in log_rows) log_counts = Counter(row["status"] for row in log_rows)
failed_now = outstanding_failures(log_rows)
def _csv_rows(path: Path) -> list[dict]:
if not path.exists():
return []
with path.open(newline="") as handle:
return list(csv.DictReader(handle))
failed_now = outstanding_failures(
log_rows,
_csv_rows(cfg.to_add_path) + _csv_rows(cfg.to_update_path),
session.rows,
)
games = len(read_games()) games = len(read_games())
return { return {
"boot": boot, "boot": boot,
+30
View File
@@ -773,3 +773,33 @@ def test_stale_queue_jobs_are_skipped(tmp_path):
assert "no longer matched" in stale["999"] assert "no longer matched" in stale["999"]
# unverifiable (no matches.csv at all) never condemns a job # unverifiable (no matches.csv at all) never condemns a job
assert stale_jobs(queue, []) == {} assert stale_jobs(queue, []) == {}
def test_failure_badge_ignores_jobs_the_human_retired():
"""A failed job whose review decision has since changed will never run
again — offering to retry it is a lie the badge kept telling."""
from bggpipe.upload import outstanding_failures
log = [
{
"action": "add",
"bgg_id": "13",
"collid": "",
"version_id": "",
"status": "failed",
},
{
"action": "add",
"bgg_id": "140509",
"collid": "",
"version_id": "",
"status": "failed",
},
]
queue = [{"bgg_id": "13"}, {"bgg_id": "140509"}]
matches = [
{"bgg_id": "13", "match_status": "auto"},
{"bgg_id": "", "match_status": "local"}, # 140509 was made local
]
assert outstanding_failures(log) == 2 # log-only view: both look pending
assert outstanding_failures(log, queue, matches) == 1 # only the live one