Our integration suite had been green for eleven weeks. That is not a boast, it is the symptom. A colleague onboarding to the repo wrote a deliberately broken test to see what a failure looked like, pushed it, and the pipeline went green in the usual four minutes.

The stage was a single shell step, npm run test:integration | tee integration.log || true, and it contains two separate mistakes, both added by people trying to be helpful. The pipe was there so the log could be uploaded as an artifact, and without set -o pipefail the exit status of the pipeline is the exit status of tee, which is always zero. The || true had been added fourteen months earlier because a cleanup command at the end of the script occasionally returned 1 and nobody wanted to debug it that week. Either one alone would have hidden every failure. We had both.

I went looking for the rest and found seven more steps across four repositories that could not report failure: three with the same pipe, two with || true, one that ran the real command inside a subshell whose status was discarded, and one where a for loop over services swallowed each iteration's result and exited on the status of the loop itself.

The fixes were mechanical. Every script step now starts set -euo pipefail, enforced by a lint job that reads the workflow YAML and fails on any run: block that does not. || true is banned outside a small allowlist, and each allowed use carries the reason in a comment on the same line. Logs are captured by redirecting to a file and cating it afterwards, not by piping the command that matters.