From 1afb1d7f63788d9c465b546f35550a2e48c47bf7 Mon Sep 17 00:00:00 2001 From: "marcin p. joachimiak" <4625870+realmarcin@users.noreply.github.com> Date: Mon, 21 Sep 2026 23:47:43 -0700 Subject: [PATCH] Build the census before opening the file it overwrites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit json.dump(census(), open(DATA + "/prefix_census.json", "w"), indent=1) Two problems in one line. The handle is never closed, so every run emits ResourceWarning — and the obvious fix for that would destroy the census. Arguments evaluate left to right, so `census()` runs to completion before `open()` truncates. Write it the idiomatic way instead, with the `with open` first, and the order reverses: a scan that raises leaves the committed file at zero bytes. census() raises for ordinary reasons — roots.mech_root when a checkout is absent, record_paths when a glob matches nothing — both deliberate fail-closed behaviour. So the current line is safe by accident, and the accident is one refactor away from losing data exactly when something else already went wrong (#102). Building the document first keeps the ordering guarantee explicit rather than incidental, and closes the handle. Verified both directions. A failing scan (`MECHS_ROOT=/nonexistent`) exits with the checkout message and leaves the census byte-identical. A successful scan against a ten-file synthetic corpus writes all nine Mechs, non-empty, valid JSON — run in a temp tree so the committed census was never a participant. Writing to a temp file and renaming would be stronger still, since an interrupted write could not leave a partial census either. Not done here: this removes the trap, and atomic replacement is a larger change to make across the four scripts that write derived data. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/fleet/prefix_census.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/fleet/prefix_census.py b/scripts/fleet/prefix_census.py index 2f43853..152daf1 100644 --- a/scripts/fleet/prefix_census.py +++ b/scripts/fleet/prefix_census.py @@ -39,7 +39,16 @@ def census(): def main(): - json.dump(census(),open(DATA+"/prefix_census.json","w"),indent=1) + # Build the document before opening the file. `json.dump(census(), open(...))` + # happens to be safe because arguments evaluate left to right, so a scan that + # exits takes the process down before the truncation — but write it the + # idiomatic way, with the open first, and a missing checkout leaves the + # committed census at zero bytes. census() exits for ordinary reasons: + # roots.mech_root when a checkout is absent, record_paths when a glob matches + # nothing, both deliberately fail-closed. Also closes the handle (#102). + document = census() + with open(DATA + "/prefix_census.json", "w") as handle: + json.dump(document, handle, indent=1) # Guarded so the module can be imported for P, rx and norm alone. Without this