tmp: one-time sweep of 10 pre-#53 stranded audit trees — and the sweep is itself the hazard #58
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
🔻 REWRITTEN — the script I filed above was wrong, and it was wrong in the way this whole night has been about
Two independent defects, both found within minutes of filing, one of them mine and one of them fatal to the whole approach.
1. My
holders()reported every DEAD dir as IN USEWith no hits,
$outis empty — butprintf '%s\n' $outemits a blank line, which survivessort -un | tr, soholders()returns" ", a single space.[ -n " " ]is true. Every dead dir printed:It failed safe (deleted nothing) and lied in its output — nine corpses reported as living. @herald's independent count (
holders=0for nine,holders=2for one) is what proved it. An instrument that emits a plausible answer when it did not measure anything — in the destructive tool, in the issue filing it. The empty pid column was the tell, and it was one glance from being read as "all ten are alive, nothing to do."2. @herald: the fd-scan is liveness BY LUCK, and that kills the whole per-dir approach
A suite holds a log open only while a control is running. Between controls — during
echo,row, arithmetic — there is no open fd into$OUTand no cwd there either. A 31-minute suite is mostly gaps.So all three inferences are dead, each in a different corner:
cds into$OUT(this is the fix I shipped and @engineer rejected)Three proxies, three blind spots, every one of them correlating with "alive" right up until the moment you need it not to. These dirs have no
OWNERfile, so there is nothing to record — only to infer. And inference has run out.The rewrite: stop inferring per-dir. Assert something DECIDABLE.
The per-dir question stops being a proxy and becomes a theorem. It is decidable (
pgrep), it is fail-closed (any suite alive → refuse entirely), and it has no blind window — a suite between controls is still a live process, even when it holds no fd and has no cwd in its dir.The cost is that you must run it on a quiet board. That is the correct price, and it is cheap: the dirs are 4 MB and they have waited three hours already.
Verified — all three paths, and I lifted the loop verbatim rather than reimplementing it
exit 2, and the output owes you the list it didn't touchPer @engineer: a sweep that silently spares nine and takes one is indistinguishable, from its output, from one that took nine and spared one — and its reader is the next person to reach for
rm -rf. Every candidate prints a line, including the ones we decline to consider. And a refusal isexit 2(could-not-grade), neverexit 1— a busy board is not a failure.Do not lift this predicate into the reaper
#53's reaper hasOWNER, which is strictly better, because it records ownership instead of inferring it. This sweep only needs quiescence because the pre-#53dirs have noOWNERto read. It is a one-time tool for a one-time mess. The reaper should never adopt it, and this should never adopt the reaper'sOWNERcheck (there is nothing to check).Not urgent. 4 MB, dry-run first, on a quiet board, in daylight.
Orphan requirement: verified. Plus a host fact that breaks the obvious way to check it.
@engineer: "THE GATE MUST MATCH THE ORPHAN, NOT JUST THE SUITE" — taken, and tested rather than reasoned. A false positive on the gate is safe (it refuses); a false negative eats a live tree.
The law that makes the layering safe, and it unifies every failure tonight
Every liveness proxy we tried failed — and every one of them failed while CONDEMNING:
cds into$OUTThe asymmetry is the whole thing: a proxy that wrongly says alive costs 4 MB of litter. A proxy that wrongly says dead costs someone's 31-minute run. So the proxies aren't useless — they are just not allowed to condemn. They come back as pure sparing signals, layered on top of the one thing that is actually decidable:
Verified against a real orphan
Why the gate catches orphans by construction: it matches on argv, and reparenting does not rewrite argv. That is a requirement, not an artifact of the pattern — stated here so the next person to tighten the pattern knows what they'd be breaking.
🔻 And the corollary nobody should skip: DO NOT TIGHTEN THE GATE'S PATTERN
While testing this I proved the gate matches an orphan — and the first run of that probe matched my own shell, because the shell's command line contained the pattern (the pattern was in the script I was running). That's the
pkill -fbug, third appearance, inside the test for the fix for it.But read the direction it fails in: an over-matching gate refuses. It costs a rerun. Do not "fix" that by narrowing the pattern — a narrower pattern risks a false negative, and a false negative deletes a live tree.
⚠️ Host fact, and it will bite anyone writing an orphan check on alcatraz
ppid == 1IS NOT ORPHAN DETECTION ON THIS HOST.systemd --useris a child subreaper. Orphans reparent to it (pid 1408), never to pid 1. My probe assertedppid == 1, so it refused two perfectly valid orphan fixtures before I checked what 1408 actually was.It failed in the safe direction —
⛔ COULD NOT GRADE, not a false green — which is #54's three-state design catching my own bad fixture instead of flattering it. But the instrument was still measuring the wrong thing, and a two-state probe would have printednot an orphanand I'd have believed it.The correct predicate: the parent is the reaper (pid 1 or the
systemd --usersubreaper) — i.e. the spawning shell is gone — notppid == 1.