Audit round 7, upload cluster: evidence over inference at every exit
Five blind reviewers swept the real-data-era surface; this lands the upload findings, all verified against the code and the documented site behavior before fixing. The two HIGHs shared a root: logging outcomes the browser never proved. add_game waited for an "Add To" button that an owned game's page does not have — so a second-copy add could never succeed, and worse, an add that LANDED but missed the log became an unretryable failure loop (every retry: 30s timeout, logged failed, nothing ever settles). add_game now polls for either button state: "In Collections" without second_copy returns the previously-dead already_present status (the landed-but-unlogged case heals itself on retry); with second_copy it refuses loudly (that flow is unverified — add by hand). A save whose dialog is slow to hide reloads the page and asks for ownership evidence instead of guessing "failed". update_entry no longer trusts the editor merely closing: the cell must settle on text matching the CHOSEN version, else the AJAX save failed server-side and "updated" would mark a job done forever that never touched the site. Per-copy bookkeeping: stale_jobs endorsed per game, so rejecting one of two queued editions let the rejected copy upload on the survivor's endorsement — it now counts endorsements per (bgg_id, version) and retires the game with "re-run diff" when a copy loses its backing. annotate_queue stamped every row sharing a job key with the same log status, so one success marked both vetoed duplicates done; completions are now claimed one row per done log line. Smaller findings: the version-drift note queued a doomed re-add after warning about it (now skips — the entry exists on BGG; re-adding only duplicates); the one-update-per-game deferral rested on a claim the collid-exact editor disproves (removed — same-game updates run together); the 3-identical-failures abort compared exception class only, so three unrelated problems aborted a healthy run (now compares whole messages). Also from the test seat: run_upload's stale filtering finally executes against a real matches.csv in tests; rejected credentials pin that no anonymous storage state is saved; update_entry's three guarded exits each have a test; _scrub's newline flattening is pinned. 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
22fa17b5ee
commit
32b6aae841
@@ -9,6 +9,7 @@ from bggpipe.models import (
|
||||
parse_collection,
|
||||
parse_search,
|
||||
parse_things,
|
||||
parse_things_full,
|
||||
)
|
||||
|
||||
SEARCH_XML = """<items total="2">
|
||||
@@ -134,3 +135,41 @@ def test_search_partial_malformed_tolerated_with_warning():
|
||||
with pytest.warns(UserWarning, match="unparseable"):
|
||||
results = parse_search(xml)
|
||||
assert [r.bgg_id for r in results] == [13]
|
||||
|
||||
|
||||
def test_parse_search_dedupes_multitype_duplicates_preferring_specific():
|
||||
"""A multi-type search lists an expansion under BOTH types; keeping the
|
||||
bare-boardgame copy would erode the base-vs-expansion guard."""
|
||||
xml = """<items total="2">
|
||||
<item type="boardgame" id="290448">
|
||||
<name type="primary" value="Wingspan: European Expansion"/>
|
||||
</item>
|
||||
<item type="boardgameexpansion" id="290448">
|
||||
<name type="primary" value="Wingspan: European Expansion"/>
|
||||
</item>
|
||||
</items>"""
|
||||
(result,) = parse_search(xml)
|
||||
assert result.type == "boardgameexpansion"
|
||||
|
||||
|
||||
def test_parse_things_full_reads_rpggeek_link_vocabulary():
|
||||
"""RPGGeek items use their own link types; a board-game-only reader
|
||||
silently returns nothing for them."""
|
||||
xml = """<items>
|
||||
<item type="rpgitem" id="311654">
|
||||
<name type="primary" sortindex="1" value="Alice is Missing"/>
|
||||
<yearpublished value="2020"/>
|
||||
<link type="rpgdesigner" id="1" value="Spenser Starke"/>
|
||||
<link type="rpgpublisher" id="2" value="Hunters Entertainment"/>
|
||||
<link type="rpggenre" id="3" value="Modern"/>
|
||||
<link type="rpgcategory" id="4" value="Core Rules (min needed to play)"/>
|
||||
<link type="rpgmechanic" id="5" value="Card Play"/>
|
||||
<link type="rpgproducer" id="6" value="Someone"/>
|
||||
</item>
|
||||
</items>"""
|
||||
(game,) = parse_things_full(xml)
|
||||
assert game["designers"] == ["Spenser Starke"]
|
||||
assert game["publishers"] == ["Hunters Entertainment"]
|
||||
assert game["categories"] == ["Modern", "Core Rules (min needed to play)"]
|
||||
assert game["mechanics"] == ["Card Play"]
|
||||
assert game["producers"] == ["Someone"]
|
||||
|
||||
Reference in New Issue
Block a user