2.2 Structural Models: What Is Connected to What?

A structural model suppresses behavior to expose components, boundaries, and relationships. It says what parts exist and which may depend on which, and it leaves time out. Consider document mutation in DocAble — the running accessibility service — as the first example.

DocAble supports several structured document formats through libraries powerful enough to alter their underlying object structures. Those libraries are necessary, but they sit behind a deliberate architectural boundary. Most remediation logic works through DocAble's structured document abstractions rather than reaching directly into the format-specific implementation.

MODEL CARD

Document-mutation model · Structural

The useful model is small. Figure 2.2-1 draws it: remediation logic operates through a structured document model, which is realized through a format-specific implementation, which finally touches the concrete DOCX, PPTX, XLSX, and PDF formats.

DocAble's document-mutation model: mutation reaches formats through a sanctioned seam Remediation logic operates through a structured document model, the sanctioned seam. That model is realized through a format-specific implementation, which reaches the concrete formats DOCX, PPTX, XLSX, and PDF. The structured document model marks where mutation is supposed to occur; it does not by itself prevent code from bypassing the seam. DOCUMENT-MUTATION MODEL remediation logic operates through structured document model the sanctioned seam realized through format-specific implementation DOCX PPTX XLSX PDF The model marks where mutation is supposed to occur.
Figure 2.2-1. Document-mutation structural model. The reduction preserves one architectural relation: ordinary remediation reaches format-specific mutation through a structured-document seam. Enforcement of that relation is a separate Alignment decision.

The model leaves almost everything else out. It says nothing about queues, retries, deployment, user sessions, cost, or the mechanics of individual repairs. Those facts are real but irrelevant to this question. The model deliberately preserves only the architectural boundary that matters here.

Note that the model only states that relation; it does not enforce it. Part III returns to the same relation when a static control detects code that bypasses the seam. The model supplies the architectural claim; the mechanism gives that claim authority.

A structural model carries the opposite risk too. The code moves and the drawing does not, so the boundary it shows quietly stops matching the system. That gap between a model and the system it describes is model drift. Later sections make the correspondence explicit by deriving, generating, or tracing between model and implementation.

The reduction is the point. Figure 2.2-2 shows what the model keeps and what it drops: a territory crowded with UI, queues, workers, retries, storage, and deployment collapses to the one seam the question is about.

Structural reduction: the full territory reduced to the seam that answers one question On the left, the full territory: UI, queue, workers, retries, remediation and format libraries, storage, and deployment — a crowd of runtime and implementation detail. A purposeful reduction arrow points right to a clean three-layer model: remediation logic, structured document model, format implementation. The reduction preserves one question — where may document mutation occur — and suppresses everything unrelated to it. TERRITORY UI queue workers retries scaling cache storage deployment logging metrics auth config remediation format libs billing most of the system is not relevant to this question purposeful reduction MODEL remediation logic structured document model the surviving seam format implementation Question preserved: “Where may document mutation occur?” The question determines what survives the reduction.
Figure 2.2-2. Purposeful reduction. The structural model suppresses unrelated runtime and implementation detail while preserving the architectural seam needed to answer where document mutation belongs.

The engineering question — where may document mutation occur? — is preserved; everything the question does not need is gone.

The document-mutation model asked where one kind of change belongs. A second structural question reaches further inside the system: what computations make up remediation, and how do they depend on one another? DocAble runs a document through a collection of registered remediation passes. A pass may detect a condition, produce information a later pass uses, decide whether remediation should proceed, apply a bounded change to the intermediate representation, or edit a larger region directly. That structure exists in the implementation whether or not a model names it. The first reduction is the obvious one: treat each registered pass as a node, and suppress the statements, library calls, and loops inside it.

MODEL CARD

Remediation-computation model · Structural

An early version of the graph held 113 nodes and two edges. The nodes were already meaningful, because the pass registry gave DocAble a stable decomposition into computations; the two edges were relationships someone had written down by hand. That asymmetry looks obvious once stated, but it was not obvious in the running system, which had a good answer to what computations exist and almost none to how they compose. The implementation knew more than the model. Data moved between passes, signals gated them, and passes mutated shared state, but that knowledge lived heterogeneously in code rather than in one explicit model of composition.

The mismatch does not establish that the model should have existed from the start. The pass decomposition itself emerged while the remediation system was being built, and some implementation freedom was useful while that structure was still shifting. By this point, though, composition had grown hard to reason about informally. The sparse graph was not evidence of missing documentation. It showed that the system had reached a point where a stronger representation could help us understand the territory.

The next move was to derive the missing relationships from what each pass actually reads and writes. That raised a second question: what should an edge mean? A first sweep found 33 candidate producer–consumer edges, and typing them changed the picture. Twenty-two were values a pass read only inside a routing predicate (a ShouldRun or IsRouted decision) to choose whether it executed at all; those values never reached the pass's remediation output. Treating all 33 as one kind of dependency would have produced a graph dominated by routing. Two relations were hiding inside one: a value another computation consumes to produce its result, and a value another computation consults only to decide whether to run. Both are dependencies, and they are not the same dependency.

The model was refined to keep them apart. Each PDF pass declares three sets over a typed facet vocabulary: Produces, Consumes, and ConsumesForControl. The graph projects a data edge from a produced facet that another pass consumes, and a control edge from a produced facet that another pass consumes for control. Re-typing the 33 candidates partitions them: 22 become CONTROL_GATE edges, and the remaining 11 carry payload — 10 DATA_FLOW edges plus one CROSS_SERVICE edge that preserves composition across a service boundary. The 11 payload-bearing edges stay distinct from the 22 control gates.

Figure 2.2-3 shows both moves in one picture: the sparse model as first built, and the typed partition that separated the payload-bearing edges from the control gates.

From computations to composition Two panels. Left, computations without composition: a field of faint computation nodes crossed by only two conspicuous hand-authored relations — 113 computations were registered but only two relations were authored. Center: derive and type the relations. Right, composition made explicit: the derived relations split into two semantics — a payload-bearing group of eleven (ten DATA_FLOW and one CROSS_SERVICE) bracketed together, and twenty-two CONTROL_GATE relations. The transformation is two authored edges to thirty-three derived, typed relations to eleven payload plus twenty-two control. derive + type relations COMPUTATIONS WITHOUT COMPOSITION COMPOSITION MADE EXPLICIT RELATION TYPES PAYLOAD-BEARING ×11 DATA_FLOW ×10 Pass A Pass B Produces → Consumes CROSS_SERVICE ×1 Pass B Service cross-boundary payload CONTROL ×22 CONTROL_GATE ×22 Pass A Pass C ConsumesForControl 113 computations 2 authored relations 2 authored edges → 33 derived, typed relations → 11 payload + 22 control
Figure 2.2-3. From computations to composition. The initial projection captured 113 registered computations but only two hand-authored relations. Deriving and typing thirty-three candidate dependencies exposed two distinct semantics: eleven payload-bearing relations — ten data-flow and one cross-service — and twenty-two control gates.

We did not begin with an ontology that distinguished data flow from control gating and then encode it. It emerged while we tried to construct a model that could answer the engineering question. The representation did two jobs at once: it captured structure we already knew, and it exposed a distinction we had not previously expressed uniformly.

The same exercise exposed a second dimension hidden by a bare node: how bounded each computation's effect is. Passes do not change the document the same way. Some produce a well-scoped typed patch onto the intermediate representation; some mutate document state directly; some only analyze or validate. The model records that as a mutation kind across 68 pass sites: 15 are TypedPatchProducer passes with a bounded typed effect, 40 are DirectEditor passes whose mutation is not yet reduced to a typed patch, and 13 are ReadOnly. DirectEditor is not a defect. The model says something narrower: the effect of those passes is not currently bounded by the typed-patch abstraction. Some of that freedom may be appropriate and some may later prove expensive; the classification makes the question inspectable instead of leaving it tacit. A model need not remove every implementation choice, but it should make it possible to distinguish deliberately preserved freedom from an unexamined choice.

We had modeled the computations before we modeled their composition. The node projection worked because the implementation already carried stable computational units. Modeling their composition then did two further things: it separated data flow from control gating, and it made effect boundedness explicit where an untyped node had hidden it.

The graph is deliberately static. It says nothing about which pass ran in a given job, how long it took, what it cost, whether it retried, or which model fingerprint took part. Those questions belong to an execution model or an execution record. DocAble already records part of that runtime history — a per-session log of the mutations a remediation actually made — but it does not yet join that history to the static computation graph. That record answers a different question, what happened to this artifact, and belongs with the provenance model later in this Part. The two could eventually be joined through shared computation identity; today they are separate by design.

The next chapter adds time: what states a thing occupies, and the orderings it is allowed to move through.

© James C. Davis, 2026–present