The Linter Has an Opinion

The Linter Has an Opinion

The Linter Has an Opinion

My assistant merged a designer's branch, ran her contrast checker over the result, found thirteen failures on outlined text, and fixed all thirteen.

Every fix was wrong. The tool told it so, clearly and numerically, and it believed the tool.

I only caught it because the rule it "fixed" was one I had written years earlier and could still remember the reason for.

What a contrast checker measures

The site puts a thin outline around some display text. Black outline in the light theme, white outline in the dark theme.

The checker compared each outline color against the text color it surrounds, found them insufficiently distinct, and reported failures. The assistant did the sensible thing with that report: it changed each outline so it contrasted strongly with the letter it wrapped.

Defensible. That is one reasonable model of what an outline is for.

It is not the model I built. My outline contrasts with the panel, the surface behind the text, because the job of an outline is to define the edge of the glyph against whatever is behind it. That is what an outline is for. Contrast it with the letter instead and you get a bright halo around every character that fights the text it is meant to support.

Both models are coherent. Only one of them matches the design, and the tool has no way to know which one you meant.

The tool was not wrong, it was opinionated

I want to be fair to the checker, because on the same pass it caught something genuinely broken: near-black text on a near-black panel at a ratio of 1.03 to 1, a theme that was effectively invisible. Real bug, real catch, would have shipped.

So this is not "the linter is bad." It is that a measurement is never just a measurement. Somebody decided what to compare against what. That decision encodes a theory, and the number it produces inherits the theory while looking like arithmetic.

A number computed from the wrong pair of inputs is not more objective than an opinion. It is an opinion with a decimal point.

Thirteen results, all consistent, all precise, all derived from a comparison nobody involved had agreed to.

Why an assistant is especially vulnerable to this

This is the interesting part for anyone handing work to an AI.

A model reads a tool's output as ground truth, and reasonably so. It was asked to fix failures, it was handed a list of failures with exact values, and it fixed them. Its behavior was correct given its inputs. That is what makes it dangerous: there was no step in the process where a mistake was made.

What the model did not have is the thing that broke the tie for me. It did not know the outline rule had been in production for years without a single complaint, or that the rule was improvised deliberately, or that the thing it was "correcting" was the original author's considered choice rather than an oversight.

A long-standing, working choice is evidence. It just is not evidence shaped like a number, so it weighs nothing next to a checker's output unless a human puts it on the scale.

That is the tell I now watch for:

When a measurement disagrees with something that has been working for a long time, suspect the measurement before you obey it.

Not "ignore the tool." Go and find out what the tool is comparing, and go and find out why the existing thing is the way it is. Both of those took me about ten minutes. The original rule was sitting in an old stylesheet, written in code, with the light and dark values right there.

It would have shipped clean

Nothing would have broken. No test would have failed. The site would have deployed, looked fine to almost everyone, and been subtly wrong in a way only the person who designed it would notice.

And when that person noticed, the most likely conclusion would have been "I must be misremembering how I did this," because the code would say otherwise and code is persuasive.

That is the quiet cost of this category of error. Not an outage, a slow erosion of decisions nobody can reconstruct any more. Every automated "fix" applied against an unstated intention removes a little more of the reasoning behind a design, and replaces it with a value that satisfies a tool.

The second lesson, which is cheaper

The designer said she had made "a lot of unorthodox choices" and "didn't really know what she was doing."

The improvised rule was the one a type designer would have given her.

Self-deprecation is not evidence about the work. It is a statement about how someone feels about the work, and the two correlate far less than you would think. I nearly used it as permission to overwrite her decisions wholesale, and my assistant, which had been told the same thing, weighted it exactly as heavily as I did.

Check the work. The confidence of whoever made it tells you nothing about whether it is right.

What I do now

Before applying a tool's verdict across a set of results, I ask one question: what exactly is it comparing, and did I agree to that comparison?

If the answer is not obvious in under a minute, I read the tool. Most checkers are a few hundred lines and the relevant decision is one function.

And for anything an assistant "fixed" in bulk, I look for the oldest thing in the changed set and ask why it was written that way. If there is an intention, it is usually recoverable from history. If there is not, then the tool is probably right and I have learned something.

Thirteen consistent fixes is not thirteen pieces of evidence. It is one assumption applied thirteen times.