fix: give the roster's column zip an explicit strict=False (387 D1, B905)
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 6s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 32s
Build images / build-web (push) Successful in 58s
Build images / smoke-web (push) Skipped
CI / integration (push) Successful in 2m5s
Build images / build-ml (push) Successful in 2m46s
Build images / promote (push) Skipped

ef91fcf failed ruff's B905 lane on one zip(labels, cells) without strict=. Tests, integration and the frontend were already green on that SHA.

strict=False is the deliberate side, not the quiet one. strict=True raises a bare ValueError - not SubscribeStarDriftError - and would fail the whole roster sync over a column mismatch in `details`, which nothing reads yet. That would take down reconciliation and the gated-post reasons over a cosmetic markup change, while creator identity (id, slug) never depended on the columns at all.

But a shifted column would mislabel details silently (a price filed under "discord"), so a count mismatch now logs a canary warning, mirroring the feed parser's existing parse canary: diagnosable from the worker log, never fatal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SHQB1YukL3VyvMK8rcbmV9
This commit is contained in:
2026-09-13 10:56:18 -04:00
co-authored by Claude Opus 5
parent ef91fcfd26
commit 0835da8a91
+11 -1
View File
@@ -396,6 +396,16 @@ def _roster_rows(table: str, identifier: str, base: str) -> list[Membership]:
name = _ROSTER_NAME_RE.search(row)
slug = unescape(href.group(1))
cells = _ROSTER_CELL_RE.findall(row)
if len(cells) != len(labels):
# Canary, not a refusal. Identity above does not depend on columns,
# so a shifted column must not fail the whole roster — but it would
# silently mislabel `details` (a price filed under "discord"), so
# say so in the worker log where it is diagnosable.
log.warning(
"SubscribeStar roster %r: %d cells against %d headers — column "
"details may be mislabelled; markup likely changed (note #3989)",
identifier, len(cells), len(labels),
)
rows.append(Membership(
campaign_id=user_id.group(1),
display_name=(_cell_text(name.group(1)) if name else "") or None,
@@ -420,7 +430,7 @@ def _roster_rows(table: str, identifier: str, base: str) -> list[Membership]:
# its <th>'s class at all.
"columns": {
label: _cell_text(cell)
for label, cell in zip(labels, cells)
for label, cell in zip(labels, cells, strict=False)
if label not in _ROSTER_SKIP_COLUMNS
},
},