← Zahir Khan · Artifact · October 2026
190 Runs, Zero Found
For eight days, a small job on my home server gave me the same answer every hour: nothing to do. My AI assistant read that answer and told me the work was finished. It was not. 1,870 photo pairs were still waiting.
This is a short story about the quietest kind of bug. Nothing crashed. No error appeared. The log was clean. And that clean log was the problem.
The setup
My phone saves many photos twice. One copy is a RAW file, which keeps every detail for editing. The other is a normal JPG. I keep all my photos in Immich, a photo app I run on my own home server. Immich shows both copies, so every one of those photos appears twice.
Immich can "stack" the two copies, so you see one photo with the RAW file kept underneath it. Doing that by hand for thousands of photos is not realistic. So I had a small job that runs every hour. It finds each RAW and JPG pair and stacks them.
The false "done"
The job ran every hour, and every hour it wrote the same three lines:
Scanned 47066 images; 16008 already in stacks. Found 0 RAW+JPG pairs to stack. Stacked 0 pairs, 0 failures. Scanned 47066 images; 16008 already in stacks. Found 0 RAW+JPG pairs to stack. Stacked 0 pairs, 0 failures. Scanned 47066 images; 16008 already in stacks. Found 0 RAW+JPG pairs to stack. Stacked 0 pairs, 0 failures.
The first lines of the real log. The same block repeats 190 times.
My assistant read this and reported back: everything is already stacked. It sounded reasonable. No failures. Nothing left to do.
But I could open Immich and see the duplicates with my own eyes. Pair after pair, the same photo twice. The report and the screen did not agree. I believed the screen.
What was actually wrong
The job matched pairs with a simple rule: the two files must have the same name and the same capture time. Both parts of that rule were wrong for my phone.
The names were different. My phone does not name the two copies the same way. A real pair looks like this:
PXL_20260806_091903576.RAW-01.jpg PXL_20260806_091903576.RAW-02.ORIGINAL.dng
One shot, two files, two different names.
The times were different. The phone writes the JPG a few hundred milliseconds after the RAW. So "exactly the same time" also failed.
Either bug alone was enough to find nothing. With both, the job could never find a single pair. It was not finished. It was blind.
The fix was small. Remove the extra parts the phone adds to the name before comparing, and compare the time to the minute, not to the millisecond. Once it was fixed, it stacked all the waiting pairs in one go.
The lesson
A zero is a result. It needs proof, just like any other result.
When a report says "something went wrong," we check it. When a report says "nothing to do," we relax. But "nothing to do" is also a claim. And a job that cannot see the work will say exactly the same thing as a job that has finished it.
So now I ask one question before I accept a zero: has this job ever found anything? One zero is normal. A long, flat line of zeros, with no other result ever, is far more likely to be a broken job than a finished one.
The second lesson is simpler. When a person's eyes and a tool's report disagree, believe the eyes. The person is looking at the result. The tool is only reporting its own assumptions.
There is a nice ending in the log itself. Today the job still often reports zero. But now I trust that zero, because the history shows it can find pairs. It found new ones 26 times since the fix. The zero has proof behind it now.
What I changed
Two things.
A new rule for my assistant. Before it tells me a scheduled job is healthy, it has to read the job's history and check whether the result was ever anything other than zero. A flat line of zeros means "go and look," not "all good."
A proof gate. I also built a small check that runs every time my assistant finishes a reply. If the reply says something "works" or "is fixed," the check looks at what the assistant actually did. Did it change something, and then test it after that change? If not, the reply is stopped once, and the assistant has to run the test first. The words are the claim. The actions are the proof.
My Agent Verification Checklist is something I run by hand. The proof gate is the first part of it that runs by itself.
About this page
An AI agent wrote the first draft of this page from my notes and the real log. I checked it against my own checklist before publishing.
Item 1, I saw the problem myself, is the whole story. The duplicates were on my screen before any code changed.
Item 2, proof from a tool and not a summary, applies to every number here. 190, 1,870 and 26 were counted from the job's log file, not remembered.
Tell me yours
What is the quietest bug you have ever had, the one that looked like success? Tell me on LinkedIn.