Your linter cannot tell you that you built the wrong thing
Static analysis answers whether an implementation is likely defective. It is entirely silent on whether this is still the thing you set out to build — and that question compounds.
Algodyne
Conventional tooling is good at one question: is this implementation likely to be defective? Linters, type checkers, security scanners and test suites attack it from different angles, and between them the coverage is genuinely strong. A modern repository with the gates turned up is a hard place to hide a null dereference.
None of them has anything to say about a second question that matters more across a portfolio: is this still the venture we intended to build? A repository can be free of defects, fully typed, comprehensively tested, and have quietly stopped being the project it started as.
What drift actually looks like
It is almost never a decision. Nobody proposes to fork the source of truth. Drift accumulates as a sequence of individually reasonable moves, each made under time pressure by someone competent.
A rewrite lands and the old path stays behind, because something still imports it and deleting it was not in scope. Now there are two implementations and no statement about which is authoritative. A rename ships and residue survives in half the tree — in a config key, a database column, a comment, a directory name. A compatibility shim gets added for a migration that completed months ago, and it has no exit condition because nobody wrote one.
Terminology from an abandoned direction persists in the schema, so new engineers learn a vocabulary that describes a strategy the company no longer holds. A second source of truth appears because editing the first required a review that was inconvenient that afternoon. A dependency drifts off the declared stack because one service needed something the standard did not cover, and the exception was never recorded as an exception.
Each of those is individually defensible. None is a bug. Together they are why a codebase stops matching its own intent, and no correctness tool will ever raise them, because nothing is broken.
Why correctness tools structurally cannot see it
This is not an oversight in linter design. A correctness tool analyses an artifact against properties that are intrinsic to it — types line up, memory is released, the shape of this call matches that signature. Intent is not intrinsic to the artifact. Two repositories with identical code can be perfectly conformant and badly adrift, depending on what each was supposed to be.
That means the question is unanswerable until intent is written down in a form a machine can read. Not a README, not a design document, not a shared understanding held by whoever was in the room. A declaration: this is the standard this repository adopts, at this version; these are the required runtimes and frameworks; these are the canonical artifacts that must exist; this is the naming system; these are the deviations we accept and why.
Once intent is declared, drift becomes computable. That single move is what converts an unfalsifiable worry into a scan.
Scanning for intent
So we scan for it deterministically, the same way we scan for defects: superseded copies, version-suffixed artifacts, transitional aliases with no exit condition, unresolved placeholders, parallel sources of truth, obsolete names, declared stack against actual stack, missing canonical artifacts, and operating surfaces that the standard requires and the repository does not have.
Every finding carries a stable identifier, a severity and category, concrete repository evidence, the policy it derives from, a rationale, executable remediation, a stable fingerprint, and a disposition. The provenance matters as much as the finding: a rule that cannot point at the policy it enforces is an opinion, and opinions in a scanner get switched off within a month.
The fingerprint is what makes the disposition durable. A finding needs a stable identity across runs so that accepting it once does not mean re-accepting it every time the file moves. Without that, the accept path is unusable and the tool degrades into noise that everybody learns to scroll past.
An accepted deviation is a first-class recorded decision, not a suppression. It states the reason and, where it is genuinely temporary, the exit condition. This is the entire point of the exercise: the alternative to a recorded deviation is not conformance, it is drift that nobody chose and everybody inherits.
The result worth reporting
The conformance scan finds more per unit of effort than the defect scan does. That is the finding, and it surprised us enough to be worth stating plainly.
The explanation is not that the code is worse than we thought. It is that the entire industry is pointed at the first question. Decades of investment have gone into making defects hard to write and easy to catch, and the marginal defect a new tool finds is correspondingly rare and cheap. Almost nobody is pointed at the second question, so the marginal finding there is abundant and expensive — because drift compounds silently and gets more costly to reverse the longer it runs.
It is the same reason an under-examined market beats a fashionable one. The return is not in how hard you look. It is in whether anyone else is looking.
The limit
This only works where a standard exists to conform to. A repository with no declared intent cannot drift from it, and running the scan there produces nothing except a list of things a tool guessed you might have meant.
Which means the cost is front-loaded and unavoidable: someone has to decide what the standard is, write it down precisely enough to be machine-checkable, and keep it current. Teams that want the scan without that work are asking for an oracle, and there is not one. The scanner does not know what you intended. It only knows what you declared, and it is relentless about the gap.