Audit: 5-reviewer sweep — 19 fixes across every stage, +24 tests
Correctness: review vetoes persist via a dedupe_veto column (resolve re-runs no longer overturn humans); diff emits second copies whose confident version matches no owned copy (spec: pairs own only on both ids) and fetches the live collection with refresh; resolve pairs titles.json entries to rows by title so a reshoot photo updates provenance instead of duplicating rows; version lookups survive empty /thing results; publisher tie-break now honors the mixed base/expansion veto and refuses multi-candidate picks; empty-normalized (non-Latin) titles never count as exact. Upload: LoginError aborts a run instead of logging N bogus failures (and 3 identical consecutive failures abort as systemic); Cloudflare interstitials are detected; added-without-version gets its own logged status that verify understands; same-game updates run one per pass so the name-targeted row edit can't overwrite a fresh version; absent diff outputs fail loudly; pagination clicks are paced. Web review: a lock serializes freshen/decide (threadpool race dropped decisions); failed saves roll memory back and always alert the browser (non-JSON 500s included); session warnings reach the page instead of a StringIO; state-load failures and dead servers show banners instead of a blank page; duplicate (title, photos) rows are addressable by ordinal. Consistency: shared CONFIDENT_VERSION_STATUSES, client_for(), Config paths for every artifact, one review-port constant, named matching thresholds, strict collection-id parsing, error-doc responses never cached, unknown config keys warn, extract reports dropped vision entries, fixture generators share escaping + marker text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
"""Shared plumbing for the two stub-fixture generators.
|
||||
|
||||
Both write into the same cache dirs, so they must agree on XML escaping
|
||||
(a title containing & or " must not produce malformed XML) and on the
|
||||
provenance-marker text the upload guard depends on.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
CACHE_MARKER_TEXT = (
|
||||
"This cache contains hand-written stub XML, not real BGG "
|
||||
"responses. Data resolved from it must not be uploaded.\n"
|
||||
)
|
||||
DATA_MARKER_TEXT = (
|
||||
"The CSVs in this directory were resolved from hand-written stub "
|
||||
"fixtures, not real BGG data — version_ids are SYNTHETIC. The "
|
||||
"upload stage refuses to run while this file exists. Delete it "
|
||||
"only after re-resolving against real recorded fixtures "
|
||||
"(BGG_API_TOKEN + scripts/record_fixtures.py + resolve --force).\n"
|
||||
)
|
||||
|
||||
|
||||
def esc(text: str) -> str:
|
||||
"""Minimal XML attribute/text escaping for hand-built fixture strings."""
|
||||
return str(text).replace("&", "&").replace("<", "<").replace('"', """)
|
||||
|
||||
|
||||
def write_cache_marker(target: Path) -> None:
|
||||
(target / "STUB_FIXTURES.marker").write_text(CACHE_MARKER_TEXT)
|
||||
|
||||
|
||||
def write_data_marker(data_dir: Path = Path("data")) -> None:
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
(data_dir / "STUB_DATA.marker").write_text(DATA_MARKER_TEXT)
|
||||
Reference in New Issue
Block a user