Updates go through the collection cell: collid- and version_id-exact

The last unverified flow failed on its guess — the collection row has no
link named "own"; the edit affordances are icon anchors with no text. The
site offers something far better, now verified: the row's VERSION CELL
carries its own collid in an onclick, and the inline editor it opens is a
radio list whose values ARE version ids.

So an update addresses the copy by collid and the edition by version id —
no name matching, no pagination, no dialog, and structurally incapable of
creating a duplicate entry (it sets one field on one collid). Clicking
the radio fires CE_SaveData itself; there is no Save button, and the save
has landed when the cell stops reading "Editing". A version id the editor
doesn't offer aborts with the entry untouched.

The class docstring's UNVERIFIED list is now empty but for the
second-copy add, which --verify already reports as a copy-count
shortfall.

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:15:39 -04:00
co-authored by Claude Fable 5
parent 74ecd5059b
commit 0af9ae86c5
6 changed files with 122 additions and 86 deletions
+58
View File
@@ -803,3 +803,61 @@ def test_failure_badge_ignores_jobs_the_human_retired():
]
assert outstanding_failures(log) == 2 # log-only view: both look pending
assert outstanding_failures(log, queue, matches) == 1 # only the live one
def test_update_targets_collid_and_version_id_exactly():
"""The collection row's version cell carries its collid; the editor's
radios carry version ids. Both are addressed by value, so neither the
copy nor the edition can be picked by resemblance."""
from bggpipe.upload import PlaywrightUploader, UploadJob
seen = {"clicked": [], "text": "Editing"}
class _Loc:
def __init__(self, selector):
self.selector = selector
@property
def first(self):
return self
def count(self):
return 1
def wait_for(self, **kw):
return None
def click(self):
seen["clicked"].append(self.selector)
if "radio" in self.selector:
seen["text"] = "Avalon Hill second edition" # CE_SaveData ran
def text_content(self):
return seen["text"]
class _Page:
def goto(self, url, **kw):
seen["url"] = url
def locator(self, selector):
return _Loc(selector)
def wait_for_timeout(self, ms):
pass
up = PlaywrightUploader("someone")
up._page = _Page()
up._authed = True
job = UploadJob(
action="update",
bgg_id=240,
name="Britannia",
collid="53429559",
version_id="24621",
version_name="Avalon Hill second edition",
)
status, note = up.update_entry(job)
assert status == "updated" and note == ""
assert "objectid=240" in seen["url"]
assert any('onclick*="53429559"' in s for s in seen["clicked"]) # the copy
assert any('value="24621"' in s for s in seen["clicked"]) # the edition