The Executable Zoo

The previous chapter argued that a model is the sweet spot between prose too vague to enforce and code too verbose to reason over. It ended on a promise: this book would walk each kind of model on real code, with real invariants, and show how to keep the code from drifting away from them. This Part cashes that promise.

The expense that buried MBSE is the one a fleet pays for free

Model-based systems engineering never failed on its ideas. It failed on its upkeep. A model earns its keep only while it matches the code, and keeping a hand-drawn model matched to a moving codebase is human work — a person notices the code changed, finds the diagram it touched, and edits the diagram to agree. That labor is dull, unending, and the first thing a deadline cuts. So the diagrams drifted, then lied, then got ignored, and a discipline with sound ideas earned a reputation for ceremony that never paid its way.

The agent changes exactly that term. Re-inducing a model from the code, diffing it against the last version, regenerating the artifacts it feeds — this is the dull, unending work a fleet does for nearly nothing. The one expense that buried MBSE is the one thing an agent fleet supplies cheaply. A practice that never repaid its upkeep suddenly pays: the map stays equal to the territory because keeping it equal costs almost nothing. This chapter is where that claim is earned — every model below is drift-checked by a tool on every build, not by a human who might forget.

The move is to stop listing kinds of model and start walking them. The companion catalogue holds nineteen real, typed, drift-checked system-models — the actual embodiments of every kind the last chapter named. Reconciled with the general model types a systems-engineering course teaches, the zoo runs to twenty-nine named models. That number is not a target to hit. It is evidence for a single claim: the zoo is large enough that one model is never the whole picture, which is exactly Philippe Kruchten's thesis about architecture.

Walking the zoo is also where a larger claim starts to earn itself, so I will plant it here and pay it off in the back matter. Working at the model level, with an agent doing the lifting, buys three things a team usually has to trade against each other: fewer tokens spent, more velocity, and higher quality — together, and without a corresponding cost. The fewer-tokens leg is the Modeling Thesis paying rent: a model binds intent to implementation and shrinks what the agent must hold in-window to act on it, which is the book's answer to churn, the failure that limits an agent fleet. That combination is the shape of what Fred Brooks called a silver bullet, and Brooks argued no such thing exists. The careful version of the claim, defended in the implications, is that the model level is the closest thing to one, because it changes the representation the agent reasons over rather than promising to make the hard part easy. Each model page below is a small piece of the evidence.

Kruchten's 4+1, promoted from a closing sentence to the spine

The last chapter invoked Kruchten's 4+1 views in a final sentence — "the reason one model is never enough." This Part promotes that sentence to its organizing structure. Kruchten observed that no single diagram captures a software architecture, and that four complementary views plus a fifth that ties them together cover what a working engineer needs to see:

One chapter of this Part takes each view. A reader leaves with four views seen built on real code, plus the scenarios that validate them — each view with its invariants and the checker that holds them true.

One trunk of drift-proof machinery, five Kruchten views branching from it A shared trunk sits at the base: the executable source-of-truth, the drift and parity gates, the agent-first harness, and the read-and-generate surfaces — the machinery that makes every view executable and holds each one true against the code. Five branches fan up from that trunk, each a Kruchten view: the Logical view (what the system is), the Process view (what runs at once), the Development view (how the source is organized), the Physical view (where the parts live), and the Scenarios view (what the system does for someone, the +1 that validates the other four). The reading: no single view is the whole picture, and the one trunk keeps all five from drifting away from the code. Five views — no one of them the whole picture Logical what it is Process runs at once Development how it is packaged Physical where it runs Scenarios the +1 — validates the four The trunk — machinery that holds any view true Executable source-of-truth Drift + parity gates Agent-first harness Read + generate surfaces
One trunk of drift-proof machinery, five views branching from it. The trunk at the base holds the shared machinery — the executable source-of-truth, the drift and parity gates, the agent-first harness, and the read-and-generate surfaces — that makes every view executable and keeps each one equal to the code. Five branches fan up from it: the Logical view (what the system is), the Process view (what runs at once), the Development view (how the source is organized), the Physical view (where the parts live), and the Scenarios view, the +1 that validates the other four. No single view is the whole picture; the one trunk keeps all five from drifting away from the code.

What this book adds to 4+1: the drift gate

Kruchten described the views. He did not have a drift gate. That is this book's contribution on top of 4+1: every view here is not a diagram a human maintains but a typed model a tool reads on every build, and a gate that fails the build the moment the model and the code disagree. 4+1 tells you which views you need. The drift gate is what keeps each view from becoming a diagram that rots.

The trunk: machinery that holds any view true

Before the views, one chapter of framing. Most of the catalogue's method models do not belong to a single view. They are the machinery that makes every view executable and drift-proof, and rather than re-explain the drift gate in each view chapter, this chapter introduces it once and each later chapter revisits it.

These are the framing chapter's home. The view chapters name them again where each view's model reconnects to them. A few concepts have to land before the views begin: what an invariant is and how you write one, what model checking buys you, and what drift is. Each is introduced at the point it is first needed, and later chapters link back rather than repeat it.

Three beats frame the whole Part.

Beat 1 — a model is derived and joined, never repeated

The last chapter warned against repetition: two models that say the same thing must now be kept in sync. This Part sharpens that warning into the zoo's organizing rule. A model here does not sit beside the code as a parallel document. It is derived from the code, or the code is derived from it. And it joins to its neighbours on a shared key rather than restating them.

The service-flow model does not re-list the endpoints. It is the list the access policy is generated from and the call graph is checked against. The journey model does not copy those endpoints either. It joins to them by call-site. Repetition is the failure. Derivation and join are the cure. The flagship demonstration is the third worked example in the Scenarios chapter, where four models join so a journey's criticality reaches all the way to which host a test runs on, with no fact stated twice.

Beat 2 — name the direction of derivation

A model and the code it concerns stay equal by derivation, and derivation runs in one of two directions. Say which up front, because the machinery differs.

Most models in the zoo are model-from-code, because the codebase pre-existed the models. The service-flow model is the clearest model-to-code case, and it is bidirectional — some fields generated to code, others reconciled from it — which is why its gate checks both directions. Each model page names its direction.

Beat 3 — every model traces to the code

A model earns trust only if you can get from a model element back to the lines that realize it, and forward from a line to the model element that governs it. That round-trip is traceability. It is exactly what the safety-critical standards demanded and exactly what the drift gate mechanizes: the reconciler is a traceability check that runs on every build.

Traceability is why the per-model template folds a one-line note into each page — the direction the model derives, and the join key from a model row back to the code. A reader always knows how to round-trip from the picture to the lines.

The round-trip is also what the whole zoo rests on. A set of views earns a reader's trust only while every view still tracks the code it depicts. The moment one view describes a subsystem the code has retired, that view misleads every agent that reasons through it. A zoo of drifted views is worse than no views, because it lends false confidence. Kruchten gave the reader four views and a fifth to validate them. He did not say how a view stays equal to the code once both have hundreds of authors and a fleet rewriting the territory daily.

The answer this book defends is that the traceability round-trip must itself be derived, not snapshotted. Picture the graph the round-trip walks — model element to lint to code entry point to test to registry row, each hop an edge. If those edges are written down once and trusted thereafter, the graph is a frozen snapshot, and it drifts the first time a symbol it names is deleted and nobody edits the snapshot to match. If instead each edge carries the mechanism that re-proves it — resolve the target symbol against the code and see whether it still exists — then a deletion turns the edge red and the drift becomes visible. A derived edge cannot fall behind the code, because it is re-read from the code every time it is checked. A snapshotted one always can. Derived sensors defend; snapshotted ones drift — the principle the drift gate rests on, carried up from a single model to the whole set of views.

State the distinction at its root and it stops being a rule of thumb. A stored trace matrix keeps a snapshot of the code and needs a sync job to re-align it; a sync job can lag, can fail, is one more thing to govern. A derived edge stores no snapshot — reading it is reading the code as it stands right now. So liveness stops being a process you run beside the model and becomes a property of the model itself, and a property cannot drift the way a process can. This is the whole content of "the map must equal the territory": not a discipline you keep, but a representation in which the map and the territory are the same read. The graph earns a second dividend from the same property. Because a resolving edge means the map is current, an agent can walk the graph to pull the relevant slice of a codebase it cannot hold in one window — up from a line to the invariant that governs it, down from an invariant to the code that realizes it. The externalized systems model that a senior engineer carries in their head becomes a navigable index the fleet reasons through. Drift-detection and that navigation are one property wearing two faces: an edge that resolves is both a true claim and a current map.

Two details make the derived graph hold where a snapshot would rot, and both generalize past any one project. Anchor an edge to a symbol definition, never a line number: lines churn under every edit above them, a symbol survives every edit that does not delete it. And read a symbol the model wants but cannot cleanly find as a finding, not an error — the absence of a clean anchor means the code is missing an abstraction the model needs, so the traceability check doubles as a probe for where the code is under-factored. The catalogue carries the concrete mechanism as its own entry: the model↔code traceability graph, its symbol anchors and its pointer-drift guard. This chapter needs only the principle it embodies. A model zoo is trustworthy exactly as long as its edges to the code are re-derived rather than remembered.

How to read a model page

Every model in this Part is rendered by filling the same five-field template. The uniformity is deliberate: a reader who has read one page can read any of them on reflex.

The first four fields map onto the four questions a reader brings to a model: what is it for, what is it made of, what does it look like, how do I trust it. Field (e) answers the fifth this chapter raised: how does the model stay tied to the code. Each view chapter opens with the Kruchten view it embodies, then walks its models through this template.

---

Inset I1 — What is an invariant, and how do you write one?

An invariant is a statement that must be true in every state your system can reach — a property the system promises never to violate. You write one as a predicate over the model's state, then you ask the model whether any reachable state breaks it. Take a job that can be free, leased, or done. The invariant "a job is never both leased and free" is a predicate over one state: not (leased and free). Because it concerns a single state, you check it by visiting every reachable state and evaluating the predicate there. If none breaks it, the invariant holds. The move that makes this more than a comment: the predicate is checked, exhaustively, by a tool, not eyeballed on a diagram. That is the step from "we believe this holds" to "we proved it holds."

STATES = {"free", "leased", "done"}
def invariant(state): return not (state == "leased" and state == "free")   # never both
assert all(invariant(s) for s in reachable_states())   # check every reachable state

Inset I8 — Derivation direction, boxed for reference

Two directions, from Beat 2. Model-from-code: the code is authoritative, the model is a projection reconciled from it, and the gate re-induces the model and fails on divergence. Model-to-code: the model is authoritative, the code or config is generated from it, and the gate is a freshness-plus-provenance check that catches a hand-edit or a stale regeneration. Reach for model-from-code when a large codebase pre-exists the model; reach for model-to-code when the model is the design intent you want the artifact to obey. A model can be both at once, on different fields.

Inset I9 — What is drift, and what is a drift gate?

Drift is the condition where a model and the code it describes disagree — the map no longer matches the territory. A human-maintained diagram drifts silently the first time a developer changes the code and forgets the diagram. A drift gate is the build-time check that set-diffs the model against reality in both directions and fails the build on any divergence. Model ⊆ reality catches a model element with no code behind it; reality ⊆ model catches code the model never declared. Because the gate runs on every build, drift cannot accumulate: the first divergent commit fails, not the fiftieth. This is what makes an executable model different from a diagram — the diagram can drift, the gated model cannot.

The remaining insets appear in the view chapters where they are first needed: assertions over sequences and the temporal-logic step-up, bounded model checking, automata, data-flow diagrams, safety versus liveness, protocols and TLA+, and coverage over model nodes.

Contents
© James C. Davis, 2026–present