
The Log Printed Exactly What I Wanted. The Fix Was Still Wrong.
In a single day of debugging, four different signals each looked like proof and each supported a smaller claim than I borrowed it for. A log line that printed exactly as designed while the process it was in died ten seconds later. An address that looked like proof of a cellular test and was identical on Wi-Fi. A fix that was clean and plausible and would have broken a whole class of users. A ten-minute hang with no error output at all. Evidence is not the problem. Using a true signal to support a claim it cannot carry is.
Table of Contents
I spent two days on a bug where a screen-capture stream never came back after the display went to sleep. When I finally had a patch I believed in, I ran it, put the machine’s display to sleep, woke it, and watched the log print the exact line I had been chasing for two days:
Display [1] woke from sleep, reinitializing capture
That is the line. Detection working, capture reinitializing, precisely as designed. I had the confirmation I wanted. About ten seconds later the entire host process died.
The detection was right. The log line was true. And the patch it belonged to was worse than the bug it fixed, because the original bug only failed to recover, while my version took the whole process down with it. The message I had been hoping to see is exactly what nearly convinced me the thing was ready to ship.
Every piece of evidence supports exactly one claim. Trouble starts when you borrow it for a bigger claim than it can carry. A log line proves the line ran, not that the fix is right. Before you trust a signal, name the claim it actually supports, and check that it is the claim you are making.
This belongs to the same first-principles line as a wrong ruler is worse than no ruler and validation is a loop, not an assertion. A wrong ruler is about a measurement that reports the wrong number. Validation-is-a-loop is about proving an outcome rather than asserting it. This piece is about the layer underneath both: the raw signals you reason from, and the quiet ways a true signal gets promoted into a false conclusion. It came out of the same investigation as the NAT64 address bug, and it happened four separate times in one day.
The claim a signal actually supports
The frame that would have saved me each time is small. Every signal, a log line, a captured packet, a returned value, an assistant’s answer, is true about one specific thing. It supports one claim. The failure is never that the signal lied. It is that I read one claim off it and used a larger one.
The log line above supports the claim the code detected the wake and started reinitializing. It does not support the reinitialization succeeded, and it certainly does not support the process is healthy. I used it for the third claim. Here it is written out, and then the other three from that day, because together they map the distinct ways a true signal turns into a wrong conclusion.
Case one: a signal that is present but not diagnostic
The wake line printed and the process died ten seconds later because the patch detected the event correctly and then tore down the capture in the wrong order. It released the video outputs while the capture session still held them, and the runtime hit a fatal over-release a moment later. The correct teardown, the one the normal stop path already used, removes the outputs from the session and its bookkeeping first, so that by the time anything is released nothing else is still pointing at it. My version skipped that and went straight to stopping the session, which felt equivalent and was not.
The point is not the ordering bug. The point is that the log line and the crash were both true, and the log line was upstream of the crash in time, so it printed before anything went wrong and told me nothing about what came after. A signal that fires at the start of an operation cannot testify about the end of it. It was present, it was accurate, and it was not diagnostic of the thing I was using it to judge. Had I closed the loop the way validation is a loop argues, checking that the process was still alive and streaming ten seconds later rather than trusting the announcement that it had started, the patch would never have looked ready. This is also the completion-ownership gap in miniature: woke from sleep, reinitializing is the accepted signal, and the process is still up and delivering frames is the observed effect, and I reported the first as if it were the second.
Case two: a signal that is correct but incomplete
Earlier that day I needed to prove a test had actually run over cellular rather than accidentally over Wi-Fi. The server logged the connecting client at an address on my VPN, I saw it, and I took it as proof the phone was on the cellular path. The address was genuinely the client’s address. It was completely correct. It also proved nothing, because that same VPN address is what the phone presents on Wi-Fi too. The signal was accurate and it was insufficient, and the gap between accurate and sufficient is exactly where the wrong inference lived.
The evidence that would actually have supported the claim was different: the peer endpoint the VPN was using at that moment, which on cellular was a global address on the carrier’s network and on Wi-Fi would have been a local one. That is the signal that distinguishes the two cases. The one I had could not, no matter how true it was. Reaching for a real but insufficient signal because it points the way you want is the same failure a wrong ruler describes, one measurement standing in for another it only resembles.
Case three: a fix that is plausible but wrongly scoped
When I first understood the address bug, I had a fix ready that was clean and obvious. Force the resolver to keep IP literals verbatim, so the address I typed is the address that gets dialed. It reads well, it is one flag, and it would have quietly broken every user who legitimately needs address synthesis to reach a public host from an IPv6-only network. The plausibility of the fix was doing the work that evidence of its correctness should have been doing.
The fix that actually shipped upstream scopes the fallback narrowly, keeping the raw literal only for private and carrier-grade-NAT ranges, because those addresses do not exist on the public internet and never needed synthesizing, while leaving synthesis intact for everyone else. The difference between the two is not cleverness. It is that the narrow one asked who does this break and the broad one only asked does this fix me. A solution feeling tidy and complete is not evidence that it is correct, and the tidier it feels the more it invites you to skip the question of who falls outside its scope.
Case four: no signal at all where one was expected
The fourth one was the emptiest. A build configuration step hung for ten minutes and produced no output whatsoever. The log simply stopped, mid-sentence, on an ordinary line, with no error and no progress. It is tempting to read a long quiet stretch as slow work, and I started to.
What had happened was that the build’s search for a Git executable matched a graphical application on the machine that happened to be named like Git, launched it, asked it for its version, and waited forever for a GUI app to answer a question it would never answer. There was no error because nothing had failed. A process was simply blocked on something that would never return, and a blocked process emits nothing. The absence of output was the signal, and I only read it by looking at what the process was actually doing, its children, one of which was a window-less app sitting open, rather than waiting for a log line that was never going to come. Silence past the expected time is not the absence of information. It is information, and it usually means look at the state directly.
Four ways a true signal lies
Lined up, the four cases are a small taxonomy of how evidence misleads without ever being false:
- Present but not diagnostic. The wake line was true and fired before the failure, so it could not speak to it.
- Correct but incomplete. The client address was really the client’s and still could not distinguish the two networks.
- Plausible but wrongly scoped. The verbatim-literal fix was clean and would have broken a class of users the narrow fix protects.
- Absent where expected. The silent hang produced no error because nothing failed, only blocked.
None of these is a fabrication. Every signal was real. Each one supported a claim, and in each case I attached it to a larger claim it could not hold. The discipline is not to distrust evidence. It is to know exactly what each piece proves and refuse to let it prove one inch more.
The assistant is another signal
All four happened while I was pairing with an AI assistant, and it was genuinely fast and genuinely useful. It read both codebases in minutes. It decoded a synthesized address to its embedded IPv4 by hand. It was also the source of the wrongly scoped fix in case three, a fix that was fluent, confident, and worse than the one already merged upstream.
The lesson people usually reach for here is that AI produces confident wrong answers. That is true, and it is tired, and it turns the observation into a complaint. The sharper version is that the assistant’s output is one more signal, subject to the same single question as every other signal in this piece: what claim does this actually support? A fast, well-read, fluent answer is still just an answer, and fluency is not evidence of correctness any more than a hoped-for log line is. Building with these tools does not change the discipline. It raises the stakes on it, because the wrong signals now arrive faster and better argued. Naming the claim before trusting the signal is exactly what keeps a persuasive wrong answer from becoming a shipped one, which is the whole reason judgement matters more in this workflow rather than less.
What was real, and what it proved
In every one of these the evidence was real. The log line printed. The address appeared. The fix compiled and read cleanly. The build genuinely had no error. Not one of them was noise or fabrication, and every one of them was borrowed for a conclusion it could not support. That is the failure mode worth internalizing, because it survives more experience and better tools than the obvious kind. You get better at reading logs, and the misleading log line still reads as confirmation. You get faster with an assistant, and the plausible wrong fix still arrives plausible.
The habit that holds up is boring and it is cheap. For each piece of evidence, before it becomes load-bearing, say out loud the one claim it actually supports, and then check that against the claim you are about to make. Most of the time they match. The day they do not is the day the log line you were hoping for talks you into shipping the thing that breaks.
This piece sits in the Generative Systems, First Principles line, alongside A Wrong Ruler Is Worse Than No Ruler, Validation Is a Loop, Not an Assertion, and Tool Calls Need Completion Ownership. The four cases here came out of the investigation in Your VPN Is Fine. iOS Swapped the Address.
🎧 More Ways to Consume This Content
I occasionally advise small teams on backend reliability, Go performance, and production AI systems. Learn more: /services
Comments
This space is waiting for your voice.
Comments will be supported shortly. Stay connected for updates!
This section will display user comments from various platforms like X, Reddit, YouTube, and more. Comments will be curated for quality and relevance.
Have questions? Reach out through:
Want to see your comment featured? Mention us on X or tag us on Reddit.