Skip to content

test(disk-accounting): a gate for the root-only bash nothing ever ran β€” plus the live defects three audit rounds found in it - #1366

Open
ZacxDev wants to merge 7 commits into
mainfrom
test/diagnose-disk-accounting-coverage
Open

test(disk-accounting): a gate for the root-only bash nothing ever ran β€” plus the live defects three audit rounds found in it#1366
ZacxDev wants to merge 7 commits into
mainfrom
test/diagnose-disk-accounting-coverage

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Sep 7, 2026

Copy link
Copy Markdown
Member

scripts/diagnose-disk-accounting.sh is root-privileged bash that had no test file, in a repo with no shellcheck gate. That combination is why an E2BIG abort and a hard 0.0 GiB shipped invisibly β€” nothing here was ever executed by a gate, so nothing here could ever be seen to be wrong.

This adds scripts/tests/test_diagnose_disk_accounting.sh, registers it in run-tests.sh SHELL_TESTS, and ships scripts/tests/mutants-diagnose-disk-accounting.sh so the "mutation-verified" claim below can be re-derived rather than believed.

No line count is quoted anywhere in this PR any more. Three separate places carried one, in three different files, and each went stale within a round while still being cited from the others. The only figure that cannot go stale is anchored to a sha: the file was 282 lines at the merge base c1169e3b (git show c1169e3b:scripts/diagnose-disk-accounting.sh | wc -l). For the current figure, run wc -l.

The title used to read "127 guards for 282 lines" β€” both numbers stale, in a title. It now names no count at all.

Four audit rounds have run on this branch. Each found something the previous round's fix introduced or left standing, and in every one of them at least one finding was a false sentence written by the round that was correcting a false sentence β€” round 4 almost entirely so, which is why it deletes claims instead of rewriting them. Every ✏️ block below is a claim this PR previously made and later measured false; they are kept rather than deleted, because a reader who believes the old wording stops looking.


✏️ Correction 1 β€” this PR did not fix the root command injection

An earlier revision listed "root command injection" among the defects this PR fixed. It was already fixed before this PR. Measured on the merge base c1169e3b: the file contains zero xargs -I occurrences in code β€” the only match is inside a comment describing the historical defect β€” and the inode walk was already find … -exec sh -c '…' _ {} \;. The fix landed in d8fe0bc (#1227).

What this PR adds is the test for it: a fixture directory literally named evil";echo PWNED-AS-$(id -un) >&2;"x, asserted against the expansion PWNED-AS-<whoami> and never the word PWNED (the filename contains it), with the old vulnerable xargs -I{} pipeline run first as a positive control and confirmed to leak the expansion.

That guard earned its keep in round 1: adding a 2>/dev/null to the new xargs stage silently disarmed it β€” the historical defect's own proof of execution is a planted name printing to stderr β€” and the mutation battery caught it as WRONG-KILLER while the suite stayed green.

✏️ Correction 2 β€” the seam was reachable from the environment

This description used to quote the seam as [ "${BASH_SOURCE[0]}" != "$0" ] and claim "the guard is not reachable from the environment". Measured false. bash imports BASH_SOURCE from the environment as an ordinary scalar:

  • env 'BASH_SOURCE=(nope)' bash scripts/diagnose-disk-accounting.sh β†’ takes the sourced branch, returns at top level, rc 2, no report at all β€” and rc 2 is this script's own "you forgot sudo" status, so two unrelated causes shared one exit code. Only a guard asserting the refusal message can tell them apart.
  • bash < script / bash -s β†’ BASH_SOURCE unset, set -u, dead on the guard's own line, rc 1 β€” a genuine (narrow) regression the refactor introduced.

It is now if (return 0 2>/dev/null); then, which reads no variable, and BASH_SOURCE is a banned pattern in the suite's own scanner.

✏️ Correction 3 β€” section 5 is not a verbatim move

This description said "Everything else in the diff is a verbatim move into a helper." Not quite. Section 5's enumeration changed from a glob to find … -print0 | xargs -0, and find enumerates dotfiles that the glob skipped. That is a behaviour change β€” an improvement for an accounting tool, and it is kept, but it should not have been filed under "verbatim".

✏️ Correction 4 β€” the %D cross-implementation evidence disagreed with itself

Round 2's evidence for the %D defect was quoted in three places and no two agreed: the script said "the two GNU findutils builds … (Not measured on bfs)", the round-2 commit message said "Measured on two implementations" while printing bfs numbers, and a PR comment said three. The byte counts could not all have been true either β€” "-print0 116 B (4.10.0) / 119 B (4.11.0)" over one fixture, when -print0 emits the paths it found, not the binary's path.

Re-measured in round 3 β€” one fixture (a 35-character mode-0400 base holding three entries), three implementations, each run twice:

implementation -print0 -printf '%D\t%p\0'
GNU findutils 4.10.0 (what a non-interactive bash, and so a sudo run, resolves) 114 B, rc 0 0 B, rc 1
GNU findutils 4.11.0 (the nix dev shell) 114 B, rc 0 0 B, rc 1
bfs 4.1.1 (the interactive alias) 114 B, rc 0 0 B, rc 1

Two things were wrong, not one: the builds agree (114 B is a figure about that fixture's path length and nothing else), and -print0 exits 0, not 1 β€” it needs no stat, which is exactly why it still emits the names. The load-bearing half β€” 0 bytes under %D β€” reproduces identically on all three and was never in doubt. The script and the suite now carry these figures; the round-2 commit message is immutable and is superseded by them.


The seam I refactored

The script refuses to run as non-root (rc 2) by design, so the only way to gate it as an ordinary user is to make the transforms callable. Sourcing it defines the helpers and takes the (return 0 2>/dev/null) branch, running nothing. LSOF_BIN exists so the suite can drive both the not-on-PATH branch and the rows branch without planting a binary β€” and it is inside the sourced branch only (round 1, F4).

Defects the suite covers

All eight from claudedocs/handoff-nix-disk-cleanup.md rank 5 / cairn devrc/diagnose-disk-accounting:

  1. lsof column resolved from the HEADER β€” pinned with two fixtures: +L1 puts SIZE/OFF at col 7, plain lsof -n -P puts it at col 9. Both carry the same two sizes summing to 2.5 GiB and every other column in both sums to 0.0, so 2.5 is reachable only from the right column. Plus: an absent SIZE/OFF column must refuse.
  2. Root command injection β€” pre-existing fix, newly guarded; see Correction 1.
  3. E2BIG β€” a fixture sized from the live getconf ARG_MAX, with the glob form run as a positive control and confirmed to die Argument list too long.
  4. Subshell accumulator β€” behavioural: with foreign mounts present the report must name them and must not print none found, plus a positive control that the none branch can fire at all.
  5. grep -c prints 0 and exits 1 β€” an empty denial log must produce exactly three clean zero lines and must not trip the broken-counter guard.
  6. NR-1 β†’ βˆ’1 β€” empty input, header-only input and a missing lsof binary are three different answers, none of them a bare zero.
  7. du -x is not "only this filesystem" β€” per-candidate device comparison, in both section 6c and section 6d.
  8. A count with no denial figure is a floor β€” denials counted, paths listed, FLOORS, not totals asserted.

Round 1 β€” defects found while writing the tests

(a) The no-rows message in section 7 was unreachable dead code. LSOF_OUT=$(lsof +L1 2>/dev/null); LSOF_RC=$? is a checked command under set -e, and lsof documents exit 1 when it finds nothing β€” the ordinary case. Now || rc=$?, with a probe that runs the real set -euo pipefail and demands a marker printed after section 7.

(b) <producer> | sort | head -N under pipefail is a live, size-dependent abort. Measured at two points: 40 entries survive rc 0, 20,000 die rc 141. The real /tmp had 171,886. Fixed with head_n() { awk -v n="$1" 'NR<=n'; }.

(F1) A vanished entry mid-scan killed the whole run β€” two routes, not one. GNU find exits 1 when an entry disappears between readdir and stat; xargs exits 123 when any du it ran exited 1. Both are promoted by pipefail and fatal under set -e. Two deterministic fixtures isolate one route each (a mode-0400 directory; a directory holding a mode-000 subdirectory), so neither guard is scored on the other's failure and neither needs a concurrent deleter.

(F5) Defect 7 was fixed at /home and left standing at /tmp. -xdev only stops find descending past a mount β€” it still lists the mountpoint at depth 1, so it arrived as a starting point for du -sh -x, the one case du -x cannot handle. Section 6d now applies the same per-candidate device comparison, through a single _on_device filter over find -printf '%D\t%p\0'. _dev_of moved from stat -c '%D' (hex) to stat -c '%d' (decimal) to match find's own %D.

(F2a) The head ban was SPELLED, not structural. The banned pattern was | *head -[0-9], demanding a digit after head - β€” so head -n 20, head -n 30 and head -n 15 all SURVIVED a fully green suite. Widened to | *head *-, with all four spellings in the battery.

(F2b) The E2BIG fixture was files-only, so inode_breakdown measured nothing. It filters -type d and the fixture was 17,550 touched files, so its probe call returned zero rows and the whole SIGPIPE battery row was killed by size_breakdown alone. The fixture now also builds 600 directories, the probes are split one per breakdown, and a non-vacuity assertion fails loudly if the row count returns to 0.

Round 2 β€” the round-1 fix created the headline defect

(πŸ”΄ F-1) -printf '%D\t%p\0' emits NOTHING for an unstattable entry. Round 1 swapped -print0 for -printf '%D\t%p\0' to get the device id for the new filter. %D forces a stat per entry, and a failed stat emits no record at all where -print0 still emitted the name. So an entry root cannot stat β€” a FUSE mountpoint without allow_other, gvfs, sshfs, or a device answering ESTALE/EIO β€” vanished from size_breakdown, inode_breakdown and foreign_entries at once, and foreign_entries then printed the affirmative "none β€” every depth-1 entry is on the same filesystem". Fixed by keeping each enumeration's stderr in a file, counting it, reporting it (!! UNSTATTABLE), and downgrading the affirmative "none" to "none VISIBLE". Numbers in Correction 4.

(πŸ”΄ F-2) A bare statement-level du -sh under set -e. Section 5's total sat directly beneath two carefully || true-guarded pipelines, under a comment describing the treatment it did not have. Round 1's site enumeration was done by eye and missed it; round 2 replaced that with a mechanical sweep, which is now section 7b of the suite.

(🟑 F-3) foreign_entries reintroduced F7 in the commit that fixed F7 β€” | tr '\0' '\n' | head_n 15 turned a directory name containing a newline into two report rows. Now one row per NUL record.

(🟑 F-4/F-5) Two stale claims, each in a file the scanner cannot see β€” run-tests.sh and test_no_real_launchers_all_targets.py. The banned-pattern scanner only reads diagnose-disk-accounting.sh, so both copies walked past it.

Round 3 β€” this round

(🟑 1) Three mktemp files in NO trap, opened into the directory under diagnosis. size_breakdown, inode_breakdown and foreign_entries each opened errf=$(mktemp) β€” an anonymous /tmp/tmp.XXXXXXXXXX β€” removed only by that function's last statement. The realistic way this run ends is SIGINT, not an abort: the run it was written for took ~3 h over 78 million entries. MEASURED: an EXIT trap does run when bash is killed by an untrapped SIGINT, so the trap removed the named $DENIED_LOG and left up to three unattributable files in /tmp.

Fixed structurally rather than by extending a list: every temp file now goes through _scan_mktemp <kind> (template /tmp/disk-accounting-<kind>.XXXXXX) and is removed by _cleanup_temps, which reads its variables at call time β€” so one trap _cleanup_temps EXIT, installed before the first mktemp, covers every file opened later. That also deletes the hand-widened second trap at section 6c, which is the mechanism the three files fell out of in the first place.

Guarded end-to-end: a probe stubs _report_unstattable (called after both mktemps and before the rm) to record the paths and signal itself. The positive control runs first and must LEAK β€” with no trap, both files survive β€” because a "nothing was left behind" assertion is otherwise indistinguishable from a probe that never opened a file. That control caught a real harness bug: a first draft used kill -INT alone and produced three FAILs the moment the mutation battery ran the suite from nohup … &, since bash sets SIGINT to SIG_IGN for a command started asynchronously without job control and a non-interactive shell cannot reset a signal ignored on entry. The probe now falls back to SIGTERM and says which signal it delivered.

(🟑 5) du's stderr was still discarded, and the new blind-spot report made the silence mean something it hadn't. _report_unstattable fires only when find's stderr is non-empty. An entry find can stat but du cannot fully read is listed with an under-counted figure and no marker of any kind β€” and once !! UNSTATTABLE existed, the absence of a blind-spot line started reading as "nothing was missed". MEASURED on base/{open,locked/inner}, each holding one 4 KiB file with inner mode 000: du -sh -x prints 8.0K for locked against a true 12K β€” a 33% under-count presented as a total β€” and exits 1.

du's stderr is now captured the way find's is at the sites that call _report_unreadable β€” size_breakdown's own capture, section 5's PVC listing and section 6c's /home listing β€” and reported as !! PARTIALLY READ: du could not read N path(s). (This sentence used to read "at all three du sites", which asserted a count of the file's du invocations and was wrong; see round 4 🟑 A below. The scope is now stated structurally, and _report_unreadable's own comment declares that it says nothing about any other du in the file.) The two sinks are deliberately separate files: one blind spot erases an entry, the other shortens its number, and a merged count would be one number standing for two different claims. A mutant that points the du report at find's stderr is in the battery for exactly that.

(🟒 1) The sweep's framing was wider than what the sweep can see. The script's comment read "Everything that scan reports is guarded above EXCEPT these" and listed only the two out=$(… | sort …) captures; the suite header said 7b "sweeps the whole file". The scan keys on a line's first word and drops any line containing ||, so a pipeline headed by for/done/printf is invisible to it, and so is one whose early stages are guarded while its last stage is not. Five trailing sort stages are unguarded, not two β€” three of them statement-level pipelines the sweep cannot reach.

Both halves fixed: the claims are narrowed to what the scan actually does, and Β§7b gained a second ledger over trailing sort stages that fails when the set GROWS or SHRINKS, with its own canary exercising both branches (a guarded { … } || true group must be excluded). Nothing here is a live bug β€” sort over ≀30 lines will not spill β€” but the exception list read as exhaustive and was not.

(🟑 2, 🟑 3) The round's own corrective prose was false, twice. run-tests.sh said "282 at the merge base (567 after round 1, 730 after round 2)" β€” the file was 766, i.e. the sentence explaining that stale counts get quoted downstream carried a stale count. And test_no_real_launchers_all_targets.py said the suite sources the script "ten more times, counting the four probe scripts" β€” there are five, and nodev-probe.sh was added by the same commit. Both now state no drifting count at all: the historical figure is anchored to a sha, and the current ones are re-derivable with wc -l / grep -c.

While correcting them I found a third of the same kind, in the suite's own header: "It was 282 lines when this suite was written" β€” 282 is the count at the merge base, before this suite's commit; by the end of that commit the file was 414.

(Out of range, declared not fixed) split_by_device is a known fourth site. Its [ -d "$p" ] || continue silently drops a directory root cannot stat, with no count, feeding report_foreign_mounts. Round 2's comment claimed "every caller reports the count", which is true of _depth1_nul's three callers only; that over-claim is corrected. The site itself is recorded, not fixed: [ -d "$p" ] says no for three different reasons β€” not a directory, stat refused, or an unmatched glob left its own pattern β€” and bash's file tests cannot separate them, so a count needs a different enumeration. Inventing one inside an audit-fix round is precisely how each round of this ladder produced the next round's finding. What limits it is that report_foreign_mounts's empty branch already tells the reader an empty list is a BUG rather than a clean result.

Round 4 β€” this round

No πŸ”΄: one 🟑 and three 🟒, and nearly all of it is again this ladder's own corrective prose being wrong β€” the fifth consecutive round in which that is the most reliable finding. So this round removes claims rather than restating them. Where a sentence needed a number to be true, the number is gone and the command that derives it is in its place.

(🟑 A) "du's stderr is kept at all three du sites" was false β€” and one of the uncovered sites printed a figure with no marker at all. The file has more du invocations than the ones that route stderr into a file. Some of the others at least print a || echo fallback. Section 6's per-tree row printed nothing: "$(du -sh -x "$d" 2>/dev/null | awk '{print $1}')" renders a partial total exactly like a complete one, which is what a stale NFS/CSI mount under /var/lib/kubelet produces. Since _report_unreadable landed, the absence of a marker reads as an affirmative "nothing was missed" β€” its own thesis β€” so that site was more misleading after round 3 than before it, at a site the round's prose said was covered.

Two fixes, and neither is a new count. The claim is narrowed to the callers of _report_unreadable, named structurally; the rest are declared in that function's comment the way split_by_device's blind spot is declared, with the greps that derive both sets instead of a figure that goes stale. And section 6 now branches on du's status β€” if du_out=$(du …); then du_mark=; else du_mark=' !! FLOOR β€” du could not read all of it'; fi β€” with the marker printed as part of the row. MEASURED 2026-09-08 over a fixture holding a mode-000 subdirectory: 20K printed against a true 24K, now marked, and the run continues. if VAR=$(…) rather than a bare assignment, because a command in an if condition is not checked by set -e.

Guarded by two separate required rows with two isolated mutants, because the site has two independent ways to be wrong: the branch can be removed, or the marker can be computed and never reach the output. Section 6 is root-only, so both are INVARIANT PINS; the fixture above exercises the expression, not the script's own line, and is reported as such.

(🟒 D) : > "$DU_ERR" is set -e-fatal and was invisible to both ledgers. A redirection failure on a special builtin ends the shell β€” MEASURED 2026-09-08, bash 5.3.15: set -euo pipefail; : > /absent/x exits 1 with nothing after it running; the same line with || is caught and the run continues. The line is headed by :, so 7b's first-word sweep cannot see it, and it carries no | sort, so the trailing-sort ledger cannot either. It was in neither ledger and absent from the "left open on purpose" list β€” and round 3's own 🟒 1 was "the exception list read as exhaustive and was not", in the same commit that added this site. Section 6c's copy fires after sections 1–6b have printed, which fails the file's own criterion for leaving a site unguarded.

Guarded rather than listed, so the exception list does not have to grow: : > "$DU_ERR" || echo "COULD NOT MEASURE: …". Deliberately not || true β€” a file that did not truncate still holds an earlier site's paths, and _report_unreadable would then attribute them here. Pinned as a relationship rather than a literal: the suite counts : > "$DU_ERR" lines and guarded ones and asserts they are equal and non-zero, so it goes red when a guard is dropped and when a new unguarded truncation is added. Both directions have a mutant; a single required row would have stayed green with one of the two sites unguarded.

(🟒 B) The recorded cost of hardcoding /tmp said "empty", and omitted the consequence that matters. MEASURED 2026-09-08 on this host: leftovers of both kinds were sitting in /tmp and not all of them were empty β€” some held a fixture's captured stderr (du: cannot read directory '/tmp/tmp.XXXXXXXXXX/du-errors/locked': Permission denied). Mode 0600, so "harmless" holds; "empty" did not. The comment now says so, and quotes ls -l /tmp/disk-accounting-* rather than a number, because the number is whatever the last interrupted sweep happened to leave.

The half that was never recorded: hardcoding /tmp also removes TMPDIR as an escape route, on exactly the failure this script is pointed at. $DENIED_LOG and $DU_ERR are opened unguarded at the top of the executable region, so a root filesystem out of inodes ends the run on those lines with a blank report β€” which the exception list accepts as the honest outcome. What it did not say, and now does, is that the bare mktemp this replaced would have honoured an inherited $TMPDIR and the template cannot: pointing this run's scratch at another filesystem now means editing the file.

(🟒 C) The control in "the pytest tier is RED" miscounted the tests and files it rests on. Fixed above, by deleting the counts and pointing at the table. The conclusion is unchanged and is now stated in terms the table itself carries.

Red-at-old-code / green-at-HEAD

The current suite run against each earlier revision of the script, unmodified:

suite vs scripts/diagnose-disk-accounting.sh @ 491fc447 (pre-audit) :  96 FAIL, 106 ok
suite vs                                     @ 4d8228c3 (round 1)   :  55 FAIL, 147 ok
suite vs                                     @ eb4e3a81 (round 2)   :  23 FAIL, 179 ok
suite vs                                     @ 530a5c56 (round 3)   :   3 FAIL, 199 ok
suite vs HEAD                                                       :   0 FAIL, 202 ok

Every row was re-run with the round-4 suite, not quoted from a previous round β€” which is why the first three are each three higher than the figures round 3 published (93 / 52 / 20): round 4's three new guards are red at every earlier revision too. The three red at 530a5c56 are exactly those guards, one per fix β€” section 6's branch on du's status, section 6's printed marker, and the : > "$DU_ERR" ledger, which reports 0 of 2 guarded there.

The 20 red at eb4e3a81 as round 3's suite reported them β€” the table above now reads 23 there, the extra three being round 4's guards β€” are exactly round 3's new guards, and they account for all of it: 4 absent helpers (_errline_count, _report_unreadable, _scan_mktemp, _cleanup_temps), 3 route-(b) du assertions, 5 temp-file rows (the name, the file's existence, the leak positive control, and the two _cleanup_temps empty-slot rows), 7 structural pins in section 7, and 1 sort-ledger row.

One of them is worth naming: "an interrupt mid-breakdown leaves NO temp file behind" passes at eb4e3a81 β€” vacuously, because the probe records no paths there. Its positive control is what goes red. A leak assertion without one is a claim about a probe that never ran.

Mutation battery

bash scripts/tests/mutants-diagnose-disk-accounting.sh β€” one row per mutant plus a SURVIVES control, each an exact single-occurrence replacement whose application is checked, each scored on whether its own guard's FAIL: line appears. A mutant killed only by some other guard reports WRONG-KILLER, not ok. (The roster size used to be written here as a number and is not any more: it is one of the counts that drifts every round. Run the battery β€” it prints one line per mutant.)

== BASELINE ==            FAIL-lines=0  ok-lines=199   (green)
== NEGATIVE CONTROL ==    FAIL-lines=6                 (the harness can go red)
== 64 mutants ==          every row KILLED by its own guard
== SURVIVES control ==    comment-reword β€” behaviour-free edit killed nothing

Round 3's ten new rows, all KILLED by its own guard:

du-stderr-discarded                 du's stderr back to /dev/null
du-blind-spot-not-reported          _report_unreadable call removed
du-report-reads-finds-stderr        the two stderr sinks swapped
scan-temp-file-anonymous            named mktemp -> bare mktemp
cleanup-forgets-the-scan-temps      the historical fixed-list cleanup, restored
trap-named-as-a-fixed-list          trap _cleanup_temps -> trap 'rm -f "$DENIED_LOG"'
trap-installed-after-the-first-mktemp   the two lines swapped; the NAME pin stays green
k3s-du-listing-stderr-discarded     section 5's du stderr back to /dev/null
sort-ledger-site-guarded-away       a sort stage guarded -> ledger shrinks
sort-ledger-site-added              a sort stage added    -> ledger grows

Round 4's new rows, all KILLED by its own guard, and deliberately isolated in pairs:

section6-du-status-not-read              the branch removed; the printf pin stays green
section6-marker-computed-but-not-printed the marker dropped from the argument list;
                                         the branch pin stays green
duerr-truncation-unguarded-6c            section 6c's guard removed  -> ledger 1 of 2
duerr-truncation-added-unguarded         a new unguarded truncation  -> ledger 2 of 3

The occurrence check earned its keep again, on this round's own edit. A first draft of section 6's new comment quoted ROOT_DEV=$(_dev_of /) || ROOT_DEV= verbatim while explaining the checked-assignment reasoning. The mutator matches raw text, so that made an existing mutant ambiguous: root-dev-reading-unguarded reported occurrences=2 and scored MUTATION DID NOT APPLY. Without that check it would have silently measured the unmutated file β€” "the guard held", the most flattering possible wrong answer. The comment now paraphrases, and says why.

It also earned it in round 3: unstattable-report-suppressed reported occurrences=2 the moment _report_unreadable gained the same [ "$n" -gt 0 ] || return 0 line, so the mutation now carries the local line above it as an anchor. A count=1 replace on a two-occurrence pattern would have scored the wrong function.

Both tiers, read as counts rather than as "BUILD OK"

tier command result
dev-host Β· pytest nix develop … -c scripts/gate.sh --tier both TOTAL collected=22003 passed=21992 skipped=3 failed=8, RESULT: FAIL (exit=1). PASS scripts/tests/test_diagnose_disk_accounting.sh (script) β€” 202 ok:, 0 FAIL:, read from the gate's own log.
dev-host Β· node same run TOTAL suites=5 files=41 tests=1449 pass=1449 fail=0 skipped=0 (floor 1367), RESULT: PASS (exit=0)
sandbox Β· pytest nix build -L .#checks.x86_64-linux.pytests TOTAL collected=22003 passed=22000 skipped=3 failed=0, RESULT: PASS (exit=0). My suite ran here too: 202 ok:, 0 FAIL:.
sandbox Β· node nix build -L .#checks.x86_64-linux.nodetests TOTAL suites=5 files=41 tests=1449 pass=1449 fail=0 skipped=0, RESULT: PASS (exit=0)

Both nix builds were run with -L, so the counts above were read from the streamed build log rather than from a silent exit 0 β€” a quiet nix build is cached, not a verdict.

πŸ”΄ The pytest tier is RED, and none of it is this PR

The two tiers disagree, and the disagreement is itself the useful reading: the dev host is red, the sandbox is fully green (failed=0), and every dev-host failure is a toolchain the sandbox pins away. (Round 4 update: the sandbox previously reported one failure β€” test_git_repo_isolation.py::test_live_cotenants…, called a flake at the time. It did not recur in this round's sandbox run, which is the only evidence available that the "flake" reading was right; it is still the reading, not a proof.)

failure tier control
test_analyze_service_index_escrow_verify.py::test_a_TAMPERED_or_TRUNCATED_artifact_is_ARTIFACT_CORRUPT_not_EMPTY Γ—3 dev-host only reproduced at eb4e3a81
…::test_every_decrypt_family_VERDICT_is_pinned_WHOLE dev-host only reproduced at eb4e3a81
test_analyze_service_index_backup.py::test_the_LEAKING_manglers_really_DO_make_age_keygen_echo_the_secret dev-host only reproduced at eb4e3a81
…::test_resolve_recipient_NEVER_quotes_age_keygens_INPUT_ECHOING_stderr dev-host only reproduced at eb4e3a81
test_opencode_engine.py::test_engine_is_the_version_every_measurement_is_keyed_to dev-host only reproduced at eb4e3a81
test_browser_agent.py::test_the_release_handler_EXITS_rather_than_resuming[INT] dev-host only known signal race under load; 0 files of this PR touch browser-bridge
test_git_repo_isolation.py::test_live_cotenants_sees_another_process_in_the_repo sandbox only, and did not recur in round 4's sandbox run known flake

The control was run properly rather than reasoned about: git archive eb4e3a81 | tar -x into a scratch directory β€” no worktree, no shared-repo write β€” then the dev-host rows re-run there. Each one reproduced, which is what the table's control column records row by row. (Round 4 correction: this paragraph used to summarise that as "the six named tests … the two test files involved are byte-identical", and neither number matched the table directly above it β€” "six" is only reachable by counting table rows, which would include the [INT] row the table itself calls a signal race, and that reading gives four files. The counts are gone; the table is the record.) The visible causes are toolchain drift the dev host has and the sandbox pins: age 1.3.1 β†’ 1.3.2 changed the stderr these guards assert on, and opencode is 1.18.29 against a pinned 1.18.21.

No file in that table is one this PR touches β€” git diff --name-only c1169e3b..HEAD lists scripts/diagnose-disk-accounting.sh, scripts/run-tests.sh, scripts/tests/test_diagnose_disk_accounting.sh, scripts/tests/mutants-diagnose-disk-accounting.sh and scripts/tests/test_no_real_launchers_all_targets.py, and nothing else. This PR does not fix these failures, and it should not be read as having made the gate green.

What I could NOT cover without root

Sections 1, 2, 3, 5, 6, 6b and 8 do privileged whole-filesystem measurement β€” dumpe2fs -h /dev/nvme0n1p2, find / -xdev across /root, /var/lib/docker, /var/lib/kubelet, /var/lib/private, /var/lib/rancher/k3s/storage, findmnt /mnt/rootcheck. Their arithmetic is unguarded here: the hardlink dedup in section 2's awk, the residual subtraction in section 3, the inode-table arithmetic in section 1. du -x is in the same category, which is why its pin is structural and labelled as such β€” as are section 5's and section 6c's du-stderr captures, section 6's FLOOR marker, and the : > "$DU_ERR" ledger.

Reported, not fixed: stat -f / measures the real root filesystem while dumpe2fs measures $DEV, and nothing cross-checks that they are the same filesystem. split_by_device's silent drop, above β€” declared, not closed. And the du invocations outside _report_unreadable's callers still send stderr to /dev/null and produce no path count. That scope is declared in _report_unreadable's comment, with the two greps that derive it, rather than counted anywhere.

Registration

SHELL_TESTS in run-tests.sh, plus the deliberate ledger in test_no_real_launchers_all_targets.py. The suite touches no launcher, no spool and no git: it sources the script β€” directly, and once inside each probe script it writes β€” and executes it only on the non-root refusal path, where every run exits 2 at the root check before the script opens a temp file. The suite aborts if it is itself running as root, since several fixtures are inert under uid 0. Its EXIT trap chmod -R u+rwXs before rm -rf, because section 4b deliberately builds unreadable fixture directories.

… no gate ever ran

`scripts/diagnose-disk-accounting.sh` had no test file, in a repo with no
shellcheck gate. That is why a root command injection, an E2BIG abort and a hard
`0.0 GiB` all shipped invisibly: nothing here was ever executed by a gate, so
nothing here could be SEEN to be wrong.

The script refuses non-root (rc 2) by design, so the suite could not run it. It
now carries a sourceable seam β€” `BASH_SOURCE[0] != $0` returns before the root
check β€” and nine helpers hold the transforms verbatim. Sourcing measures
nothing; executing is byte-for-byte the same report as before.

Covered, each with a positive control and each watched red:
  * lsof column resolved from the HEADER, pinned with TWO fixtures (+L1 -> col
    7, plain -n -P -> col 9) whose every other column sums to 0.0, so a fixed
    index cannot pass both
  * root command injection, driven by a directory named
    `evil";echo PWNED-AS-$(id -un) >&2;"x` and asserted on the EXPANSION
  * E2BIG, with the fixture sized from the live ARG_MAX and the glob form
    watched to die rc 126 first
  * the foreign-mount listing, the device split, the denial counts, the
    `grep -c` two-line zero, and the never-negative lsof count

Three defects found while writing them, and fixed:
  a) `OUT=$(lsof …); RC=$?` is a CHECKED command under `set -e` and lsof exits 1
     when it finds nothing, so section 7's no-rows message β€” written precisely
     to stop a zero being read as a measurement β€” was unreachable, and sections
     7 and 8 never printed.
  b) `<producer> | sort | head -N` under pipefail is a SIZE-DEPENDENT abort:
     measured 40 entries survive rc 0, 20,000 die rc 141, silently. The real
     /tmp had 171,886. Replaced by head_n (awk reads to EOF) at all nine sites.
  c) a second glob-into-du in section 5.

19 mutants, all KILLED by their own guard, in
`scripts/tests/mutants-diagnose-disk-accounting.sh`.

Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
…guard it is

`du` never starts a shell, so no mutation of `size_breakdown` short of adding
`sh -c` could make that assertion go red. It pins a real property β€” the pipeline
stays shell-free β€” but it is not a test of a bug that ever existed, and counting
it as regression coverage overstates what this suite guards. Named so a reader
stops at the right line.

Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
…e whole run, and three guards were narrower than their own descriptions

Round-1 audit findings on #1366. Five payload fixes, two guard fixes, 56 new
assertions (71 -> 127) and 22 new mutants (19 -> 41).

PAYLOAD

F1 A vanished entry mid-scan aborted the report, at three sites.
   GNU find exits 1 when an entry disappears between readdir and stat; the
   target host's /tmp holds ~270,000 churning top-level entries and section 4's
   own counter already calls those ENOENTs "benign, transient". 2>/dev/null ate
   the message, pipefail promoted it, set -e killed the run: sections 6d-inodes,
   7 and 8 never printed and the report ended with NO error. Third route to the
   same truncated-scan failure (E2BIG and SIGPIPE were the first two).

   MEASURED A FOURTH ROUTE the audit did not name and the prescribed fix does
   not cover: xargs exits 123 when any du it ran exited 1 β€” the same vanished
   entry, one step later. Both stages are now `|| true` at all three sites
   (size_breakdown, inode_breakdown, section 5) plus section 6c's own xargs.
   Isolated fixtures: a mode-0400 directory makes find exit 1 while still
   listing (route a); a mode-000 subdirectory makes du exit 1 with find at 0 and
   the readable sibling still reported (route b).

F3 The seam was reachable from the environment and the comment denied it.
   `[ "${BASH_SOURCE[0]}" != "$0" ]` β€” bash imports BASH_SOURCE from the env as
   a scalar, so `env 'BASH_SOURCE=(nope)' bash <script>` took the SOURCED branch
   and returned at top level: rc 2, no report. rc 2 is also the script's "you
   forgot sudo" status, so two causes shared one exit code β€” which is why only a
   guard asserting the refusal MESSAGE can see it. `bash < script` was the
   mirror image: BASH_SOURCE unset, set -u, dead on the guard's own line, rc 1
   (base ran fine that way, so that half was a genuine regression).
   Replaced with `(return 0 2>/dev/null)`, which reads no variable. The header
   comment now states what was measured instead of asserting immunity.

F4 LSOF_BIN was a test seam that widened what a ROOT run executes.
   `LSOF_BIN=${LSOF_BIN:-lsof}` sat ABOVE the seam, so an inherited
   LSOF_BIN=/anything was what root would run; base hardcoded `lsof`. The
   override now lives inside the sourced branch; the execute path pins
   `LSOF_BIN=lsof`. Observed through `bash -x` on the real script, since the
   execute path exits 2 before printing anything of its own.

F5 Defect 7 (`du -x` is not "only this filesystem") was fixed at /home and left
   standing at /tmp. `-xdev` stops find DESCENDING past a mount but still LISTS
   the mountpoint at depth 1, so a mount under /tmp arrived as a starting point
   for `du -sh -x` β€” the exact case du -x cannot handle β€” and its whole size
   landed in a figure labelled root-fs /tmp usage. Section 6d now applies the
   same per-candidate device comparison section 6c uses, in both breakdowns, via
   a single `_on_device` filter over `find -printf '%D\t%p\0'` (one process, not
   a stat fork per entry). `_dev_of` moved from `stat -c '%D'` (HEX) to
   `stat -c '%d'` (DECIMAL) so it matches find's own %D β€” one format everywhere.
   `du -x` itself is now pinned structurally, labelled as the invariant pin it
   is: a second filesystem needs root, so it cannot be checked behaviourally.

   πŸ”΄ THE FILTER CREATES ITS OWN BLIND SPOT, so section 6d now REPORTS what it
   excluded (`foreign_entries`), the way 6c already does for /home. Dropping a
   foreign mount is right; dropping it silently is the floor-presented-as-a-
   total failure this whole file catalogues. The device id is also validated as
   DIGITS in one place (`_dev_is_valid`) before it is interpolated into a `sed`
   script β€” `stat -c '%d'` cannot produce a `/` today, which is an argument for
   checking it once rather than trusting it at three call sites.

F7 split_by_device wrote the foreign list one-per-line and read it with
   `while IFS= read -r`, so a directory name containing a newline split into two
   rows in the report. Both lists are NUL-separated now.

GUARDS

F2 The `head` ban was SPELLED, not structural: `| *head -[0-9]` requires a digit
   right after `head -`, so `head -n 20` β€” the POSIX-preferred spelling β€” walked
   straight through. Widened to `| *head  *-`; `head -n 20`, `head -n 30`,
   `head -n 15` and `head -15` are all now caught, each as its own mutant. The
   canary line deliberately spells it `head -n 20`, so narrowing the pattern
   back trips the SCANNER-BROKEN branch instead of reporting ok.

F2 The E2BIG fixture was 17,550 touched FILES and inode_breakdown filters
   `-type d`, so it returned ZERO rows and the `inode_breakdown "$BIG"` call in
   the SIGPIPE probe was vacuous β€” the whole battery row was killed by
   size_breakdown alone. The fixture now also builds 600 directories (~140 KiB
   of sort output against a 64 KiB pipe buffer; under ~258 rows the SIGPIPE
   abort does not fire at all), the probes are split one per breakdown, and a
   non-vacuity assertion fails loudly if the row count ever returns to 0.

Also fixed while doing the above: adding `2>/dev/null` to inode_breakdown's new
xargs stage silently disarmed the injection guard β€” the historical defect's own
proof of execution is a planted name printing to STDERR. Caught by the battery
scoring that row WRONG-KILLER, not by a green suite.

EVIDENCE

  new suite vs the base script (491fc44): 43 FAIL,  84 ok
  new suite vs HEAD:                        0 FAIL, 127 ok
  mutation battery: 41 mutants, every one KILLED by its own guard;
    baseline green (127 ok / 0 FAIL), negative control red (6 FAIL),
    SURVIVES control unkilled

NOT FIXED, deliberately: `stat -f /` measures the real root fs while `dumpe2fs`
measures $DEV and nothing cross-checks they are the same filesystem. Reported,
not touched β€” it only executes under root and I cannot verify a change to it.

Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
@ZacxDev ZacxDev changed the title test(disk-accounting): 71 guards for 282 lines of root-only bash that no gate ever ran β€” plus three live defects they found test(disk-accounting): 127 guards for 282 lines of root-only bash that no gate ever ran β€” plus eight live defects they found Sep 8, 2026
@ZacxDev

ZacxDev commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

Round 1 audit β€” claims block

Round 1 was a first, full adversarial audit (7 findings: 1 πŸ”΄, 4 🟑, 2 🟒). Its fixes landed in 4d8228c3. Recording what that round's fixes CLAIM, so the round-2 delta audit can check each against the diff rather than against a narrative.

1. F1 (πŸ”΄): a vanished-mid-scan entry no longer aborts the run β€” `find` guarded at scripts/diagnose-disk-accounting.sh:124, :137, :337, and the fix round claims a FOURTH route the audit did not name: `xargs` exiting 123 when a `du` it ran exited 1, guarded at those three sites plus Β§6c's own `xargs`.
2. F1 guard: the SIGPIPE probe's fixture was static so `find` never errored; claimed replaced with a deterministic permission-fixture probe (mode-0400 dir makes `find` exit 1 while still listing; mode-000 subdir makes `du` exit 1 with `find` at 0), asserting a post-pipeline marker still prints.
3. F2 (🟑): the `head` ban pattern claimed widened from `| *head -[0-9]` to `| *head  *-`, so `head -n N` no longer walks through it; all four spellings claimed to have their own mutant.
4. F2 vacuity: `inode_breakdown "$BIG"` scored 0 rows because the fixture was files and it filters `-type d`; claimed fixed by adding 600 directories to the fixture, sized so `sort`'s output exceeds the 64 KiB pipe buffer, plus a non-vacuity assertion that fails if the row count returns to 0, and probes split one per breakdown.
5. F3 (🟑): the seam claimed changed to `(return 0 2>/dev/null)`, and the header comment β€” which asserted the guard was not reachable from the environment β€” claimed rewritten to state what was measured.
6. F4 (🟑): `LSOF_BIN` override claimed moved inside the sourced branch with the execute path pinning `LSOF_BIN=lsof`, plus a guard pinning it (the prior mutant SURVIVED).
7. F5 (🟑): the per-candidate device filter claimed applied to BOTH breakdowns via one `_on_device`; `_dev_of` claimed moved hexβ†’decimal to match `find -printf '%D'`; `-x` claimed pinned structurally and labelled an invariant pin; and a new `foreign_entries` listing claimed added because the filter itself created a silent blind spot.
8. F6 (🟒): §5's dotfile enumeration change claimed left in code and corrected in the PR body instead.
9. F7 (🟒): both lists in `split_by_device` claimed NUL-separated, read with `read -r -d ''`.
10. PR body: the claim that this PR FIXED the `xargs -I{}` root command injection claimed corrected β€” the injection was fixed in `d8fe0bc` (#1227) and this PR adds only the test.
11. Suite/battery counts claimed: 127 ok / 0 FAIL at HEAD; 43 FAIL / 84 ok when the new suite runs against the base script at 491fc447; 41 mutants each KILLED by its own guard, baseline green, negative control red at 6 FAIL, SURVIVES control unkilled.
12. Deliberately NOT fixed: `stat -f /` measures the real root fs while `dumpe2fs` measures `$DEV`, with no cross-check that they are the same filesystem β€” claimed reported in the body and untouched because it executes only under root.

Independently re-verified before round 2 (not accepted from the fix round's report)

Re-ran in a detached worktree at 4d8228c3, and against the pre-fix script in a cp -a copy with .git removed:

claim measured
127 ok / 0 FAIL at HEAD 127 ok / 0 FAIL, rc 0
43 FAIL / 84 ok vs base script @ 491fc447 43 FAIL / 84 ok, rc 1 β€” includes FAIL: bash < script exited 1, expected 2, the F3 regression guard
41 mutants, all killed by their own guard 41 rows, 0 SURVIVED, 0 WRONG-KILLER, 0 DID-NOT-APPLY; baseline 127 ok / 0 FAIL, negative control 6 FAIL, SURVIVES control unkilled

Ledger β€” round 1 Β· payload lines changed THIS round: 207 (scripts/diagnose-disk-accounting.sh +180/βˆ’27), scaffolding +540/βˆ’41 across the two test files. The attribution gate does not fire; the ladder is still auditing the PR.

…ntly DROPPED the entries it could not stat, and said "none"

Round 2 of the audit ladder found 2 πŸ”΄ and 3 🟑. The headline one was created
by round 1's own fix, which is the third consecutive round where a fix round
produced the next round's finding.

## πŸ”΄ F-1 β€” `-printf '%D\t%p\0'` emits NOTHING for an unstattable entry

Round 1 swapped `-print0` for `-printf '%D\t%p\0'` to get the device id for the
new per-candidate device filter. But `%D` forces find to STAT each entry to
format the record, and when that stat fails GNU find emits no record at all β€”
where `-print0` still emitted the name. Measured on two implementations:

  -print0                    345 bytes, rc 0   (bfs 4.1.1)
  -printf '%D\t%p\0'           0 bytes, rc 1   (bfs 4.1.1)
  findutils 4.10.0             0 bytes; 4.11.0 (nix dev shell) 119 / 0 bytes

Consequence: an entry root cannot stat β€” a FUSE mountpoint without
`allow_other` (AppImage `/tmp/.mount_*`, gvfs, sshfs), or a device returning
ESTALE/EIO β€” vanished from `size_breakdown`, from `inode_breakdown` AND from
`foreign_entries`, which then printed the affirmative sentence "none β€” every
depth-1 entry is on the same filesystem". All three finds discarded stderr and
`report_denials` only reads section 2's log, so nothing counted it.

πŸ”΄ That is the floor-presented-as-a-total failure this script exists to
catalogue, produced by the function added to prevent it β€” the FIFTH route to it
in this one file (E2BIG, SIGPIPE, find rc 1, xargs rc 123, now this). It also
falsified the comment round 1 wrote in the same commit claiming "a total
failure is still visible, as an empty section".

Fixed by capturing each enumeration's stderr, counting and reporting the
unstattable entries, and changing `foreign_entries` to say only that none is
VISIBLE rather than asserting none exists.

## πŸ”΄ F-2 β€” a bare statement-level `du -sh` under `set -e`

`du -sh /var/lib/rancher/k3s/storage` sat directly beneath two carefully
`|| true`-guarded pipelines, under a comment saying the same treatment was
needed. A pod unlinking a file between du's readdir and stat made it print an
UNDER-COUNTED total, exit 1, and kill sections 6, 6b, 6c, 6d, 7 and 8 with no
error. Round 1's site enumeration covered pipelines and missed the one direct
`du`; that is twice an enumeration missed a member, so this round swept
mechanically rather than by eye. Now `|| echo "COULD NOT MEASURE …"`, which
labels the floor as a floor instead of leaving it to read as a total.

## 🟑 F-3 β€” `foreign_entries` reintroduced F7 in the commit that fixed F7

`| tr '\0' '\n' | head_n 15`: a directory name containing a newline became two
report rows, one reading as a real path, and consumed two of the fifteen slots.
`/tmp` is mode 1777, so any user can create one. Now one row per NUL record,
matching `report_foreign_mounts`.

## 🟑 F-4 / F-5 β€” two stale claims, each in a file the scanner cannot see

`scripts/run-tests.sh` still described the sourceable seam this PR REMOVED and
now BANS, and called the script "282 lines" (567 at head). The banned-pattern
scanner only reads `diagnose-disk-accounting.sh`, so nothing caught the copy.
And `test_no_real_launchers_all_targets.py` pinned a justification saying the
suite "does execute the script itself ONCE" β€” it is now seven times, and
section 2c ran the real root script OUTSIDE the suite's root guard, so under
root it would have run `find / -xdev` and both breakdowns over a 78-million-
entry /tmp for hours and then reported green. Both corrected, and each now
records what it previously said so the next reader is not sent hunting.

## Verification

  suite at HEAD                       162 ok / 0 FAIL
  suite vs the round-2 script 4d8228c  27 FAIL / 135 ok
  mutation battery                    54 mutants, every one KILLED by its own
                                      guard; baseline 162/0, negative control
                                      red at 6 FAIL, SURVIVES control unkilled

The red-at-4d8228c3 run is the evidence that matters: the new guards fail
against the exact code they were written for, including
"foreign_entries does NOT claim every entry is on the same filesystem".

NOT verified: sections 1, 2, 3, 5, 6, 6b and 8 execute only under root and
remain unguarded; F-2 is demonstrated on an isolated reconstruction of section
5's code, not on a live root run. The device filter's behaviour against a real
second filesystem is asserted nowhere β€” the suite stubs `_dev_of`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvuSKVRMV7KEmXH8KVe4gb
Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
@ZacxDev

ZacxDev commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

Round 2 audit β€” claims block

Round 2 was a delta re-audit of 491fc447..4d8228c3 (2 πŸ”΄, 3 🟑). Its fixes landed in eb4e3a81. Recording what those fixes CLAIM, so round 3 can check each against the diff rather than against a narrative.

1. F-1 (πŸ”΄): `-printf '%D\t%p\0'` emitted NO record for an entry it could not stat (where the replaced `-print0` still emitted the name), so such an entry vanished from size_breakdown, inode_breakdown AND foreign_entries β€” which then printed the affirmative "none β€” every depth-1 entry is on the same filesystem". Claimed fixed by capturing each of the three enumerations' stderr instead of discarding it, counting and reporting the unstattable entries, and changing foreign_entries to say only that none is VISIBLE.
2. F-1 comment: the round-1 comment claiming "a total failure is still visible, as an empty section" was falsified by F-1; claimed rewritten, and the `%D` behaviour claimed documented across three find implementations (bfs 4.1.1, findutils 4.10.0, findutils 4.11.0 in the nix dev shell).
3. F-1 guard gap: the "SURVIVING IS NOT ENOUGH β€” the readable entries must still be REPORTED" assertion was applied to route (b) only; claimed now applied to route (a) as well.
4. F-2 (πŸ”΄): the bare statement-level `du -sh /var/lib/rancher/k3s/storage` under `set -e` printed an under-counted total, exited 1 and killed sections 6/6b/6c/6d/7/8 silently. Claimed fixed with `|| echo "COULD NOT MEASURE …"` so the floor is labelled a floor. The round claims it swept for this class MECHANICALLY rather than by eye, because a by-eye enumeration had already missed a member twice.
5. F-3 (🟑): `foreign_entries`' `| tr '\0' '\n' | head_n 15` split a newline-containing directory name into two report rows and consumed two of fifteen slots; claimed fixed to one row per NUL record, matching report_foreign_mounts.
6. F-4 (🟑): `scripts/run-tests.sh` described the sourceable seam this PR REMOVED and now BANS, and called the script "282 lines" (567 at head); claimed corrected, and the comment claims to record what it previously said.
7. F-5 (🟑): section 2c executed the real root script OUTSIDE the suite's root guard (under root it would run `find / -xdev` and both breakdowns over a 78M-entry /tmp); claimed fixed. The pinned justification in test_no_real_launchers_all_targets.py:219 saying the suite executes the script "ONCE" β€” actually seven times β€” claimed corrected.
8. Counts claimed: suite 162 ok / 0 FAIL at HEAD; 27 FAIL / 135 ok when the round-2 suite runs against the round-2 script at 4d8228c3; 54 mutants each KILLED by its own guard, baseline 162/0, negative control red at 6 FAIL, SURVIVES control unkilled.
9. Still NOT verified and claimed as such: sections 1, 2, 3, 5, 6, 6b and 8 execute only under root and remain unguarded; F-2 is demonstrated on an isolated reconstruction of section 5's code, not a live root run; the device filter's behaviour against a real second filesystem is asserted nowhere because the suite stubs `_dev_of`.

Independently re-verified before round 3 (not accepted from the fix round)

The round-2 fix agent was stopped mid-run by the operator and had committed and pushed nothing β€” all 728 insertions were uncommitted in its worktree. Its work was preserved, checked for TEMP-DISABLED/skip markers (none), verified, and committed as eb4e3a81.

claim measured
162 ok / 0 FAIL at HEAD 162 / 0, rc 0
27 FAIL / 135 ok vs the round-2 script @ 4d8228c3 27 / 135, rc 1 β€” including route (a): foreign_entries does NOT claim every entry is on the same filesystem and size_breakdown calls its own figures a FLOOR
54 mutants all killed by their own guard 54 rows, 0 SURVIVED, 0 WRONG-KILLER, 0 DID-NOT-APPLY; baseline 162/0, negative control 6 FAIL, SURVIVES control unkilled
%D drops unstattable entries reproduced independently on bfs 4.1.1: -print0 β†’ 345 bytes rc 0; -printf '%D\t%p\0' β†’ 0 bytes rc 1. Not findutils-specific.

Gate status β€” one red, not attributable to this branch

scripts/gate.sh --tier both on the PR branch: pytest collected=22003 passed=21999 skipped=3 failed=1, node 1449/1449 PASS.

The single failure is scripts/browser-bridge/tests/test_browser_agent.py::test_the_release_handler_EXITS_rather_than_resuming[INT]. Controls run before concluding:

  • this PR's commits touch 0 files under scripts/browser-bridge/;
  • the only shared file, scripts/run-tests.sh, has no non-comment changed line;
  • test_browser_agent.py and browser-agent are byte-identical between this branch and origin/main;
  • the test passes in isolation, 2 passed in 6.24s (both INT and TERM);
  • the run was load-inflated across the board β€” scripts/tests took 611s against a normal ~90s β€” with 5 concurrent gates on the host. Load inflates every target; a failed assertion inflates one.

It is a signal-delivery race under saturation, and scripts/browser-bridge/browser-agent:372 already names this test. Per this repo's own rule a flaky test is fixable rather than re-runnable β€” the timing dependency should be removed β€” but that is browser-bridge's, not this PR's, and is deliberately not folded in here.

Merged-tree gate in flight: this branch is 22 commits behind main, and a gate on the PR branch says nothing about the tree its merge creates. An integration branch off cb86343d with this PR merged (04c2f8e9, merge rc 0, no textual conflict) is being gated separately.

Ledger β€” round 2 Β· payload lines changed THIS round: 60 non-comment Β· since round 1: 193 non-comment. The attribution gate does not fire.

ZacxDev and others added 2 commits September 8, 2026 00:39
…ed into the directory under diagnosis, and a du under-count the new blind-spot report made read as complete

Round 3 found no πŸ”΄: five 🟑/🟒 and one out-of-range item. Two of the 🟑s were
the round-2 commit's own CORRECTIVE PROSE being false β€” the fourth consecutive
round in which the fix round's correction was itself wrong β€” so every number in
this commit was re-derived in the tree it is written about, and every count that
would drift again next round has been REMOVED rather than updated.

## 🟑-1 β€” three `mktemp` files in NO trap, in /tmp

`size_breakdown`, `inode_breakdown` and `foreign_entries` each opened
`errf=$(mktemp)` β€” an anonymous `/tmp/tmp.XXXXXXXXXX` β€” removed only by that
function's last statement. The realistic way this run ends is SIGINT, not an
abort: the run it was written for took ~3 h over 78 million entries. MEASURED on
bash 5.3.15: an EXIT trap DOES run when the shell is killed by an untrapped
SIGINT, so the trap removed the NAMED $DENIED_LOG and left up to three files
nothing could attribute to anything β€” in the directory under diagnosis.

Fixed structurally, not by extending a list. Every temp file goes through
`_scan_mktemp <kind>` (`/tmp/disk-accounting-<kind>.XXXXXX`) and is removed by
`_cleanup_temps`, which reads its variables at CALL time β€” so ONE
`trap _cleanup_temps EXIT`, installed BEFORE the first mktemp, covers every file
opened later. That deletes the hand-widened second trap at section 6c, which is
the mechanism the three files fell out of.

## 🟑-5 β€” du's stderr was still discarded, and silence had started to mean something

`_report_unstattable` fires only on FIND's stderr. An entry find can stat but du
cannot fully read is listed with an under-counted figure and no marker β€” and
once `!! UNSTATTABLE` existed, the ABSENCE of a blind-spot line began reading as
"nothing was missed". MEASURED over `base/{open,locked/inner}`, each holding one
4 KiB file with `inner` mode 000: `du -sh -x` prints 8.0K for `locked` against a
true 12K, a 33% under-count presented as a total, rc 1 (xargs 123).

du's stderr is now kept at all three du sites and reported as
`!! PARTIALLY READ: du could not read N path(s)`. The two sinks are separate
FILES on purpose: one blind spot erases an entry, the other shortens its number,
and one count standing for two claims is how both stop meaning anything. A
mutant that points the du report at find's stderr is in the battery for that.

## 🟒-1 β€” the sweep's framing was wider than the sweep

The script said "Everything that scan reports is guarded above EXCEPT these" and
listed two sites; the suite header said Β§7b "sweeps the whole file". The scan
keys on a line's FIRST WORD and drops any line containing `||`, so a pipeline
headed by `for`/`done`/`printf` is invisible, and so is one guarded only in an
early stage. FIVE trailing `sort` stages are unguarded, not two β€” three of them
statement-level pipelines the sweep cannot reach. Both halves fixed: the claims
are narrowed to what the scan does, and Β§7b gained a SECOND ledger over trailing
`sort` stages that fails when the set GROWS or SHRINKS, with a canary exercising
both branches. Nothing is a live bug; the exception list read as exhaustive.

## 🟒-2 β€” the `%D` evidence disagreed with itself in three places

Re-measured: ONE fixture (a 35-character mode-0400 base holding three entries),
THREE implementations, each run twice.

  GNU findutils 4.10.0 (the bash PATH)  -print0 114 B rc 0  |  %D 0 B rc 1
  GNU findutils 4.11.0 (nix dev shell)  -print0 114 B rc 0  |  %D 0 B rc 1
  bfs 4.1.1 (interactive alias)         -print0 114 B rc 0  |  %D 0 B rc 1

Two things were wrong, not one: the builds AGREE (the old "116 B / 119 B" over
one fixture could not both be true β€” `-print0` emits the paths it FOUND, not the
binary's path), and `-print0` exits 0, not 1, because it needs no stat. bfs was
measured this round, so the script's "not measured on bfs" is gone. The
load-bearing half β€” 0 bytes under `%D` β€” is identical on all three.

πŸ”΄ This commit message SUPERSEDES eb4e3a8's figures (345 B for bfs, "two
implementations" above three rows). That message is immutable; the script, the
suite and the PR body now carry the re-measured table.

## 🟑-2 / 🟑-3 β€” the round's own corrective prose, false twice

`run-tests.sh` said "282 at the merge base (567 after round 1, 730 after round
2)". The file was 766 β€” a stale count inside the sentence explaining that stale
counts get quoted downstream. `test_no_real_launchers_all_targets.py` said the
suite sources the script "ten more times, counting the FOUR probe scripts";
there are FIVE, and `nodev-probe.sh` was added by that same commit. A third of
the same kind turned up in the suite's own header: "282 lines when this suite
was written" β€” 282 is the count at the MERGE BASE, before this suite's commit;
by the end of that commit the file was 414.

All three now state no drifting count: the historical figure is anchored to
`c1169e3b`, the current ones are `wc -l`. No grep recipe is offered for the
source/execute counts either β€” the obvious ones are wrong in opposite directions.

## Out of range, DECLARED not fixed β€” `split_by_device`

Its `[ -d "$p" ] || continue` silently drops a directory root cannot stat, with
no count, feeding `report_foreign_mounts`. Round 2's "every caller reports the
count" is true of `_depth1_nul`'s three callers only; that over-claim is
corrected in place. The site is RECORDED, not fixed: `[ -d "$p" ]` says no for
three different reasons β€” not a directory, stat refused, or an unmatched glob
left its own pattern β€” and bash's file tests cannot separate them, so a count
needs a different enumeration. Inventing one inside an audit-fix round is
precisely how every previous round produced the next round's finding.

## Verification

  suite vs diagnose-disk-accounting.sh @ 491fc44 (pre-audit) : 93 FAIL, 106 ok
  suite vs                             @ 4d8228c (round 1)   :  52 FAIL, 147 ok
  suite vs                             @ eb4e3a8 (round 2)   :  20 FAIL, 179 ok
  suite vs HEAD                                               :   0 FAIL, 199 ok
  mutation battery                     64 mutants, every one KILLED by its
                                       own guard; baseline 199/0, negative
                                       control 6 FAIL, SURVIVES control unkilled

The 20 red at eb4e3a8 are exactly this round's guards: 4 absent helpers, 3
route-(b) du assertions, 5 temp-file rows, 7 structural pins and 1 sort-ledger
row. One of them is worth naming: "an interrupt mid-breakdown leaves NO temp
file behind" PASSES at eb4e3a8 β€” vacuously, because the probe records no paths
there. Its positive control is what goes red.

πŸ”΄ That control also caught a harness bug in this round's own new guard. A first
draft signalled with `kill -INT` alone; it was green in the foreground and
produced THREE FAILs the moment the mutation battery ran the suite from
`nohup … &`, because bash sets SIGINT to SIG_IGN for a command started
asynchronously without job control and a non-interactive shell cannot reset a
signal ignored on entry. Without the leak positive control it would have gone
VACUOUSLY GREEN there. The probe now falls back to SIGTERM and reports which
signal it delivered.

NOT verified: sections 1, 2, 3, 5, 6, 6b and 8 execute only under root and
remain unguarded arithmetically. Section 5's and section 6c's du-stderr captures
are INVARIANT PINS with no behavioural half, and are labelled as such; only
`size_breakdown`'s is measured against a fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XLiNARJLqsDf6EhaGnEhe
Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
…instead of honouring $TMPDIR

The round-3 fix replaced a bare `mktemp` β€” which HONOURS `$TMPDIR` β€” with a
`/tmp/disk-accounting-<kind>.XXXXXX` template that does not. That is a behaviour
change and it was undocumented, which is how the next round "fixes" it back.

It is deliberate and it goes the safer way for this file: `$DENIED_LOG` already
hardcodes /tmp, and the script's whole premise is that a local unprivileged
process must not influence a root run β€” an inherited `TMPDIR=/anything` choosing
where a root run writes its scan stderr is the `LSOF_BIN` lesson under a
different name.

The cost is recorded rather than hidden: a NON-root caller (the suite) now
writes into the system /tmp instead of its own sandbox, and a deliberately
broken copy that dies between the `mktemp` and the `rm` leaves the file there.
MEASURED: a clean suite run leaks nothing; a full mutation sweep left ~60 empty
files, because ~a dozen mutants exist precisely to make the function abort
mid-way. They are empty, harmless and β€” the entire point of the round-3 change β€”
NAMED, which is the only reason they were noticed and swept.

Re-verified after this comment-only edit: suite 199 ok / 0 FAIL, red-at-eb4e3a81
still 20 FAIL / 179 ok, mutation battery 64/64 KILLED by their own guard with
baseline 199/0 and the SURVIVES control unkilled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XLiNARJLqsDf6EhaGnEhe
Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
@ZacxDev ZacxDev changed the title test(disk-accounting): 127 guards for 282 lines of root-only bash that no gate ever ran β€” plus eight live defects they found test(disk-accounting): a gate for the root-only bash nothing ever ran β€” plus the live defects three audit rounds found in it Sep 8, 2026
@ZacxDev

ZacxDev commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

Round 3 audit β€” claims block

Round 3 was a delta re-audit of 4d8228c3..eb4e3a81 (0 πŸ”΄, five 🟑/🟒 plus one out-of-range item). Its fixes landed in 530a5c56 (two commits). Recording what those fixes CLAIM, so round 4 checks each against the diff rather than a narrative.

1. 🟑-1 untrapped temp files: claimed fixed by routing every temp file through `_scan_mktemp <kind>` -> `/tmp/disk-accounting-<kind>.XXXXXX`, removed by `_cleanup_temps`, which claims to read its variables at CALL time so ONE `trap _cleanup_temps EXIT` installed before the first mktemp covers files opened later; the hand-widened second trap at §6c claimed deleted as the mechanism the three files fell out of.
2. 🟑-5 du stderr: claimed captured at all three `du` sites into a SEPARATE file from find's, reported as `!! PARTIALLY READ: du could not read N path(s)`, kept separate deliberately because one blind spot erases an entry and the other shortens its number. Claims the auditor's fixture reproduces at 8.0K against a true 12K, and that `xargs` adds no stderr line of its own so the count is du's alone.
3. 🟑-2 false line count: claimed fixed with NO drifting count written back β€” the only figure kept is sha-anchored (282 at `c1169e3b`), current is `wc -l`.
4. 🟑-3 probe count: claimed fixed by stating no count, and deliberately offering NO grep recipe either, because the two obvious ones are wrong in opposite directions (`grep -c 'source "$SCRIPT"'` misses the `bash -c "source '$SCRIPT'"` spellings; `grep -c '"$BASH_BIN"'` counts probe scripts as the script).
5. 🟑-4 PR body: claimed fixed, plus the TITLE which carried the same stale `127 guards for 282 lines`; body claims round-2 and round-3 sections, a Correction 4 for `%D`, and a verification table describing HEAD.
6. 🟒-1 sweep framing: claimed fixed on BOTH halves β€” claims narrowed to what the scan does (first word; any `||` silences the whole line), and Β§7b claims a SECOND ledger over trailing `sort` stages that fails when the set grows OR shrinks, with a canary exercising both branches.
7. 🟒-2 `%D` evidence: claimed re-measured on ONE fixture across three implementations, each run twice β€” `-print0` 114 B rc 0 and `%D` 0 B rc 1 on findutils 4.10.0, 4.11.0 AND bfs 4.1.1.
8. `split_by_device`: claimed DECLARED not fixed, with the over-claim corrected β€” `[ -d "$p" ]` says no for three different reasons (not a directory / stat refused / unmatched glob) and bash's file tests cannot separate them, so a count needs a different enumeration.
9. Three CORRECTIONS TO THE AUDIT, claimed measured: (a) `-print0` exits 0, NOT 1 β€” it needs no stat, which is why it still emits the names; the script and suite both said "both rc 1". (b) the `%D` fixture byte count is 114 B, not the auditor's 387 β€” 3 entries x (35-char base + `/a` + NUL) β€” and the figure scales with the fixture path, so neither 387 nor 116/119 is portable. (c) the suite header's "282 lines when this suite was written" was a FOURTH instance of the same stale-count defect: 282 is the merge-base count, before the suite's own commit, by the end of which the file was 414.
10. A harness bug the round's own control caught: the SIGINT probe's first draft used `kill -INT` alone, green in the foreground but THREE FAILs when the battery ran the suite from `nohup … &`, because bash sets SIGINT to SIG_IGN for a command started asynchronously without job control and a non-interactive shell cannot reset a signal ignored on entry. Claims that without the LEAK POSITIVE CONTROL (an untrapped run must leak both files) it would have gone vacuously green in that runner; probe now falls back to SIGTERM and reports which signal it delivered.
11. A deliberate, documented behaviour change: the temp-file template HARDCODES `/tmp` rather than honouring `$TMPDIR`, which the bare `mktemp` did. Claimed deliberate (DENIED_LOG already does; an inherited TMPDIR steering where a root run writes is the LSOF_BIN lesson again) with the accepted cost written down β€” a full mutation sweep leaves ~60 empty NAMED files in /tmp, a clean suite run leaks none.
12. Counts claimed: suite 199 ok / 0 FAIL at HEAD; red->green across every earlier tip, unmodified β€” `491fc447` 93 FAIL/106 ok, `4d8228c3` 52/147, `eb4e3a81` 20/179, HEAD 0/199; 64 mutants each KILLED by its own guard, baseline 199/0, negative control 6 FAIL, SURVIVES control unkilled.

Independently re-verified before round 4

claim measured
199 ok / 0 FAIL at HEAD 199 / 0, rc 0
20 FAIL / 179 ok vs the round-2 script @ eb4e3a81 20 / 179, rc 1 β€” including route (b): size_breakdown REPORTS that du could not read a path and the under-counted figures are called FLOORS
64 mutants battery re-running independently; result to follow

Ledger β€” round 3 Β· payload lines changed THIS round: 300 (scripts/diagnose-disk-accounting.sh +239/βˆ’61), scaffolding +419/βˆ’49 across four files. The attribution gate does not fire.

Gate β€” both tiers red, and NONE of it is this PR

Established by control, not by reasoning:

  • Sandbox tier (Tekton β€” the tier the merge gates on) was GREEN on the round-2 head: collected=22003 passed=22000 skipped=3 failed=0, nodetests 1449/1449.
  • The merged-tree gate (integration branch off cb86343d with this PR merged, merge rc 0) showed 8 failures. Running the same three test files on pristine main with the PR absent reproduces 7 of them exactly (7 failed, 406 passed); the 8th is the known test_browser_agent.py::test_the_release_handler_EXITS_rather_than_resuming[INT] signal race, which passes in isolation and whose file is byte-identical to origin/main.
  • Cause is dev-host toolchain drift the sandbox pins away: opencode on PATH is 1.18.29 against a repo pinned to 1.18.21 (the test prints its own remedy β€” nix profile remove opencode, then home-manager switch), and age 1.3.1 β†’ 1.3.2 changed the stderr the escrow guards assert on.
  • ⚠ A hypothesis I formed and then refuted by control: that the lockfile bump #1382 caused it. The same test fails at cb86343d^, before that bump.
  • The merged run showed 28 targets / 20906 collected against the branch's 30 / 22003. Accounted for: scripts/initiatives/tests and scripts/repo-cos/tests were deleted by main in the intervening 22 commits.

…read as "nothing was missed", and two set -e-fatal truncations in neither ledger

Round 4 found no πŸ”΄: one 🟑 and three 🟒. Nearly all of it is again THIS
LADDER'S OWN CORRECTIVE PROSE being wrong β€” the fifth consecutive round in which
that is the most reliable finding. So this commit REMOVES claims rather than
restating them. No new count is written anywhere in it; where a sentence needed
a number to be true, the number is gone and the command that derives it is in
its place.

## 🟑-A β€” "du's stderr is kept at all three du sites" was FALSE, and one of the
##        uncovered sites printed a figure with NO marker at all

The file holds more `du` invocations than the ones that route stderr into a
file. Some of the others at least print a `|| echo` fallback. Section 6's
per-tree row printed nothing:

    printf '%10s %12d inodes  %s\n' \
      "$(du -sh -x "$d" 2>/dev/null | awk '{print $1}')" \

A `du` that cannot fully read a tree β€” a stale NFS/CSI mount under
/var/lib/kubelet is the realistic case β€” prints a PARTIAL total on stdout, exits
1, and with its message at /dev/null and its status discarded the row rendered
that floor exactly like a complete figure. Since `_report_unreadable` landed the
ABSENCE of a marker reads as an affirmative "nothing was missed" β€” that is
`_report_unreadable`'s own thesis β€” so this site was MORE misleading after
round 3 than before it, at a site the round's prose said was covered.

Two fixes, neither of them a new count:

  * The claim is narrowed to the callers of `_report_unreadable`
    (`size_breakdown`'s capture, section 5's PVC listing, section 6c's /home
    listing), named structurally rather than counted, and the rest are DECLARED
    in that function's comment the way `split_by_device`'s blind spot is
    declared β€” carrying the `grep` that enumerates them instead of a figure that
    goes stale next round. The suite row that called section 5 "the third du
    site" now says it is about that pipeline and no other.

  * Section 6 BRANCHES on du's status and prints a FLOOR marker. MEASURED
    2026-09-08 over a fixture holding a mode-000 subdirectory: 20K printed
    against a true 24K, now marked, and the loop continues. `if VAR=$(…)` and
    not a bare assignment β€” a command in an `if` condition is not checked by
    `set -e`.

Two SEPARATE `required` rows with two ISOLATED mutants, because the site has two
independent ways to be wrong: the branch can be removed, or the marker can be
computed and never reach the output. Section 6 is root-only, so both are
INVARIANT PINS; the fixture exercises the expression, not the script's own line.

## 🟒-D β€” `: > "$DU_ERR"` is set -e-FATAL and was in NEITHER ledger

MEASURED 2026-09-08 on bash 5.3.15: `set -euo pipefail; : > /absent/x` ends the
shell, rc 1, with nothing after it running; the same line with `||` is caught and
the run continues. The line is headed by `:`, so Β§7b's first-word sweep cannot
see it, and it carries no `| sort`, so the trailing-sort ledger cannot either. It
was in neither, and absent from the "left open on purpose" list β€” and round 3's
own 🟒-1 was "the exception list read as exhaustive and was not", in the same
commit that added this site. Section 6c's copy fires AFTER sections 1..6b have
printed, which fails the file's own criterion for leaving a site unguarded.

GUARDED rather than listed, so the exception list does not have to grow.
Deliberately NOT `|| true`: a file that did not truncate still holds an earlier
site's paths, and `_report_unreadable` would then attribute them here β€” the "one
count standing for two claims" the two-sinks comment is about.

Pinned as a RELATIONSHIP, not a literal: the suite counts `: > "$DU_ERR"` lines
and guarded ones and asserts they are equal and non-zero, so it goes red when a
guard is dropped AND when a new unguarded truncation is added. Both directions
have a mutant. A single `required` row would have stayed green with one of the
two sites unguarded, which is why this counts instead of pinning one literal.

## 🟒-B β€” the recorded cost of hardcoding /tmp said "empty", and omitted the
##        consequence that matters

MEASURED 2026-09-08 on this host: leftovers of both kinds were sitting in /tmp
and NOT all of them were empty β€” some held a fixture's captured stderr, e.g.
`du: cannot read directory '/tmp/tmp.XXXXXXXXXX/du-errors/locked': Permission
denied`. Mode 0600, so "harmless" holds; "empty" did not. The comment says so and
quotes `ls -l /tmp/disk-accounting-*` rather than a number, because the number is
whatever the last interrupted sweep happened to leave. The stale "~60 times per
full sweep" in the same paragraph is gone for the same reason.

The half that was never recorded: hardcoding /tmp also removes TMPDIR as an
ESCAPE ROUTE, on exactly the failure this script is pointed at. $DENIED_LOG and
$DU_ERR are opened unguarded at the top of the executable region, so a root
filesystem out of inodes ends the run on those lines with a blank report β€” which
the exception list accepts as the honest outcome. What it did not say, and now
does, is that the bare `mktemp` this replaced would have honoured an inherited
$TMPDIR and the template cannot.

## 🟒-C β€” the PR body's own control miscounted the tests and files it rested on

PR body only, no code. The counts are deleted and the table is the record; the
conclusion is unchanged and is now stated in terms the table itself carries.

## The battery's occurrence check earned its keep again

A first draft of section 6's new comment quoted `ROOT_DEV=$(_dev_of /) ||
ROOT_DEV=` verbatim while explaining the checked-assignment reasoning. The
mutator matches RAW text, so that made an EXISTING mutant ambiguous:
`root-dev-reading-unguarded` reported `occurrences=2` and scored MUTATION DID NOT
APPLY. Without that check it would have silently measured the unmutated file β€”
"the guard held", the most flattering possible wrong answer. The comment now
paraphrases, and says why.

## Verification

Every row re-run with THIS round's suite, not quoted from a previous round β€”
which is why the first three are three higher than round 3 published:

  suite vs diagnose-disk-accounting.sh @ 491fc44 (pre-audit) : 96 FAIL, 106 ok
  suite vs                             @ 4d8228c (round 1)   : 55 FAIL, 147 ok
  suite vs                             @ eb4e3a8 (round 2)   : 23 FAIL, 179 ok
  suite vs                             @ 530a5c5 (round 3)   :  3 FAIL, 199 ok
  suite vs HEAD                                               :  0 FAIL, 202 ok

The 3 red at 530a5c5 are exactly this round's three new guards, one per fix:
section 6's branch, section 6's printed marker, and the `: > "$DU_ERR"` ledger
(which reports `0 of 2` guarded there).

  mutation battery  baseline 202 ok / 0 FAIL; negative control 6 FAIL;
                    EVERY mutant KILLED BY ITS OWN GUARD, 0 problems;
                    SURVIVES control (comment reword) killed nothing.
                    Round 4's four new rows all KILLED by their own guard:
                    section6-du-status-not-read,
                    section6-marker-computed-but-not-printed,
                    duerr-truncation-unguarded-6c (ledger shrinks),
                    duerr-truncation-added-unguarded (ledger grows).

Both tiers, read as COUNTS:

  dev-host pytest  TOTAL collected=22003 passed=21992 skipped=3 failed=8
                   RESULT: FAIL (exit=1) β€” the 8 are the DECLARED toolchain
                   drift (age 1.3.1->1.3.2, opencode 1.18.29 vs pinned
                   1.18.21) plus the browser-bridge [INT] signal race; none is
                   in a file this PR touches. This suite inside that run:
                   PASS, 202 ok / 0 FAIL.
  dev-host node    TOTAL suites=5 files=41 tests=1449 pass=1449 fail=0
                   RESULT: PASS (exit=0)
  sandbox pytest   TOTAL collected=22003 passed=22000 skipped=3 failed=0
                   RESULT: PASS (exit=0) β€” fully green; this suite 202 ok / 0
                   FAIL. The sandbox's previously-declared flake did not recur.
  sandbox node     TOTAL suites=5 files=41 tests=1449 pass=1449 fail=0
                   RESULT: PASS (exit=0)

NOT verified: sections 1, 2, 3, 5, 6, 6b and 8 execute only under root and their
arithmetic remains unguarded. Section 6's FLOOR marker and both `: > "$DU_ERR"`
guards are INVARIANT PINS with no behavioural half β€” what the fixture above shows
is the expression, not the script's own line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XLiNARJLqsDf6EhaGnEhe
Claude-Session-Id: c8eedffa-36a5-41b3-b250-99d5d2851435
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant