Skip to content

Commit 9d36aa0

Browse files
committed
fix: apply cached GSMArena confirmations to source files
1 parent 89b8877 commit 9d36aa0

2 files changed

Lines changed: 77 additions & 8 deletions

File tree

‎app/verify/gsmarena_backfill.py‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -794,12 +794,16 @@ def write_source_url_if_unchanged(path: Path, record: dict[str, Any], url: str)
794794
current = json.loads(raw)
795795
except (OSError, UnicodeDecodeError, json.JSONDecodeError):
796796
return False
797-
if not isinstance(current, dict) or content_hash(current) != content_hash(record):
797+
if not isinstance(current, dict):
798+
return False
799+
source_urls = current.get("source_urls")
800+
if isinstance(source_urls, list) and url in source_urls:
801+
return True
802+
if content_hash(current) != content_hash(record):
798803
return False
799804
updated = add_source_url_text(raw, url)
800805
if updated is None:
801-
source_urls = current.get("source_urls")
802-
return isinstance(source_urls, list) and url in source_urls
806+
return False
803807
tmp = path.with_suffix(path.suffix + ".tmp")
804808
try:
805809
tmp.write_bytes(updated.encode("utf-8"))
@@ -1165,7 +1169,15 @@ def fetch(url: str) -> tuple[int | None, str, str]:
11651169
digest = content_hash(record)
11661170
cached = cache.get(rel)
11671171
if cached and cached.get("hash") == digest and cached.get("decision") in DECISIONS:
1168-
result.rows.append(_row_from_cache(cached))
1172+
row = _row_from_cache(cached)
1173+
if not dry_run and cached["decision"] == CONFIRM:
1174+
url = cached.get("proposed_url")
1175+
if not isinstance(url, str) or not write_source_url_if_unchanged(
1176+
repo / rel, record, url
1177+
):
1178+
row["decision"] = "write-failed"
1179+
row["reason"] = "source-urls-write-failed-or-record-changed"
1180+
result.rows.append(row)
11691181
result.cached += 1
11701182
continue
11711183
outcome = evaluate_record(record, fetcher, fetch)
@@ -1190,8 +1202,8 @@ def fetch(url: str) -> tuple[int | None, str, str]:
11901202
"source-urls-write-failed-or-record-changed",
11911203
outcome.suffix_only,
11921204
)
1193-
# Transient blocks stay uncached so a later run can retry them. A real
1194-
# CONFIRM is cached only after the guarded source_urls write succeeded.
1205+
# Transient blocks stay uncached so a later run can retry them. Cached
1206+
# dry-run CONFIRMs are written through the same guard on an apply run.
11951207
if outcome.liveness not in RETRY_LIVENESS and outcome.reason != "network-error":
11961208
append_cache(
11971209
cache_entry(rel_path=rel, record=record, result=outcome, ts=_now_iso()),

‎tests/verify/test_gsmarena_backfill.py‎

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
add_source_url_text,
2222
backfill,
2323
compare_specs,
24-
content_hash,
2524
gate_page,
2625
parse_cat_file_batch,
2726
parse_page,
@@ -370,7 +369,65 @@ def test_dry_run_does_not_write_the_record_and_caches(tmp_path: Path):
370369
)
371370
assert client.requests == 0
372371
assert again.cached == 1
373-
assert content_hash(DX650_RECORD) == again.rows[0]["decision"] or again.cached == 1
372+
assert again.rows[0]["decision"] == CONFIRM
373+
374+
# The cached confirmation still needs to be applied to the source file.
375+
applied = backfill(
376+
repo=repo,
377+
cache_path=state / "gsmarena_backfill_cache.jsonl",
378+
index_path=state / "phone_index.json",
379+
summary_path=state / "summary.md",
380+
limit=5,
381+
sleep_s=0,
382+
dry_run=False,
383+
refresh_index=False,
384+
client=client,
385+
paths=[rel],
386+
records={rel: DX650_RECORD},
387+
)
388+
url = "https://www.gsmarena.com/acer_dx650-2888.php"
389+
written = target.read_text(encoding="utf-8")
390+
assert json.loads(written)["source_urls"].count(url) == 1
391+
assert applied.cached == 1
392+
assert applied.rows[0]["decision"] == CONFIRM
393+
assert client.requests == 0
394+
395+
# Applying again must leave the file byte-for-byte unchanged.
396+
reapplied = backfill(
397+
repo=repo,
398+
cache_path=state / "gsmarena_backfill_cache.jsonl",
399+
index_path=state / "phone_index.json",
400+
summary_path=state / "summary.md",
401+
limit=5,
402+
sleep_s=0,
403+
dry_run=False,
404+
refresh_index=False,
405+
client=client,
406+
paths=[rel],
407+
records={rel: DX650_RECORD},
408+
)
409+
assert target.read_text(encoding="utf-8") == written
410+
assert reapplied.rows[0]["decision"] == CONFIRM
411+
assert client.requests == 0
412+
413+
changed = {**DX650_RECORD, "battery_mah": 9999}
414+
target.write_text(json.dumps(changed, indent=2) + "\n", encoding="utf-8")
415+
stale = backfill(
416+
repo=repo,
417+
cache_path=state / "gsmarena_backfill_cache.jsonl",
418+
index_path=state / "phone_index.json",
419+
summary_path=state / "summary.md",
420+
limit=5,
421+
sleep_s=0,
422+
dry_run=False,
423+
refresh_index=False,
424+
client=client,
425+
paths=[rel],
426+
records={rel: DX650_RECORD},
427+
)
428+
assert stale.rows[0]["decision"] == "write-failed"
429+
assert url not in target.read_text(encoding="utf-8")
430+
assert client.requests == 0
374431

375432

376433
def test_retry_after_is_parsed_and_honored_without_a_fixed_delay(tmp_path: Path, monkeypatch):

0 commit comments

Comments
 (0)