First real upload lands: three browser-flow bugs, found by doing it

A Gentle Rain is on BGG (collid 148198034, version 701315 — the
English Bloom edition matched from a shelf photo), verified by
re-fetching the collection. The failures on the way, all in the
login gate the docs called "verified" and none in the version-picker
code they called "unverified":

1. BGG's Sign In is an <a class="btn"> with NO href, so it has no
   implicit link role: get_by_role("link", name="Sign In") matched
   zero elements in EVERY state, and "no Sign In link" was read as
   "already signed in". Every run browsed anonymously.
2. The header hydrates after domcontentloaded, so for a moment
   neither control exists — a check resting on one absence guesses.
   _signed_out() now polls until the page proves one state or the
   other (Sign In vs Sign Out) and raises after 30s rather than
   assume; login is verified by the transition, and the session file
   saves only after that proof.
3. get_by_label("Own") also matched "Prev. Owned" — strict-mode
   violation; the Own checkbox is now matched exactly.

Also: Playwright's multi-line call logs no longer break upload_log.csv
into ragged rows (errors flatten to one line). Three unit tests cover
the hydration window, positive detection, and the undeterminable case.

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 22:22:11 -04:00
co-authored by Claude Fable 5
parent 481fa63488
commit 6ae2667c58
6 changed files with 206 additions and 24 deletions
+13 -13
View File
File diff suppressed because one or more lines are too long
+61 -4
View File
@@ -1,7 +1,64 @@
bgg_id,bgg_name,year,type,version_id,version_name,title_raw,source_photos,second_copy
235096,Cat Crimes,2017,boardgame,360982,English edition,CAT CRIMES,IMG_4499.jpeg;IMG_4505.jpeg,
268163,A Gentle Rain,2019,boardgame,268164,Bloom Edition,a Gentle Rain,IMG_4501.jpeg;IMG_4507.jpeg,
334011,A Gentle Rain,2021,boardgame,701315,English Bloom edition,a Gentle Rain,IMG_4501.jpeg;IMG_4507.jpeg,
589,Wiz-War,1983,boardgame,27352,Chessex sixth edition,Wiz-War,IMG_4502.jpeg,
125921,Catan: Junior,2012,boardgame,476263,English third edition,CATAN JUNIOR,IMG_4516.jpeg,
31260,Agricola,2007,boardgame,297589,Z-Man Games English fifth edition,AGRICOLA,IMG_4518.jpeg,
181304,Mysterium,2015,boardgame,536289,English edition 2018-2,MYSTERIUM,IMG_4520.jpeg,
312786,Poetry for Neanderthals,2020,boardgame,514050,English edition 2020,Poetry for Neanderthals,IMG_4526.jpeg,
273240,The Red Dragon Inn Smorgasbox,2019,boardgame,446069,Kickstarter edition,The Red Dragon Inn: Smorgasbox,IMG_4527.jpeg,
419687,Munchkin Big Box,2025,boardgame,711400,English edition,Munchkin Big Box,IMG_4530.jpeg,
252153,Tang Garden,2019,boardgame,404702,English edition,Tang Garden,IMG_4533.jpeg,
255984,Sleeping Gods,2021,boardgame,701034,English Gamefound edition,Sleeping Gods,IMG_4534.jpeg,
283766,Sleeping Gods: Tides of Ruin,2021,boardgame,463140,English edition,Sleeping Gods: Tides of Ruin,IMG_4534.jpeg,
280794,Etherfields,2020,boardgame,458300,English edition,ETHERFIELDS,IMG_4535.jpeg,
380837,Botany,2024,boardgame,650545,English edition,BOTANY,IMG_4536.jpeg,
393672,Gloomhaven: Buttons & Bugs,2024,boardgame,669782,English edition,GLOOMHAVEN Buttons & Bugs,IMG_4537.jpeg,
14535,SPANC: Space Pirate Amazon Ninja Catgirls,2005,boardgame,29075,English first edition,SPANC Space Pirate Amazon Ninja Catgirls,IMG_4537.jpeg,
9666,Greed Quest,2004,boardgame,215137,English edition,Greed Quest,IMG_4537.jpeg,
40508,Scrabble Slam!,2008,boardgame,644326,English edition with Hasbro logo,SCRABBLE SLAM!,IMG_4543.jpeg,
3181,Farkle,1930,boardgame,87931,Legendary Games cannister edition,POCKET FARKEL,IMG_4545.jpeg,
193485,Dastardly Dirigibles,2016,boardgame,300446,English edition,Dastardly Dirigibles,IMG_4548.jpeg,
226065,Sheriff of Nottingham: Merry Men,2017,boardgame,353389,English edition,SHERIFF OF NOTTINGHAM MERRY MEN,IMG_4550.jpeg,
143884,Machi Koro,2012,boardgame,453051,"English fifth anniversary edition, first printing",MACHI KORO,IMG_4551.jpeg,
358880,Etherfields: Kittenburg Expansion,2022,boardgame,603694,English edition,ETHERFIELDS KITTENBURG EXPANSION,IMG_4570.jpeg,
432858,Artistry,2025,boardgame,734890,English edition,ARTISTRY,IMG_4515.jpeg,
417060,Botany: Tantalizing Trees,2024,boardgameexpansion,706506,English edition,BOTANY: TANTALIZING TREES,IMG_4571.jpeg,
417064,Botany: Perilous Perfumes,2024,boardgameexpansion,706510,English edition,BOTANY: PERILOUS PERFUMES,IMG_4571.jpeg,
161928,Utter Nonsense,2014,boardgame,,,Utter Nonsense!,IMG_4501.jpeg;IMG_4507.jpeg;IMG_4556.jpeg,
50381,Cards Against Humanity,2009,boardgame,,,Cards Against Humanity,IMG_4501.jpeg;IMG_4556.jpeg,
1078,Skip-Bo,1967,boardgame,,,SKIP-BO,IMG_4501.jpeg;IMG_4542.jpeg,
218866,Scrawl,2017,boardgame,,,SCRAWL,IMG_4502.jpeg,
1269,Skip-Bo,1967,boardgame,,,SKIP-BO,IMG_4501.jpeg;IMG_4542.jpeg,
202982,Scrawl,2016,boardgame,,,SCRAWL,IMG_4502.jpeg,
195314,Herbaceous,2017,boardgame,,,Herbaceous,IMG_4507.jpeg,
320202,Dragon Land,2020,boardgame,,,Dragon Land,IMG_4508.jpeg;IMG_4542.jpeg,
2452,Jenga,1983,boardgame,,,Jenga,IMG_4509.jpeg,
42063,Code Master,1997,boardgame,,,CODE MASTER,IMG_4510.jpeg,
340420,Throw Throw Avocado,2021,boardgame,,,THROW THROW AVOCADO,IMG_4511.jpeg,
1260,Rook,1906,boardgame,,,ROOK,IMG_4511.jpeg,
116,Guillotine,1998,boardgame,,,Guillotine,IMG_4512.jpeg,
169124,Flick 'em Up!,2015,boardgame,,,Flick'em UP!,IMG_4513.jpeg,
20866,The Rocky Horror Trivia Game,2005,boardgame,,,The Rocky Horror Trivia Game,IMG_4514.jpeg,
269564,Captain Marvel: Secret Skrulls,2019,boardgame,,,CAPTAIN MARVEL SECRET SKRULLS,IMG_4516.jpeg,
18755,Pie Face!,1964,boardgame,,,Pie Face!,IMG_4517.jpeg,
140509,Dungeons & Dragons,1985,boardgame,,,DUNGEONS & DRAGONS,IMG_4519.jpeg,
201248,Evolution: The Beginning,2016,boardgame,,,evolution The Beginning,IMG_4520.jpeg,
362205,Sleeping Gods: Primeval Peril,2023,boardgame,,,Sleeping Gods PRIMEVAL PERIL,IMG_4521.jpeg,
453845,Murder at the Manor,2021,boardgame,,,Murder at the Manor,IMG_4522.jpeg,
329230,Bluffaneer,2021,boardgame,,,Bluffaneer,IMG_4522.jpeg,
358320,Sleeping Gods: Distant Skies,2023,boardgame,,,Sleeping Gods DISTANT SKIES,IMG_4523.jpeg,
389113,Rivals,2025,boardgame,,,THE RIVALS FOR CATAN CARD GAME,IMG_4523.jpeg,
324937,Wiz-War (9th Edition),2023,boardgame,,,WIZ-WAR,IMG_4528.jpeg,
295770,Frosthaven,2022,boardgame,,,FROSTHAVEN,IMG_4531.jpeg,
174430,Gloomhaven,2017,boardgame,,,GLOOMHAVEN,IMG_4532.jpeg,
442312,Deadly Doodles,2025,boardgame,,,DEADLY DOODLES,IMG_4533.jpeg,
332398,Everdell: The Complete Collection,2022,boardgame,,,Everdell The Complete Collection,IMG_4533.jpeg,
334065,Verdant,2022,boardgame,,,Verdant,IMG_4534.jpeg,
283155,Calico,2020,boardgame,,,Calico,IMG_4534.jpeg,
291457,Gloomhaven: Jaws of the Lion,2020,boardgame,,,GLOOMHAVEN - Jaws of the Lion,IMG_4538.jpeg,
150925,Hold Your Breath!,2014,boardgame,,,Hold your Breath!,IMG_4547.jpeg,
2980,The Simpsons Trivia Game,2000,boardgame,,,The Simpsons Trivia Game,shelf-20260803-213735.jpg,
1197,Blink,1995,boardgame,,,BLINK,shelf-20260803-215650.jpg,
352819,The Office Trivia Game,2019,boardgame,,,The Office Trivia Game,shelf-20260803-215703.jpg,
163412,Patchwork,2014,boardgame,,,Patchwork,IMG_4501.jpeg,
291847,Mantis Falls,2021,boardgame,,,MANTIS FALLS,IMG_4505.jpeg,
2058,Civilization: West Extension Map,1986,boardgameexpansion,,,Civilization: West Extension Map,,
452833,Artistry: Delightful Doorways Mini Expansion,2025,boardgameexpansion,,,Artistry: Delightful Doorways Mini Expansion,,
1 bgg_id bgg_name year type version_id version_name title_raw source_photos second_copy
2 235096 334011 Cat Crimes A Gentle Rain 2017 2021 boardgame 360982 701315 English edition English Bloom edition CAT CRIMES a Gentle Rain IMG_4499.jpeg;IMG_4505.jpeg IMG_4501.jpeg;IMG_4507.jpeg
3 268163 589 A Gentle Rain Wiz-War 2019 1983 boardgame 268164 27352 Bloom Edition Chessex sixth edition a Gentle Rain Wiz-War IMG_4501.jpeg;IMG_4507.jpeg IMG_4502.jpeg
4 125921 Catan: Junior 2012 boardgame 476263 English third edition CATAN JUNIOR IMG_4516.jpeg
5 31260 Agricola 2007 boardgame 297589 Z-Man Games English fifth edition AGRICOLA IMG_4518.jpeg
6 181304 Mysterium 2015 boardgame 536289 English edition 2018-2 MYSTERIUM IMG_4520.jpeg
7 312786 Poetry for Neanderthals 2020 boardgame 514050 English edition 2020 Poetry for Neanderthals IMG_4526.jpeg
8 273240 The Red Dragon Inn Smorgasbox 2019 boardgame 446069 Kickstarter edition The Red Dragon Inn: Smorgasbox IMG_4527.jpeg
9 419687 Munchkin Big Box 2025 boardgame 711400 English edition Munchkin Big Box IMG_4530.jpeg
10 252153 Tang Garden 2019 boardgame 404702 English edition Tang Garden IMG_4533.jpeg
11 255984 Sleeping Gods 2021 boardgame 701034 English Gamefound edition Sleeping Gods IMG_4534.jpeg
12 283766 Sleeping Gods: Tides of Ruin 2021 boardgame 463140 English edition Sleeping Gods: Tides of Ruin IMG_4534.jpeg
13 280794 Etherfields 2020 boardgame 458300 English edition ETHERFIELDS IMG_4535.jpeg
14 380837 Botany 2024 boardgame 650545 English edition BOTANY IMG_4536.jpeg
15 393672 Gloomhaven: Buttons & Bugs 2024 boardgame 669782 English edition GLOOMHAVEN Buttons & Bugs IMG_4537.jpeg
16 14535 SPANC: Space Pirate Amazon Ninja Catgirls 2005 boardgame 29075 English first edition SPANC Space Pirate Amazon Ninja Catgirls IMG_4537.jpeg
17 9666 Greed Quest 2004 boardgame 215137 English edition Greed Quest IMG_4537.jpeg
18 40508 Scrabble Slam! 2008 boardgame 644326 English edition with Hasbro logo SCRABBLE SLAM! IMG_4543.jpeg
19 3181 Farkle 1930 boardgame 87931 Legendary Games cannister edition POCKET FARKEL IMG_4545.jpeg
20 193485 Dastardly Dirigibles 2016 boardgame 300446 English edition Dastardly Dirigibles IMG_4548.jpeg
21 226065 Sheriff of Nottingham: Merry Men 2017 boardgame 353389 English edition SHERIFF OF NOTTINGHAM MERRY MEN IMG_4550.jpeg
22 143884 Machi Koro 2012 boardgame 453051 English fifth anniversary edition, first printing MACHI KORO IMG_4551.jpeg
23 358880 Etherfields: Kittenburg Expansion 2022 boardgame 603694 English edition ETHERFIELDS KITTENBURG EXPANSION IMG_4570.jpeg
24 432858 Artistry 2025 boardgame 734890 English edition ARTISTRY IMG_4515.jpeg
25 417060 Botany: Tantalizing Trees 2024 boardgameexpansion 706506 English edition BOTANY: TANTALIZING TREES IMG_4571.jpeg
26 417064 Botany: Perilous Perfumes 2024 boardgameexpansion 706510 English edition BOTANY: PERILOUS PERFUMES IMG_4571.jpeg
27 161928 Utter Nonsense 2014 boardgame Utter Nonsense! IMG_4501.jpeg;IMG_4507.jpeg;IMG_4556.jpeg
28 50381 Cards Against Humanity 2009 boardgame Cards Against Humanity IMG_4501.jpeg;IMG_4556.jpeg
29 1078 1269 Skip-Bo 1967 boardgame SKIP-BO IMG_4501.jpeg;IMG_4542.jpeg
30 218866 202982 Scrawl 2017 2016 boardgame SCRAWL IMG_4502.jpeg
31 195314 Herbaceous 2017 boardgame Herbaceous IMG_4507.jpeg
32 320202 Dragon Land 2020 boardgame Dragon Land IMG_4508.jpeg;IMG_4542.jpeg
33 2452 Jenga 1983 boardgame Jenga IMG_4509.jpeg
34 42063 Code Master 1997 boardgame CODE MASTER IMG_4510.jpeg
35 340420 Throw Throw Avocado 2021 boardgame THROW THROW AVOCADO IMG_4511.jpeg
36 1260 Rook 1906 boardgame ROOK IMG_4511.jpeg
37 116 Guillotine 1998 boardgame Guillotine IMG_4512.jpeg
38 169124 Flick 'em Up! 2015 boardgame Flick'em UP! IMG_4513.jpeg
39 20866 The Rocky Horror Trivia Game 2005 boardgame The Rocky Horror Trivia Game IMG_4514.jpeg
40 269564 Captain Marvel: Secret Skrulls 2019 boardgame CAPTAIN MARVEL SECRET SKRULLS IMG_4516.jpeg
41 18755 Pie Face! 1964 boardgame Pie Face! IMG_4517.jpeg
42 140509 Dungeons & Dragons 1985 boardgame DUNGEONS & DRAGONS IMG_4519.jpeg
43 201248 Evolution: The Beginning 2016 boardgame evolution The Beginning IMG_4520.jpeg
44 362205 Sleeping Gods: Primeval Peril 2023 boardgame Sleeping Gods PRIMEVAL PERIL IMG_4521.jpeg
45 453845 Murder at the Manor 2021 boardgame Murder at the Manor IMG_4522.jpeg
46 329230 Bluffaneer 2021 boardgame Bluffaneer IMG_4522.jpeg
47 358320 Sleeping Gods: Distant Skies 2023 boardgame Sleeping Gods DISTANT SKIES IMG_4523.jpeg
48 389113 Rivals 2025 boardgame THE RIVALS FOR CATAN CARD GAME IMG_4523.jpeg
49 324937 Wiz-War (9th Edition) 2023 boardgame WIZ-WAR IMG_4528.jpeg
50 295770 Frosthaven 2022 boardgame FROSTHAVEN IMG_4531.jpeg
51 174430 Gloomhaven 2017 boardgame GLOOMHAVEN IMG_4532.jpeg
52 442312 Deadly Doodles 2025 boardgame DEADLY DOODLES IMG_4533.jpeg
53 332398 Everdell: The Complete Collection 2022 boardgame Everdell The Complete Collection IMG_4533.jpeg
54 334065 Verdant 2022 boardgame Verdant IMG_4534.jpeg
55 283155 Calico 2020 boardgame Calico IMG_4534.jpeg
56 291457 Gloomhaven: Jaws of the Lion 2020 boardgame GLOOMHAVEN - Jaws of the Lion IMG_4538.jpeg
57 150925 Hold Your Breath! 2014 boardgame Hold your Breath! IMG_4547.jpeg
58 2980 The Simpsons Trivia Game 2000 boardgame The Simpsons Trivia Game shelf-20260803-213735.jpg
59 1197 Blink 1995 boardgame BLINK shelf-20260803-215650.jpg
60 352819 The Office Trivia Game 2019 boardgame The Office Trivia Game shelf-20260803-215703.jpg
61 163412 Patchwork 2014 boardgame Patchwork IMG_4501.jpeg
62 291847 Mantis Falls 2021 boardgame MANTIS FALLS IMG_4505.jpeg
63 2058 Civilization: West Extension Map 1986 boardgameexpansion Civilization: West Extension Map
64 452833 Artistry: Delightful Doorways Mini Expansion 2025 boardgameexpansion Artistry: Delightful Doorways Mini Expansion
+34
View File
@@ -1 +1,35 @@
collid,bgg_id,bgg_name,version_id,version_name
53429559,240,Britannia,24621,Avalon Hill second edition
53429530,71,Civilization,24006,Avalon Hill first edition 1981
53429542,177,Advanced Civilization,24972,English edition
53429504,3090,Doctor Who: The Game of Time & Space,25782,English edition
53429482,3585,Sorcerer: The Game of Magical Conflict,211154,SPI Designer's Edition
53429367,2524,StarForce 'Alpha Centauri': Interstellar Conflict in the 25th Century,219137,SPI boxed designer's edition
53429816,224,History of the World,20727,Avalon Hill/Hasbro edition
53429636,9209,Ticket to Ride,294188,English edition 2012 with Spiel des Jahres logo
53430595,13,Catan,347121,English edition 2016
53430485,1219,Labyrinth,488621,English edition 2017
53429649,137909,Bugs in the Kitchen,216474,English first edition
53430142,27710,Catan Dice Game,606657,English edition 2018
53429953,169784,Castle Panic: The Dark Titan,260454,English first edition
53429666,147370,Robot Turtles,231664,English second edition
53430559,43443,Castle Panic,103068,"English edition, fourth printing"
53429632,24310,The Red Dragon Inn,374258,English fifth edition
53429748,39856,Dixit,296529,Asmodee/Libellud English edition 2015
53430257,35505,Walk the Plank!,781669,English MDG-4311 edition
53430020,164,"Before I Kill You, Mister Bond",28465,"Cheapass black and white ""Better Edition"" edition"
53429887,65244,Forbidden Island,31208,English edition 051210
53429908,95386,Tempurra,290572,English edition
53430200,258,Fluxx,20840,Looney Labs Version v2.1
53430332,188614,Simon's Cat Card Game,779792,"English edition, second printing"
53429850,4324,Risk: The Lord of the Rings,26859,English edition 2002
53429933,1927,Munchkin,28144,"English edition 2009, 15th printing"
53430007,1784,Dark Cults,110926,First edition
53429986,176,Give Me the Brain!,27673,Czech edition
53430040,257,Kill Doctor Lucky,520364,"Cheapass envelope edition, second printing"
53612880,153999,"...and then, we held hands.",280845,English edition
53612866,166976,Consentacle,410382,English Kickstarter edition
53430652,231302,The Cat Game,361880,English/French edition
53430517,40692,Small World,294178,English third edition
53429718,172503,Mage Wars Academy,265107,English edition
53429642,104710,Wiz-War (Eighth Edition),117685,English first edition
1 collid bgg_id bgg_name version_id version_name
2 53429559 240 Britannia 24621 Avalon Hill second edition
3 53429530 71 Civilization 24006 Avalon Hill first edition 1981
4 53429542 177 Advanced Civilization 24972 English edition
5 53429504 3090 Doctor Who: The Game of Time & Space 25782 English edition
6 53429482 3585 Sorcerer: The Game of Magical Conflict 211154 SPI Designer's Edition
7 53429367 2524 StarForce 'Alpha Centauri': Interstellar Conflict in the 25th Century 219137 SPI boxed designer's edition
8 53429816 224 History of the World 20727 Avalon Hill/Hasbro edition
9 53429636 9209 Ticket to Ride 294188 English edition 2012 with Spiel des Jahres logo
10 53430595 13 Catan 347121 English edition 2016
11 53430485 1219 Labyrinth 488621 English edition 2017
12 53429649 137909 Bugs in the Kitchen 216474 English first edition
13 53430142 27710 Catan Dice Game 606657 English edition 2018
14 53429953 169784 Castle Panic: The Dark Titan 260454 English first edition
15 53429666 147370 Robot Turtles 231664 English second edition
16 53430559 43443 Castle Panic 103068 English edition, fourth printing
17 53429632 24310 The Red Dragon Inn 374258 English fifth edition
18 53429748 39856 Dixit 296529 Asmodee/Libellud English edition 2015
19 53430257 35505 Walk the Plank! 781669 English MDG-4311 edition
20 53430020 164 Before I Kill You, Mister Bond 28465 Cheapass black and white "Better Edition" edition
21 53429887 65244 Forbidden Island 31208 English edition 051210
22 53429908 95386 Tempurra 290572 English edition
23 53430200 258 Fluxx 20840 Looney Labs Version v2.1
24 53430332 188614 Simon's Cat Card Game 779792 English edition, second printing
25 53429850 4324 Risk: The Lord of the Rings 26859 English edition 2002
26 53429933 1927 Munchkin 28144 English edition 2009, 15th printing
27 53430007 1784 Dark Cults 110926 First edition
28 53429986 176 Give Me the Brain! 27673 Czech edition
29 53430040 257 Kill Doctor Lucky 520364 Cheapass envelope edition, second printing
30 53612880 153999 ...and then, we held hands. 280845 English edition
31 53612866 166976 Consentacle 410382 English Kickstarter edition
32 53430652 231302 The Cat Game 361880 English/French edition
33 53430517 40692 Small World 294178 English third edition
34 53429718 172503 Mage Wars Academy 265107 English edition
35 53429642 104710 Wiz-War (Eighth Edition) 117685 English first edition
+4
View File
@@ -0,0 +1,4 @@
action,bgg_id,collid,name,version_id,second_copy,status,timestamp,error
add,334011,,A Gentle Rain,701315,,failed,2026-08-06T02:15:34+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""A\ Gentle\ Rain"", re.IGNORECASE)) to be visible"
add,589,,Wiz-War,27352,,failed,2026-08-06T02:20:33+00:00,"Error: Locator.check: Error: strict mode violation: get_by_role(""dialog"").get_by_label(""Own"") resolved to 2 elements: 1) <input type=""checkbox"" ng-model=""item.status.own"" class=""ng-pristine ng-untouched ng-valid ng-empty""/> aka get_by_role(""checkbox"", name=""Own"", exact=True) 2) <input type=""checkbox"" ng-model=""item.status.prevowned"" class=""ng-pristine ng-untouched ng-valid ng-empty""/> aka get_by_role(""checkbox"", name=""Prev. Owned"") Call log: - waiting for get_by_role(""dialog"").get_by_label(""Own"")"
add,334011,,A Gentle Rain,701315,,added,2026-08-06T02:21:32+00:00,
1 action bgg_id collid name version_id second_copy status timestamp error
2 add 334011 A Gentle Rain 701315 failed 2026-08-06T02:15:34+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"A\ Gentle\ Rain", re.IGNORECASE)) to be visible
3 add 589 Wiz-War 27352 failed 2026-08-06T02:20:33+00:00 Error: Locator.check: Error: strict mode violation: get_by_role("dialog").get_by_label("Own") resolved to 2 elements: 1) <input type="checkbox" ng-model="item.status.own" class="ng-pristine ng-untouched ng-valid ng-empty"/> aka get_by_role("checkbox", name="Own", exact=True) 2) <input type="checkbox" ng-model="item.status.prevowned" class="ng-pristine ng-untouched ng-valid ng-empty"/> aka get_by_role("checkbox", name="Prev. Owned") Call log: - waiting for get_by_role("dialog").get_by_label("Own")
4 add 334011 A Gentle Rain 701315 added 2026-08-06T02:21:32+00:00
+40 -7
View File
@@ -213,12 +213,13 @@ def build_queue(
def _scrub(text: str) -> str:
"""Credentials must never reach the log, even via a selector error that
echoes filled form values."""
echoes filled form values. Playwright errors carry multi-line call
logs; a CSV cell keeps one line."""
for key in ("BGG_PASSWORD", "BGG_USERNAME"):
value = os.environ.get(key)
if value:
text = text.replace(value, "***")
return text
return " ".join(text.split())
class LoginError(RuntimeError):
@@ -275,11 +276,32 @@ class PlaywrightUploader:
# plus per-element auto-waiting is the reliable pattern.
self._page.goto(url, wait_until="domcontentloaded")
# BGG's Sign In control is an <a class="btn"> with NO href, so it has
# no implicit link role — a role="link" query never matched it in any
# state, and "no Sign In link" silently meant "already logged in".
_SIGN_IN = 'a:has-text("Sign In"), button:has-text("Sign In")'
_SIGNED_IN = ':text-is("Sign Out"), :text-is("Log Out")'
def _signed_out(self) -> bool:
# Heuristic: the header shows a "Sign In" link only when logged out.
return (
self._page.get_by_role("link", name=re.compile(r"^sign in$", re.I)).count()
> 0
"""True = signed out. Waits for the header to prove ONE state or
the other: BGG hydrates it after domcontentloaded, so an early read
finds NEITHER control — and any check resting on a single absence
(the original bug) then guesses, silently, in the unsafe direction.
Undeterminable state raises rather than assumes."""
page = self._page
deadline = time.monotonic() + 30
while time.monotonic() < deadline:
out = page.locator(self._SIGN_IN).count()
inside = page.locator(self._SIGNED_IN).count()
if out and not inside:
return True
if inside and not out:
return False
page.wait_for_timeout(250)
raise LoginError(
"could not tell whether this browser is signed in (neither a "
"Sign In nor a Sign Out control appeared in 30s) — BGG's header "
"may have changed; see docs/bgg-upload-flow.md"
)
def _ensure_logged_in(self) -> None:
@@ -313,6 +335,15 @@ class PlaywrightUploader:
"login did not complete (wrong credentials, or the login "
"page changed — see docs/bgg-upload-flow.md)"
) from err
# Verify the TRANSITION: the Sign In control was visible a
# moment ago, so its disappearance is evidence, not inference.
self._goto(f"{BGG}/")
if self._signed_out():
raise LoginError(
"the login form was submitted but the site still offers "
"Sign In — credentials rejected, or a challenge is "
"pending in the browser window"
)
self._context.storage_state(path=str(self._storage_state))
self._storage_state.chmod(0o600) # session cookies: owner-only
self._authed = True
@@ -382,7 +413,9 @@ class PlaywrightUploader:
dialog.get_by_role(
"heading", name=re.compile(re.escape(job.name), re.I)
).wait_for(timeout=15_000)
dialog.get_by_label("Own").check()
# exact: "Own" is a substring of "Prev. Owned", and a loose label
# match resolves to both checkboxes (strict-mode violation)
dialog.get_by_role("checkbox", name="Own", exact=True).check()
status, note = "added", ""
if job.version_name and not self._select_version(dialog, job.version_name):
status = "added_no_version"
+54
View File
@@ -491,3 +491,57 @@ def test_drift_warning_suppressed_for_multi_edition_partial_run(tmp_path, capsys
)
run_upload(cfg, uploader=FakeUploader(), sleep=lambda s: None, now=_now)
assert "manual correction" not in capsys.readouterr().out
# -- sign-in detection: never guess from a single absence ----------------
class _FakePage:
"""Counts per selector, replayed one poll at a time — the header
hydrates late, so the first reads legitimately see nothing."""
def __init__(self, script):
self.script = list(script)
self.polls = 0
def locator(self, selector):
counts = self.script[min(self.polls, len(self.script) - 1)]
class _Loc:
def count(self):
return counts["out" if "Sign In" in selector else "in"]
return _Loc()
def wait_for_timeout(self, ms):
self.polls += 1
def _uploader_with(script):
from bggpipe.upload import PlaywrightUploader
up = PlaywrightUploader("someone")
up._page = _FakePage(script)
return up
def test_signed_out_waits_through_hydration():
# neither control for two polls (the window the old check misread as
# "already signed in"), then the Sign In control appears
up = _uploader_with([{"out": 0, "in": 0}, {"out": 0, "in": 0}, {"out": 1, "in": 0}])
assert up._signed_out() is True
def test_signed_in_is_detected_positively():
up = _uploader_with([{"out": 0, "in": 0}, {"out": 0, "in": 1}])
assert up._signed_out() is False
def test_undeterminable_state_raises_instead_of_guessing(monkeypatch):
from bggpipe.upload import LoginError
ticks = iter([0, 1, 2, 31]) # force the deadline to pass
monkeypatch.setattr("time.monotonic", lambda: next(ticks))
up = _uploader_with([{"out": 0, "in": 0}])
with pytest.raises(LoginError, match="could not tell"):
up._signed_out()