That was one of five. In a single day of hardening this machine, five different tools told me things that were not true. None of the answers looked like an error. Each one arrived as a clean, confident finding, and under each one a check had quietly failed or asked the wrong question. All five had the same shape underneath. Once I could name the shape, I stopped falling for it.
Case 1: null means “I don’t know”, not “no”#
The plan was simple: free disk space by removing apps that had never been used. The evidence came from Spotlight metadata:
$ mdls -name kMDItemLastUsedDate -raw "/Applications/Google Chrome.app"
2026-08-15 20:18:18 +0000
$ mdls -name kMDItemLastUsedDate -raw "/Applications/Microsoft Word.app"
(null)
Chrome had a date. Word did not. The conclusion looked solid, because the same command told the two apps apart: Chrome is in use, Word is not.
It was not solid. kMDItemLastUsedDate is null when an app has never been
opened, and when Spotlight’s metadata store has been reset. My store had been
reset. I even knew that, because four hours earlier I had written this line
into my own diagnostic report:
12:14:16.629 lsd _CSStoreCreateWithURL failed with error ... "The file
com.apple.LaunchServices-33554481-v2.csstore couldn't be opened
because there is no such file."The LaunchServices database was rebuilding at boot. In one section of my report, this was a strange log line. In another section, its consequences became hard evidence for deletion. I never connected the two.
What answers “is this app still needed” is user data:
$ find ~/Documents ~/Desktop ~/Downloads -iname '*.docx' -o -iname '*.pptx' | wc -l
150
$ ls -t ~/Documents/**/*.pptx | head -3
cs6460-final-GT.pptx
~$cs6460-milestone2-GT.pptx # lock file: exists only while the file is open
cs6460-milestone2-GT.pptx
Documents, lock files, container contents. Things a person made on purpose. An index field is different: the OS is free to throw it away and rebuild it, and while that happens the field tells you nothing.
Case 2: a query that never ran is not a query that found nothing#
My environment audit reported “no git remotes configured” for a repository that had pushed four signed commits and opened a pull request earlier the same day.
The check behind that sentence was this:
$ cd ~ && git remote -v
fatal: not a git repository (or any of the parent directories): .git
These dotfiles are managed with yadm, and yadm keeps its
bare repository in ~/.local/share/yadm/repo.git. $HOME is the work tree,
not a git directory. Plain git in $HOME cannot answer the question at all.
Then “cannot answer” got recorded as “the answer is none”.
$ yadm remote -v
origin [email protected]:nickboy/dotfiles.git (fetch)
origin [email protected]:nickboy/dotfiles.git (push)
The tool did not lie. fatal: not a git repository and empty output are two
different results, but the code reading them treated both as “nothing there”.
Case 3: a 404 from the wrong endpoint#
Same audit, same day: “branch protection could not be determined”. The check had asked the classic API:
$ gh api repos/nickboy/dotfiles/branches/master/protection
{"message":"Branch not protected","status":"404"}
That is a real 404, and the message reads like a finding. But GitHub has two protection mechanisms, and this repo uses the newer one:
$ gh api repos/nickboy/dotfiles/rulesets --jq '.[] | "\(.name) \(.enforcement)"'
Main Branch Protection active
A branch protected by a ruleset returns 404 from /branches/*/protection.
Any tool that only checks the old endpoint will report every ruleset-protected
branch as unprotected, in a sentence that sounds like it actually checked.
Asking the right endpoint paid off twice, because the true answer held a
detail the false one would have hidden. The ruleset requires a pull request
and four status checks, with no bypass actors. But
required_approving_review_count is 0, and there is no signature
requirement. “Protected” here means “must go through a PR and CI”. It does not
mean “must be reviewed”. My signed commits are a habit; the server never
checks them. Recording how strong a control is beats recording that one
exists.
Case 4: the number was real, the units were not#
My health check started with a headline number: WindowServer was eating
62.4% CPU, the biggest single CPU user on the machine. The number came from
ps:
$ ps -Ao pid,%cpu,comm | grep WindowServer
436 62.4 .../SkyLight.framework/Resources/WindowServer
On macOS, ps %cpu is a decaying average. It leans hard toward the last
minute, not toward the life of the process. The cumulative figure is CPU time
divided by elapsed time:
$ ps -o time=,etime= -p 436
26:03.57 01:02:14 # 1563s CPU / 3734s elapsed = 41.9%
So 42%, not 62%. The next morning brought a bigger correction, after sixteen hours of normal use:
WindowServer 6.6% (16.4 hours)
ghostty 3.3% (16.4 hours)Six point six. My original 62% came from an hour in which I was the load. I was running diagnostics nonstop, with Activity Monitor open and a backup copying files in the background. I had measured the observer and blamed the system. The whole “WindowServer is the problem” section of that report was an accident of timing.
Case 5: the benchmark that measured nothing happening#
ll felt slow. The alias behind it is eza with a long list of flags,
including --git. I benchmarked it and got a number that ended the
discussion:
eza --all --long --git --icons ... 8.4 msEight milliseconds. Nothing to fix. Except the same command, in the same directory, also reported this:
$ eza --all --long --git ... ~/Downloads | wc -lc
0 0
Zero lines, zero bytes, exit 0, and 128 ms of system time. The benchmark had
run inside the sandboxed shell my coding agent uses, and that sandbox blocks
the metadata and git reads that --long --git needs. eza was making
syscalls, and the sandbox refused every one of them. My benchmark timed the
result with great precision: a program doing nothing, very fast.
I re-ran everything in a real terminal:
| directory | size | with --git | without |
|---|---|---|---|
nickboy.github.io | 47 entries, 263 tracked | 68.8 ms | 13.9 ms |
claudedeck | 125 tracked | 49.0 ms | 20.8 ms |
Downloads | 622 entries, not a repo | 49.6 ms | 39.8 ms |
Inside a repo, --git costs 2x to 5x, and the cost follows the repository,
not the directory being listed: eza resolves git status for every tracked
file to fill one column. Listing a 47-entry folder inside a 263-file repo pays
for all 263 files. My everyday alias paid that price in every project
directory, which is exactly where I type it most.
The flag moved to an opt-in alias, llg. It also came out of ls, l, lt
and tree completely, because the git column only renders in long view. For
those four, the output is byte-identical with and without the flag. I verified
that instead of assuming it:
$ [[ $(eza --git ... | md5) == $(eza ... | md5) ]] && echo "no-op"
no-op
Dead config, carried for months, costing a git query on every call.
The common shape#
Five cases, one sentence:
A query that failed and a query that found nothing are different results.
Every case was a tool reporting an absence. In none of them had anyone checked whether the question ever reached the thing it was asking about.
“Absence of evidence is not evidence of absence” is an old phrase. The working version is more direct: evidence gathered by a broken method is not evidence at all, and a broken method usually exits 0.
The test that could not fail#
The same day turned up a bug that had survived for a year because the test guarding it was written backwards.
Ghostty on macOS reads both ~/.config/ghostty/config and
~/Library/Application Support/com.mitchellh.ghostty/config. My bootstrap
script had symlinked the second to the first, so the same file was parsed
twice. For single-value keys the last value wins, so nothing looked wrong. But
repeatable keys append:
$ ghostty +show-config | grep -c '^custom-shader = '
4 # the file declares 2
Two extra full-screen shader passes on every frame, for a year. And the test suite stayed green the whole time, because it contained this:
GHOSTTY_LINK="$HOME/Library/Application Support/com.mitchellh.ghostty/config"
if [ -e "$GHOSTTY_LINK" ] || [ -L "$GHOSTTY_LINK" ]; then
run_test "Ghostty config is symlink" "[ -L \"$GHOSTTY_LINK\" ]"
fiTwo problems in four lines. The assertion checks the opposite of the correct rule, because the symlink should not exist at all. And the assertion sits inside a guard, so when I deleted the symlink, the test did not fail. It silently stopped running. The first post in this series was a catalog of safety nets that had quietly died. This test is the sharpest example I have found since: it disappeared at the exact moment it finally had something to say.
The replacement tests the property instead of the mechanism:
run_test "Ghostty config is not parsed twice (custom-shader not duplicated)" \
"[ '$LOADED_SHADERS' -eq '$CFG_SHADERS' ]"Whatever causes a double parse next time (this symlink, a different symlink, an include directive, some future Ghostty change), the count stops matching and the test goes red. I put the symlink back once, on purpose, and watched the test fail before I trusted it.
Lessons#
- Null, empty, and 404 are answers about the query, not always about the world. Before treating one as a finding, confirm the query reached the right place.
- Decide “is this app still needed” from data a person created. An index the OS can reset is not a record of anything.
- Know which average your tool reports.
ps %cpuon macOS leans toward the last minute; cumulative load is CPU time divided by elapsed time. - Measure where the work really happens. A sandbox that blocks the syscalls under test produces a fast, precise, meaningless number.
- Never measure a system while you are the heaviest thing running on it.
- Test the property, not the mechanism. The symlink was one way to get a double parse; the count catches all of them.
References#
- eza (
--gitcost measured on v0.23.5) - yadm (bare repo location:
~/.local/share/yadm/repo.git) - GitHub rulesets API (rulesets
are invisible to the older
/branches/*/protectionendpoint) - Ghostty configuration (macOS reads both the XDG path and the Application Support path)
ps(1)on macOS (%cpuis documented as a decaying average)- The repo and its test suite: nickboy/dotfiles
