Credibility pass: comments state constraints, not development history
A skeptical-cloner review flagged the patterns that read as AI-iteration residue: test comments and section headers narrating the review process that produced them, "legacy format" framing in a days-old repo, shadow re-imports appended without reading file headers, one genuine machine leftover (FIXTURE_CACHE = FIXTURE_CACHE), and a few register slips. Every history-narrating comment is rewritten as the timeless invariant it was guarding, test sections are grouped by behavior, function-local imports are hoisted, and the README loses its one marketing clause and heaviest dash runs. No behavior changes; 176 tests unchanged and green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
92aaa91a49
commit
10f65d8aba
@@ -199,6 +199,6 @@ def client_for(cfg: Config) -> BGGClient:
|
||||
|
||||
|
||||
def cached_paths(cache_dir: Path, endpoint: str) -> list[Path]:
|
||||
"""Cache files for one endpoint — the ONLY sanctioned way to glob the
|
||||
cache, so the filename layout stays private to cache_key."""
|
||||
"""Cache files for one endpoint. Glob the cache only through this
|
||||
helper so the filename layout stays private to cache_key."""
|
||||
return sorted(cache_dir.glob(f"{endpoint}_*.xml"))
|
||||
|
||||
+7
-10
@@ -136,10 +136,10 @@ def compute_diff(rows: list[dict], collection: list[CollectionItem]) -> DiffResu
|
||||
c for c in by_object.get(bgg_id, []) if c.coll_id not in consumed_collids
|
||||
]
|
||||
|
||||
# Ordered sub-passes over the confident rows. Greedy per-row handling
|
||||
# let an EARLIER row's disagreement consume the exact-version copy a
|
||||
# LATER row matched — producing a duplicate upload. Claims must settle
|
||||
# strongest-first across ALL rows: exact version matches, then
|
||||
# Ordered sub-passes over the confident rows: greedy per-row handling
|
||||
# would let an earlier row's disagreement consume the exact-version copy
|
||||
# a later row matches, manufacturing a duplicate upload. Claims settle
|
||||
# strongest-first across all rows — exact version matches, then
|
||||
# versionless upgrades, then disagreement/second-copy handling.
|
||||
confident_rows = [r for r in recognized if is_confident_version(r)]
|
||||
leftover: list[dict] = []
|
||||
@@ -251,10 +251,6 @@ def compute_diff(rows: list[dict], collection: list[CollectionItem]) -> DiffResu
|
||||
return result
|
||||
|
||||
|
||||
def _write_csv(path: Path, columns: list[str], rows: list[dict]) -> None:
|
||||
atomic_write_csv(path, columns, rows) # a killed diff never tears the queue
|
||||
|
||||
|
||||
def run_diff(cfg: Config, *, client: BGGClient | None = None) -> DiffResult:
|
||||
rows = read_matches(cfg.matches_path)
|
||||
if not rows:
|
||||
@@ -289,8 +285,9 @@ def run_diff(cfg: Config, *, client: BGGClient | None = None) -> DiffResult:
|
||||
|
||||
result = compute_diff(rows, collection)
|
||||
|
||||
_write_csv(cfg.to_add_path, TO_ADD_COLUMNS, result.to_add)
|
||||
_write_csv(cfg.to_update_path, TO_UPDATE_COLUMNS, result.to_update)
|
||||
# atomic: a killed diff never leaves a torn upload queue
|
||||
atomic_write_csv(cfg.to_add_path, TO_ADD_COLUMNS, result.to_add)
|
||||
atomic_write_csv(cfg.to_update_path, TO_UPDATE_COLUMNS, result.to_update)
|
||||
|
||||
merged_note = f" · {result.merged} merged duplicate(s)" if result.merged else ""
|
||||
typer.echo(
|
||||
|
||||
@@ -108,8 +108,8 @@ def parse_vision_response(text: str) -> tuple[list[dict], list[dict], int]:
|
||||
"""Parse the model's JSON defensively: strip code fences, locate the
|
||||
payload amid any prose. Returns (title entries, unidentified sightings,
|
||||
dropped-malformed-entry count).
|
||||
A bare JSON array (the pre-unidentified response shape) still parses —
|
||||
it's all titles."""
|
||||
Accepts either response shape: a bare JSON array (all titles) or an
|
||||
object with titles/unidentified keys."""
|
||||
cleaned = _CODE_FENCE.sub("", text).strip()
|
||||
if cleaned[:1] in ("[", "{"):
|
||||
# trim trailing prose after a leading JSON payload ("{...}\nNote:")
|
||||
@@ -260,13 +260,13 @@ def rebuild_artifacts(
|
||||
raw_dir: Path, titles_path: Path, unidentified_path: Path
|
||||
) -> tuple[list[dict], dict[str, list[dict]]]:
|
||||
"""Regenerate titles.json and unidentified.json from the per-photo raw
|
||||
cache. Raw files written before the unidentified feature are bare
|
||||
cache. A raw file is either an object with titles/unidentified or a bare
|
||||
arrays — still readable."""
|
||||
entries: list[dict] = []
|
||||
unidentified: dict[str, list[dict]] = {}
|
||||
for raw_file in sorted(raw_dir.glob("*.json")):
|
||||
data = json.loads(raw_file.read_text())
|
||||
if isinstance(data, list): # legacy format
|
||||
if isinstance(data, list): # bare-array shape
|
||||
entries.extend(data)
|
||||
continue
|
||||
entries.extend(data.get("titles") or [])
|
||||
|
||||
@@ -155,9 +155,9 @@ def load_titles(path: Path) -> list[TitleEntry]:
|
||||
entries.append(
|
||||
TitleEntry(
|
||||
title_raw=title_raw,
|
||||
# always recompute: a stale/hand-written stored value would
|
||||
# always recompute: a hand-written stored value would
|
||||
# silently break exact matching (both sides must normalize
|
||||
# by the CURRENT rules)
|
||||
# by the current rules)
|
||||
title_normalized=normalize_title(title_raw),
|
||||
confidence=raw.get("confidence", "high"),
|
||||
publisher_hint=raw.get("publisher_hint") or "",
|
||||
@@ -483,7 +483,7 @@ def read_matches(path: Path) -> list[dict[str, str]]:
|
||||
return []
|
||||
with path.open(newline="") as f:
|
||||
rows = list(csv.DictReader(f))
|
||||
for row in rows: # files written before these columns existed
|
||||
for row in rows: # optional columns: tolerate rows without them
|
||||
row.setdefault("merged_into", "")
|
||||
row.setdefault("dedupe_veto", "")
|
||||
return rows
|
||||
|
||||
@@ -329,10 +329,8 @@ class PlaywrightUploader:
|
||||
try:
|
||||
dialog.get_by_role("listitem").first.wait_for(timeout=15_000)
|
||||
except self._timeout_error as err:
|
||||
# A version resolve found on BGG cannot legitimately be missing
|
||||
# from the picker — an unrendered list means a slow page or
|
||||
# changed markup. Raising keeps the attempt retryable instead
|
||||
# of a terminal (and false) added_no_version.
|
||||
# a version resolve found on BGG can't be missing from the
|
||||
# picker: an unrendered list means a slow page or changed markup
|
||||
raise RuntimeError(
|
||||
"version picker never rendered — site slow or markup "
|
||||
"changed; attempt is retryable"
|
||||
@@ -350,8 +348,8 @@ class PlaywrightUploader:
|
||||
nxt.click()
|
||||
self._page.wait_for_timeout(2_000) # etiquette: paginating hits BGG too
|
||||
else:
|
||||
# never saw the end of the list: "not in picker" would be a
|
||||
# false verdict frozen into DONE_STATUSES — stay retryable
|
||||
# never saw the end of the list: "not in picker" would be a false
|
||||
# verdict frozen into DONE_STATUSES
|
||||
raise RuntimeError(
|
||||
f"hit MAX_VERSION_PAGES ({MAX_VERSION_PAGES}) without "
|
||||
"finding the version or the end of the list — retryable"
|
||||
|
||||
Reference in New Issue
Block a user