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
+38 -23
View File
@@ -290,10 +290,11 @@ class Uploader(Protocol):
class PlaywrightUploader:
"""Drives the real site. Selector documentation: docs/bgg-upload-flow.md.
Verified selectors (2026-08-01): the login form (#inputUsername /
#inputPassword / "Sign In") and the Add-to-Collection dialog structure.
UNVERIFIED: version-picker pagination, post-save behavior, and the whole
collection-row edit flow for updates — expect first-real-run adjustments.
All flows verified against the live site 2026-08-06 (adds, the version
picker with pagination, and the collection-row version edit). The
remaining unknown is the second-copy add: BGG may edit the existing
entry instead of creating one, which run_upload reports as a copy-count
shortfall during --verify.
"""
def __init__(
@@ -583,33 +584,47 @@ class PlaywrightUploader:
def update_entry(self, job: UploadJob) -> tuple[str, str]:
"""Set the version on an EXISTING entry — strictly additive.
UNVERIFIED FLOW: the collection table can't target a collid directly,
so this filters by game and opens the row's status link. With several
copies of one game the wrong row could open — acceptable only while
every 2018 entry is version-less; revisit after the first real run.
Verified 2026-08-06. The collection table's version cell carries its
own collid in an onclick and opens an inline editor whose radios
carry VERSION IDS as their values, so both the copy and the edition
are addressed exactly — no name matching, no dialog, no pagination.
Clicking a radio fires CE_SaveData itself; there is no Save button.
"""
self._ensure_logged_in()
page = self._page
self._goto(
f"{BGG}/collection/user/{self._username}?objectid={job.bgg_id}&own=1"
)
row = (
page.get_by_role("row")
.filter(has_text=re.compile(re.escape(job.name), re.I))
.first
)
opener = row.get_by_role("link", name=re.compile("own", re.I)).first
dialog = self._open_dialog(opener)
picked, why = self._select_version(dialog, job.version_name)
if not picked:
# Never guess a version: close without touching the entry.
dialog.get_by_role("button", name="Cancel").first.click()
cell = page.locator(f'td.collection_version[onclick*="{job.collid}"]')
if cell.count() == 0:
raise RuntimeError(
f"version {job.version_name!r}: {why} — entry left untouched"
f"collid {job.collid} has no version cell on the collection "
"page — the entry may have been removed; re-run diff"
)
dialog.get_by_role("button", name="Save").click()
dialog.wait_for(state="hidden", timeout=15_000)
return "updated", "row-edit flow is unverified; confirm with --verify"
cell.first.click()
radio = page.locator(
f'form[id^="form_version"] input[type="radio"][value="{job.version_id}"]'
)
try:
radio.first.wait_for(timeout=15_000)
except self._timeout_error as err:
# the editor lists every version of the game: an absent id means
# the wrong game's editor opened, or BGG retired that version
page.keyboard.press("Escape")
raise RuntimeError(
f"version {job.version_id} not offered for collid "
f"{job.collid} — entry left untouched"
) from err
radio.first.click() # fires CE_SaveData: no separate Save button
for _ in range(40):
settled = " ".join((cell.first.text_content() or "").split())
if settled and "editing" not in settled.casefold():
return "updated", ""
page.wait_for_timeout(500)
raise RuntimeError(
"the version cell never left its editing state — the save may "
"not have landed; re-run with --verify"
)
def _process(