Summary
path.write_text(json.dumps(data), encoding="utf-8") is not atomic. If the process is interrupted (SIGINT, SIGKILL, power loss) mid-write, the file is left truncated or malformed.
Impact
On the next run, read_cache detects the JSONDecodeError, deletes the file, and returns None — the network fetch is retried correctly. No data loss or incorrect result; only an unnecessary extra API call.
Proposed fix
Write-then-rename pattern (atomic on POSIX):
import os
tmp = path.with_suffix(".tmp")
tmp.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")
os.replace(tmp, path) # atomic rename on POSIX; best-effort on Windows
Notes
Low priority for Phase 1 since recovery is already in place. Recommended for a hardening pass before Phase 2 when batch/concurrent auditing is considered.
Summary
path.write_text(json.dumps(data), encoding="utf-8")is not atomic. If the process is interrupted (SIGINT, SIGKILL, power loss) mid-write, the file is left truncated or malformed.Impact
On the next run,
read_cachedetects theJSONDecodeError, deletes the file, and returnsNone— the network fetch is retried correctly. No data loss or incorrect result; only an unnecessary extra API call.Proposed fix
Write-then-rename pattern (atomic on POSIX):
Notes
Low priority for Phase 1 since recovery is already in place. Recommended for a hardening pass before Phase 2 when batch/concurrent auditing is considered.