A lab environment had a make target that started a background daemon before bringing up a virtual machine. It had worked for weeks. After one unclean shutdown it began reporting success while doing nothing at all, and every VM that depended on the daemon failed further down the run.

The guard looked reasonable:

tpm.up:
	@if [ -S $(RUNDIR)/swtpm-sock ]; then \
		echo "already running"; \
	else \
		swtpm socket --daemon ... ; \
	fi

A Unix domain socket is a file. When the process exits cleanly it unlinks it; when it is killed, the file stays behind. So the guard saw a socket path, concluded the daemon was running, and skipped the start, permanently, because nothing ever removed the stale file.

The check has to test the thing you actually care about, which is a process listening on that socket, not an inode:

tpm.up:
	@if ss -lx | grep -q "$(RUNDIR)/swtpm-sock"; then \
		echo "already running"; \
	else \
		rm -f $(RUNDIR)/swtpm-sock; \
		swtpm socket --daemon ... ; \
	fi

Two things changed. The check asks the kernel for listening sockets rather than asking the filesystem for a path, and the start path clears the stale file first, so a crashed run self-heals instead of poisoning every later one.

The same shape catches people out with PID files that outlive their process, lock files left by a killed job, and “already deployed” markers written before the deployment finished. In each case an idempotency guard is testing a side effect of success rather than success itself.

The test I now apply to any guard of this kind: if the previous run was killed at the worst possible moment, does this check still tell the truth? If the answer is no, the check is caching a claim that nothing ever invalidates.