enolaBlogEnola Is an Architecture Fitness Sensor

Blog

Enola is an architecture fitness sensor. Here is the rest of the grid it does not fill.

Dejan Menges8 min read

In April 2026, Birgitta Böckeler published Harness Engineering for Coding Agent Users on martinfowler.com. It is the first framing I have read that makes the tooling around a coding agent legible as a system rather than a pile of plugins, and it gave me a vocabulary for something I had built without being able to name.

It also gave me a grid with four cells in it, and Enola fills one of them. This post is about which one, and about the other three, because a positioning post that only shows you the cell it occupies is not telling you very much.

The framing, in one paragraph

The starting point is agent = model + harness. The harness is everything outside the model that raises your confidence in what comes out of it. Böckeler's definition of what a good one does:

"A well-built outer harness serves two goals: it increases the probability that the agent gets it right in the first place, and it provides a feedback loop that self-corrects."

Those two goals become two mechanisms. Guides are feedforward controls that steer the agent before it acts. Sensors are feedback controls that observe after it acts, so it can correct itself. Each of those can be computational — deterministic and fast, like a linter, a type checker or a test suite — or inferential — semantic and slow, like an AI reviewer or an LLM-as-judge.

And the things a harness regulates fall into three categories: a maintainability harness for internal code quality, an architecture fitness harness for structural and performance characteristics, and a behaviour harness for functional correctness.

Where Enola sits

Enola parses your source into a deterministic graph of modules, symbols, routes and storage. Your agent reads that graph over MCP before it edits, which makes it a guide. Enola then pins that graph as a baseline, and after the edit enola check compares the new graph against it and exits 1 if the change introduced a structural regression — which makes it a sensor. Same artifact, both directions.

Guide — before the editSensor — after the edit
Computational The graph over MCPWhat depends on this, and what it depends on, read from parsed source rather than inferred from a sample of files. enola checkExit 1 on a structural regression this change introduced, with the added edges named.
Inferential Not what Enola does. Not what Enola does.

One row, in one of the three categories. That is the honest extent of it. Enola contributes nothing to the behaviour harness — it cannot tell you whether the code does what it was supposed to do — and it touches maintainability only where maintainability is structural. If your problem is that the agent writes code that passes the wrong test, none of this helps you.

Why the empty row is deliberate

The inferential cells are not a roadmap item. They are a different product, and I think putting them in the same tool would damage the one property that makes this one useful.

A sensor is only a sensor if its signal means the same thing twice. A control loop built on a measurement that drifts is not a control loop, it is a mood. So every Enola snapshot carries a receipt: the version, the git ref, whether the tree was dirty, the extractor set, and a snapshot ID that is a sha256 of the facts rather than a random identifier. Before comparing two snapshots it checks they were built the same way, because a changed extractor set or changed ignore rules makes a diff meaningless — and reports that, rather than presenting the mismatch as your change.

That was measured rather than asserted: across 72 open-source repositories indexed three times each, all 72 produced a byte-identical snapshot ID and a byte-identical fact file, over 6.8 million facts.

An inferential judge cannot make that promise, and should not try. It is genuinely better than a computational check at the things it is good at — reading intent, weighing whether a design fits the problem, noticing that a name is wrong. Those are not measurements. Mixing the two inside one verdict would mean the deterministic half inherits the reliability of the probabilistic half, which is a bad trade in exactly one direction.

The category that is least served

Böckeler notes that the maintainability harness is the most developed of the three. That matches what I see: linters, formatters, type checkers and test runners have owned internal code quality for twenty years, they are fast, they are deterministic, and every agent harness ships with them wired in.

Architecture fitness is thinner, and the tools that do exist there are mostly inferential. Ask an LLM to review your architecture and it will give you an opinion, sometimes a good one, differently phrased each time you ask. There are honourable exceptions — ArchUnit and its ports let you assert architectural rules as tests, and fitness functions are an old idea — but they mostly require you to write the rule down first, which means they catch the violations you anticipated.

A dependency cycle is a different kind of object. It is not a rule you declared, it is a property of the import graph: either two modules can reach each other or they cannot. Tarjan's strongly-connected-components algorithm answers it exactly, at confidence 1.00, without anybody having written a policy first. That is why it is the one thing Enola fails a build on, and why everything else it finds — a function nearly everything calls, an import chain ten modules deep, a package that exports its whole contents — is reported and never enforced. Those are estimates measured against your own repository, and an estimate that breaks the build is an estimate people learn to switch off.

Three of her ideas that changed something concrete

Keep quality left

The phrase is hers, and it describes distributing checks across the lifecycle rather than piling them at the end. Enola's verdict runs in three places from one command: a session hook that grades what the agent just did and hands the result back to it, a pre-commit hook, and CI. Same command, same exit code. The policy lives in flags rather than in a config file, deliberately, so a pre-commit hook and a CI job can hold you to different standards.

The interesting part is the first placement. A hook that returns the verdict to the agent means the agent repairs its own regression before it tells you it is done, which is the self-correcting loop from her definition, closed inside a single session.

Harnessability, and admitting where you are blind

Her term harnessability is a codebase's capacity to be governed, and I had no word for this before. The thing it named for me is that a harness with an unmeasured blind spot is worse than a smaller harness that knows its own edges — because a tool that quietly drops what it could not resolve looks exactly like one that found everything.

So enola coverage reports, per service, how many outbound calls it found, how many it matched to a route, and how many it could not. That is the difference between a service that genuinely talks to nothing and a service whose edges we simply failed to follow. The cross-repo example in the repository contains one deliberately unresolvable call, so you can see what a miss looks like before you go hunting for them in your own code.

Sensors are for the consequences you did not look at

The clearest case I have for the whole framing is a change that passes every existing check. A new helper in one package that calls into another: it compiles, tests pass, no cycle, nothing a reviewer would flag. What a graph-derived sensor sees is that two packages moved — including one the author never opened, which became measurably more depended-upon than it was that morning.

No review catches that, because review looks at the diff, and the diff does not contain the other package. This is the class of consequence a feedback control exists for: not the mistake, the side effect.

Where this leaves the rest of your harness

If you are assembling one, the useful takeaway is not "add Enola". It is that the grid has four cells and three categories, and most teams have filled the same corner twelve times. Tests, a type checker and three linters are all computational sensors for maintainability and behaviour. An AI reviewer is an inferential sensor across all three. Agent instructions and a good CLAUDE.md are inferential guides.

The cells that tend to be empty are the computational ones for architecture: something deterministic that tells the agent what depends on what before it edits, and something deterministic that grades what its edit did to the structure after. That is the pair Enola is, and it is one pair among several you need.

The open-source build is the entire engine, Apache 2.0, and runs locally against local files. One read-only command on a repository you already have, with no baseline and nothing written to disk:

shell
enola --explain /path/to/your/repo

If you want to compare it with the other open-source code graphs first, that comparison is here, including where each of the others is the better pick.

FAQ

What is harness engineering?

A framing from Birgitta Böckeler's Martin Fowler article, built on agent = model + harness, where the harness is everything outside the model that raises confidence in its output. It divides harness controls into guides (steer the agent before it acts) and sensors (check its work afterward), and each can be computational (deterministic, like a linter) or inferential (semantic, like an LLM judge).

Is Enola a guide or a sensor?

Both. Queried over MCP before an edit, Enola's dependency graph is a guide. Run as enola check after an edit, comparing the new graph against a pinned baseline and exiting 1 on a structural regression, it is a sensor. Same graph, two positions in the loop.

Why does enola check only fail the build on dependency cycles?

Because a cycle is decidable, not estimated: Tarjan's algorithm can say with certainty whether two modules reach each other, without anyone having declared a rule first. Enola's other findings, like a heavily-called function or a deep import chain, are measurements against your own repository's norms rather than proofs, so they're reported rather than enforced.

What does enola coverage measure?

Per service, the number of outbound calls Enola found, how many it resolved to a route, and how many it could not. That separates a service with genuinely no dependents from one whose edges just weren't traced, since a tool that quietly drops unresolved calls is indistinguishable from one that found everything, unless it reports the gap.

Does Enola do inferential architecture review, like an AI code reviewer?

No. Every snapshot it produces carries a receipt (version, git ref, dirty-tree flag, extractor set, and a sha256 snapshot ID over the facts), so identical inputs reproduce identical output. An inferential judgment can't offer that guarantee, and mixing one into the same verdict would drag the deterministic half down to the probabilistic half's reliability.