This is the story of a bug class that almost certainly lives in tooling you use today — and how it made us believe, for several hours, that nearly half of one network's traffic was leaking past a filter that was in fact blocking every single visit.
The scare
During a routine audit we found that 46% of one campaign's arrivals came from placements that were on the block list. The event log showed them as ACCEPTED. Accepted! From blocked placements! We assumed a leaking gate and went hunting for the hole.
There was no hole. Every one of those visitors had been blocked to a safe page. The traffic was fine. The log was lying.
The bug class: verdict-after-log
The route in question did its work in this order:
- run the per-visitor bot checks — and write the log row with that verdict;
- then check the placement block list and flip the final response to “block” if the placement was banned.
The visitor got blocked. The response was correct. The money was safe. But the log row — written a few milliseconds too early — recorded the pre-override verdict: ACCEPT. We call these phantom accepts: records that describe a decision that was later overridden, with no trace of the override.
Once you know the shape, you see how easy it is to create: any pipeline where a decision can be amended after the telemetry is emitted will produce phantoms. Filters, routers, edge functions, tag managers — anywhere with a “final say” layer downstream of the logging layer.
Why phantoms are worse than they sound
- They poison audits. Our “46% leak” was pure phantom. We nearly filed a dispute with a traffic network over deliveries that never happened.
- They inflate your accepted-traffic stats — which feed optimization decisions, bids, and whitelists.
- They hide the win. The filter was blocking thousands of visits and getting zero credit for it in its own reporting.
The fix: the verdict IS the decision
The repaired order is boring and absolute: decide first, log once, log the truth. If the placement is blocked, that is the final verdict — log exactly one row saying BLOCK with the real reason, skip the now-pointless downstream checks, and serve the block response. No amendments after emission. One event per visit, ever.
How to audit your own stack for phantoms
- Compare the response path to the log, not the log to itself. Take a visit your logs call “accepted” from a placement you know is blocked, and check what the visitor's browser was actually served. If those disagree, you have phantoms.
- Look at record shapes. In our case, true gate blocks carried 16 fields; full-pipeline records carried over 100. A record's field count told you which code path wrote it — a fingerprint that made the audit possible at all.
- Grep for the override. Any code that mutates a verdict variable after a logging call is a phantom factory. The fix is usually moving one block of code above another.
We found ours because a customer asked an uncomfortable question about a number that did not smell right. Audit before your customer does. And if a vendor's dashboard numbers ever disagree with what visitors actually experience — now you know the name of the thing to ask them about.
FAQ
How common is this bug class?
Any system with layered decisions (visitor checks + list checks + business overrides) is at risk unless the logging happens strictly last. We have seen the pattern in filters, redirect chains, and edge middleware. Assume it exists until you have compared response to log.
Did the phantoms cost money?
Directly, no — the visitors were blocked. Indirectly, nearly: they inflated a dispute claim (embarrassing), inflated accepted-traffic stats (misleading), and burned hours of forensic time (expensive).
What is the one-line takeaway?
Trust the response, not the record — until you have proven your records describe final decisions, not first drafts.
