A compile script warned that a release had dropped 117 rule blocks between a stylesheet’s source and its compiled output. 910 rule blocks went in, 793 came out. That is the kind of number that makes you assume a minifier ate real styles on the way to production.
It was already there before our change
We had just shipped a batch of visual changes to the same page the stylesheet served, so the first question was whether our change broke it. We compiled the source file as it stood before our edits and got 909 blocks in, 792 out. Same 117-block gap. Our branch added exactly one rule, and both sides of the count moved by exactly one. The loss predated us. We shipped, and rather than block a release on an investigation with no clear scope, we filed the loss as a separate, deferred ticket and moved on.
Doing the deferred investigation right away
After wrapping up, we were asked directly whether that deferred investigation should happen right there instead of waiting. The context was already loaded and the diagnosis looked cheap, so we did it immediately.
The audit that lied a different way
Instead of trusting a raw block count, we wrote an audit that parses both the source and the compiled stylesheet into actual rules, keyed by media context and selector, and diffs which declared properties survive. The first run looked almost too good: 837 distinct rules in the source, 5 of them with zero declarations (which a minifier is right to drop), and 832 in the output. That accounted for the drop exactly.
Then the same audit reported something else: 102 non-empty rules present in the source and missing from the output, and nearly every one of them lived inside a media query.
Too neat a pattern to be real
A hundred-plus rules going missing is alarming. A hundred-plus rules going missing, with nearly every one sharing the same syntactic feature, is a finding about the comparison and not about the CSS. We picked three of the flagged rules and checked the compiled file directly for each one, by hand. All three were there.
The minifier had rewritten the media query text during compilation, stripping the space out of a size value. The audit’s “before” key and “after” key for the same rule no longer matched as strings. We fixed the audit to strip that formatting difference out before comparing, and reran it. The count dropped from 102 to one, an import line, and a direct check of the compiled file confirmed that it and its properties were still there. Nothing was actually missing.
What the 117 was counting
Once the audit stopped being fooled by formatting, the original 117 stopped meaning anything too. It had never been counting rules. It was counting opening braces, a rough proxy that moves for reasons that have nothing to do with lost content: several comma-separated selectors collapsing into one block, empty rules disappearing correctly, and each media wrapper contributing its own extra brace. None of that is loss. We rewrote the original ticket to say what was true: nothing was missing, and the warning that started this was measuring the wrong thing.
Two stand-ins
The first alarm and the tool we built to check it both measured a stand-in instead of the thing itself. One counted braces, the other compared formatted text, and each called the difference “loss.” A more careful, purpose-built comparison does not protect you from that if its key has a blind spot of its own.
What caught the second false alarm was a pile of “missing” results clustered almost entirely inside one syntactic shape, which is the signature of a broken comparison and not of real damage.
AI Skills
Use this lesson with the AI assistant you already use
A compile warning said a stylesheet build had dropped over a hundred rules. The audit built to verify that claim reported a different, equally wrong number of missing rules, for a completely different reason, before either alarm turned out to be false.
Paste the prompt, share only the context needed to answer it, and treat the result as a draft for your review. Do not include confidential information or let an AI assistant make changes without your approval.
Optional: for a visual report and saved memory, run /dxdev first.
Don’t have it? Get it at dxdev.com/skills/dxdev. The prompt works without it.
dxdev LESSON · paste into your AI coding agent
LESSON: A Second Check Can Fail the Same Way the First One Did
SOURCE: dxdev.com/blog/the-css-diff-that-cried-wolf
WHAT HAPPENED: A build's compile script warned that a stylesheet had gone from 910 rule blocks in the source to 793 in the compiled output, a 117-block loss. That looked pre-existing rather than caused by the change being shipped, since the base branch showed the same drop, so the release went out and the loss itself was filed as a separate, lower-priority investigation. When that investigation ran, a proper audit was built to check the claim: parse both files into actual rules, keyed by media context and selector, and diff the declared properties instead of trusting a raw count. That audit came back reporting 102 real rules missing, almost all of them inside media queries, a pattern too uniform to be a real defect. Spot-checking three of the flagged rules against the compiled file found all three present. The audit's own comparison key was broken: the minifier had stripped a space out of the media query text, so the "before" key never matched the "after" key. Fixing that dropped the count to a single import line, which a direct check of the compiled file confirmed was present, so nothing was actually missing. The original warning was also wrong, for an unrelated reason: it counted opening braces as a proxy for rule count, and a brace count moves for reasons that have nothing to do with lost content.
THE RULE: A tool built specifically to double-check a suspicious result is still just another comparison, and it can carry a blind spot of its own, such as keying on formatted text instead of parsed, normalized structure. Don't stop at "I built a more careful check and it disagrees with the first tool." Ask what the second tool's key actually is, and treat an unusually tidy failure pattern (every miss falling inside one syntactic feature, one context, one shape) as a signal that the comparison itself is broken, not that the content is.
CHECK MY CODE, then report PASS or FAIL with file:line for each:
1. Any build-verification or diff script that reports a raw proxy count (braces, lines, bytes) as if it were a semantic count (rules, records, items) instead of actually parsing the structure it claims to measure.
2. Any purpose-built audit or diff, especially one written specifically to verify another tool's alarm, that keys its comparison on formatted text (whitespace, spacing, quote style, property order) rather than parsed and normalized structure.
3. Any "N things missing" result, from a first-pass tool or the second-pass check meant to confirm it, that was accepted without spot-checking at least one flagged item against the real output by hand.
THEN PRINT: a table (check, PASS/FAIL, evidence, fix) + a verdict (applies / partially / OUT_OF_SCOPE / no) + the single most important next action.