Re-audit round 2: 5 blind reviewers, 17 fixes, +12 tests
The re-run confirmed round 1 held and then caught second-order bugs in its own fixes plus two long-standing ones everyone missed. TUI decisions after a mid-session reload were counted but never written (rows are now re-adopted into the fresh list on every save, preferring undecided slots on duplicate keys); row_ix was computed by equality so duplicate rows shared an ordinal (identity now, merges included, veto sends it); upload job keys collided for two same-version copies (completions are counted per key, so --limit or an interrupt can no longer strand the second copy); diff consumes collids on exact-version matches (a vetoed same-version second copy was silently swallowed) and splits mismatches: report-only disagreement while an unclaimed copy exists, second-copy add only when every copy is claimed. Also: XML responses are validated and written atomically before caching (a torn or truncated 200 body can never poison a re-run), JSON artifacts write atomically, thing/search parsers refuse missing ids like the collection parser, empty game names are refused by the upload queue, a never-rendering version picker fails retryably instead of terminally, the systemic-failure abort compares exception types, blocked same-title entries defer as a group so positional pairing can't misalign, truncation heads pick the earliest separator, diff messages tell the truth when a token exists without a username, and the shared-constant sweep now actually covers every module (statuses, search types, marker names, client_for, ports). pydantic declared as a direct dependency. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,8 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from bggpipe.config import STUB_CACHE_MARKER_NAME, STUB_DATA_MARKER_NAME
|
||||
|
||||
CACHE_MARKER_TEXT = (
|
||||
"This cache contains hand-written stub XML, not real BGG "
|
||||
"responses. Data resolved from it must not be uploaded.\n"
|
||||
@@ -28,9 +30,9 @@ def esc(text: str) -> str:
|
||||
|
||||
|
||||
def write_cache_marker(target: Path) -> None:
|
||||
(target / "STUB_FIXTURES.marker").write_text(CACHE_MARKER_TEXT)
|
||||
(target / STUB_CACHE_MARKER_NAME).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)
|
||||
(data_dir / STUB_DATA_MARKER_NAME).write_text(DATA_MARKER_TEXT)
|
||||
|
||||
@@ -19,7 +19,7 @@ from pathlib import Path
|
||||
|
||||
from fixture_common import esc, write_cache_marker, write_data_marker
|
||||
|
||||
from bggpipe.bgg_client import cache_key
|
||||
from bggpipe.bgg_client import SEARCH_TYPES, cache_key
|
||||
|
||||
TARGETS = (Path("tests/fixtures/bgg_cache"), Path("data/bgg_cache"))
|
||||
|
||||
@@ -27,7 +27,6 @@ TARGETS = (Path("tests/fixtures/bgg_cache"), Path("data/bgg_cache"))
|
||||
# gitignored, so this is what protects a fresh clone): upload refuses to
|
||||
# run while it exists.
|
||||
DATA_MARKER = Path("data/STUB_DATA.marker")
|
||||
SEARCH_TYPES = "boardgame,boardgameexpansion"
|
||||
|
||||
BG, EXP = "boardgame", "boardgameexpansion"
|
||||
|
||||
@@ -345,7 +344,6 @@ def versions_xml(bgg_id: int, versions: list[tuple]) -> str:
|
||||
)
|
||||
|
||||
|
||||
|
||||
def main() -> None:
|
||||
files: dict[str, str] = {}
|
||||
for query, results in SEARCHES.items():
|
||||
|
||||
@@ -16,10 +16,9 @@ from pathlib import Path
|
||||
|
||||
from fixture_common import esc, write_cache_marker
|
||||
|
||||
from bggpipe.bgg_client import cache_key
|
||||
from bggpipe.bgg_client import SEARCH_TYPES, cache_key
|
||||
|
||||
FIXTURE_CACHE = Path("tests/fixtures/bgg_cache")
|
||||
SEARCH_TYPES = "boardgame,boardgameexpansion"
|
||||
|
||||
|
||||
def search_item(bgg_id: int, name: str, year: int | None, type_: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user