Expand description
Owned temp-path registry — makes the (tmp-dir) / (tmp-file) leak
unrepresentable. See the module docs for the incident it closes.
ScratchRegistry — the interpreter OWNS every temp path it mints.
§The leak this exists to make unrepresentable (measured 2026-07-31)
tmp-dir / tmp-file used to create_dir_all under std::env::temp_dir()
and hand the path back as a bare Value::Str. Nothing owned it, so nothing
ever removed it. On rio that produced:
ls -d /tmp/tatara-script-* | wc -l -> 21,608
du -shc /tmp/tatara-script-* -> 13 GB
oldest 05:02, newest 22:26, uptime 17h19m => ~1,250 dirs/hour, since bootThat box mounts /tmp as a 48 GiB tmpfs on 29 GiB of RAM, so those 13 GB
were not disk — they were memory. Combined with ~25 GB of other scratch it
filled RAM and all 31.9 GiB of swap (SwapFree: 176 kB), drove PSI
memory.full avg60 to 92%, and left the OOM killer as the only reclaim
path — it killed comin’s git mid-deploy. A leaked temp dir is not a
tidiness problem on a tmpfs host; it is a memory leak that takes the node
down.
§Why a registry rather than “remember to delete it”
The old signature made the leak the DEFAULT and correctness opt-in: a script
had to remember an explicit delete, on every exit path including error. The
registry inverts that. scratch_dir / scratch_file are the only
constructors, they always record, and Drop always removes — so “created
but never cleaned” has no representation. Correctness is what you get by
doing nothing.
§Two failure modes, two mechanisms
Drop covers normal exit, early return, and panic-unwind. It CANNOT cover
SIGKILL, an OOM kill, or a power loss — and on the very host that
motivated this, OOM kills were happening three times in six hours. So RAII
alone would have left a residue that regrows. [sweep_stale] is the
reconciler for that path: a bounded, best-effort sweep of our own prefix,
old enough that no live process can still hold it. Invariant for the normal
case, reconciler for the violent one.
Escape hatch: set TATARA_SCRIPT_KEEP_SCRATCH=1 to retain scratch for
debugging. It is deliberately an env var rather than a Lisp argument —
keeping is an operator’s debugging choice, not a script’s contract, and a
script that could opt into leaking would reopen the class.
Structs§
- Scratch
Registry - Owns the temp paths minted during one interpreter run and removes them on drop.
Functions§
- is_
scratch_ path - Path helper for tests + callers that want to reason about our namespace.
- sweep_
stale - Remove OUR OWN stale scratch left behind by processes that died without
running
Drop(SIGKILL, OOM kill, power loss).