When a Lint Rule Needs a Lint Rule

Build failures are usually straightforward: a syntax error, a missing module. But there’s a whole category of cases where we want the build to fail even when the code technically compiles. Lint failures are the classic example. You don’t want to deploy a build that fails linting, even if it made it into main. If a rule is wrong, you can suppress it—but then you want that suppression to go through human review in the pull request.

The Trouble With Suppressions

Suppressions are genuinely useful. Rules can be overly strict, or you’re migrating code that predates a new rule. In those cases, the code never actually not violated the rule. But suppression habits can become a problem. Some rules are dangerous to suppress—even when it seems like the right call at the time, you might be introducing a site outage or a major performance regression. People have shipped broken code this way with suppressions that seemed safe.

You can’t simply forbid all suppressions. They serve as an escape hatch for real false positives and special cases, and they allow teams to introduce or deprecate rules gradually. The solution isn’t to remove the hatch, but to control it.

Restricting the Escape Hatch

One approach is to add another lint rule that flags any attempt to suppress a configurable set of other rules. Teams that own the lint configuration in the parent directory chain can declare certain rules “non-suppressable.” Trying to suppress one of those rules now triggers an additional violation—namely, of the rule that forbids that suppression.

In short: a lint rule that prevents you from suppressing other lint rules.

This sounds almost meta, but it has real-world precedent. A rule along these lines existed at Facebook and was quite effective. In the open-source world, eslint-plugin-eslint-comments/no-restricted-disable appears to be motivated by the same idea.

The Limit of Layered Rules

There’s a flaw in this plan: a determined developer can suppress the rule that prevents suppressions. At that point, the safeguard is code review and the social contract. Some things are simply “not cool to do,” and if you truly need that double suppression, you talk to the owner of the lint config and explain your PR.

Automation can help here too. Post-merge, you could grep for newly added “double suppressions” and auto-assign tickets with SLAs to the committers. You could also require that every such suppression links to a ticket. If you want to be stricter, block the merge entirely—any PR containing a double suppression would need a stamp from a site-wide infrastructure team. This is a way to prevent the “I broke the rule and took down the site” scenario. Of course, emergencies happen, and you sometimes need to ship fast—hopefully the infra on-call is awake.

There’s room for more discussion about the social contracts embedded in our tooling design. They show up in versioning, in aligning organizational structure with file structure, in how teams are split, and in distributing shared responsibility for feature development, error prevention, and codebase evolution. And, of course, in keeping the site up.