(Spine Ch. 37.)
“POSITIVE, adj. Mistaken at the top of one’s voice.” Ambrose Bierce, The Devil’s Dictionary (1911)
One night in August a database optimization of mine sat one approval
away from overwriting 337,000 rows with thinner data.
It threw nothing. The config parsed, the tests passed, and I was busy
being pleased about a different fix that had made a graph go up. What
stopped it was a reviewer running a COUNT query before
clicking approve. Not me, and not clever.
Bottom line: You fixed the loud one and shipped the quiet one. The bug that generates complaints gets a ticket, a branch, a fix, and a green checkmark. The bug three feet away, the one with no error text and no angry user, ships in the same commit. Loud failures recruit humans. Quiet ones don’t, so they survive every review, including the careful ones. What has caught them in my systems is always an independent check, a machine or a second person: a COUNT query before approval, a curl that logs in for real, a timestamp read the next morning. Never the author. The author already believes it works, which is why he shipped it.
created_at
had a plausible name.Loud failures come with a recruiting mechanism attached: a stack trace, a 500 page, a user who cannot log in.
Quiet failures have no recruiter. A cache serving the wrong body still serves a body. Success is what gets read at review, and the system reports success while losing something.
So the two live together. You go looking for the loud one, fix it, and the quiet one is in the same file, sometimes the same function. Ch. 33 covers the asymmetry in how failures announce themselves. This chapter is what that asymmetry does to a workday. It sets your ordering, and your ordering is wrong.
The counter is small and specific. Before the next deploy, name the
three checks something other than you will run: a COUNT
against production for anything that writes, a curl against
a real logged-in session for anything that touches caching or auth, and
a timestamp on the newest log line for anything scheduled. Those three,
run by a second person or a cron job, are what caught every save in this
chapter. Nothing about them is sophisticated. That is the point.
airank, 8 August 2026. Ten-hour session, six fixes landed. Two of them are the whole chapter.
The loud one first. The backlog said duplicates “corrupt every
successful observation.” Before writing the guard I ran the grouping the
metric rested on, then ran a second grouping over the same 169 rows.
Grouped by product_name alone, 58 of 169
rows were duplicates. Grouped by brand plus name plus
use_case_segment, 4 of 169 were. Same
data, two definitions of “the same observation.” So 54 of the
58 were grouping false positives, not a fake bug: four real
duplicates hiding behind a denominator nobody had questioned, mine
included.
Now the quiet one. The composer selector was a defensive union of
five fallbacks, written that way so a UI change at OpenAI would not kill
collection. It matched the real composer, and it also matched a hidden
<textarea style="display:none"> sitting
earlier in DOM order. Earlier wins. The collector typed
into an invisible element and reported it had done its job: across the
five phrases tested, five failures, zero errors. The fix was
.filter({visible:true}).first(), applied to the typing
target and the wait. Result on the same five phrases: 5 for
5.
Nobody filed that one. It surfaced only because the loud bug turned out mostly fake and there was time left in the day.
The session punished me once more. Recovery ran against a 112 MB
NDJSON buffer using File::get() plus
explode(), three copies in memory, and it died:
Allowed memory size of 134217728 bytes exhausted (tried to allocate 111115272 bytes).
Loud, so it got fixed fast, hiding two things next to it:
created_at was the wrong timestamp axis, and
--limit=50 could report the queue idle while work remained.
Neither throws. I wrote the recovery path. Then I picked
created_at because it had a friendly name, which is roughly
the engineering rigor of a GeoCities under-construction GIF: it looks
like something is being handled.
airank, 10 August 2026. A finding about tracking
parameters in ChatGPT citation URLs moved 6.04% to 1.38% to
19.10% in one day, and every move was me correcting my own
methodology, starting with confusing msclkid (Microsoft
Advertising’s click id) with msockid (an undocumented
parameter Bing appends to search-result clicks, organic ones included).
The final number was smaller than the one I started with and held up
under every check I could then run against my own data; Ch. 47 turns
that sequence into a rule about what you are allowed to publish.
airank, 13 August 2026. Four decisions, one night, three nearly shipped broken.
A database optimization would have overwritten 337,000
rows of richer archive pointers with thinner ones. Caught by a
reviewer who ran a COUNT against production before
approving.
The nginx microcache would have broken every login, twice over. The
bypass map used $cookie_airanks_session, and nginx variable
syntax cannot express a hyphenated cookie name, so logged-in users were
served the anonymous cache. The second break was Set-Cookie
stripping. Caught by curl test failures, not config review, because the
config looked correct in exactly the way that matters least.
And the scheduler had been dead for six hours. The cron entry’s
>> /var/log/file redirect is opened by cron’s shell
as www-data, which cannot create files in root-owned
/var/log. The line died at the redirect, before PHP ever
started, silently, at the exact moment logrotate did its job and rotated
the file away. Caught the next morning by a timestamp check on the
newest log line.
Three saves, none from the person who wrote the change.
aigate, 17 August 2026. Not airank, so you can see
the shape repeat. Hardening the Content Security Policy with
default-src 'self' visibly broke the Vue dashboard into
unstyled template soup, which took a minute to fix. Underneath, the same
policy blocked the unsafe-eval that Vue needs to compile
in-DOM templates with new Function(), so the page came back
beautiful and rendered nothing while the suite passed and curl saw green
headers. A Playwright screenshot with console output caught it, because
a browser was the only thing that ever looked at the page.
The loud failure of this chapter is the obvious one: you fix the reported bug, the real one ships beside it, the deploy is green.
The quiet failure sits underneath it. Your triage order is set by volume, and volume is an unreliable severity proxy. The duplicate report was the loudest item in the backlog and most of it was an artifact of how I had grouped the rows. How often that happens across a whole backlog, I cannot tell you. My recollection is that it was not the only item that shrank when I re-ran the number under it, but I never counted, so do not let me hand you a rate. The composer race had no report at all and was destroying every session it touched. A backlog sorted by how upset the reporter was is a 1998 hit counter: a number that goes up and measures nothing you can spend.
Second: you count the fix, not the check. The
composer fix took ten minutes. The grouping query that cut the duplicate
bug from 58 to 4 took ninety seconds and saved ten hours. The write-up
of that night logs the same arithmetic one line lower: 10
sessions spent re-measuring what a single
git show --stat answered for free.
Third: you optimize for the number that gets applause. A wrong 6.04% costs you the entire finding the moment somebody reads the parameter docs, which is the whole argument of Ch. 47.
Do
Don’t
File::get() plus explode() on 112 MB is three
copies and a fatal at the exact moment recovery matters.$cookie_airanks_session parses fine and means nothing.crontab -l. The
line existed. It died at the redirect.Ch. 33 is the asymmetry itself: why some failures recruit a human and some do not. This chapter is the operational consequence: the recruiting mechanism chooses your work order, and chooses it badly. Ch. 38 takes the next step, the failure invisible because the system reports success in good faith. Ch. 47 turns the 10 August retraction sequence into a publishing standard: what you are allowed to claim when you correct a number in public.
Thesis is Jeremy’s (fix the loud one, ship the quiet one; an independent check catches the quiet one, never the author). Argument, not citation.
Verified:
product_name alone vs 4 of 169 by brand + name +
use_case_segment, so 54 of the 58 were grouping false
positives; the shipped guard keys on brand+name+segment. Also “Sessions
spent re-measuring what git show --stat answered free: 10.”
Internal artifacts, not public: airank engineering posts dated 8 August
2026, 2026-08-08-fifty-eight-duplicates-four-of-them-real
and 2026-08-08-six-fixes-and-a-ceiling, in the private
airank repo.<textarea style="display:none"> earlier in DOM order;
fix .filter({visible:true}).first(); 5 for 5. Same
post.File::get() + explode(),
Allowed memory size of 134217728 bytes exhausted (tried to allocate 111115272 bytes).
Same post.msclkid (Microsoft Advertising) vs
msockid (undocumented Bing parameter appended to organic
search-result clicks). Internal artifact: airank post dated 10 August
2026, 2026-08-10-every-correction-cost-us-a-bigger-number,
private repo.$cookie_airanks_session,
nginx variable syntax cannot express a hyphenated cookie name, logged-in
users served the anonymous cache; plus Set-Cookie
stripping. Internal artifact: airank post dated 13 August 2026,
2026-08-13-three-saves-in-one-night, private repo.>> /var/log/file
redirect opened by cron’s shell as www-data, which cannot
create files in root-owned /var/log; the line died at the
redirect before PHP started, silently, as a log-management tool rotated
the file. Same post.COUNT on
production. Cache improved throughput from 16.6 to 1,873 requests per
second. Same post.default-src 'self' broke the Vue dashboard visibly, and
also blocked the unsafe-eval Vue needs to compile in-DOM
templates with new Function(); caught by a Playwright
screenshot plus console output, not config review. Internal artifact:
aigate post dated 17 August 2026,
2026-08-17-the-fleet-approved-the-outage, private
repo.What I could not verify:
www-data failure class.