{
  "content": {
    "kind": "tabbed",
    "layout": "chapter",
    "meta": {
      "subtitle": "A system as a graph, principles as typed records, and the predicate set that makes an architecture real when a model writes the code.",
      "title": "Software Architecture",
      "version": "1.0.0"
    },
    "tabs": [
      {
        "icon": "bi-diagram-3",
        "id": "model",
        "label": "Model",
        "sections": [
          {
            "icon": "bi-share",
            "id": "a-system-is-a-graph",
            "intro": "This section covers the model the rest of the page evaluates, in which a system is a graph and a question about the system is a question about reach, answered by a walk over that graph. [the four parts] shows the parts of the model, [one feature] shows a walk over one feature, and [the four fractures] shows the test the model applies. The practice of the model for a tree is described in [derived state](/disciplined-methodology/verify#derived-state) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the components and the relation kinds are named, the schema is stated as invariants a walk can evaluate over the graph, and the way a change propagates is stated, so [impact analysis](/records/architecture/impact-analysis) is a traversal rather than a guess. Every value the system carries is then tested by asking whether the system can observe that value in its own self-description, and a value that fails the question is treated as a fracture.",
                    "boundary": "The model is a description of structure, and it says nothing about which components are good. A graph with clean edges and a bad decomposition is still a graph, and the decomposition is judged by the schema applied to it, never by the model that holds it.",
                    "cause": "A system described in prose has parts that cannot be enumerated and relations that cannot be traversed, so every question about it is answered by recollection.",
                    "decision": "The graph is modeled before any part of it, rather than parts being assembled and the graph inferred afterwards.",
                    "failureMode": "A limit is declared in two places, a state is written by hand where nothing reads it back, a description goes stale beside the code it describes, and a step is performed manually. None of the four is recorded as a defect, because none of them has a name.",
                    "kind": "lesson",
                    "principle": "For this reason a system is modeled as components, relations, an evaluative schema and a propagation topology, and it is healthy when its behavior is derivable from its self-description.",
                    "problem": "Software is usually reasoned about as a pile of parts rather than as a graph, so neither the developer nor the model can say what a change reaches or what the system claims about itself.",
                    "validation": "To check this, pick a component and derive what a change to it reaches, from the graph alone. Then change it and observe what actually moved. The difference between the two sets is the part of the topology that was never modeled."
                  },
                  {
                    "caption": "the four parts",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    components[\"Components · the nodes\"]\n    relations[\"Relations · the edges\"]\n    schema[\"The evaluative schema · applied to the graph\"]\n    propagation[\"The propagation topology · how a change travels\"]\n    rest[\"The graph at rest · what the system is\"]\n    motion[\"Propagation · the system in motion\"]\n    healthy{\"Is the behavior derivable from the self-description?\"}\n    yes[\"Healthy\"]\n    fracture[\"A fracture · dual write, hidden side effect, schema drift, manual-only governance\"]\n    components --> rest\n    relations --> rest\n    schema --> rest\n    propagation --> motion\n    rest --> healthy\n    motion --> healthy\n    healthy -- yes --> yes\n    healthy -- no --> fracture"
                  }
                ],
                "title": "Components, relations, schema, propagation"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Which modules a change touches is a walk over the [dependency graph](/records/architecture/dependency-graph). Which of two components knows about the other is the direction of one edge. Whether the whole can be built in one pass is whether the graph is a [directed acyclic graph](/records/architecture/directed-acyclic-graph), and a [circular dependency](/records/architecture/circular-dependency) is the one shape that makes the answer no."
                  },
                  {
                    "kind": "text",
                    "text": "[Traceability](/records/architecture/traceability), from a requirement to the code that carries it and back, is a path. [Modularity](/records/architecture/modularity), [loose coupling](/records/architecture/low-coupling) and [high cohesion](/records/architecture/high-cohesion) are each a statement about how many edges cross a boundary and how many stay inside it. A list can hold every one of those facts and can answer none of the questions, because a list has no edges to walk."
                  },
                  {
                    "caption": "one feature",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subgraph domain[\"domain\"]\n        model[\"order model\"]\n        policy[\"pricing policy\"]\n    end\n    subgraph application[\"application\"]\n        coordinator[\"checkout coordinator\"]\n        store[\"cart store\"]\n    end\n    subgraph processing[\"processing\"]\n        converter[\"order converter\"]\n        validator[\"order validator\"]\n    end\n    subgraph product[\"product\"]\n        view[\"checkout view\"]\n    end\n    view --> coordinator\n    coordinator --> store\n    coordinator --> converter\n    converter --> model\n    validator --> model\n    validator --> policy\n    coordinator --> validator\n    policy -. circular dependency .-> coordinator"
                  }
                ],
                "title": "Why a graph and not a list"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Self-describing architecture](/records/architecture/self-describing-architecture) is the property the health test names, and it is stronger than [observability](/records/architecture/observability). An observable system can be watched from outside. A self-describing one carries its own description as data it can read, and [introspection](/records/architecture/introspection) over that data answers the reach questions without running anything."
                  },
                  {
                    "kind": "text",
                    "text": "The four fractures are the four ways a description and a behavior come apart. A [dual write](/records/architecture/dual-write) is one fact declared twice, and it disagrees with itself the moment either copy moves. A [hidden side effect](/records/architecture/hidden-side-effect) is a value the system changes where nothing reads it back, so it can be wrong forever. [Schema drift](/records/architecture/schema-drift) is a description the system cannot check against itself, so it is right only on the day it was written. [Manual-only governance](/records/architecture/manual-only-governance) is a step the description does not contain, so the system behaves differently depending on who performs it."
                  },
                  {
                    "caption": "the four fractures",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    test{\"Can the system observe this value in its own self-description?\"}\n    dual[\"Dual write · one fact declared twice\"]\n    hidden[\"Hidden side effect · a value nothing reads back\"]\n    drift[\"Schema drift · a description the system cannot check\"]\n    manual[\"Manual-only governance · a step the description does not contain\"]\n    closed[\"Closed · one declaration, derived everywhere\"]\n    test -- no --> dual\n    test -- no --> hidden\n    test -- no --> drift\n    test -- no --> manual\n    test -- yes --> closed"
                  }
                ],
                "title": "The four fractures"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Take any system you already have and ask of each fact where it is declared and what reads that declaration. A port written in a manifest and again in a start script is a dual write. A [feature toggle](/records/architecture/feature-toggle) flipped by hand in a console is a hidden side effect. A document that names three services where the tree holds four is schema drift. A release checklist a developer walks is manual-only governance."
                  },
                  {
                    "kind": "text",
                    "text": "None of the four is a bug in the ordinary sense. All four are fractures in the derivation, and each has the same repair, which is one declaration with every other appearance derived from it or deleted."
                  }
                ],
                "title": "The example is the system you have"
              }
            ],
            "title": "A system is a graph"
          },
          {
            "icon": "bi-braces",
            "id": "definitions-own-what",
            "intro": "This section covers the split between definitions and code. A registry declares what variants exist and the code discovers them, a schema declares what a record carries and the code validates against it, and a manifest declares what a module is for and the code derives its surface. The split runs through every fact a tree carries, as shown in [derivation or restatement] and typed in [the model typed], and its practice is described in [one home](/disciplined-methodology/build#one-home) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every fact is assigned to the side that owns it. A fact about what exists goes into a definition the code reads, and the code derives the rest from it, such as the list of variants, the shape of a record and the surface of a module. Where a fact already has a definition, the copy in the code is deleted. Where the code holds a fact nothing declares, the declaration is written and the code derives the fact from it, because a fact that lives only in behavior cannot be checked without running the behavior.",
                    "boundary": "A definition declares what and never how. A schema that carries a validation routine, or a manifest that carries a build step, has crossed into code and gained a second implementation of something the code already does.",
                    "cause": "Restating a definition in code is cheaper than reading it at the moment of writing, and the cost only arrives when one of the two copies changes and the other keeps the old truth.",
                    "decision": "The definition is read at the site rather than restated there, even where reading costs more on the day.",
                    "failureMode": "A registry lists twelve variants, a switch in the composer handles eleven, and the twelfth exists everywhere except where it is dispatched, because the switch was a second declaration that was never recognized as one.",
                    "kind": "lesson",
                    "principle": "For this reason definitions own what, code owns how, and a fact with two declarations and no derivation between them is a fracture.",
                    "problem": "Code that restates a definition looks complete on the day it is written and becomes a second truth the day the definition moves.",
                    "validation": "To check this, take any fact the system carries and count the places it is stated. The target is one statement plus derivations. Two statements with no edge between them will disagree."
                  },
                  {
                    "caption": "derivation or restatement",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    definition[\"A definition · what exists\"]\n    code[\"Code · how it behaves\"]\n    derived[\"A derivation · read from the definition\"]\n    restated[\"A restatement · written twice\"]\n    definition --> derived --> code\n    definition -. never .-> restated\n    restated -. disagrees the moment either copy moves .-> code"
                  }
                ],
                "title": "One declaration, derived everywhere"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The split is [single source of truth](/records/architecture/single-source-of-truth) stated for a whole system rather than for a database. [Declarative configuration](/records/architecture/declarative-configuration) states what is wanted and leaves the how to whatever reads it. [Manifest-based design](/records/architecture/manifest-based-design) puts what a module is for into data beside the module, so its surface is derived rather than described. [Metadata-driven design](/records/architecture/metadata-driven-design) lets the description drive the behavior."
                  },
                  {
                    "kind": "text",
                    "text": "[Code as data](/records/architecture/code-as-data) is where the split pays off, because a definition that is data can be inspected, transformed, validated and generated from, while a definition that is code can only be run. The [registry pattern](/records/architecture/registry-pattern) with [auto-discovery](/records/architecture/runtime-discovery) applies the same idea to variants. The registry declares that variants exist, the tree holds one file per variant, and a [glob-resolvable tree](/records/architecture/glob-resolvable-tree) lets the code find them without a list that must be edited when one is added."
                  },
                  {
                    "kind": "text",
                    "text": "[Convention over configuration](/records/architecture/convention-over-configuration) is the complement. A convention is a definition too, written once as a rule the reader derives from rather than a value the reader looks up."
                  }
                ],
                "title": "The patterns that keep the split"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The graph model is what makes the split checkable. A declaration is a node, a derivation is an edge, and a fact with two nodes and no edge between them is the [dual write](/records/architecture/dual-write) in the graph's own terms. Written as a type, the model is small."
                  },
                  {
                    "kind": "text",
                    "text": "A component carries an identity, a concern and a layer. A relation carries its two ends and a kind from a [closed vocabulary](/records/architecture/closed-vocabulary), so a new relation kind is a vocabulary edit rather than a new field. The schema carries the invariants and one evaluation over the graph, and [schema validation](/records/architecture/schema-validation) is that evaluation run over every record that claims the shape. Health is [one derivation](/records/reasoning/invariant-epi-one-derivation), in which the schema is evaluated against the system's description of itself, and an empty finding set means the system is healthy."
                  },
                  {
                    "code": "export interface Component {\n    readonly id: ComponentId;\n    readonly concern: Concern;\n    readonly layer: Layer;\n}\n\nexport interface Relation {\n    readonly from: ComponentId;\n    readonly to: ComponentId;\n    readonly kind: \"imports\" | \"exports\" | \"registers\" | \"consumes\" | \"emits\" | \"subscribes\" | \"interfaces\";\n}\n\nexport interface Schema {\n    readonly invariants: readonly Invariant[];\n    readonly evaluate: (graph: SystemGraph) => readonly Finding[];\n}\n\nexport interface Propagation {\n    readonly reaches: (change: ComponentId, graph: SystemGraph) => readonly ComponentId[];\n}\n\nexport interface SystemGraph {\n    readonly components: readonly Component[];\n    readonly relations: readonly Relation[];\n    readonly schema: Schema;\n    readonly propagation: Propagation;\n}\n\nexport const derivable = (graph: SystemGraph, described: SystemGraph): boolean =>\n    graph.schema.evaluate(described).length === 0;",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the model typed"
                  }
                ],
                "title": "The model as a type"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A definition may say a record has a name and a kind from a closed set. It may not say how the kind is checked, because checking is behavior. A manifest may say a module publishes three entry points. It may not build them. Either crossing produces the same defect, a truth held in two places with no edge between them."
                  }
                ],
                "title": "Where the line sits"
              }
            ],
            "title": "Definitions own what, code owns how"
          },
          {
            "icon": "bi-layers-half",
            "id": "the-layer-spine",
            "intro": "This section covers the layer spine, the one axis along which systems decompose, running from domain through application, processing, runtime, infrastructure and operations to product, as shown in [the spine] and [concerns to layers]. The spine is a classification axis, and who may import whom is described separately in [the direction axis](/software-architecture#the-direction-axis). The practice that parses a tree against the spine is described in [placement is a grammar](/disciplined-methodology/build#placement-is-a-grammar) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every concern in the vocabulary is tagged to one layer of the spine, and a file's layer follows from its concern. A file is classified by what it does, never by the folder it happens to sit in, and a file that fits two concerns equally well is treated as two files rather than as a tie to break. The tagging is held in data a check reads, so a layer is a derivation from the concern and never a fact the developer or the model has to remember.",
                    "boundary": "The spine orders kinds of thing and never orders importance. A product-layer file is not lower than a domain-layer file, and a layer is never a folder. Two files in one concern folder sit on the same layer because their concern does, whatever the folder above them is called.",
                    "cause": "A layer inferred from a folder name changes when the folder is renamed, and a layer inferred from a file's importance is argued at every review, so only a layer derived from the concern stays true without attention.",
                    "decision": "Layer membership goes by type, rather than by directory or by status.",
                    "failureMode": "A converter sits in a folder named for the feature it serves, the feature is renamed, and every rule that keyed on the folder now sees a file of no layer at all.",
                    "kind": "lesson",
                    "principle": "For this reason classification rests on kind, which a [closed vocabulary](/records/architecture/closed-vocabulary) can decide, instead of on location, which a rename can change.",
                    "problem": "Layering is usually a diagram, and neither the developer nor the model can say which layer a given file is on, because the layer was never derived from anything the file declares.",
                    "validation": "To check this, take a file and derive its layer from its concern tag alone, without opening it. A file whose layer cannot be derived is outside the model, and a file whose derived layer surprises you is misclassified, or is two files."
                  },
                  {
                    "caption": "the spine",
                    "kind": "mermaid",
                    "text": "block-beta\n    columns 1\n    domain[\"domain · what the system is about\"]\n    application[\"application · what it does with that\"]\n    processing[\"processing · how data is transformed\"]\n    runtime[\"runtime · what runs and when\"]\n    infrastructure[\"infrastructure · what everything else stands on\"]\n    operations[\"operations · how it is observed and kept alive\"]\n    product[\"product · what a customer meets\"]"
                  }
                ],
                "title": "Classification"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Every [layered architecture](/records/architecture/layered-architecture) has to answer what makes a thing belong to a layer, and most answer it by folder. A folder is a rule about placement and says nothing about kind, so the layer of a file is whatever its author believed on the day. [Clean architecture](/records/architecture/clean-architecture) and [hexagonal architecture](/records/architecture/ports-and-adapters-architecture) answer the direction question well and leave this one to taste."
                  },
                  {
                    "kind": "text",
                    "text": "The spine answers it by kind. Every concern in a closed vocabulary is tagged to one layer, the concern is decided by reading what the file does under [one concern per file](/records/architecture/one-concern-per-file) and the [narrowest concern](/records/architecture/narrowest-concern) that fits, and the layer is a derivation. [Concern-folder correspondence](/records/architecture/concern-folder-correspondence) makes the derivation visible in the tree, because the folder names the concern and the concern names the layer, so nothing has to be remembered."
                  }
                ],
                "title": "Belonging by kind, never by folder"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The seven layers map onto how a system decomposes rather than onto how a team is organized. The domain holds what the system is about, such as its models, records, policies and specifications. The application holds what it does with that, such as coordinators, behaviors, intents, selectors and stores. Processing holds transformation, such as converters, normalizers, analyzers, validators and pipelines."
                  },
                  {
                    "kind": "text",
                    "text": "Runtime holds what runs and when, such as entrypoints, lifecycles, timers and pools. Infrastructure holds what everything else stands on, such as registries, factories, adapters, resolvers, constants, schemas and the vocabulary itself. Operations holds observation and upkeep, such as probes, counters and reporters. Product holds what a customer meets, such as views, components, renderers, styles and the strings."
                  },
                  {
                    "kind": "text",
                    "text": "A concern belongs to exactly one layer, and a concern whose layer is contested is two concerns. [Layer spine precedence](/records/architecture/layer-spine-precedence) is the one tie-break the canon holds, and it applies only to an irreducible overlap between two tags for one concern. In that case the file classifies to the domain-ward tag, and the rule stays a classification rule, never a dependency rule."
                  },
                  {
                    "caption": "concerns to layers",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    converter[\"converter\"] --> processing[\"processing\"]\n    validator[\"validator\"] --> processing\n    registry[\"registry\"] --> infrastructure[\"infrastructure\"]\n    factory[\"factory\"] --> infrastructure\n    view[\"view\"] --> product[\"product\"]\n    renderer[\"renderer\"] --> product\n    model[\"model\"] --> domain[\"domain\"]\n    policy[\"policy\"] --> domain"
                  }
                ],
                "title": "The seven layers"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Take a converter. It takes one shape and returns another, so it is processing whatever it converts and whichever feature asked for it. Put it in a folder named for the feature and it has a home but no layer, and the next feature that needs the same conversion either reaches across a boundary or copies the file."
                  },
                  {
                    "kind": "text",
                    "text": "Put it under its concern and the layer follows, the second feature finds it where the concern says it is, and a check can hold that nothing in processing reaches into product. [Separation of concerns](/records/architecture/separation-of-concerns) then has a mechanism behind it. [Package by feature](/records/architecture/package-by-feature) answers a different question, how a team navigates, and a feature cuts across every layer as a layer cuts across every feature, so only one of the two can be the folder."
                  }
                ],
                "title": "A converter, placed twice"
              }
            ],
            "title": "The layer spine"
          },
          {
            "icon": "bi-sign-turn-right",
            "id": "the-direction-axis",
            "intro": "This section covers the direction axis, which says who may depend on whom, as shown in [one way], while the classification described in [the layer spine](/software-architecture#the-layer-spine) says what kind of thing a file is. The two axes are orthogonal, as typed in [two axes]. The canon's architecture styles are each one picture of the same direction rule, and a wrong-way edge has one repair, shown in [the repair].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, one tier is named the engine and the other the consumer. Each container is classified by prefix, and only the trees a prefix cannot decide are classified per file. Both classifications feed the check, which refuses an import that runs from the engine toward a consumer.",
                    "boundary": "The direction rule governs dependencies and says nothing about classification. A file is not on the engine tier because it is generic, and a consumer is not lower because it is specific. The tier is a fact declared about a tree, and the check reads the fact rather than inferring it.",
                    "cause": "A dependency rule with no check refuses nothing, so the first import that crosses the wrong way is the one that was convenient that afternoon.",
                    "decision": "Engine and consumer are assigned by prefix and data, rather than judged from how general the code appears.",
                    "failureMode": "A shared module gains one import from a page, the page changes, the module now breaks on every page, and the layering that was supposed to prevent that never had a rule behind it.",
                    "kind": "lesson",
                    "principle": "For this reason the dependency direction is an orthogonal axis that runs one way, from consumer to engine, and is held by its own check.",
                    "problem": "Nothing refuses the import that crosses the wrong way, so the engine slowly learns about its consumers one convenient import at a time.",
                    "validation": "To check this, take any import and ask which tier each end is on. An import whose ends cannot be tiered is outside the model, and an import that runs from the engine toward a consumer is a move waiting to happen."
                  },
                  {
                    "caption": "one way",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    engine[\"The engine tier · knows nothing about any consumer\"]\n    consumer[\"The consumer tier · depends on the engine\"]\n    consumer -- imports --> engine\n    engine -. never .-> consumer\n    prefix[\"Classified by container prefix\"]\n    override[\"Two trees a prefix cannot decide · classified per file\"]\n    prefix --> engine\n    prefix --> consumer\n    override --> engine\n    override --> consumer"
                  }
                ],
                "title": "Engine and consumer"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The direction rule is the [dependency inversion principle](/records/architecture/dependency-inversion) drawn at the scale of a whole tree, and the canon's architecture styles are each one way of drawing it. [Hexagonal architecture](/records/architecture/ports-and-adapters-architecture) and [clean architecture](/records/architecture/clean-architecture) put the thing that knows nothing at the center and let everything specific depend inward. [Layered architecture](/records/architecture/layered-architecture) draws the same arrow downward."
                  },
                  {
                    "kind": "text",
                    "text": "What they share is one direction and one rule. What they differ on is a picture, and the picture is not the mechanism. The mechanism is a tier declared for every file, a check that reads the [dependency graph](/records/architecture/dependency-graph) and refuses an edge from the engine toward a consumer, and a repair that is always a move."
                  },
                  {
                    "kind": "text",
                    "text": "[Inversion of control](/records/architecture/inversion-of-control) and [dependency injection](/records/architecture/dependency-injection) are the two techniques the rule pushes you toward. The only way an engine uses something specific without knowing it is to be handed it, and [extension points](/records/architecture/extension-points) with [runtime discovery](/records/architecture/runtime-discovery) are how the engine finds the consumers it must not import."
                  }
                ],
                "title": "One rule, many pictures"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Most of a tree classifies by where it sits, because a container is built for one tier and everything under it inherits that. A few kinds of file resist that reading. Copy and type declarations serve whichever side names them, so their location says nothing about their tier, and those are classified one file at a time in data that starts empty."
                  },
                  {
                    "kind": "text",
                    "text": "What a file with no entry resolves to is a decision with a reason, not a default that fell out of the code. A type with no classification resolves to no tier, so the check treats it as unclassified rather than guessing a side. Copy with no classification resolves to the consumer tier, because copy is nearly always specific to one product. The two defaults differ because the cost of a wrong guess differs, and the general rule is that a default is chosen by which mistake is cheaper to discover."
                  },
                  {
                    "code": "export const SPINE = [\"domain\", \"application\", \"processing\", \"runtime\", \"infrastructure\", \"operations\", \"product\"] as const;\nexport type Layer = (typeof SPINE)[number];\n\nexport const TIERS = [\"engine\", \"consumer\"] as const;\nexport type Tier = (typeof TIERS)[number];\n\nexport interface Classification {\n    readonly concern: Concern;\n    readonly layer: Layer;\n}\n\nexport interface Direction {\n    readonly byPrefix: Readonly<Record<string, Tier>>;\n    readonly overrides: Readonly<Record<string, Tier>>;\n}\n\nexport const tierOf = (path: string, direction: Direction): Tier | null =>\n    direction.overrides[path] ?? direction.byPrefix[prefixOf(path)] ?? null;\n\nexport const crossesUpward = (from: string, to: string, direction: Direction): boolean =>\n    tierOf(from, direction) === \"engine\" && tierOf(to, direction) === \"consumer\";",
                    "kind": "code",
                    "language": "typescript",
                    "title": "two axes"
                  }
                ],
                "title": "Where a tier comes from"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The check reads a dependency graph derived from the tree, never the tree's claims about itself, and it fails closed, so a missing graph is a refusal rather than a pass over nothing. It refuses rather than repairs, because the only repair for a wrong-way import is to move the file."
                  },
                  {
                    "kind": "text",
                    "text": "A file that produces a [circular dependency](/records/architecture/circular-dependency), an upward dependency or a bypass of a declared entry point is in the wrong module. [Lazy evaluation](/records/architecture/lazy-evaluation) of an import, a direct path past the entry point, a re-export across modules and an import-sort trick each make the graph pass while the structure stays wrong. Those tricks preserve [concrete coupling](/records/architecture/concrete-coupling) and [inappropriate intimacy](/records/architecture/inappropriate-intimacy), because the engine still knows a consumer, only through a door no check watches. [Encapsulation](/records/architecture/encapsulation) and [information hiding](/records/architecture/information-hiding) are what the entry point protects."
                  },
                  {
                    "caption": "the repair",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    edge[\"An edge from the engine toward a consumer\"]\n    trick[\"A trick · lazy import, direct path, re-export, sort order\"]\n    move[\"A move · to the module whose layer and entry point satisfy every dependency\"]\n    lies[\"The graph passes and the structure stays wrong\"]\n    holds[\"The graph and the structure agree\"]\n    edge -. tempting .-> trick --> lies\n    edge --> move --> holds"
                  }
                ],
                "title": "The repair is a move"
              }
            ],
            "title": "The direction axis"
          }
        ]
      },
      {
        "icon": "bi-bounding-box",
        "id": "principles",
        "label": "Principles",
        "sections": [
          {
            "icon": "bi-book",
            "id": "principles-are-typed",
            "intro": "This section covers how a principle is held as a typed record rather than a slogan. The record is typed in [a principle record], its slots are shown in [ten slots], and its edges are traced in [the five edges]. The whole canon resolves by identity join, so a list of principles becomes something a check can consult, and [every record](/ontology) this page names can be opened and walked on the ontology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every principle has one identity that nothing else carries, a kind from a closed taxonomy and a category from the data that holds it. Its relations to the other records are recorded as names that resolve to identities, never as free prose, together with what violates it, what detects and measures a violation, the repairs that reverse it and the gates that enforce it. An exemplar with a before and an after is attached, and the gate proves the whole before anything consults it.",
                    "boundary": "A canon is a vocabulary for reasoning, and it is the wrong home for a threshold or a path. A principle says that complexity is bounded. The number lives in the gate's config and the check reads it there. A canon that carries numbers is a second config, and a canon that carries paths is bound to one tree.",
                    "cause": "Prose principles cannot be joined, so nothing can compute which principle a finding violates, which repair follows, or which two principles a design has set against each other.",
                    "decision": "The canon is held as data a gate resolves rather than as a document a reviewer cites.",
                    "failureMode": "A review cites a principle by name, a second review cites its opposite by another name, both are in the document, and neither review can show that the two were ever meant to conflict or how the conflict resolves.",
                    "kind": "lesson",
                    "principle": "For this reason principles are typed and related, and a canon that does not resolve by identity is refused by its gate.",
                    "problem": "Architecture principles are usually a reading list, and a reading list cannot tell you which of its entries a given change just broke.",
                    "validation": "To check this, take a finding from any check and resolve its canonical id. It must reach the principle, the principle's severity, its repairs and its relation graph in one lookup. A finding that reaches only a message has no canon behind it."
                  },
                  {
                    "caption": "ten slots",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    principle[\"A principle · one canonical id, one kind, one category, a severity\"]\n    requires[\"requires · cannot hold without\"]\n    reinforces[\"reinforces · holds more easily beside\"]\n    enables[\"enables · makes possible\"]\n    tensions[\"in tension with · a record it pulls against, resolved by mechanism\"]\n    conflicts[\"conflicts with · the anti-patterns that negate it\"]\n    violated[\"violated by · what a violation looks like\"]\n    detected[\"detected by · the signals that see it\"]\n    measured[\"measured by · the numbers that size it\"]\n    refactored[\"refactored by · the repairs that reverse it\"]\n    enforced[\"enforced by · the gates that hold it\"]\n    principle --> requires\n    principle --> reinforces\n    principle --> enables\n    principle --> tensions\n    principle --> conflicts\n    principle --> violated\n    principle --> detected\n    principle --> measured\n    principle --> refactored\n    principle --> enforced\n    gate[\"A resolution gate · every edge resolves to a record or a defined term, every kind is in range, or the gate refuses\"]\n    requires -.-> gate\n    tensions -.-> gate\n    conflicts -.-> gate"
                  }
                ],
                "title": "Ten slots, one gate"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Requires says a principle cannot hold without another, so a design that adopts [modularity](/records/architecture/modularity) has adopted its [whole closure](/records/algorithms/dependency-closure) whether it meant to or not. Reinforces says two principles hold more easily together, which is how an improvement [propagates](/records/algorithms/reinforcement-propagation) past the record it was made to. Enables says one makes another possible."
                  },
                  {
                    "kind": "text",
                    "text": "In tension with says two records pull against each other on one construct, and every such pair carries a resolution whose mechanism follows from what the two records are. Conflicts with is the one negative edge, pointing from a principle to the [anti-patterns](/records/kind/anti-pattern) that negate it, and the polarity law says it may [point nowhere else](/ontology/schema#the-relation-ranges)."
                  },
                  {
                    "caption": "the five edges",
                    "kind": "mermaid",
                    "text": "classDiagram\n    class Principle {\n        id\n        name\n        kind\n        category\n        severity\n        violatedBy\n        detectedBy\n        measuredBy\n        refactoredBy\n        enforcedBy\n    }\n    class Term {\n        id\n        name\n        kind\n        definition\n    }\n    class AntiPattern {\n        id\n        absentControl\n    }\n    class Layer {\n        id\n        observes\n        feeds\n    }\n    Principle --> Principle : requires\n    Principle --> Principle : reinforces\n    Principle --> Principle : enables\n    Principle --> Term : tensions with\n    Principle --> AntiPattern : conflicts with\n    Principle --> Layer : member of"
                  }
                ],
                "title": "The five edges"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The descriptors are prose a developer reads. Violated-by describes the violation, detected-by the [signals that see it](/records/algorithms/violation-detection), measured-by the numbers that size it, refactored-by the [repairs that reverse it](/records/algorithms/refactor-selection), and enforced-by the [gates that hold the line](/records/algorithms/enforcement-gate)."
                  },
                  {
                    "kind": "text",
                    "text": "[Severity](/records/algorithms/severity-policy) says how strictly the principle binds and, where the record states one, the condition under which it binds that strictly. It is a routing field that decides which handler a failure reaches, whether a refusal, a review note or an information line, and it never ranks one principle above another. A check still answers pass or fail, and severity says what happens to the answer."
                  },
                  {
                    "code": "export type Kind =\n    | \"anti-pattern\" | \"metric\" | \"quality-attribute\" | \"principle\" | \"constraint\"\n    | \"capability\" | \"activity\" | \"pattern\" | \"mechanism\" | \"technique\"\n    | \"approach\" | \"model\" | \"artifact\" | \"style\";\n\nexport interface Principle {\n    readonly id: string;\n    readonly name: string;\n    readonly type: Kind;\n    readonly category: string;\n    readonly scope: readonly string[];\n    readonly requires: readonly string[];\n    readonly reinforces: readonly string[];\n    readonly enables: readonly string[];\n    readonly conflictsWith: readonly string[];\n    readonly tensionsWith: readonly string[];\n    readonly violatedBy: string;\n    readonly detectedBy: string;\n    readonly measuredBy: string;\n    readonly refactoredBy: string;\n    readonly enforcedBy: string;\n    readonly severity: string;\n    readonly exemplar?: { readonly before: string; readonly after: string; readonly lang: string };\n}\n\nexport interface Issues {\n    readonly danglingEdges: readonly { from: string; relation: string; target: string }[];\n    readonly duplicateIds: readonly string[];\n}\n\nexport const validate = (canon: readonly Principle[], resolveId: (name: string) => string | null): Issues => {\n    const ids = new Set(canon.map((principle) => principle.id));\n    const edges = [\"requires\", \"reinforces\", \"enables\", \"conflictsWith\", \"tensionsWith\"] as const;\n    return {\n        danglingEdges: canon.flatMap((principle) =>\n            edges.flatMap((relation) =>\n                principle[relation]\n                    .filter((target) => resolveId(target) === null && !ids.has(target))\n                    .map((target) => ({ from: principle.id, relation, target })),\n            ),\n        ),\n        duplicateIds: canon.map((principle) => principle.id).filter((id, index, all) => all.indexOf(id) !== index),\n    };\n};",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a principle record"
                  }
                ],
                "title": "The five descriptors"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Modularity is a mandatory principle in the [structural core](/records/layer/structural-core). It requires [high cohesion](/records/architecture/high-cohesion), [low coupling](/records/architecture/low-coupling) and [explicit boundaries](/records/architecture/explicit-boundaries), because a module whose insides do not belong together, or whose edges were never drawn, is not one you can replace. It reinforces [separation of concerns](/records/architecture/separation-of-concerns) and [composability](/records/architecture/composability), and it enables [replaceability](/records/architecture/replaceability) and [plugin architecture](/records/architecture/plugin-architecture)."
                  },
                  {
                    "kind": "text",
                    "text": "It is in tension with cross-cutting concerns, and that pair carries a recorded resolution. It conflicts with the [big ball of mud](/records/architecture/big-ball-of-mud), the one anti-pattern that is its outright negation. A reading list can tell you modularity is good. The record can tell you what you have already committed to by choosing it, what you will get for free, and what it refuses."
                  },
                  {
                    "kind": "text",
                    "text": "Its descriptors meet the tree. It is violated by [cyclic dependencies](/records/architecture/circular-dependency), [shared mutable state](/records/architecture/shared-mutable-state) and [boundary leakage](/records/architecture/boundary-leakage). It is detected by dependency cycles and an unstable module graph, measured by a modularity score, graph density and instability, and refactored by splitting the module, introducing a boundary or inverting the dependency. It is enforced by module rules, package ownership and [fitness functions](/records/architecture/fitness-functions). The last slot is what separates a canon from a book, because a principle with an empty enforced-by is held by nothing."
                  }
                ],
                "title": "One record, walked"
              }
            ],
            "title": "Principles are typed"
          },
          {
            "icon": "bi-tags",
            "id": "every-record-has-a-kind",
            "intro": "This section covers the kind every record carries, drawn from a [closed taxonomy](/ontology/schema#the-kind-taxonomy). How a kind is read from a definition is shown in [kind from definition], the kinds are grouped in [the fourteen kinds], and a kind record is typed in [a kind record]. The kind decides what may point at a record, how a tension with it resolves and whether a check can measure it, so a wrong kind is a wrong answer to every one of those questions at once.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the definition is read and asked what it describes, whether a degree a system exhibits, a number, a rule that prescribes, a rule that must hold, a facility, a method, an arrangement, a representation, a produced thing, a convention of expression, or a condition to avoid. The kind is assigned from that reading and never from the name.",
                    "boundary": "A kind classifies what a record is, never how important it is. Two records of the same kind can differ in severity, and a quality that a whole system depends on is still a quality rather than a rule, because the taxonomy answers one question and severity answers another.",
                    "cause": "Names are chosen for recognition and definitions are written for precision, so the name of a record tends to overclaim its kind, and the overclaim is only visible once the definition is read against the taxonomy.",
                    "decision": "Each kind's discriminator is held as data the gate reads, rather than as a reviewer's judgment, so a record whose definition disagrees with its kind is refused rather than shipped.",
                    "failureMode": "A quality that a system exhibits to a degree is filed as a principle, a check is written to enforce it as a rule, and the check has nothing to return because a degree has no violation to report.",
                    "kind": "lesson",
                    "principle": "For this reason a record's kind follows from its definition, and the taxonomy of kinds is closed.",
                    "problem": "Everything on a reading list is called a principle, so a quality, a mechanism and a technique are argued as though they were rules.",
                    "validation": "To check this, take any record and cover its name. Read the definition and name the kind from the definition alone. If it differs from the kind the record carries, the record is mis-filed, and every edge that points at it has been reasoning about the wrong thing."
                  },
                  {
                    "caption": "kind from definition",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    record[\"A record\"]\n    question{\"What does the definition say it is?\"}\n    property[\"a property held to a degree · quality attribute\"]\n    number[\"a measurement · metric\"]\n    rule[\"a rule that prescribes · principle\"]\n    bound[\"a rule that must hold · constraint\"]\n    facility[\"a facility that does it · mechanism\"]\n    method[\"a method a developer applies · technique\"]\n    arrangement[\"a design-level arrangement · pattern\"]\n    avoided[\"a condition to avoid · anti-pattern\"]\n    record --> question\n    question --> property\n    question --> number\n    question --> rule\n    question --> bound\n    question --> facility\n    question --> method\n    question --> arrangement\n    question --> avoided\n    polarity[\"The polarity law · only conflicts-with may point at an anti-pattern\"]\n    avoided -.-> polarity"
                  }
                ],
                "title": "Read the definition, not the name"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Each kind answers one question, whether about a rule, a measure, a doing, a shape or a condition to avoid. The pairs most often confused sit closest together. A metric is the measurement and a quality attribute is the property measured, a principle prescribes and a constraint binds, and a mechanism is the facility while a technique is the method a developer applies. The gate checks that every kind is in range, and for a [defined term](/ontology/lexicon) it checks that the kind agrees with the definition, so a term cannot call itself a principle while defining a metric."
                  },
                  {
                    "caption": "the fourteen kinds",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    kind((\"kind\"))\n    rule[\"a rule\"]\n    measure[\"a measure\"]\n    doing[\"a doing\"]\n    shape[\"a shape\"]\n    avoid[\"a condition to avoid\"]\n    kind --> rule & measure & doing & shape & avoid\n    rule --> principle[\"principle · prescribes\"] & constraint[\"constraint · must hold\"]\n    measure --> metric[\"metric · a number\"] & quality[\"quality attribute · a degree\"]\n    doing --> capability[\"capability · what can be done\"] & mechanism[\"mechanism · the facility\"] & technique[\"technique · the method\"] & approach[\"approach · the strategy\"]\n    shape --> pattern[\"pattern · an arrangement\"] & model[\"model · a representation\"] & convention[\"style · a convention\"] & artifact[\"artifact · a produced thing\"]\n    avoid --> anti[\"anti-pattern\"]"
                  },
                  {
                    "code": "export interface KindRecord {\n    readonly kind: Kind;\n    readonly discriminator: string;\n    readonly distinguishesFrom: string;\n    readonly definitionSignatures: readonly string[];\n}\n\nexport const kindAgrees = (term: { readonly kind: Kind; readonly definition: string }, taxonomy: readonly KindRecord[]): boolean => {\n    const record = taxonomy.find((entry) => entry.kind === term.kind);\n    return record !== undefined && record.definitionSignatures.some((signature) => term.definition.includes(signature));\n};",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a kind record"
                  }
                ],
                "title": "The fourteen kinds"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Reading a kind off a name is the mistake the taxonomy exists to catch. [Homoiconicity](/records/architecture/homoiconicity) is a quality attribute, a degree a system exhibits, whatever a reading list calls it. [Orchestration](/records/architecture/orchestration) and [choreography](/records/architecture/choreography) are mechanisms, facilities that do a thing. [Pure functions](/records/architecture/pure-functions) are a technique a developer applies. [Event sourcing](/records/architecture/event-sourcing) and [CQRS](/records/architecture/command-query-responsibility-segregation) are patterns, arrangements a design takes. [Fail fast](/records/architecture/fail-fast) is a principle and [idempotency](/records/architecture/idempotency) is a principle, because each prescribes."
                  },
                  {
                    "kind": "text",
                    "text": "A check can enforce a principle and measure a metric, but it cannot enforce a quality attribute. A tension between two principles can separate by scope, while a tension between a principle and a quality attribute can only be traded, as derived in [separate, trade, or mitigate](/software-architecture/principles#separate-trade-or-mitigate)."
                  }
                ],
                "title": "What a name overclaims"
              }
            ],
            "title": "Every record has a kind"
          },
          {
            "icon": "bi-collection",
            "id": "the-canon-is-grouped-twice",
            "intro": "This section covers the two groupings of the canon and the different questions they answer. The records are held in topical categories, so a reader looking for [least privilege](/records/architecture/least-privilege) finds it beside the other security records and [backpressure](/records/architecture/backpressure) beside the other [resilience](/records/architecture/resilience) records. Each category is then [a member of one layer](/ontology/schema#the-membership), in the topology shown in [the layers], and the layers are where tensions resolve, because a layer is a scope a principle can hold whole in.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, records are grouped by topic for the reader looking for one, and every topical group maps to exactly one layer for the check that has to decide a scope. The two groupings are held as data with [one derivation](/records/reasoning/invariant-epi-one-derivation) between them, so a record's layer is read from its category and never stated twice. Which layer observes, feeds or cuts across which is recorded too, because that topology is what a scope-separation between two principles is decided against.",
                    "boundary": "A grouping is a lookup structure and never a claim about a record. A principle in the security category is not more important than one in the structural category, and a layer is not a rank. The layer says only which scope a principle holds whole in.",
                    "cause": "One grouping cannot serve both a reader and a check, because a reader looks by topic and a check decides by scope, and a canon that picks one leaves the other question answered by guesswork.",
                    "decision": "Both groupings are kept rather than one being picked, at the cost of one derivation between them.",
                    "failureMode": "Two principles pull against each other, the reviewer looks for the domain each belongs to, and finds two topical categories that say nothing about scope, so the tension is settled by the reviewer who argues longer.",
                    "kind": "lesson",
                    "principle": "For this reason a canon is grouped by topic for people and by layer for checks, and the layer is derived from the topic rather than stated beside it.",
                    "problem": "A canon organized one way answers one question, and the other question is answered from memory.",
                    "validation": "To check this, take any principle and name its layer without opening the record, from its category alone. If the category does not decide it, the grouping is a reading order and not a scope, and no tension that names this principle can be resolved by data."
                  },
                  {
                    "caption": "the layers",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph core[\"The four core layers\"]\n        computation[\"computation · stateless\"]\n        resource[\"resource · stateful\"]\n        execution[\"execution · control flow and events\"]\n        structural[\"structural · applies to all, observes itself\"]\n    end\n    human[\"human factors · what a developer can hold\"]\n    evolution[\"evolution · how the whole changes\"]\n    subgraph crosscut[\"Cross-cutting layers · each cuts across the structural core\"]\n        correctness[\"correctness\"]\n        security[\"security\"]\n        performance[\"performance\"]\n        contracts[\"contracts\"]\n        causality[\"causality\"]\n        declarative[\"declarative\"]\n        extensibility[\"extensibility\"]\n        observability[\"observability\"]\n        enforcement[\"enforcement\"]\n        atomic[\"atomic boundary\"]\n        domain[\"domain modeling\"]\n        patterns[\"design patterns\"]\n    end\n    resource -- observe --> computation\n    computation --> execution\n    resource --> execution\n    execution --> structural\n    structural -- feedback --> execution\n    structural --> human\n    structural --> evolution\n    evolution --> human\n    crosscut -. cross-cuts .-> structural"
                  }
                ],
                "title": "By topic for people, by layer for checks"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Four layers form the core. [Computation](/records/layer/computation-core) is stateless and its outputs are frozen. [Resource](/records/layer/resource-core) is stateful, and every handle has one owner and a bounded lifetime. [Execution](/records/layer/execution-core) is control flow and events. [Structural](/records/layer/structural-core) applies to everything and observes itself."
                  },
                  {
                    "kind": "text",
                    "text": "Beneath the core sit [human factors](/records/layer/human-factors), which bound the whole by what a developer can hold, and [evolution](/records/layer/evolution-principles), which says how the whole changes over time. Around the core sit the twelve layers that cut across it, which are [correctness](/records/layer/correctness-core), [security](/records/layer/security-core), [performance](/records/layer/performance-core), [contracts](/records/layer/contracts-core), [causality](/records/layer/causality-core), [declarative design](/records/layer/declarative-core), [extensibility](/records/layer/extensibility-core), [observability](/records/layer/observability), [enforcement](/records/layer/enforcement-core), the [atomic boundary](/records/layer/atomic-boundary), [domain modeling](/records/layer/domain-modeling) and [design patterns](/records/layer/design-patterns-core)."
                  },
                  {
                    "kind": "text",
                    "text": "The [topology](/ontology/schema#the-layer-topology) records which layer observes, feeds or cuts across which. A principle stated in one layer reaches the others by relation, never by being restated there."
                  }
                ],
                "title": "The layers"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The derivation is [single source of truth](/records/architecture/single-source-of-truth) applied to the grouping, and the same reasoning shapes how a record names its relations. Identity is the one thing written literally, and everything that points at a record does so by a name that resolves to that identity, so a leaf record depends on nothing beside it and a display name can be corrected without breaking an edge. Held that way the canon is a graph rather than a list, the [whole of it is traversable](/records/algorithms/architecture-knowledge-graph), and each [principle record](/records/algorithms/architectural-relationship-record) reconciles to one vocabulary rather than the vocabulary bending to the records."
                  }
                ],
                "title": "One derivation, never two facts"
              }
            ],
            "title": "The canon is grouped twice"
          },
          {
            "icon": "bi-cpu-fill",
            "id": "computation-and-resource",
            "intro": "This section covers the split at the core of the canon, between what happens to data, [computation](/records/layer/computation-core), and where data lives, a [resource](/records/layer/resource-core). The split is the first question to ask of any unit, because the two halves answer the same question with different rules. Who releases a resource decides whether it leaks, as shown in [who releases], and a lifetime runs from one owner to one release, as shown in [a lifetime] and typed in [ownership as types].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every unit is sorted into computation or resource before it is designed. What computation produces is frozen, each variable is assigned once, and a computation carries no persistent state, so it can be replayed and its [rollback](/records/architecture/rollback) restores meaning rather than bytes. Every resource has one owner and a lifetime bound to that owner's, every open is paired with a close and every start with a stop, and release happens by scope or by an explicit destroy rather than by the developer or the model remembering. Every cache and pool is bounded by a declared capacity and an eviction policy, and registered where it can be seen.",
                    "boundary": "The split does not let one rule stand in for the other. A computation is stateless while a resource is snapshotted before mutation, computed data is immutable while resource state is mutable but managed, and a broken resource invariant halts while a computation's uncertainty is marked and carried on.",
                    "cause": "A stateful thing treated as stateless leaks, because nothing owns its release, and a stateless thing treated as stateful drifts, because it acquires a lifetime nothing bounds.",
                    "decision": "Release is by structure rather than by discipline, and a unit is frozen rather than managed wherever it can be a computation.",
                    "failureMode": "A cache with no capacity grows until the process dies, a listener that is never unsubscribed fires against a component that was removed an hour ago, and both were written correctly by their authors.",
                    "kind": "lesson",
                    "principle": "For this reason a unit either transforms data or holds it, and each kind follows its own rules.",
                    "problem": "Most code mixes the two, so data that should have been frozen is mutated and handles that should have been owned are shared, and the leaks are found in production.",
                    "validation": "To check this, take any resource and name its owner and the structure that releases it. A resource with two owners, or with a release that depends on a developer, will leak."
                  },
                  {
                    "caption": "who releases",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    resource[\"A resource is acquired\"]\n    who{\"Who releases it?\"}\n    discipline[\"The developer remembering · it leaks\"]\n    structure[\"The structure · scope, a finally, an explicit destroy\"]\n    owner{\"Exactly one owner?\"}\n    weak[\"Every other reference is weak or ephemeral\"]\n    shared[\"Shared ownership · ambiguity, then a leak\"]\n    resource --> who\n    who -- discipline --> discipline\n    who -- structure --> structure --> owner\n    owner -- yes --> weak\n    owner -- no --> shared"
                  }
                ],
                "title": "What happens to data, where data lives"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The computation half is the canon's [computation core](/records/layer/computation-core) read as one rule. [Immutability](/records/architecture/immutability) freezes what a computation produces. [Pure functions](/records/architecture/pure-functions) give it no effect but its return value, and [referential transparency](/records/architecture/referential-transparency) lets any call be replaced by its result. [Determinism](/records/architecture/determinism) makes the same input give the same output, which is what makes [repeatability](/records/architecture/repeatability) and [reproducibility](/records/architecture/reproducibility) properties rather than hopes, and [testability](/records/architecture/testability) follows from all of them at once."
                  },
                  {
                    "kind": "text",
                    "text": "[Statelessness](/records/architecture/statelessness) is the same rule seen from the outside. Nothing is retained between calls, so a computation can run anywhere and be replayed. [Idempotency](/records/architecture/idempotency) is its consequence at the edge, because a [retry](/records/architecture/retry-pattern) of a stateless step has one effect however many times it lands. Validation and [verification](/records/architecture/verification) are then cheap, since a frozen output can be compared against an expected one without a running system around it."
                  }
                ],
                "title": "The computation half"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Being reachable is not the same as being useful. A collector frees what nothing reaches and keeps what something still points at, so an architectural leak survives collection because it is reachable, as with a cache entry that will never be read, an observer on a dead subject, or a handle held by an injection container."
                  },
                  {
                    "kind": "text",
                    "text": "For this reason every non-owning reference is weak or ephemeral, hidden retention in injection, mapping and observer machinery is made observable and bounded, and anything that outlives a single call carries an initialize, a run and a shutdown. [Graceful shutdown](/records/architecture/graceful-shutdown) is the resource rule at the scale of a process. A long-lived component with no shutdown is a leak by construction."
                  },
                  {
                    "caption": "a lifetime",
                    "kind": "mermaid",
                    "text": "stateDiagram-v2\n    [*] --> Acquired : the owner opens it\n    Acquired --> InUse : initialize\n    InUse --> InUse : use · one owner writes\n    InUse --> Released : shutdown · by scope or explicit destroy\n    InUse --> Halted : invariant broken · fail fast\n    Halted --> Released : the owner still releases\n    Released --> [*]"
                  },
                  {
                    "code": "export interface Owned<Handle> {\n    readonly acquire: () => Handle;\n    readonly release: (handle: Handle) => void;\n}\n\nexport interface Lifecycle {\n    readonly init: () => void;\n    readonly run: () => void;\n    readonly shutdown: () => void;\n}\n\nexport const withOwned = <Handle, Result>(owned: Owned<Handle>, use: (handle: Handle) => Result): Result => {\n    const handle = owned.acquire();\n    try {\n        return use(handle);\n    } finally {\n        owned.release(handle);\n    }\n};\n\nexport interface Bounded<Item> {\n    readonly capacity: number;\n    readonly evict: \"lru\" | \"fifo\";\n    readonly items: readonly Item[];\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "ownership as types"
                  }
                ],
                "title": "The resource half"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Caching](/records/architecture/caching) is where the two halves meet most often and where the split is most often lost. A cache holds computed data, so its entries are immutable, and it is a resource, so it has one owner, a declared capacity and an eviction policy. [Cache poisoning by design](/records/architecture/cache-poisoning-by-design) is what happens when the first half is forgotten, and a cache with no capacity is what happens when the second is."
                  },
                  {
                    "kind": "text",
                    "text": "[Configuration externalization](/records/architecture/configuration-externalization) is the same split at the boundary of the process. What the process reads at boot is a resource with one source and a validation at the door, and what it computes from that is frozen for the run. [Environment parity](/records/architecture/environment-parity) follows from it, because the same computation over a different resource behaves the same, or the difference is in the resource and can be named."
                  }
                ],
                "title": "Where the halves meet"
              }
            ],
            "title": "Computation and resource"
          },
          {
            "icon": "bi-broadcast",
            "id": "execution-joins-the-halves",
            "intro": "This section covers [execution](/records/layer/execution-core), the layer where the two halves meet, as shown in [the core split]. Execution has its own rules, each the refusal of one improvised join, and one exchange under those rules is shown in [one exchange] and typed in [execution as types].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a child announces what happened as an event and the parent decides what to do with it, so the child never holds a reference to what reacts. A correction is appended as a new record that supersedes rather than edits history, and an earlier state is restored by reinstantiating from a snapshot rather than by patching in place. Ordering uses a monotonic sequence the system owns, never the host's clock. Every error is a typed value in the system's own vocabulary, each error is marked as halting or carried, and a guard that fails does so closed.",
                    "boundary": "Execution rules govern how [computation and resources](/software-architecture/principles#computation-and-resource) interact at runtime, and they do not decide what either half is. A resource that halts on a broken invariant is obeying the resource rule, and a computation that marks an uncertainty is obeying the computation rule. Execution only carries the result between them.",
                    "cause": "A callback couples a child to a parent it should not know, a retraction is a second path every reader must handle, a clock is a dependency on the host, and a sentence in an error is a contract no consumer can dispatch on.",
                    "decision": "Order and failure are defined by the system itself rather than taken from its environment.",
                    "failureMode": "A child calls back into its parent, the parent is replaced, and the child keeps calling into something that no longer exists, while the error that would have said so was a string no consumer parsed.",
                    "kind": "lesson",
                    "principle": "For this reason execution joins the halves through events rather than callbacks, appends rather than retracts, and treats errors as part of the language.",
                    "problem": "Control flow is usually improvised per call site, so the same two halves are joined a different way in every place they meet.",
                    "validation": "To check this, follow one event from the child that emits it to every parent that reacts, and one error from where it is raised to where it is handled. A callback that runs upward, a retraction, or an error handled by string comparison is a place where execution has no rule."
                  },
                  {
                    "caption": "the core split",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph computation[\"Computation · what happens to data\"]\n        pure[\"pure functions · immutable · idempotent\"]\n        marked[\"uncertainty marked, never hidden\"]\n    end\n    subgraph resource[\"Resource · where data lives\"]\n        owner[\"one owner · bounded lifetime\"]\n        symmetric[\"open then close · start then stop · guaranteed\"]\n        halt[\"invariant broken · halt\"]\n    end\n    subgraph execution[\"Execution · control flow\"]\n        events[\"children emit · parents subscribe\"]\n        monotonic[\"append only · never retract\"]\n        snapshot[\"backtrack by reinstantiation\"]\n    end\n    structural[\"Structural · applies to all three · observes itself\"]\n    resource -- observe --> computation\n    computation --> execution\n    resource --> execution\n    execution -- feeds --> structural\n    structural -- feedback --> execution"
                  }
                ],
                "title": "Events, growth, order, errors"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Event-driven architecture](/records/architecture/event-driven-architecture) is the shape the first rule produces. [Domain events](/records/architecture/domain-events) are what a child emits, the [publish/subscribe pattern](/records/architecture/publish-subscribe-pattern) is how a parent hears them without the child knowing who listens, and an [event bus](/records/architecture/event-bus) is the mechanism that carries them. The [observer pattern](/records/architecture/observer-pattern) is the same relation inside one process. Execution may counter-propose by emitting an intent a parent can refuse, which is [asynchronous communication](/records/architecture/asynchronous-communication) with the refusal kept explicit."
                  },
                  {
                    "kind": "text",
                    "text": "An [append-only log](/records/architecture/append-only-log) is the growth rule as a store, and [event sourcing](/records/architecture/event-sourcing) is it as a whole architecture, where the current state is a fold over the events and a correction is a new event that supersedes. Backtracking is by snapshot and reinstantiation rather than by patching state in place, which is the [memento pattern](/records/architecture/memento-pattern) held as a rule rather than a trick."
                  },
                  {
                    "kind": "text",
                    "text": "Ordering is by a monotonic sequence or an append-only id, never a wall clock. A clock is a dependency on the host and a sequence is a dependency on nothing, which is why [causality](/records/architecture/causality) is tracked with [Lamport clocks](/records/architecture/lamport-clocks), [vector clocks](/records/architecture/vector-clocks) or [hybrid logical clocks](/records/architecture/hybrid-logical-clocks) rather than timestamps, and why [event ordering](/records/architecture/event-ordering) is a constraint the system owns. A [happens-before relationship](/records/architecture/happens-before-relationship) is derivable from a sequence and never from two clocks."
                  },
                  {
                    "caption": "one exchange",
                    "kind": "mermaid",
                    "text": "sequenceDiagram\n    participant Child\n    participant Bus as Event bus\n    participant Parent\n    Child->>Bus: emit intent · ordinal 41\n    Bus->>Parent: deliver\n    Parent-->>Bus: accept\n    Child->>Bus: emit intent · ordinal 42\n    Bus->>Parent: deliver\n    Parent-->>Bus: refuse · typed error, halts: false\n    Note over Child,Parent: the child never calls the parent · the log only grows"
                  }
                ],
                "title": "Events and growth"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Errors are part of the language. [Error handling](/records/architecture/error-handling) uses the system's own vocabulary and the errors are machine-processable, so a consumer dispatches on an error rather than parsing a sentence. An [inconsistent error model](/records/architecture/inconsistent-error-model), one boundary raising and another returning a code, is the anti-pattern this rule refuses, and [exception control flow](/records/architecture/exception-control-flow) is its twin."
                  },
                  {
                    "kind": "text",
                    "text": "A resource invariant that breaks [fails fast](/records/architecture/fail-fast) and halts, because carrying on with a corrupt handle is worse than any crash. A computation that is uncertain marks the uncertainty and carries on, because temporary inconsistency in data is acceptable exactly while it is visible. [Defensive programming](/records/architecture/defensive-programming) is the wrong reflex here, and the practice that replaces it is described in [fail at the boundary](/disciplined-methodology/build#fail-at-the-boundary) on the methodology page. [Fail safe](/records/architecture/fail-safe) and [fail secure](/records/architecture/fail-secure) are the same decision made once for a domain rather than per call site."
                  },
                  {
                    "code": "export interface Emitted<Intent> {\n    readonly ordinal: number;\n    readonly intent: Intent;\n}\n\nexport interface Child<Intent> {\n    readonly emit: (intent: Intent) => Emitted<Intent>;\n}\n\nexport interface Parent<Intent> {\n    readonly subscribe: (react: (event: Emitted<Intent>) => \"accept\" | \"refuse\") => Unsubscribe;\n}\n\nexport type Failure` =\n    | { readonly ok: true }\n    | { readonly ok: false; readonly code: Code; readonly halts: boolean };`",
                    "kind": "code",
                    "language": "typescript",
                    "title": "execution as types"
                  }
                ],
                "title": "Errors as language"
              }
            ],
            "title": "Execution joins the halves"
          },
          {
            "icon": "bi-bricks",
            "id": "the-structural-domain",
            "intro": "This section covers the [structural](/records/layer/structural-core) domain, which applies to all three cores and observes itself. Its principles are the classical ones, each paired with the practice the canon adds to it, as shown in [principle and practice].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each classical principle is paired with the practice that makes it recognizable in a tree, and its violation is written as a shape a check can match. Where the pairing yields no shape, the principle is not yet held by anything.",
                    "boundary": "A pairing sharpens a principle and never replaces it. The classical name still carries the intent a reader recognizes, and the practice only says how that intent shows in a tree. A practice with no principle behind it is a house rule, and a principle with no practice is held by nothing.",
                    "cause": "A principle stated without a shape gives a reviewer nothing to point at, so the disagreement moves to what the principle means in this file, and that is the argument the pairing settles in advance.",
                    "decision": "Every classical principle arrives with its detectable form, rather than being left to interpretation.",
                    "failureMode": "Two reviewers agree that a module should have one responsibility and disagree about whether this one does, because responsibility was never derived from anything either of them could point at.",
                    "kind": "lesson",
                    "principle": "For this reason a principle becomes enforceable only once its violation has a recognizable form.",
                    "problem": "Classical principles are agreed at a level no check can reach, so what they mean in a given file is argued every time.",
                    "validation": "To check this, take any structural principle you hold and state, in one sentence, what a violation of it looks like in a file. If the sentence names a shape, the principle has its practice. If it names an opinion, the pairing is still missing."
                  },
                  {
                    "caption": "principle and practice",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    classical[\"A classical principle · separation of concerns, simplicity, one responsibility\"]\n    sharpened[\"The practice that sharpens it · the whole system in view, compression, an invariant\"]\n    pair[\"One pair · the principle holds, the practice says how\"]\n    human[\"Human factors · bounded by what a developer can hold\"]\n    evolution[\"Evolution · state protected, room left, nothing built unneeded\"]\n    classical --> pair\n    sharpened --> pair\n    pair --> human\n    pair --> evolution"
                  }
                ],
                "title": "A principle and the practice that sharpens it"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Separation of concerns](/records/architecture/separation-of-concerns) is paired with reasoning about the whole system, so one module holds one concern while the design is still read as one thing. Simplicity is paired with compression, because the simplest solution is a rule or a generator, never an enumeration, and a repeated shape is compressed by its type. A literal becomes a constant, a structure a composition, a behavior one orchestrator, a fact one source. [Do not repeat yourself](/records/architecture/duplicate-code) is that compression named for the case of knowledge."
                  },
                  {
                    "kind": "text",
                    "text": "The [single responsibility principle](/records/architecture/single-responsibility) is derived from an invariant rather than a feature. The [open/closed principle](/records/architecture/open-closed) is met through few composable primitives, so extension arrives without editing what is tested. The [Liskov substitution principle](/records/architecture/liskov-substitution) makes substitutable parts order-independent. The [interface segregation principle](/records/architecture/interface-segregation) cuts an interface by usage, and the [dependency inversion principle](/records/architecture/dependency-inversion) addresses it by meaning rather than by location. [Composition over inheritance](/records/architecture/composition-over-inheritance) is the practice all five share, because a composed part can be replaced and an inherited one cannot."
                  },
                  {
                    "kind": "text",
                    "text": "[Code as data](/records/architecture/code-as-data) makes code, data and state one interchangeable structure, and [homoiconicity](/records/architecture/homoiconicity) is the degree to which a system has that property. One truth lives in versioned, queryable symbols, which is [single source of truth](/records/architecture/single-source-of-truth) with a location. Placement in a hierarchy reflects meaning, time is a logical sequence rather than a wall clock, and the system observes its own execution as data it can query, which is where [introspection](/records/architecture/introspection) and [observability](/records/architecture/observability) meet."
                  }
                ],
                "title": "The pairs"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Human factors](/records/layer/human-factors) bound the whole by what a developer can hold. Related logic stays together, which is [high cohesion](/records/architecture/high-cohesion) read as a limit on attention. Complexity stays under a declared bound, and [bounded nesting depth](/records/architecture/bounded-nesting-depth) is one such bound made checkable. Uncertainty stops the work rather than passing silently. Internals are hidden but shipped with a live inspector, so [encapsulation](/records/architecture/encapsulation) is traded against debuggability at a point the developer chose."
                  },
                  {
                    "kind": "text",
                    "text": "[Evolution](/records/layer/evolution-principles) says how the whole changes. Units are independent and swappable, with state protected before code. Features are added externally, through [extension points](/records/architecture/extension-points), with room left deliberately unspecified. Nothing is built that nothing needs, which refuses [speculative generality](/records/architecture/speculative-generality) and [premature abstraction](/records/architecture/premature-abstraction), and what the system will not do is written down in [architecture decision records](/records/architecture/architecture-decision-records) rather than remembered. [Evolutionary architecture](/records/architecture/evolutionary-architecture) with [fitness functions](/records/architecture/fitness-functions) is that domain held by checks rather than by review."
                  }
                ],
                "title": "Beneath the core"
              }
            ],
            "title": "The structural domain"
          },
          {
            "icon": "bi-arrow-left-right",
            "id": "a-tension-has-a-mechanism",
            "intro": "This section covers how two records that pull against each other on one construct are resolved. Every resolution the canon holds is [readable as a record](/records/tension/decentralization-single-source-of-truth), and where no record exists the mechanism is derived from the kinds and scopes of the two sides, in the order shown in [recorded or derived] and over the grid shown in [kinds against scopes]. A tension held as data, in the shape typed in [a resolution record], is consulted before the collision happens, while one held in prose is rediscovered by collision.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each side is classified before anything is resolved, as a principle, a quality, a metric or a cost, together with the scope it holds in. A derived resolution is recorded with its two records by identity, the mechanism, the scope each side holds in and the rule in one sentence, so the next reader finds a rule rather than a memory.",
                    "boundary": "A tension is a pair the canon relates by a tension edge, which is a different relation from a conflict. A conflict points from a principle to the anti-pattern that negates it, and it carries no resolution because one side is simply refused. Two rules that merely differ in strictness are not a tension, and neither is a rule that does not apply to a construct. The first is one rule with a scope, and the second is a classification question.",
                    "cause": "A principle stated without its scope reads as universal, so the moment two universal statements meet on one construct one of them has to lose, and the loser is chosen by the reviewer.",
                    "decision": "A recorded resolution is looked for before one is derived, and an exemption is refused as a third option, because one side winning for a reason that was never written down is a rule with no scope.",
                    "failureMode": "A review says the config must [fail fast](/records/architecture/fail-fast), the next review says the parser must tolerate bad input, both cite a principle, both are right, and the code ends up doing neither consistently.",
                    "kind": "lesson",
                    "principle": "For this reason an apparent conflict has a mechanism that follows from the kinds and scopes on each side, and the resolution is recorded rather than remembered.",
                    "problem": "Principles that appear to conflict are resolved case by case, and case-by-case resolution is a different rule in every case.",
                    "validation": "To check this, take any construct where two things seemed to collide and name the kind and scope of each. If a resolution is recorded, it is settled, and if a mechanism follows from the kinds and scopes, writing it down settles it. If the construct still sits on both sides, it is two constructs and needs splitting."
                  },
                  {
                    "caption": "recorded or derived",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    pair[\"Two records pull against each other on one construct\"]\n    exemption[\"An exemption · one wins here, for a reason never written down\"]\n    recorded{\"Is a resolution recorded for the pair?\"}\n    kinds{\"What kind of thing is on each side, and in which scope?\"}\n    separate[\"Two principles in different scopes · each holds whole in its own\"]\n    trade[\"Anything else · a quality on either side, or two principles in one scope · measure, choose an operating point, write it down\"]\n    mitigate[\"Recorded with a discriminator · a rule names what tells the two apart\"]\n    pair -. the tempting answer .-> exemption\n    pair --> recorded\n    recorded -- yes --> mitigate\n    recorded -- no --> kinds\n    kinds -- principle and principle, scopes differ --> separate\n    kinds -- otherwise --> trade"
                  }
                ],
                "title": "Recorded, never remembered"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The resolution is typed for the same reason a principle is. It names its two records by identity, the mechanism from the closed set of three, the scope each side holds in, and the rule in one sentence. The derivation has the shape of every default that must be safe when the case has not been thought about."
                  },
                  {
                    "kind": "text",
                    "text": "A recorded resolution wins outright, since a developer has already decided. Failing that, two principles that hold in different scopes separate, because each can hold whole on its own side. Everything else, a quality on either side or two principles that share one scope, falls to a trade-off, because the only thing that can be said about an undecided pair is that it has to be measured. Mitigation is never derived, because a discriminator is a judgment, and a judgment the data does not carry explicitly does not exist."
                  },
                  {
                    "caption": "kinds against scopes",
                    "kind": "mermaid",
                    "text": "quadrantChart\n    title Where a pair lands decides its mechanism\n    x-axis one scope --> two scopes\n    y-axis a quality on one side --> two principles\n    quadrant-1 separate by scope\n    quadrant-2 trade at a measured point\n    quadrant-3 trade at a measured point\n    quadrant-4 trade at a measured point\n    statelessness against state before mutation: [0.85, 0.85]\n    single source of truth against decentralization: [0.75, 0.9]\n    fail fast against graceful degradation: [0.15, 0.8]\n    consistency against availability: [0.8, 0.2]\n    encapsulation against debuggability: [0.3, 0.15]\n    backpressure against throughput: [0.2, 0.3]"
                  },
                  {
                    "code": "export type Mechanism = \"scope-separation\" | \"irreducible-tradeoff\" | \"mitigation\";\n\nexport interface Resolution {\n    readonly a: RecordId;\n    readonly b: RecordId;\n    readonly mechanism: Mechanism;\n    readonly scopeA: LayerId;\n    readonly scopeB: LayerId;\n    readonly rule: string;\n}\n\nexport const mechanismOf = (a: Record, b: Record, recorded: ReadonlyMap<PairKey, Resolution>): Mechanism => {\n    const explicit = recorded.get(pairKey(a.id, b.id));\n    if (explicit !== undefined) {\n        return explicit.mechanism;\n    }\n    const separable = a.kind === \"principle\" && b.kind === \"principle\" && a.layer !== b.layer;\n    return separable ? \"scope-separation\" : \"irreducible-tradeoff\";\n};",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a resolution record"
                  }
                ],
                "title": "The derivation"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Recording it that way lets a check resolve a finding to its side. A validator that fires on a [fallback pattern](/records/architecture/fallback-pattern) in a resource path reaches the fail fast side, and one that fires on an unmarked uncertainty in a computation reaches the explicit-invalidity side, and neither has to know the other exists. The canon's [resolution contract](/records/algorithms/conflict-and-tension-resolution) states the same obligation from the other direction. Architecture is trade-off governance as much as principle application, and the contract's policy admits an override only as a recorded decision beside the mitigations and the documented trade-offs."
                  },
                  {
                    "kind": "text",
                    "text": "Every resolution the canon currently holds is listed on [the schema tab](/ontology/schema#the-resolutions), with its mechanism, its two scopes and its rule."
                  }
                ],
                "title": "What a check does with it"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Where two enforced checks conflict on one construct, neither is satisfied by violating the other and neither is disabled. The construct is reshaped into the single form that satisfies every rule, and where that form is not obvious the question goes to the developer who owns the rules. An exclusion added to make a check pass is the exemption this whole section refuses, arriving through the tooling instead of the review. Two such collisions are walked in [when rules collide](/disciplined-methodology/plan#when-rules-collide) on the methodology page."
                  }
                ],
                "title": "Two checks on one construct"
              }
            ],
            "title": "A tension has a mechanism"
          },
          {
            "icon": "bi-signpost-split",
            "id": "separate-trade-or-mitigate",
            "intro": "This section covers the three mechanisms that resolve every tension the canon holds, since applying the wrong one to a pair is what turns a review into an argument. Which one applies is derived in [a tension has a mechanism](/software-architecture/principles#a-tension-has-a-mechanism), and the recurring pairs under each are grouped in [the recurring pairs].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, where two principles hold in different scopes, the scope each holds in and what holding means there are named, and the construct under review is classified to one scope before either is applied. Where a principle meets a quality, or two principles share one scope, the thing in tension is measured where the construct lives, and an operating point is chosen and recorded with its owner, so it is a decision rather than a mood. Where two things share a scope and differ in meaning, the rule that names the discriminator is written. Where a construct genuinely sits on both sides of a scope boundary, it is split along the boundary rather than either rule being weakened for it.",
                    "boundary": "None of the three mechanisms is an exemption. A resolution where one principle is weakened inside its own scope was not a boundary, an unmeasured operating point is a mood, a discriminator held only in a reviewer's judgment is not yet a rule, and an override that names no scope and no reason is not a resolution at all.",
                    "cause": "A quality treated as a rule has no scope to be given, so a review argues a trade-off as though it were a violation, and a semantic difference treated as a scope has no boundary to draw, so a review draws one anyway and moves it next time.",
                    "decision": "The mechanism the pair's kinds and scopes select is applied, rather than the one the reviewer prefers.",
                    "failureMode": "A team decides that [consistency](/records/architecture/consistency) beats availability, ships a service that refuses every request under partition, and discovers that the decision was never a boundary but an operating point that had never been measured.",
                    "kind": "lesson",
                    "principle": "For this reason scope separation, a measured trade-off and a mitigating rule are the three mechanisms, and which one applies follows from what is on each side and where it holds.",
                    "problem": "One mechanism is applied to every tension, so a trade-off is argued as a violation and a semantic difference is drawn as a boundary that moves every time.",
                    "validation": "To check this, take any resolved tension and ask which mechanism resolved it. If both sides are principles and their scopes differ, the boundary settles it and both sides survive whole. If one side is a quality, or both sides share one scope, ask where the operating point sits and who measured it. If the pair claims a discriminator, ask where it is written."
                  },
                  {
                    "caption": "the recurring pairs",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph scope[\"Scope separation · both hold whole\"]\n        a1[\"stateless\"] -- computation · resource --- a2[\"state before mutation\"]\n        b1[\"immutability\"] -- computed data · resource state --- b2[\"state over code\"]\n        c1[\"fail fast\"] -- resource halts · computation marks --- c2[\"explicit invalidity\"]\n        d1[\"do not build what is not needed\"] -- implementation · interfaces --- d2[\"deliberate under-specification\"]\n        e1[\"single owner\"] -- runtime resources · definitions --- e2[\"code as data\"]\n        g1[\"normalization\"] -- the canonical store · derived read models --- g2[\"query performance\"]\n    end\n    subgraph trade[\"Irreducible trade-off · measured to an operating point\"]\n        i1[\"consistency\"] -- inside a boundary · across autonomy boundaries --- i2[\"availability\"]\n        j1[\"fail fast\"] -- where a halt is cheaper than a wrong answer --- j2[\"graceful degradation\"]\n        k1[\"encapsulation\"] -- hidden internals · a live inspector --- k2[\"debuggability\"]\n        l1[\"backpressure\"] -- bounded producers · sustained rate --- l2[\"throughput\"]\n    end\n    subgraph mitigate[\"Mitigation · a rule names the discriminator\"]\n        m1[\"one source of truth\"] -- semantic sameness · incidental likeness --- m2[\"locality of behavior\"]\n    end"
                  }
                ],
                "title": "Three mechanisms, no exemption"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Scope separation is the mechanism the core layers were built to produce, and its pairs recur because the [computation](/records/layer/computation-core) and [resource](/records/layer/resource-core) scopes answer the same question with different rules. In [statelessness](/records/architecture/statelessness) against snapshot before mutation, a computation flows through and a resource is snapshotted before it changes. In [immutability](/records/architecture/immutability) against protecting state, computed data is frozen after creation and resource state is mutable but managed."
                  },
                  {
                    "kind": "text",
                    "text": "In [fail fast](/records/architecture/fail-fast) against explicit invalidity, a broken resource invariant halts and a computation uncertainty is marked and carried. In not building the hypothetical against under-specifying deliberately, no code is written for a feature that was never requested, and no constraint is placed on an interface that would block one later. Each pair is the derivation at work, two principles on two layers."
                  },
                  {
                    "kind": "text",
                    "text": "The canon holds the same derivation as records where it has been consulted. [Single source of truth](/records/architecture/single-source-of-truth) against [decentralization](/records/architecture/decentralization), and [autonomy](/records/architecture/autonomy) against [standardization](/records/architecture/standardization), separate because each side governs a different layer. [Normalization](/records/architecture/normalization) against [query performance](/records/lexicon/query-performance) is [recorded explicitly](/records/tension/normalization-query-performance), with the [canonical model](/records/architecture/canonical-model) normalized and only derived read models denormalized, never the store. The test of a boundary is that both sides survive it whole."
                  }
                ],
                "title": "Separated by scope"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A trade-off cannot be scoped away, and seeing why is what stops a review from arguing one as if it were a violation. A quality is exhibited on both sides of any boundary you draw. Consistency against [availability](/records/lexicon/availability) is strong inside one [transaction boundary](/records/architecture/transaction-boundary) and [eventual consistency](/records/architecture/eventual-consistency) across autonomy boundaries, and both halves of that sentence are an operating point the developer chose, [not a side that won](/records/tension/availability-consistency). The [CAP theorem](/records/architecture/cap-theorem) is the reason the point exists and never the point itself."
                  },
                  {
                    "kind": "text",
                    "text": "Fail fast against [graceful degradation](/records/architecture/graceful-degradation) shows the other road into a trade-off. Both are principles, but both hold in the one [correctness](/records/architecture/correctness) scope, so there is no side for either to hold whole on. The pair is [decided](/records/tension/fail-fast-graceful-degradation) by where a halt costs less than a wrong answer, which is a measurement of the failure's blast radius and never a principle outranking another."
                  },
                  {
                    "kind": "text",
                    "text": "[Encapsulation](/records/architecture/encapsulation) against [debuggability](/records/lexicon/debuggability) is [settled](/records/tension/debuggability-encapsulation) by hiding internals and shipping a live inspector, a point on a line rather than a wall. [Backpressure](/records/architecture/backpressure) against [throughput](/records/architecture/throughput) is [bounded producers against sustained rate](/records/tension/backpressure-throughput). In each case the mechanism is the same. The quality is named, measured where the construct lives and set at a chosen point, and a record keeps who chose it and against what number."
                  }
                ],
                "title": "Traded at a measured point"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Mitigation is the mechanism for two things in one scope told apart by meaning. [Do not repeat yourself](/records/architecture/duplicate-code) against [locality of behavior](/records/lexicon/locality-of-behavior) is the recurring case. Semantics are centralized, the rules, the schemas and the one place a fact lives, and incidental co-occurrence stays local, because two passages that happen to read alike are not one fact."
                  },
                  {
                    "kind": "text",
                    "text": "No boundary separates them, since both live in the [structural](/records/layer/structural-core) scope, and no measurement decides them, since neither is a quality. What resolves them is a [rule that names the discriminator](/records/tension/do-not-repeat-yourself-dry-locality-of-behavior), which asks whether the sameness is semantic or textual. A discriminator written down is consultable before the collision. One held only in a reviewer's judgment is rediscovered at every clone report."
                  }
                ],
                "title": "Mitigated by a rule"
              }
            ],
            "title": "Separate, trade, or mitigate"
          }
        ]
      },
      {
        "icon": "bi-exclamation-octagon",
        "id": "decay",
        "label": "Decay",
        "sections": [
          {
            "icon": "bi-hourglass-bottom",
            "id": "an-anti-pattern-is-a-decay-path",
            "intro": "This section covers how an anti-pattern forms. A decay starts as a local shortcut that nothing refused, and it becomes dangerous the moment the shortcut becomes infrastructure, as shown in [a decay path] and [the propagation]. The canon carries the class as a [contract of its own](/records/algorithms/architecture-anti-pattern), and every anti-pattern it names is a [kind](/records/kind/anti-pattern) a principle may point at and nothing else may.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, an anti-pattern is named by the control whose absence causes it, and its decay path is recorded as the sequence of stages that produces it, so it can be reproduced rather than argued about. The record also holds how it presents, which principles it violates, which signals detect it, which repairs reverse it and which gate prevents its return.",
                    "boundary": "A decay path is a class, never an incident. The catalog carries the shape, how it starts, how it presents and what was missing, and never which file or which developer, because a class transfers to a tree with nothing else in common and an incident makes the next project inherit another project's history as law.",
                    "cause": "A shortcut is cheap where it is taken and expensive where it is depended on, so blaming the first change finds a small thing, and the control whose absence let it through is invisible because absent things do not appear in reviews.",
                    "decision": "The control is repaired rather than the change that revealed it, because the next change will reveal it again.",
                    "failureMode": "A module gains a second writer, then a third, each with a good reason, and by the time two of them disagree about its state no reviewer can say which change was the wrong one, because none of them was.",
                    "kind": "lesson",
                    "principle": "For this reason an anti-pattern is a reproducible decay path caused by the absence of a specific control.",
                    "problem": "Anti-patterns are usually catalogued by how they look, and how they look is the last stage of a process that started with something missing.",
                    "validation": "To check this, take an anti-pattern you have met and name the control whose presence would have made the first step of its decay path fail. If you cannot name one, you have named the symptom rather than the pattern."
                  },
                  {
                    "caption": "a decay path",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    control[\"A control is absent · boundary, contract, ownership, versioning, observability, state isolation, enforcement\"]\n    step1[\"A local shortcut lands · nothing refuses it\"]\n    step2[\"It is repeated under pressure and becomes convention\"]\n    step3[\"Dependent code forms around it · a boundary or contract erodes\"]\n    presents[\"Systemic fragility · the anti-pattern, reproducible, named, detectable\"]\n    repair[\"The repair · install the inverse control, migrate the dependents, check the absence, gate the recurrence\"]\n    control --> step1 --> step2 --> step3 --> presents --> repair"
                  }
                ],
                "title": "An absent control, a reproducible path"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A decay path is recorded as reproduction rather than description, and the [propagation](/records/algorithms/anti-pattern-propagation-kernel) runs through the same stages every time. A local shortcut lands and nothing refuses it, which is where the missing control is named. The shortcut is repeated under delivery pressure until it is a convention, dependent code forms around it, and the repair is now expensive in proportion to what depends on it."
                  },
                  {
                    "kind": "text",
                    "text": "Recorded that way, the pattern becomes a test. Once the control is installed and the path replayed, the first stage should fail. [Lava flow](/records/architecture/lava-flow) is what a path looks like once it can no longer be replayed, as code kept because no reader knows what depends on it, and [temporal coupling](/records/architecture/temporal-coupling) is a path whose stages are hidden in the order things happen to be called."
                  },
                  {
                    "caption": "the propagation",
                    "kind": "mermaid",
                    "text": "stateDiagram-v2\n    [*] --> Shortcut : a control is absent\n    Shortcut --> Repetition : nothing refuses it\n    Repetition --> Convention : delivery pressure\n    Convention --> Dependency : code forms around it\n    Dependency --> Fragility : the boundary erodes\n    Fragility --> Repair : the pattern is named\n    Repair --> [*] : inverse control installed · dependents migrated · recurrence gated\n    Repair --> Shortcut : one call site removed · the path stays open"
                  }
                ],
                "title": "The path"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The [repair](/records/algorithms/anti-pattern-remediation-algebra) follows the same algebra in reverse. The missing control is named, its inverse is introduced, the dependents are migrated off the shortcut, the old shape is verified absent, and its recurrence is gated."
                  },
                  {
                    "kind": "text",
                    "text": "A repair that removes one call site leaves the propagation path open and the pattern returns somewhere else. [Shotgun surgery](/records/architecture/shotgun-surgery) is the shape of that failed repair, one change spread across many files because the control was never installed, and [divergent change](/records/architecture/divergent-change) is its mirror, one file changed for many reasons because its concern was never split."
                  }
                ],
                "title": "The repair"
              }
            ],
            "title": "An anti-pattern is a decay path"
          },
          {
            "icon": "bi-shield-check",
            "id": "seven-controls-seven-classes",
            "intro": "This section covers the seven controls, each of which owns a decay class, as shown in [seven controls] and typed in [an anti-pattern record]. The seven are a boundary, a contract, an ownership, a [versioning](/records/architecture/versioning), an [observability](/records/architecture/observability), a [state isolation](/records/architecture/state-isolation) and an enforcement, and the [anti-pattern record](/records/algorithms/architecture-anti-pattern) holds as its invariant that every decay path is caused by the absence of one of them. The same idea generalizes past architecture, since a [taxonomy of smells](/records/algorithms/smell-taxonomy) groups any bad practice by the control it lacks rather than by how it looks, and a catalog organized that way answers a question a gallery of symptoms cannot, which is what to install.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every anti-pattern is placed under the one control whose absence lets it start, and the catalog is read as seven classes rather than as a list. When a new pattern appears, the first question is which of the seven was missing, and only then what it looks like, because the answer names the repair.",
                    "boundary": "The seven controls classify absence and never presence. A tree that has all seven is not thereby well designed. It is a tree in which the decay classes have something to refuse them, and what it refuses is still decided by the principles the controls hold.",
                    "cause": "A catalog of symptoms grows without bound and teaches recognition, while a catalog of absent controls stays small and teaches repair, because the number of ways to look wrong is unbounded and the number of things that can be missing is not.",
                    "decision": "A catalog of absences is kept rather than a gallery of symptoms.",
                    "failureMode": "A team keeps a growing list of things that went wrong, each with its own fix, and the next failure fits none of the entries because it was filed by appearance and appears differently this time.",
                    "kind": "lesson",
                    "principle": "For this reason decay is classified by what failed to refuse it, since each decay path starts where one control is absent.",
                    "problem": "A catalog organized by appearance grows without bound and never says what to install.",
                    "validation": "To check this, take any three anti-patterns you know and name the control each lacks. If two of them lack the same control, they are one class with two faces, and one check covers both."
                  },
                  {
                    "caption": "seven controls",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    boundary[\"boundary absent · a foreign model leaks in\"]\n    contract[\"contract absent · a consumer depends on a promise that was never made\"]\n    ownership[\"ownership absent · two writers, the last one wins\"]\n    versioning[\"versioning absent · a breaking change ships as ordinary\"]\n    observability[\"observability absent · the first signal is a customer\"]\n    isolation[\"state isolation absent · a side effect crosses a boundary\"]\n    enforcement[\"enforcement absent · a rule decays at the rate of attention\"]\n    decay[\"One decay class per control · placed by what was missing, never by how it looked\"]\n    boundary --> decay\n    contract --> decay\n    ownership --> decay\n    versioning --> decay\n    observability --> decay\n    isolation --> decay\n    enforcement --> decay"
                  }
                ],
                "title": "Placed by what was missing"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A missing boundary lets a foreign model leak into yours until the two are one tangled model, which shows as [boundary leakage](/records/architecture/boundary-leakage), [framework leakage](/records/architecture/framework-leakage) and the [anemic domain model](/records/architecture/anemic-domain-model) that follows. A missing contract lets a consumer depend on a behavior that was never promised, an [implicit contract](/records/architecture/implicit-contract), so the next change breaks it silently. A missing ownership lets two parties write [shared mutable state](/records/architecture/shared-mutable-state), and the write that lands last wins with no report, which is the [lost update](/records/architecture/lost-update)."
                  },
                  {
                    "kind": "text",
                    "text": "A missing versioning lets an [unversioned breaking change](/records/architecture/unversioned-breaking-change) ship as an ordinary one, and [schema drift](/records/architecture/schema-drift) follows. A missing observability lets a system run with [opaque runtime behavior](/records/architecture/opaque-runtime-behavior), so the first sign of an [unobservable failure](/records/architecture/unobservable-failure) is a customer reporting it. A missing state isolation lets a [hidden side effect](/records/architecture/hidden-side-effect) reach across a boundary it should not see, and [action at a distance](/records/architecture/action-at-a-distance) is its name once the cause can no longer be found. A missing enforcement is [manual-only governance](/records/architecture/manual-only-governance), a rule the whole team agreed to, decaying at the rate of attention."
                  }
                ],
                "title": "The seven, each with its class"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Two questions decide whether a catalog entry is real. Can the path be replayed from its first stage, so that a reader with a different tree reproduces the decay rather than recognizing the picture? And does the entry name what it violates by identity, so that a finding on the [enforcement layer](/records/layer/enforcement-core) resolves to the principle, its severity and the repair in one lookup?"
                  },
                  {
                    "kind": "text",
                    "text": "An anti-pattern held as a [typed relationship record](/records/algorithms/anti-pattern-relationship-record) answers both, and a smell [compiles into a rule](/records/algorithms/anti-pattern-rule-compiler) only once it does. [Pattern cargo cult](/records/architecture/pattern-cargo-cult) and the [golden hammer](/records/architecture/golden-hammer) are what a catalog of appearances produces, which is a shape applied because it was recognized, never because its absent control was named."
                  },
                  {
                    "code": "export const CONTROLS = [\"boundary\", \"contract\", \"ownership\", \"versioning\", \"observability\", \"state-isolation\", \"enforcement\"] as const;\nexport type Control = (typeof CONTROLS)[number];\n\nexport const PROPAGATION = [\"shortcut\", \"repetition\", \"normalization\", \"dependency-formation\", \"institutionalization\", \"high-cost-repair\"] as const;\nexport type Stage = (typeof PROPAGATION)[number];\n\nexport const REMEDIATION = [\"missing-control\", \"inverse-control\", \"migration\", \"absence-check\", \"prevention-gate\"] as const;\nexport type Repair = (typeof REMEDIATION)[number];\n\nexport interface AntiPattern {\n    readonly id: AntiPatternId;\n    readonly absentControl: Control;\n    readonly path: readonly { readonly stage: Stage; readonly change: string }[];\n    readonly presentsAs: string;\n    readonly violates: readonly PrincipleId[];\n    readonly detectedBy: readonly SignalId[];\n    readonly repairs: readonly { readonly step: Repair; readonly action: string }[];\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "an anti-pattern record"
                  }
                ],
                "title": "When an entry is real"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "For a model-authored codebase the decay classes are the same and the rate is different. A model tends to take a shortcut as readily as a developer under a deadline, and it rarely objects to its own, so a system with an absent control decays at the model's speed rather than a team's."
                  },
                  {
                    "kind": "text",
                    "text": "A control that exists only as a reviewer's habit is absent for every change the reviewer did not see. Installing the seven as checks before the model writes anything is what makes them present for every change rather than for the ones a reviewer happened to read."
                  }
                ],
                "title": "The same classes at a model's speed"
              }
            ],
            "title": "Seven controls, seven classes"
          },
          {
            "icon": "bi-toggles",
            "id": "never-and-always",
            "intro": "This section covers why every avoidance rule is written as a pair, as shown in [one inversion]. A rule that only says never leaves an empty action set the moment the forbidden thing is the obvious thing, and an empty action set is how the forbidden thing gets written anyway. The canon holds every inversion as a [contract with an invariant](/records/algorithms-domain/architectural-rules), and the practice for the pairs that recur most is described in [fail at the boundary](/disciplined-methodology/build#fail-at-the-boundary) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the consequences are kept as the rule's reason, so the rule carries its own justification and is never re-argued. A check reports the refused construct where it lands and names the required one as the remediation, and what the replacement supersedes is deleted in the same change, because a marker on the old path keeps two paths alive under one label.",
                    "boundary": "An inversion governs living code on one forward path, meaning anything something else depends on, where a shortcut taken today is read as a decision by the next developer or model to find it. It says nothing about how strict a rule is, and it is not a threshold. A bound lives where the check reads it, and the inversion only says that the bound exists.",
                    "cause": "A prohibition without its replacement names what to avoid and not what to do, so under pressure the avoided thing is the only thing the developer or the model knows how to write.",
                    "decision": "The replacement is written before the prohibition, so the rule is never a bare never.",
                    "failureMode": "A rule says no fallbacks, a value is missing at boot, the author has nowhere to go, and the fallback is written with a comment apologizing for it.",
                    "kind": "lesson",
                    "principle": "For this reason an avoidance rule is an inversion that pairs a refused construct and the debt it borrows against with a required construct and the leverage it buys.",
                    "problem": "Avoidance rules written as a list of don'ts are obeyed until the first moment the don't is convenient.",
                    "validation": "To check this, cover the second half of any rule you hold and ask what you would write instead. If nothing comes, the rule was a prohibition and the debt is already in the tree somewhere."
                  },
                  {
                    "caption": "one inversion",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    refused[\"A construct is refused · with the debt it borrows against\"]\n    required[\"Its replacement is required · with the leverage it buys\"]\n    refused -- one inversion, two consequences --> required\n    check[\"A check reports the refused construct where it lands\"]\n    refused -.-> check\n    remedy[\"The finding names the required construct as its remediation\"]\n    check --> remedy\n    required -.-> remedy"
                  }
                ],
                "title": "Half a rule"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The generalized form is a small derivation, and it can be run on any construct in any tree. It asks what the construct borrows against and from whom, names the construct that would stand in its place, and asks what that one buys."
                  },
                  {
                    "kind": "text",
                    "text": "If the second half comes, the pair is a rule and the consequences are its reason. If it does not, the construct is either not a debt or not yet understood, and either way it is not a rule."
                  }
                ],
                "title": "The derivation"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Only living code on a single forward path survives that reading. A deprecation marker, a tombstone, a compatibility shim and [zombie code](/records/architecture/zombie-code) are each a refused construct whose replacement is deletion in the same edit. [Backward compatibility](/records/architecture/backward-compatibility) is a contract a boundary declares, never a second path kept alive inside one."
                  },
                  {
                    "kind": "text",
                    "text": "An export exists only while another file imports it now, unless it is staged behind a drift check that holds it to that promise. A [utility dump](/records/architecture/utility-dump) and a [repository dump](/records/architecture/repository-dump) are the same debt at the scale of a folder, a home for constructs whose replacement was never named, and so a place where every one of them is kept."
                  }
                ],
                "title": "One forward path"
              }
            ],
            "title": "Never and always"
          },
          {
            "icon": "bi-cash-coin",
            "id": "debt-and-leverage",
            "intro": "This section covers the consequence on each side of an inversion, which lets the rule survive the moment it is inconvenient. The consequences are derived by the two questions shown in [lender and replacement], and they turn the pair into a finding a check can print, in the record typed in [an inversion record].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the refused consequence is derived by asking whom the construct borrows from, whether the next reader, the developer who meets the failure later, or every future change that has to keep two paths alive. The required consequence is derived by asking what holds without attention once the replacement is in place. Both are named, so the rule can be pointed at when it is questioned, and the same two names become the message a check prints and the remediation it proposes.",
                    "boundary": "A consequence names a lender or a purchase and never a severity. How strictly a rule binds is a separate fact held beside it, so two rules with the same consequence can bind differently, and a consequence never argues for its own rule's rank.",
                    "cause": "A rule whose reason is an adjective is re-argued because an adjective cannot be pointed at, while a rule whose reason names a lender ends the argument by naming who pays.",
                    "decision": "Each rule carries its lender and its purchase rather than a verdict about quality.",
                    "failureMode": "A rule is defended as good practice, the defense convinces no reviewer under deadline, and the construct it refused is written because no reviewer could say who would pay for it.",
                    "kind": "lesson",
                    "principle": "For this reason a consequence is a named lender or a named purchase, and a pair with both is already a finding.",
                    "problem": "Rules are justified with adjectives, and an adjective is re-argued every time the rule is inconvenient.",
                    "validation": "To check this, take any rule you hold and name who pays when it is broken and what is bought when it is kept. A rule where either answer is an adjective has no consequence yet, and it will lose the next argument it is in."
                  },
                  {
                    "caption": "lender and replacement",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    construct[\"A construct under review\"]\n    lender{\"Whom does it borrow from?\"}\n    reader[\"the next reader\"]\n    developer[\"the developer, later and elsewhere\"]\n    change[\"every future change\"]\n    nobody[\"no lender · it is not a debt\"]\n    replacement[\"What stands in its place, and what does that buy?\"]\n    rule[\"A rule · two constructs, two consequences\"]\n    construct --> lender\n    lender --> reader --> replacement\n    lender --> developer --> replacement\n    lender --> change --> replacement\n    lender --> nobody\n    replacement --> rule"
                  }
                ],
                "title": "A lender and a purchase"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The same question derives the refused consequence every time, which is whom the construct borrows from. A shortcut borrows from the next reader. A [fallback pattern](/records/algorithms/no-fallback) borrows from the developer, because it converts a loud failure into a quiet wrong answer that surfaces later and elsewhere. A [deprecation](/records/algorithms/no-deprecation) borrows from every future change, because it keeps two paths alive so the choice can be put off."
                  },
                  {
                    "kind": "text",
                    "text": "A [second path](/records/algorithms/no-dual-path) borrows from every reader, who now has to decide which one is real. Deferring borrows from the developer who will not remember. [Shared mutable state](/records/algorithms/no-shared-ownership) borrows from the developer who has to find out which writer won, and [silent data corruption](/records/architecture/silent-data-corruption) from the developer who meets the failure it hid."
                  }
                ],
                "title": "The lender"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The required consequence names what the replacement buys, and the purchase is what makes the rule worth keeping. A [constraint](/records/algorithms/no-shortcuts) is leverage because it holds without attention. [Fail fast](/records/architecture/fail-fast) is clarity, because the failure lands where its cause is. Explicit removal is coherence, because a removed path cannot be taken."
                  },
                  {
                    "kind": "text",
                    "text": "A single path is [determinism](/records/architecture/determinism). A single owner is [auditability](/records/architecture/auditability). A bounded lifetime is deterministic release. [An emitted event](/records/algorithms/no-callbacks) is [loose coupling](/records/architecture/low-coupling), and [policy as code](/records/algorithms/no-convention-enforcement) is an automated gate. Because each consequence is named this way, the same record serves the developer reading the rule and the check enforcing it, and the two never drift apart."
                  },
                  {
                    "code": "export interface Inversion {\n    readonly refused: { readonly construct: Construct; readonly borrowsAgainst: Consequence };\n    readonly required: { readonly construct: Construct; readonly buys: Consequence };\n}\n\nexport const inversionOf = (refused: Construct, required: Construct, debt: Consequence, leverage: Consequence): Inversion => ({\n    refused: { borrowsAgainst: debt, construct: refused },\n    required: { buys: leverage, construct: required },\n});\n\nexport const asFinding = (rule: Inversion, at: Location): Finding => ({\n    at,\n    reported: rule.refused.construct,\n    remediation: rule.required.construct,\n    reason: rule.refused.borrowsAgainst,\n});",
                    "kind": "code",
                    "language": "typescript",
                    "title": "an inversion record"
                  }
                ],
                "title": "The purchase"
              }
            ],
            "title": "Debt and leverage"
          }
        ]
      },
      {
        "icon": "bi-grid-3x3",
        "id": "coverage",
        "label": "Coverage",
        "sections": [
          {
            "icon": "bi-check2-square",
            "id": "an-architecture-is-its-predicate-set",
            "intro": "This section covers how an architectural intent becomes a predicate a check can run. The reasoning axis of the ontology turns a question into a type and a type into a predicate, as shown in [intent to predicate], and the same axis is walked on a request in [resolving a message](/disciplined-methodology#resolving-a-message) on the methodology page. How much of a design is real depends on who writes the code, as shown in [what is real].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every architectural intent is stated as a question about [what can drift, seen through how it drifts](/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts), and the question is resolved to a type. What exists is a set, how parts are arranged is an ordering, what connects is a graph, and how sure you are is a number. The predicate is derived from the type and run over the tree as a check.",
                    "boundary": "[Determinism](/records/architecture/determinism) lives in the predicate and never in the judgment that authored it. Which cells are worth watching is a decision, while whether a cell's predicate holds is a computation. The decision stays with the developer and the computation with the check, and a predicate never encodes taste.",
                    "cause": "An intention has no objector, so its first violation is silent, and a system whose rules are silent is governed by attention rather than by structure.",
                    "decision": "The architecture is counted by what the gate refuses rather than by what the document states.",
                    "failureMode": "A design document states twelve principles, the codebase honors four, and no reviewer can say which four without reading everything, because the other eight were never anything a check could evaluate.",
                    "kind": "lesson",
                    "principle": "For this reason an architecture is its predicate set, and a predicate selects what to examine and marks when the concern is closed.",
                    "problem": "Architecture is usually a set of intentions, and an intention cannot be evaluated, so neither the developer nor the model can say how much of the architecture is real.",
                    "validation": "To check this, list the architectural claims your system makes. Beside each, name the predicate that decides it and where that predicate runs. A claim with no predicate beside it is a sentence in a document, and the document is the only place it holds."
                  },
                  {
                    "caption": "intent to predicate",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    intent[\"An architectural intent · a sentence about how the system should be\"]\n    question[\"A question · what can drift, seen through how it drifts\"]\n    type[\"A mathematical type · a set, an ordering, a graph, a number\"]\n    predicate[\"A predicate · computable over the tree\"]\n    selects[\"Selects what to examine next\"]\n    closes[\"Marks when the concern is closed\"]\n    habit[\"A habit · held while the developer remembers\"]\n    intent --> question --> type --> predicate\n    predicate --> selects\n    predicate --> closes\n    intent -. without the walk .-> habit"
                  }
                ],
                "title": "Question, type, predicate"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The double duty is what makes derivation possible. The predicate that says an export is unreachable is the same predicate that says reachability is covered, so one reading tells you where to work and the other tells you the dimension is watched. A project that has the first without the second accumulates checks by incident, and one that has both can derive its checks from its invariants."
                  },
                  {
                    "kind": "text",
                    "text": "[Policy as code](/records/architecture/policy-as-code) is the canon's name for the whole move, and [fitness functions](/records/architecture/fitness-functions) are the same predicates run against an architecture rather than a request. [Static analysis](/records/architecture/static-analysis) is where most predicates live, because a shape in a tree can be decided without running anything, and [design by contract](/records/architecture/design-by-contract) is the same idea one level down, with preconditions, postconditions and invariants that a check can evaluate rather than a comment can promise."
                  },
                  {
                    "caption": "what is real",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    design[\"A design\"]\n    intentions[\"Its intentions · what the author meant\"]\n    predicates[\"Its predicate set · what a check can decide\"]\n    author{\"Who writes the code?\"}\n    person[\"The developer · intentions survive by attention, for a while\"]\n    model[\"A model · every intention with no predicate is absent\"]\n    real[\"The architecture that is real · the predicate set\"]\n    design --> intentions\n    design --> predicates\n    intentions --> author\n    author -- developer --> person\n    author -- model --> model\n    predicates --> real\n    model -. only this survives .-> real"
                  }
                ],
                "title": "A predicate does two jobs"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The coverage question is then answered from the grid described in what can drift, seen through how it drifts, rather than from a count of rules. [Security theater](/records/architecture/security-theater) is what a count produces, with the presence of controls standing in for their coverage. A predicate set answers the other question, which cells have something that can disagree with them, and that is the only sense in which an architecture is enforced."
                  }
                ],
                "title": "Coverage from the grid, never from a count"
              }
            ],
            "title": "From intent to predicate"
          },
          {
            "icon": "bi-grid",
            "id": "what-can-drift-seen-through-how-it-drifts",
            "intro": "This section covers the coverage grid and its two closed axes. The [dimensions](/ontology/reasoning#the-dimensions) are what can drift and the [lenses](/ontology/reasoning#the-lenses) are how it drifts, and a cell is one invariant that must hold, watched by a predicate or declared unwatched with its reason, as shown in [two axes, one cell] and [a corner] and typed in [a rule surface]. Because both axes are closed, the cells are enumerable, so the cells nothing watches are enumerable too, and a rule set is measured against the grid rather than against the incidents that happened to produce it.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the dimensions along which the system can drift and the lenses through which each drift is seen are named as two lists. Every existing check is placed in the cell it watches, one invariant per cell, and an empty cell is read as a drift class nothing watches.",
                    "boundary": "The grid enumerates where drift can be watched and says nothing about which cells deserve a rule. A full grid is not the goal. The goal is a grid whose every cell is watched, unwatched with a stated reason, or marked undecided, and the undecided cells carry the design decisions still to make.",
                    "cause": "Without closed axes there is nothing to divide by, so coverage is reported as a count that grows with every incident and never says what is missing.",
                    "decision": "The axes are closed before anything is counted, so the count has a denominator.",
                    "failureMode": "A suite reports hundreds of passing tests, the surface that fails in production was one none of them reached, and the green run was evidence over the wrong set.",
                    "kind": "lesson",
                    "principle": "For this reason coverage is a grid of what can drift against how it drifts, and an unmeasured cell is unknown rather than clean.",
                    "problem": "A rule set with no denominator reports how many checks exist, which says nothing about how many drift classes have none.",
                    "validation": "To check this, take the checks you have and place each in its cell, then count the empty cells. If you cannot place a check, its invariant was never stated, and if you cannot count the empties, the axes were never closed."
                  },
                  {
                    "caption": "two axes, one cell",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subgraph dimensions[\"What can drift\"]\n        identity[\"identity\"]\n        relation[\"relation\"]\n        change[\"change\"]\n        meaning[\"meaning\"]\n    end\n    subgraph lenses[\"How it drifts\"]\n        structural[\"structurally\"]\n        relational[\"relationally\"]\n        sequential[\"sequentially\"]\n        semantic[\"semantically\"]\n    end\n    cell[\"A cell · one invariant, watched, unwatched with a reason, or undecided\"]\n    identity --> cell\n    relation --> cell\n    change --> cell\n    meaning --> cell\n    structural --> cell\n    relational --> cell\n    sequential --> cell\n    semantic --> cell"
                  }
                ],
                "title": "Two closed axes"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A module reaching across a boundary is relation seen relationally, and a [circular dependency](/records/architecture/circular-dependency) is relation seen structurally. Two files claiming one role is identity seen structurally. A manifest entry rotting is composition seen through evolution. A discriminated union gaining a case nothing handles is change seen sequentially. A registry written and never read is function seen functionally. Intent living in a comment is meaning seen semantically. The same defect at every scale is scale seen fractally, and a convention followed everywhere except here is novelty seen as anomaly."
                  },
                  {
                    "caption": "a corner",
                    "kind": "mermaid",
                    "text": "block-beta\n    columns 5\n    corner[\" \"] structural[\"structural\"] relational[\"relational\"] sequential[\"sequential\"] semantic[\"semantic\"]\n    identity[\"identity\"] i1[\"watched\"] i2[\"unwatched · declared\"] i3[\"undecided\"] i4[\"watched\"]\n    relation[\"relation\"] r1[\"watched\"] r2[\"watched\"] r3[\"undecided\"] r4[\"unwatched · declared\"]\n    change[\"change\"] c1[\"undecided\"] c2[\"watched\"] c3[\"watched\"] c4[\"undecided\"]\n    meaning[\"meaning\"] m1[\"unwatched · declared\"] m2[\"undecided\"] m3[\"watched\"] m4[\"watched\"]"
                  },
                  {
                    "code": "export const DIMENSIONS = [\"identity\", \"composition\", \"structure\", \"relation\", \"space\", \"time\", \"state\", \"change\", \"behavior\", \"function\", \"cause\", \"meaning\", \"scale\", \"probability\", \"novelty\"] as const;\nexport const LENSES = [\"structural\", \"temporal\", \"spatial\", \"statistical\", \"frequency\", \"sequential\", \"relational\", \"behavioral\", \"functional\", \"semantic\", \"causal\", \"predictive\", \"anomaly\", \"evolutionary\", \"fractal\", \"transformational\", \"invariant\", \"optimization\", \"complexity\"] as const;\n\nexport type Dimension = (typeof DIMENSIONS)[number];\nexport type Lens = (typeof LENSES)[number];\n\nexport type Cell =\n    | { readonly kind: \"watched\"; readonly invariant: string; readonly predicate: GateId }\n    | { readonly kind: \"unwatched\"; readonly invariant: string; readonly because: string }\n    | { readonly kind: \"undecided\"; readonly question: string };\n\nexport type CellKey = readonly [Dimension, Lens];\nexport type RuleSurface = ReadonlyMap<CellKey, Cell | null>;\n\nexport const emptyCells = (surface: RuleSurface): readonly CellKey[] =>\n    [...surface.entries()].flatMap(([cell, held]) => (held === null ? [cell] : []));",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a rule surface"
                  }
                ],
                "title": "The axes, and a cell read off them"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The same grid projected onto [correctness](/records/architecture/correctness) is the [test-surface catalog](/ontology/reasoning#the-test-surfaces). Every surface a unit can fail in names its failure modes, its technique, its predicate and its evidence source, and its verdict domain carries unknown as a value distinct from pass. [Property-based testing](/records/architecture/property-based-testing) and [specification-based testing](/records/architecture/specification-based-testing) are techniques a surface names, and [chaos engineering](/records/architecture/chaos-engineering) is the technique for the surfaces only a running system can fail in."
                  },
                  {
                    "kind": "text",
                    "text": "An unmeasured surface is unknown rather than clean, as described in [unknown is not pass](/disciplined-methodology/verify#unknown-is-not-pass) and recorded in [the evidence verdict](/records/algorithms/evidence-verdict). [Test pyramid inversion](/records/architecture/test-pyramid-inversion) and the [mock mirage](/records/architecture/mock-mirage) are the two ways a green run stops being evidence, and [completion](/records/algorithms/coverage-completion) is the absence of required surfaces still unknown, never a percentage, because a percentage averages the surfaces that matter with the ones that cannot fail."
                  }
                ],
                "title": "Projected onto correctness"
              }
            ],
            "title": "What can drift, seen through how it drifts"
          },
          {
            "icon": "bi-question-square",
            "id": "a-cell-that-resists-an-invariant",
            "intro": "This section covers the walk over the grid that plans coverage, shown in [the walk], and the step in it where a cell resists an invariant.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the grid is walked with the checks that exist, and every empty cell is treated as a question rather than a gap. Where the invariant states itself, the predicate is authored. The unwatched cells are recorded with their reasons, so the unassessed set stays countable and a later reader can tell a decision from an oversight.",
                    "boundary": "A cell whose predicate nothing could ever disagree with is not authored. It is held with the forgone property written down, for the reason described in [the check comes first](/disciplined-methodology/build#the-check-comes-first) on the methodology page.",
                    "cause": "A rule set built by incident has a shape decided by which incidents happened, and the drift classes that never produced an incident are exactly the ones with nothing watching them.",
                    "decision": "Authoring stops when a cell resists, and the design is decided before the check, because the cell is saying the convention it would enforce was never chosen.",
                    "failureMode": "A team adds a check after every outage, the check count grows, and the failure that ships next lives in a cell the outages never happened to touch.",
                    "kind": "lesson",
                    "principle": "For this reason a cell that resists an invariant is an undecided intent rather than a missing rule.",
                    "problem": "Checks accumulate by incident, so the covered cells are the ones that already failed and the uncovered ones are the ones that will.",
                    "validation": "To check this, find an empty cell and try to state its invariant in one sentence that could be false. If the sentence comes, you were missing a check. If it does not, you are missing a decision, and no check can be written until it is made."
                  },
                  {
                    "caption": "the walk",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    enumerate[\"Enumerate the checks that exist\"]\n    map[\"Map each to its cell · dimension by lens\"]\n    walk[\"Walk the grid\"]\n    empty{\"Empty cell?\"}\n    name[\"Name the invariant that should hold there\"]\n    decide{\"Can the invariant be stated?\"}\n    author[\"Author the predicate, or record the cell as deliberately unwatched\"]\n    undecided[\"An undecided intent · the finding is the design, never the rule\"]\n    enumerate --> map --> walk --> empty\n    empty -- yes --> name --> decide\n    decide -- yes --> author\n    decide -- no --> undecided"
                  }
                ],
                "title": "Walk the grid"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Two invariants keep this a method rather than a rule pile. The first is that no rule exists without a consuming failure mode. A rule earns its place only if a real drift class fires it, because a rule nothing can violate is ceremony, and ceremony costs the same review attention as a real rule, which is how a rule set stops being read."
                  },
                  {
                    "kind": "text",
                    "text": "The second is that the rule set is derived while the judgment that authored it is not. Which cells need watching is a deterministic function of the architecture's declared invariants, whether an invariant was worth declaring is a decision, and the [determinism](/records/architecture/determinism) stays in the predicate rather than in the deciding."
                  }
                ],
                "title": "Two invariants of the walk"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The [walk itself](/records/algorithms/surface-grid-walk) and the [gap it derives](/records/algorithms/uncovered-gap-derivation) are records in the canon, and the cells the canon has not yet covered are [listed rather than assumed away](/ontology/reasoning#the-uncovered-cells)."
                  },
                  {
                    "kind": "text",
                    "text": "[Gap analysis](/records/architecture/gap-analysis) is the activity, and a resisting cell is its most useful output. A cell whose invariant states itself was a missing rule. A cell whose invariant will not state itself is an [architecture review](/records/architecture/architecture-review) waiting to happen, and an [architecture decision record](/records/architecture/architecture-decision-records) is where its answer lands, so the next walk finds a decision rather than the same empty cell."
                  }
                ],
                "title": "The walk in the canon"
              }
            ],
            "title": "A cell that resists an invariant"
          },
          {
            "icon": "bi-eye-slash",
            "id": "the-honest-gaps",
            "intro": "This section covers how a rule reports what it finds and how a method declares what it lacks. Every cell that earns a rule renders two ways from one entry, a detect half and a report half, as typed in [a rule entry]. Every predicate the method calls for is either running in the tree or declared absent in the one document that binds the method to the tree, as shown in [running or absent]. A method that cannot say which of its own predicates are missing has not measured itself, and a document that describes an upgrade the tree never made is the [schema drift](/records/architecture/schema-drift) described in [a system is a graph](/software-architecture#a-system-is-a-graph).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each rule is authored as one entry with a detect half and a report half, discovered by shape and consumed whole by the gate. One document names every predicate the method calls for and states, for each, whether the tree runs it.",
                    "boundary": "A declared gap is not a license. Naming a predicate as absent keeps the document honest and leaves the drift class unwatched, so an absent predicate is still a cell to decide, and the declaration only says that the decision has not been made yet.",
                    "cause": "A blocking message names a rule without its reason, so the same violation returns from the next author, and a document that only describes the ideal cannot be checked against the tree, so its gaps are found by failure rather than by reading.",
                    "decision": "The report half is written beside the detect half rather than a blocking message alone, and an absence is named in the binding document rather than left to be assumed.",
                    "failureMode": "A check refuses a change with a message that names a rule id, the author works around the id, and the document that describes the method lists a predicate that has never run anywhere.",
                    "kind": "lesson",
                    "principle": "For this reason a finding carries its own cause and repair, and a missing check is declared where the method is bound to the project.",
                    "problem": "Checks that only block teach nothing, and methods that only describe cannot say which of their own predicates exist.",
                    "validation": "To check this, take any finding your gate prints and ask whether it names the invariant and the remediation. Then take the document that describes your method and ask, for each predicate it calls for, whether the tree runs it. A finding that names only a rule, or a predicate that cannot be located, is the gap."
                  },
                  {
                    "caption": "running or absent",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    called[\"A predicate the method calls for\"]\n    exists{\"Does the tree run it?\"}\n    runs[\"Declared present · it runs in the chain\"]\n    absent[\"Declared absent · named in the one document that binds method to tree\"]\n    assumed[\"Assumed · the document describes an upgrade the tree never made\"]\n    called --> exists\n    exists -- yes --> runs\n    exists -- no --> absent\n    exists -. neither written down .-> assumed"
                  }
                ],
                "title": "Detect, report, declare"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The detect half is the predicate that fires on the violating shape. The report half is the message that names the invariant and the remediation, so the failure teaches the convention rather than only blocking. [Auto-remediation](/records/architecture/auto-remediation) follows where the remediation has [one correct answer](/disciplined-methodology/verify#one-correct-answer), and where it does not the report still carries the handle a reasoning agent needs."
                  },
                  {
                    "kind": "text",
                    "text": "Enforcement then follows the [registry pattern](/records/architecture/registry-pattern), with one entry per rule discovered by shape through [auto-discovery](/records/architecture/runtime-discovery) and consumed by the gate, and the whole set failing the build on drift. Where a project already has a registry primitive for code, enforcement reuses it rather than inventing a second one."
                  },
                  {
                    "code": "export interface Rule<Shape> {\n    readonly cell: CellKey;\n    readonly detect: (tree: Tree) => readonly Shape[];\n    readonly report: (found: Shape) => { readonly invariant: string; readonly remediation: string };\n}\n\nexport interface Declared {\n    readonly predicate: string;\n    readonly status: \"runs\" | \"absent\";\n    readonly because: string | null;\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a rule entry"
                  }
                ],
                "title": "One entry, two halves"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The walk is also how the gaps are named. A predicate the method calls for and the tree does not have is declared absent, in the one document that binds the method to the tree, rather than assumed. The epistemic and structural predicates normally exist and run, deciding whether something is reachable, consumed, grounded, drifting or covered."
                  },
                  {
                    "kind": "text",
                    "text": "The conative ones are the usual gap, such as a computed worth over branches, a detector for a run that stops making progress, and a calibrated confidence rather than a threshold. The methodology page keeps its own list under the same title, [the honest gaps](/disciplined-methodology/ship#the-honest-gaps), and the two lists are one declaration read from two sides."
                  }
                ],
                "title": "Declared absent, never assumed"
              }
            ],
            "title": "The honest gaps"
          }
        ]
      },
      {
        "icon": "bi-arrows-angle-expand",
        "id": "scale",
        "label": "Scale",
        "sections": [
          {
            "icon": "bi-bezier2",
            "id": "a-concern-is-a-component",
            "intro": "This section covers how work is partitioned into concerns and how many parties it needs. The partition is derived rather than drawn, as shown in [floor and ceiling], one body of work is walked in [three components], and the records the derivation reads are typed in [the derivation's records]. The practice for a body of work is described in [scale follows from structure](/disciplined-methodology/ship#scale-follows-from-structure) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the surfaces a body of work touches are enumerated, and the pairs that force each other are recorded with evidence, where a change to one cannot land without a change to the other. The connected components of that relation are the concerns, each gets one owner, and the number of components is the floor. The fan-in on each [shared surface](/pag/orchestration#shared-surfaces) is measured from the claims already recorded against it, and the worst fan-in sets the ceiling. A count is chosen inside that range, and the partition is written down beside the choice.",
                    "boundary": "The relation is chosen once, and that choice is the one place judgment enters. Two defensible readings of what forces what yield component counts far apart, so the claim is a derivation with a choice at the bottom. The choice is answerable to evidence, and where no mechanism yet computes the partition or the fan-in, that absence is written down as debt with its operands rather than left to read as a measurement.",
                    "cause": "A concern drawn as an area of a task list follows how the list was written, and a list is written by one developer on one day, so its areas cut across the couplings that actually force changes.",
                    "decision": "The work is cut along what forces what rather than along what the work list happened to group.",
                    "failureMode": "Two seats each own half of one coupled pair of surfaces, every change one makes forces a change in the other's, and the surface between them fills with items about the same edit from both sides.",
                    "kind": "lesson",
                    "principle": "For this reason a concern is bounded by coupling rather than by topic, so every edit that forces another stays inside one owner.",
                    "problem": "Concerns are drawn as areas of a work list, so a seat owns a region rather than a component, and every coupled edit crosses two seats.",
                    "validation": "To check this, take any two concerns and find one change that forces edits in both. If one exists, the partition put a forcing edge across a boundary, and the two concerns are one component."
                  },
                  {
                    "caption": "floor and ceiling",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    surfaces[\"The surfaces a body of work touches\"]\n    relation[\"Join two surfaces when a change to one forces a change to the other\"]\n    components[\"The connected components · one per concern\"]\n    floor[\"Floor · the number of components\"]\n    fanin[\"Fan-in · how many parties' claims rest on one surface, measured from traffic\"]\n    ceiling[\"Ceiling · where claims on one surface stop surviving composition\"]\n    count[\"A count inside the range · with the partition written down\"]\n    surfaces --> relation --> components --> floor --> count\n    surfaces --> fanin --> ceiling --> count\n    choice[\"The one choice · which reading of forces\"]\n    choice -. answerable to evidence, never taste .-> relation"
                  }
                ],
                "title": "Partition, floor, ceiling"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A concern is a [bounded context](/records/architecture/bounded-context) drawn for people rather than for models, and [context mapping](/records/architecture/context-mapping) is the activity that draws it. A concern is a component of the forcing relation for the same reason a bounded context is a region of one model, because inside it one party can be authoritative, and across its edge two parties have to be able to disagree. [Separation of concerns](/records/architecture/separation-of-concerns) at the scale of seats is the same principle as at the scale of files, and it is derived the same way, from what forces what."
                  },
                  {
                    "kind": "text",
                    "text": "Volume is the wrong operand for the floor. Quantity divides across parties and argues for a longer schedule, never a wider one. What forces a second party is indivisibility, a concern that has to be able to contradict another while both stay authoritative, and the floor counts those. [Partitioning](/records/architecture/partitioning) by volume is [horizontal scaling](/records/architecture/horizontal-scaling) of people, and it buys [throughput](/records/architecture/throughput) where the concerns are already separate and nothing where they are not."
                  },
                  {
                    "caption": "three components",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subgraph one[\"concern · one seat\"]\n        schema[\"schema\"] --- loader[\"loader\"]\n        loader --- validator[\"validator\"]\n    end\n    subgraph two[\"concern · one seat\"]\n        view[\"view\"] --- renderer[\"renderer\"]\n        renderer --- styles[\"styles\"]\n    end\n    subgraph three[\"concern · one seat\"]\n        pipeline[\"pipeline\"] --- reporter[\"reporter\"]\n    end\n    shared[\"shared surface · fan-in from every seat\"]\n    validator -.-> shared\n    renderer -.-> shared\n    reporter -.-> shared"
                  },
                  {
                    "code": "export interface Forces {\n    readonly from: SurfaceId;\n    readonly to: SurfaceId;\n    readonly evidence: string;\n}\n\nexport interface Concern {\n    readonly id: ConcernId;\n    readonly surfaces: readonly SurfaceId[];\n    readonly owner: SeatId | null;\n}\n\nexport interface Claim {\n    readonly author: SeatId;\n    readonly cites: readonly SurfaceId[];\n    readonly observedAt: Ordinal;\n}\n\nexport interface Bounds {\n    readonly floor: number;\n    readonly ceiling: number;\n    readonly partition: readonly Concern[];\n    readonly derivedBy: \"mechanism\" | \"declared-unbuilt\";\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the derivation's records"
                  }
                ],
                "title": "A concern is a bounded context for people"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The ceiling is set by fan-in rather than by the count, because a surface with one writer cannot have its volatility raised by adding a party, and staleness rises only where parties converge on one subject. Ownership bounds fan-in without defining it, since a formally owned surface that many parties reason about behaves like [shared mutable state](/records/architecture/shared-mutable-state), and the concentration is continuous."
                  },
                  {
                    "kind": "text",
                    "text": "For this reason the ceiling is measured and never declared. A count chosen because it felt right is a bound nothing can disagree with, and so it bounds nothing. Fan-in read from the claims already recorded against each surface is a number a second reader can recompute, and the ceiling follows from the worst of them."
                  }
                ],
                "title": "Fan-in, measured"
              }
            ],
            "title": "A concern is a component"
          },
          {
            "icon": "bi-speedometer2",
            "id": "the-ceiling-moves-by-cost",
            "intro": "This section covers how the ceiling on parties moves. A reader who takes the bound as fixed reaches for the wrong lever, and the expensive one, because the rate at which a claim goes stale has one writer while its cost has every reader, as shown in [rate and cost] and plotted in [the two terms].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the two terms are separated before the headcount is touched. The rate is left alone, because one writer and one composer set it and no number of readers changes it. The cost is attacked instead, by marking every claim with the state of the surface it rested on when it was written, so a claim whose surface has since moved costs its readers a glance where an unmarked one costs every party a read and a reply. The fan-in is measured again after the marker is in place, and the ceiling rises only by what the measurement shows.",
                    "boundary": "Two limits apply. Added parties never answer a claim that something is absent, because they produce agreement rather than coverage, and only a refusal that publishes its criterion turns an unanswerable absence into an ordinary read. The bound also does not move where the cost of a stale claim is dominated by the work already built on it, because no marker makes that work cheaper to redo.",
                    "cause": "Staleness looks like a rate problem because it is felt as a rate, but the rate has one writer, and what actually grows with the population is how many parties pay for each stale claim.",
                    "decision": "The ceiling is raised by cutting what a stale claim costs, never by cutting who reads it.",
                    "failureMode": "A team that keeps tripping over stale claims removes a seat, the remaining seats trip at the same rate, and the work that seat owned now has no owner.",
                    "kind": "lesson",
                    "principle": "For this reason the ceiling on fan-in moves with the cost of a stale claim, not with the rate at which claims go stale.",
                    "problem": "The bound on parties is read as fixed, so the only lever a team reaches for is fewer parties.",
                    "validation": "To check this, take any stale claim and count who read it and who answered it. If the count is the population, the cost is the term to attack, and if the claim went stale faster than one writer could produce it, you have found a second writer."
                  },
                  {
                    "caption": "rate and cost",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    rate[\"The rate a claim goes stale · set by one writer and one composer\"]\n    cost[\"The cost of a stale claim · multiplied by every reader\"]\n    marker[\"A claim marked with the surface state it rested on\"]\n    glance[\"A glance instead of an argument\"]\n    ceiling[\"The ceiling rises\"]\n    rate -. unchanged by headcount .-> ceiling\n    cost --> marker --> glance --> ceiling"
                  }
                ],
                "title": "The cost, not the rate"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A mechanism that records when a claim's cited surface was observed reduces no staleness, only what staleness costs, so it raises the ceiling without touching the partition."
                  },
                  {
                    "kind": "text",
                    "text": "The marker is a [correlation id](/records/architecture/correlation-id) for reasoning, because it joins a claim to the state it was made against, the way a correlation id joins a log line to the request that produced it. [Causal consistency](/records/architecture/causal-consistency) is the property it buys, since a reader can tell whether a claim happened before or after the surface it rests on moved, without a clock and without asking."
                  },
                  {
                    "caption": "the two terms",
                    "kind": "mermaid",
                    "text": "xychart-beta\n    title \"A stale claim: the rate has one writer, the cost has every reader\"\n    x-axis \"parties\" [1, 2, 3, 4, 5, 6, 7, 8]\n    y-axis \"cost of one stale claim\" 0 --> 16\n    line \"unmarked claim · argued by every reader\" [1, 2, 4, 6, 8, 10, 12, 14]\n    line \"marked claim · a glance per reader\" [1, 1, 2, 2, 3, 3, 4, 4]\n    line \"rate of going stale · one writer\" [1, 1, 1, 1, 1, 1, 1, 1]"
                  }
                ],
                "title": "The marker"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The lever changes one thing. The partition stays what the forcing relation derived, the seats stay what the floor demanded, and what changes is how expensive it is for the parties to be wrong about each other for a moment."
                  },
                  {
                    "kind": "text",
                    "text": "[Eventual consistency](/records/architecture/eventual-consistency) between parties is the state the marker makes affordable. Each party holds a view that may lag, and the lag is visible rather than argued. Consensus is the expensive alternative, every party agreeing before any proceeds, and it is the right mechanism only where a stale claim costs more than a halt."
                  }
                ],
                "title": "What the lever leaves alone"
              }
            ],
            "title": "The ceiling moves by cost"
          },
          {
            "icon": "bi-diagram-2",
            "id": "above-one-tier-reduction",
            "intro": "This section covers what happens above one tier, where a flat surface becomes the accumulation and the shape that survives is a tree, as shown in [reduction].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the surfaces are arranged as a tree once one tier is not enough. A parent hands scope down and publishes only the fused result of its children upward, and every record keeps its one writer at every depth, so identity and reduction hold unchanged whether the tree is two levels or ten. Each reduction is derivable and checkable, so a fusion that silently drops a live item fails exactly as a dropped record does. Where the reduction step is unbuilt, it is declared so, rather than letting a design read as if it had been measured at a headcount it never reached.",
                    "boundary": "Reduction changes what is published upward and never who may write. A parent that rewrites a child's record has taken a second writer's seat, and a child that reads the global view has bypassed the bound that made its reading finite. The tree holds only while both stay on their side.",
                    "cause": "Fan-in without reduction passes every record to every reader, so the volume a party has to read grows with the population, and that growth is the accumulation [the developer and the model](/disciplined-methodology/collaborate#the-developer-and-the-model) then try to drain by care.",
                    "decision": "Each tier answers for a derived summary rather than relaying what its members wrote.",
                    "failureMode": "An orchestrator forwards its workers' raw records upward, the composer reads everything every worker wrote, and the surface that was supposed to bound reading has become the unbounded thing it replaced.",
                    "kind": "lesson",
                    "principle": "For this reason, above one tier, scale is reduction, with fused results going up, scope coming down, and every record keeping one writer.",
                    "problem": "Flat fan-in grows without bound, and the growth is read as a discipline problem when it is the structure doing exactly what it was built to do.",
                    "validation": "To check this, take any surface above the first tier and ask what it publishes upward. If it forwards raw records, it is accumulating by construction, and no drain rule will keep up with it."
                  },
                  {
                    "caption": "reduction",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    w1[\"worker\"] --> o1[\"orchestrator · publishes the fused result of its workers\"]\n    w2[\"worker\"] --> o1\n    w3[\"worker\"] --> o2[\"orchestrator\"]\n    w4[\"worker\"] --> o2\n    o1 --> composer[\"composer · one writer, one reduction\"]\n    o2 --> composer\n    raw[\"Raw records passed upward · fan-in without reduction, accumulation by construction\"]\n    o1 -. never .-> raw"
                  }
                ],
                "title": "Fused results up, scope down"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Reduction is [fan-out/fan-in](/records/architecture/fan-out-fan-in) with the fan-in half taken seriously. Fan-out is cheap, because scope handed down divides. Fan-in is where every distributed design pays, because results handed up add, and the only way to keep the sum bounded is to reduce at each tier. [Orchestration](/records/architecture/orchestration) is the shape of one tier, a coordinating owner that hands scope down and publishes one fused result up, and [choreography](/records/architecture/choreography) is the shape between peers who share no parent."
                  },
                  {
                    "kind": "text",
                    "text": "Branching is fractal, running from workers into an orchestrator, into another orchestrator and into a composer. Every record keeps its one writer, and a reduced tier is published by one writer, so identity and reduction hold unchanged at any depth. A [message chain](/records/architecture/message-chain), one party relaying another's raw record to a third, is the anti-pattern that appears the moment a tier forwards rather than reduces."
                  }
                ],
                "title": "Fan-in taken seriously"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A reduction is derived and checkable, and a fusion that silently drops one live item beneath it fails exactly as a dropped record does. [Missing backpressure](/records/architecture/missing-backpressure) is the same defect at a queue, where a tier that accepts more than it reduces accumulates, and the accumulation is the design working as built."
                  },
                  {
                    "kind": "text",
                    "text": "The reduction step itself is declared unbuilt and unmeasured at any headcount, and saying so is what stops the design reading as though it had been measured. A design that claims [scalability](/records/architecture/scalability) it has not measured makes, in prose, the unevidenced claim the coverage tab refuses."
                  }
                ],
                "title": "Checkable, and honestly unmeasured"
              }
            ],
            "title": "Above one tier, reduction"
          },
          {
            "icon": "bi-robot",
            "id": "the-author-is-probabilistic",
            "intro": "This section covers what architecture means when a model writes the code, as shown in [three authors], and the finding that reaches the model, typed in [a finding record]. The same three parties are derived from the tooling's side in [who does what](/disciplined-methodology#who-does-what) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the seven controls are installed as checks before the model writes anything, and every architectural intent is treated as unenforced until its predicate runs in the chain. The model's authority is bounded, so every model-produced artifact is validated at the boundary it crosses and raw model output never reaches a trusted sink. The model is directed with findings rather than principles, in [the loop](/disciplined-methodology#the-loop) described in [detect, log, fix](/disciplined-methodology/build#detect-log-fix) on the methodology page.",
                    "boundary": "The model is not the reviewer and the gate is not the designer. A gate decides whether a predicate holds and nothing about whether the predicate was worth stating. That decision stays with the developer, and a system whose predicates were chosen by the model has let the author grade its own work.",
                    "cause": "A model's adherence to an instruction is a distribution rather than a commitment, so an architecture that rests on adherence is a bet placed on every change.",
                    "decision": "Design is spent on choosing predicates rather than on explaining intentions to the model.",
                    "failureMode": "An edit is judged clean by the model's own read of it, the check that would have disagreed never ran, and the design principle the edit violates is still the first paragraph of the document the model was given.",
                    "kind": "lesson",
                    "principle": "For this reason the architecture is the set of predicates the gate holds, and design is choosing them.",
                    "problem": "Development with a model scales code production and leaves architecture where it was, held by intentions the model does not keep.",
                    "validation": "To check this, delete the design document from the session and run the gate. Whatever the gate refuses is the architecture that exists. Whatever it accepts that the document forbade was never architecture, and the model has been writing it since the first session."
                  },
                  {
                    "caption": "three authors",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    intent[\"An architectural intent\"]\n    author{\"Who writes against it?\"}\n    person[\"The developer · complies by attention · drifts slowly\"]\n    model[\"A model · complies probabilistically · produces locally reasonable changes at speed\"]\n    gate[\"A gate · the only party in the loop that refuses\"]\n    holds[\"The intent holds by construction\"]\n    decays[\"The intent decays at the author's speed\"]\n    intent --> author\n    author -- developer --> person -. eventually .-> decays\n    author -- model --> model --> decays\n    model -- every intent as a predicate --> gate --> holds"
                  }
                ],
                "title": "Every principle becomes a gate"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The division of labor follows from the author being a model. The tooling detects because detection is deterministic and a model's account of its own work is not. The model is asked to remediate because a finding is a task it is likely to perform consistently. The developer governs because choosing the predicates and deciding the tensions is not computed."
                  },
                  {
                    "kind": "text",
                    "text": "The arrangement is [policy enforcement](/records/architecture/policy-enforcement), with the policy held as code and the enforcement held by a gate, and it is the only arrangement in which an [agentic architecture](/records/architecture/agentic-architecture) keeps an architecture at all. [Prompt engineering](/records/architecture/prompt-engineering) can raise the odds that a model honors an intent. It cannot make the intent hold, because a probability is not a predicate."
                  }
                ],
                "title": "Who does what"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A finding is machine-actionable for exactly this reason, and its shape is described in detect, log, fix on the methodology page. [Auto-remediation](/records/architecture/auto-remediation) takes the findings with [one correct answer](/disciplined-methodology/verify#one-correct-answer), and the rest route to the model with their operands already resolved."
                  },
                  {
                    "kind": "text",
                    "text": "[Ungrounded content](/records/architecture/ungrounded-content) is the failure this shape prevents. A model told a principle is likely to produce a plausible reading of it. A model handed a finding is asked to make the one change the finding names, and the gate that produced the finding is the same gate that checks the change, so the loop closes on evidence rather than on the model's report of itself."
                  },
                  {
                    "code": "export interface Finding<Shape> {\n    readonly at: Location;\n    readonly mismatch: { readonly expected: Shape; readonly found: Shape };\n    readonly remediation: { readonly operation: Operation; readonly operands: readonly Operand[] };\n}\n\nexport const route = (finding: Finding<unknown>): \"heal\" | \"delegate\" =>\n    finding.remediation.operands.every((operand) => operand.resolved) ? \"heal\" : \"delegate\";",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a finding record"
                  }
                ],
                "title": "A finding is the contract"
              }
            ],
            "title": "The author is probabilistic"
          },
          {
            "icon": "bi-repeat",
            "id": "scale-follows-determinism",
            "intro": "This section covers how scale relates to [determinism](/records/architecture/determinism), as shown in [check against care] and plotted in [cost per change], and why a model author is the case where the relation matters most. The same axis is stated for a mechanism in [one correct answer](/disciplined-methodology/verify#one-correct-answer) on the methodology page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the subject that has one correct answer is found for every concern and made the thing a check decides. Authors can then be counted freely, because a deterministic verdict is the same for one author or ten, and the model's non-determinism is confined to the one place it belongs, the choice among admissible changes.",
                    "boundary": "Determinism is claimed for the check, never for the author. A model stays a distribution however deterministic the gate around it is, and the gate's job is to make that fact cost nothing rather than to pretend it away.",
                    "cause": "A verdict that depends on who is looking has to be produced once per author, while a verdict that depends only on the tree is produced once, so the cost of care scales with the population and the cost of a check does not.",
                    "decision": "Judgment moves out of the check and into the choice of which checks to hold.",
                    "failureMode": "A review process that worked for two developers is applied to a model that produces a hundred changes a day, and the reviewers become the bottleneck the model was meant to remove.",
                    "kind": "lesson",
                    "principle": "For this reason a deterministic subject is checkable, healable, predictable and scalable at once, and scale follows from determinism rather than from headcount.",
                    "problem": "Enforcement that rests on care costs more for every author added, and a model is an author whose output rate makes the multiplication expensive.",
                    "validation": "To check this, take any rule you enforce by review and ask whether two reviewers would return the same verdict on the same tree. If not, the subject is not yet deterministic, and every author you add costs another review."
                  },
                  {
                    "caption": "check against care",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subject[\"A subject with one correct answer\"]\n    check[\"A deterministic check · same cost, same verdict, any author\"]\n    authors[\"One author, ten, a model · enforcement cost stays flat\"]\n    care[\"A protocol resting on care · cost multiplied by every author\"]\n    subject --> check --> authors\n    subject -. left to attention .-> care"
                  }
                ],
                "title": "The same verdict for any author"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A deterministic subject has [testability](/records/architecture/testability), [auto-remediation](/records/architecture/auto-remediation) reaches it, and [predictability](/records/architecture/predictability) and [scalability](/records/architecture/scalability) follow without being pursued."
                  },
                  {
                    "kind": "text",
                    "text": "The rest of this page lists the subjects that can be made deterministic, namely what a file is, what a principle requires, which control is absent, which cell is watched and which concern a change forces."
                  },
                  {
                    "caption": "cost per change",
                    "kind": "mermaid",
                    "text": "xychart-beta\n    title \"Enforcement cost against the number of authors\"\n    x-axis \"authors\" [1, 2, 4, 8, 16, 32]\n    y-axis \"cost per change\" 0 --> 32\n    line \"a protocol resting on care\" [1, 2, 4, 8, 16, 32]\n    line \"a deterministic check\" [1, 1, 1, 1, 1, 1]"
                  }
                ],
                "title": "Determinism is the axis the others derive from"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Flaky test normalization](/records/architecture/flaky-test-normalization) is what a team does when it stops believing this. A check that returns a different verdict on the same tree is treated as noise, the noise is tolerated, and every author learns that red means run it again. The repair is never a [retry pattern](/records/architecture/retry-pattern) around the check. It is finding the non-deterministic subject the check depends on and making it deterministic, or declaring that it cannot be and holding the check."
                  },
                  {
                    "kind": "text",
                    "text": "[Formal verification](/records/architecture/formal-verification) is the far end of the same axis, a subject made deterministic enough that a proof replaces a run, and [static analysis](/records/architecture/static-analysis) is the near end, a shape decided without running anything. Most of an architecture's predicates live at the near end, and that is enough, because a verdict that is the same for any author is what lets the author be a model."
                  }
                ],
                "title": "When a verdict moves"
              }
            ],
            "title": "Scale follows determinism"
          },
          {
            "icon": "bi-cpu",
            "id": "systems-built-around-a-model",
            "intro": "This section covers systems built around a model, which the same canon governs with one extra category whose records sit on the [correctness layer](/records/layer/correctness-core). Nothing about a model is special to the canon. The category applies the contracts, schema and security layers to an author whose output is a distribution, and the one thing it adds is the insistence that the distribution be measured before it is trusted, in the four obligations shown in [one category].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a model is versioned, gated and evaluated like any dependency, and measured before it is trusted. What it generates is grounded in retrieved evidence that cites its source rather than in recollection, and the knowledge it reasons over is structured so the output can be explained. Its authority is bounded at every boundary, so its output is validated before it reaches a sink, a raw completion never lands in a trusted store, and every capability it may invoke is declared, so it is discovered rather than reachable by default.",
                    "boundary": "The category governs a model as a component of a system and says nothing about how a model should be built or trained. A model's internals are a dependency's internals, and the canon's claim stops at the boundary where its output crosses into the system.",
                    "cause": "A model's output is a distribution, so every contract that assumes a deterministic component is violated by default where a model stands, and the only repair is to apply the contracts explicitly at the boundary the model's output crosses.",
                    "decision": "The model is treated as an author rather than a component, so every boundary its output crosses is one the contracts already govern.",
                    "failureMode": "A completion is written straight into a trusted store, the store is read as fact by the rest of the system, and the fact was a fluent guess that was never validated because the model was treated as a component rather than as an author.",
                    "kind": "lesson",
                    "principle": "For this reason a model is governed as a dependency whose output is a distribution, by the same canon applied at its boundary.",
                    "problem": "Model output is trusted like the result of a lookup, and it reaches the system's stores unchecked.",
                    "validation": "To check this, follow one model output from generation to the first trusted sink and name the validation it crossed. If there is none, the model's authority is unbounded, and the canon has a category for exactly that failure."
                  },
                  {
                    "caption": "one category",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    model[\"A model in the system\"]\n    governed[\"versioned, gated, evaluated · like any dependency\"]\n    grounded[\"generation grounded in retrieved evidence that cites its source\"]\n    structured[\"knowledge structured so the output can be explained\"]\n    bounded[\"authority bounded · output validated before any sink, capabilities declared\"]\n    canon[\"The same canon · contracts, schema and security applied to an author whose output is a distribution\"]\n    model --> governed --> canon\n    model --> grounded --> canon\n    model --> structured --> canon\n    model --> bounded --> canon"
                  }
                ],
                "title": "A dependency whose output is a distribution"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Model governance](/records/architecture/model-governance) and [model evaluation](/records/architecture/model-evaluation) are the canon's records for the first obligation. [Model drift monitoring](/records/architecture/model-drift-monitoring) keeps measuring after the model is trusted, because a distribution that was acceptable at one version is a claim about that version only, and [model version ambiguity](/records/architecture/model-version-ambiguity) is the anti-pattern of a system that cannot say which one answered."
                  },
                  {
                    "kind": "text",
                    "text": "[Retrieval-augmented generation](/records/architecture/retrieval-augmented-generation) is the grounding, with [vector search](/records/architecture/vector-search) as the retrieval and the citation as the ground. [Knowledge graphs](/records/architecture/knowledge-graphs) structure what the system reasons over so that [explainability](/records/architecture/explainability) is a property of the output rather than a hope."
                  }
                ],
                "title": "Governed, grounded, structured"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Model safety](/records/architecture/model-safety) is the canon's record for the bound. The validation is [input validation](/records/architecture/input-validation), and a capability the model may invoke is a [capability declaration](/records/architecture/capability-declaration). [Least privilege](/records/architecture/least-privilege) and [secure by default](/records/architecture/secure-by-default) are the same two principles they are for any actor, applied to one whose intentions are a distribution."
                  },
                  {
                    "kind": "text",
                    "text": "An [agentic architecture](/records/architecture/agentic-architecture) is [traded against determinism](/records/tension/agentic-architecture-determinism), and the operating point is the set of gates described in [the loop](/disciplined-methodology#the-loop), which is the same answer this whole page gives. [Prompt sprawl](/records/architecture/prompt-sprawl) is what a system looks like when the gates were never built and the prompts took their place."
                  }
                ],
                "title": "Bounded"
              }
            ],
            "title": "Systems built around a model"
          }
        ]
      },
      {
        "icon": "bi-journal-text",
        "id": "glossary",
        "label": "Glossary",
        "layout": "glossary",
        "sections": [
          {
            "icon": "bi-map",
            "id": "the-principle-architecture",
            "intro": "Three maps place the terms below. The first is the layer diagram the whole page rests on, the second sets the stateless half of the core against the stateful half, and the third sets what holds inside one boundary against what holds across boundaries. A term sits where its rule holds whole, and two terms that seem to contradict are two terms on two sides of a line the map draws.",
            "subsections": [
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Four core layers carry the rules about code itself. Computation is where data flows through and nothing is retained. Resource is where state lives and every handle has one owner. Execution is where the two meet through control flow and events. Structural applies to all of it and observes itself."
                  },
                  {
                    "kind": "text",
                    "text": "Resource observes computation, both feed execution, execution feeds structural, and structural feeds back into execution, which is [the loop](/disciplined-methodology#the-loop) that lets a system read its own behavior and correct it. Beneath the four sit [human factors](/records/layer/human-factors), which bound the whole by what a developer can hold, and evolution, which says how the whole changes over time."
                  },
                  {
                    "caption": "The principle architecture: the four core layers, the observe and feedback arrows across them, and the two domains beneath.",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph core[\"The four core layers\"]\n        direction TB\n        computation[\"COMPUTATION · stateless · data flows through, outputs are frozen\"]\n        resource[\"RESOURCE · stateful · owned, tracked, explicitly released\"]\n        execution[\"EXECUTION · how computation and resources interact\"]\n        structural[\"STRUCTURAL · applies to all code · observes itself\"]\n    end\n    human[\"HUMAN FACTORS · cognitive and discipline constraints\"]\n    evolution[\"EVOLUTION · change over time\"]\n    resource -- observe --> computation\n    computation --> execution\n    resource --> execution\n    execution -- feeds --> structural\n    structural -- feedback --> execution\n    structural --> human\n    structural --> evolution"
                  }
                ],
                "title": "The layers"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Five pairs of terms look like contradictions until the layer is read. They are [statelessness](/records/architecture/statelessness) against state before mutation, [immutability](/records/architecture/immutability) against state over code, explicit invalidity against [fail fast](/records/architecture/fail-fast), deliberate under-specification against not building what is not needed, and [homoiconicity](/records/architecture/homoiconicity) against single ownership."
                  },
                  {
                    "kind": "text",
                    "text": "Each pair is two principles on two layers, so each is resolved by scope, and the edge between them names the boundary. A computation flows through while a resource is snapshotted. Computed data is frozen while resource state is managed. An uncertainty is marked in a computation while a broken invariant halts a resource."
                  },
                  {
                    "caption": "Stateless against stateful: each pair is resolved by scope, and the edge names the boundary that separates them.",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subgraph stateless[\"COMPUTATION · stateless\"]\n        direction TB\n        s1[\"Statelessness\"]\n        s2[\"Immutability\"]\n        s3[\"Explicit Invalidity\"]\n        s4[\"Deliberate Under-Specification\"]\n        s5[\"Homoiconicity\"]\n    end\n    subgraph stateful[\"RESOURCE · stateful\"]\n        direction TB\n        r1[\"State-Before-Mutation\"]\n        r2[\"State Over Code\"]\n        r3[\"Fail Fast\"]\n        r4[\"YAGNI\"]\n        r5[\"Single Owner\"]\n    end\n    s1 -- data flows through · a resource is snapshotted before it changes --- r1\n    s2 -- computed data is frozen · resource state is mutable but managed --- r2\n    s3 -- a computation uncertainty is marked · a resource invariant halts --- r3\n    s4 -- interfaces stay open · implementation is not built ahead --- r4\n    s5 -- definitions are shared freely · runtime resources have one owner --- r5"
                  }
                ],
                "title": "Stateless against stateful"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The distributed pairs live where one boundary ends. [Consistency](/records/architecture/consistency) against availability, and [asynchronous communication](/records/architecture/asynchronous-communication) against immediate consistency, are trade-offs, strong or immediate inside one [transaction boundary](/records/architecture/transaction-boundary) or trust boundary and eventual across [autonomy](/records/architecture/autonomy) boundaries, with the operating point a measured choice. A [canonical model](/records/architecture/canonical-model) against the autonomy of a [bounded context](/records/architecture/bounded-context) is a trade-off too, one model where contexts share meaning and an [anti-corruption layer](/records/architecture/anti-corruption-layer) where they do not."
                  },
                  {
                    "kind": "text",
                    "text": "[Normalization](/records/architecture/normalization) against query performance separates by scope, the canonical store one way and the derived read models the other. [Do not repeat yourself](/records/architecture/duplicate-code) against locality of behavior is the one pair a rule resolves, by asking whether a sameness is semantic or merely textual."
                  },
                  {
                    "caption": "Inside a boundary against across boundaries: the distributed pairs, each labeled with the mechanism that resolves it.",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    subgraph inside[\"INSIDE ONE BOUNDARY\"]\n        direction TB\n        i1[\"Consistency\"]\n        i2[\"Asynchronous Communication\"]\n        i3[\"Canonical Model\"]\n        i4[\"Normalization\"]\n        i5[\"Do Not Repeat Yourself\"]\n    end\n    subgraph across[\"ACROSS BOUNDARIES\"]\n        direction TB\n        a1[\"Availability\"]\n        a2[\"Immediate consistency\"]\n        a3[\"Bounded context autonomy\"]\n        a4[\"Query performance\"]\n        a5[\"Locality of behavior\"]\n    end\n    i1 -- traded · strong inside a transaction, eventual across autonomy boundaries --- a1\n    i2 -- traded · synchronous inside a trust boundary, asynchronous across autonomy boundaries --- a2\n    i3 -- traded · one model where contexts share meaning, a translation where they do not --- a3\n    i4 -- by scope · the canonical store is normalized, derived read models are denormalized --- a4\n    i5 -- by rule · semantics are centralized, incidental co-occurrence stays local --- a5"
                  }
                ],
                "title": "Inside a boundary, across boundaries"
              }
            ],
            "title": "The principle architecture"
          },
          {
            "blocks": [
              {
                "entries": [
                  {
                    "code": "SoC",
                    "description": "Each module owns exactly one concern, and the cut is made with the whole system in view, so the pieces still compose into one thing rather than a pile of tidy parts that no longer fit. Traded against [over-layering](/records/lexicon/over-layering): a separation that [only adds indirection](/records/tension/over-layering-separation-of-concerns) has cost more than it separated.",
                    "term": "Separation of Concerns",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/separation-of-concerns"
                  },
                  {
                    "code": "KISS",
                    "description": "The chosen solution is the simplest one that meets the invariant, where simple means expressible as a rule or a generator rather than as an enumeration of cases. Compression is the test, since a repeated shape is compressed by its type, and the simplest form is the one nothing can be removed from without breaking the invariant.",
                    "domains": [
                      "quality attribute",
                      "Structural Core"
                    ],
                    "term": "Simplicity",
                    "href": "/records/lexicon/simplicity"
                  },
                  {
                    "code": "DRY",
                    "description": "A piece of logic or knowledge has one definition, and a repetition is compressed by its type, such as a literal into a constant, a structure into a composition, a behavior into one orchestrator and a rule into one predicate. Mitigated against [locality of behavior](/records/lexicon/locality-of-behavior) by a [rule that names the discriminator](/records/tension/do-not-repeat-yourself-dry-locality-of-behavior): semantics are centralized, incidental textual likeness stays local.",
                    "term": "Do Not Repeat Yourself",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/duplicate-code"
                  },
                  {
                    "description": "A unit has one reason to change, and that reason is derived from an invariant it protects rather than from a feature it serves. Features cut across units, and an invariant belongs to one. Traded against [excessive fragmentation](/records/lexicon/excessive-fragmentation): units [split finer than their invariants](/records/tension/excessive-fragmentation-single-responsibility-principle-srp) scatter one reason to change across many files.",
                    "term": "Single Responsibility Principle",
                    "code": "SRP",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/single-responsibility"
                  },
                  {
                    "description": "A unit is open for extension and closed for modification, so new behavior arrives through a few composable primitives, and the existing tested code is not edited to admit it.",
                    "term": "Open/Closed Principle",
                    "code": "OCP",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/open-closed"
                  },
                  {
                    "description": "Anything that claims a type can stand in for it without a caller noticing. A substitute honors every behavioral guarantee of what it replaces.",
                    "term": "Liskov Substitution Principle",
                    "code": "LSP",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/liskov-substitution"
                  },
                  {
                    "description": "An interface is cut by usage, so a client depends only on the operations it calls, never on a wide surface it mostly ignores.",
                    "term": "Interface Segregation Principle",
                    "code": "ISP",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/interface-segregation"
                  },
                  {
                    "description": "High-level policy depends on [abstractions](/records/architecture/abstraction), and the concrete details depend on the same abstractions, so the direction of dependency runs toward stability.",
                    "term": "Dependency Inversion Principle",
                    "code": "DIP",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/dependency-inversion"
                  },
                  {
                    "description": "A reference names what a thing means, never where it sits, so a move changes no reference and a location is never a dependency.",
                    "domains": [
                      "Structural Core"
                    ],
                    "term": "Semantic Addressing",
                    "href": "/records/layer/structural-core"
                  },
                  {
                    "description": "Code, data and state share one representation, so a definition can be inspected and transformed like any other value, and the degree to which a system has that property is what the term names. Resolved by scope against Single Owner: ownership governs runtime resources, homoiconicity governs definitions.",
                    "term": "Homoiconicity",
                    "domains": [
                      "quality attribute",
                      "Declarative Core"
                    ],
                    "href": "/records/architecture/homoiconicity"
                  },
                  {
                    "description": "Every fact has one canonical, queryable home, and every other place it appears is a derivation of that home. Resolved by scope against [Decentralization](/records/tension/decentralization-single-source-of-truth): the truth is one, and the parties that read it are many.",
                    "term": "Single Source of Truth",
                    "domains": [
                      "principle",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/single-source-of-truth"
                  },
                  {
                    "description": "Order is a logical sequence or an append-only identifier, never a wall-clock timestamp, because a clock is a dependency on the host and a sequence depends on nothing.",
                    "domains": [
                      "Structural Core"
                    ],
                    "term": "Ordinal Time",
                    "href": "/records/layer/structural-core"
                  },
                  {
                    "description": "Computed data is frozen after creation, and a variable is bound exactly once. Resolved by scope against State Over Code: computed outputs are immutable, resource state is mutable but managed.",
                    "term": "Immutability",
                    "domains": [
                      "principle",
                      "Computation Core"
                    ],
                    "href": "/records/architecture/immutability"
                  },
                  {
                    "description": "Computation carries no persistent state, so data flows through and nothing is retained between calls. Resolved by scope against State-Before-Mutation: computation is stateless, a resource is snapshotted before it changes.",
                    "term": "Statelessness",
                    "domains": [
                      "principle",
                      "Performance Core"
                    ],
                    "href": "/records/architecture/statelessness"
                  },
                  {
                    "description": "Repeating an operation produces the same result as running it once, so a [retry](/records/architecture/retry-pattern) is safe and a duplicate delivery has one effect.",
                    "term": "Idempotency",
                    "domains": [
                      "principle",
                      "Atomic Boundary"
                    ],
                    "href": "/records/architecture/idempotency"
                  },
                  {
                    "description": "What is wanted is specified rather than how to get it, and the how is left to the system that reads the specification, which can explain why while it runs.",
                    "domains": [
                      "Computation Core"
                    ],
                    "term": "Declarative Specification",
                    "href": "/records/layer/computation-core"
                  },
                  {
                    "description": "Units combine freely into larger units, and the combination has no special cases the parts did not have.",
                    "term": "Composability",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/composability"
                  },
                  {
                    "description": "Temporary inconsistency is allowed exactly while it is marked. Resolved by scope against [Fail Fast](/records/architecture/fail-fast): a broken resource invariant halts, a computation uncertainty is marked and carried on.",
                    "domains": [
                      "Computation Core"
                    ],
                    "term": "Explicit Invalidity",
                    "href": "/records/layer/computation-core"
                  },
                  {
                    "description": "Errors use the system's own vocabulary and are machine-processable, so a consumer dispatches on an error rather than parsing a sentence.",
                    "domains": [
                      "Computation Core"
                    ],
                    "term": "Errors as Language",
                    "href": "/records/layer/computation-core"
                  },
                  {
                    "description": "Every resource has exactly one owner responsible for its release, and every other reference to it is weak. Resolved by scope against Homoiconicity: ownership governs runtime resources, definitions are freely shared.",
                    "domains": [
                      "Resource Core"
                    ],
                    "term": "Single Owner",
                    "href": "/records/layer/resource-core"
                  },
                  {
                    "description": "A resource lives no longer than its owner, and every open has its close.",
                    "domains": [
                      "Resource Core"
                    ],
                    "term": "Bounded Lifetime",
                    "href": "/records/layer/resource-core"
                  },
                  {
                    "description": "Release is guaranteed by scope or structure, never by a developer remembering, because release that depends on discipline eventually leaks.",
                    "domains": [
                      "Resource Core"
                    ],
                    "term": "Structural Release",
                    "href": "/records/layer/resource-core"
                  },
                  {
                    "description": "Resource state is snapshotted before it changes, so a change can be reverted by reinstantiation rather than by patching. Resolved by scope against Statelessness: computation flows through, a resource is snapshotted.",
                    "domains": [
                      "Resource Core"
                    ],
                    "term": "State-Before-Mutation",
                    "href": "/records/layer/resource-core"
                  },
                  {
                    "description": "A child never calls back into its parent. Communication runs the other way, by events the parent subscribes to, so the child stays free of a parent it should not know.",
                    "domains": [
                      "Execution Core"
                    ],
                    "term": "Don't Call Back",
                    "href": "/records/layer/execution-core"
                  },
                  {
                    "description": "Components communicate by emitting events, the producer does not know its subscribers, and a pause or a resume is an ordinary control message. Traded against [debuggability](/records/lexicon/debuggability): a flow that cannot be followed end to end cannot be fixed, so [tracing is bought explicitly](/records/tension/debuggability-event-driven-architecture).",
                    "term": "Event-Driven Architecture",
                    "domains": [
                      "style",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/event-driven-architecture"
                  },
                  {
                    "description": "Append, never retract. A retraction is a second path every reader must handle, and a correction is a new record that supersedes.",
                    "domains": [
                      "Execution Core"
                    ],
                    "term": "Monotonic Growth",
                    "href": "/records/layer/execution-core"
                  },
                  {
                    "description": "A change in one area does not affect an unrelated one, so the effect of an edit is local by construction.",
                    "domains": [
                      "Execution Core"
                    ],
                    "term": "Orthogonality",
                    "href": "/records/layer/execution-core"
                  },
                  {
                    "description": "An error is detected and reported at once, and invalid state halts rather than carrying on behind a fallback that masks it. Resolved by scope against Explicit Invalidity: a resource halts, a computation marks and continues. Traded against [graceful degradation](/records/tension/fail-fast-graceful-degradation): a halt is chosen where it costs less than a wrong answer.",
                    "term": "Fail Fast",
                    "domains": [
                      "principle",
                      "Correctness Core"
                    ],
                    "href": "/records/architecture/fail-fast"
                  },
                  {
                    "description": "Related logic lives together, bounded by what a developer can hold in mind at once rather than by what a file system permits.",
                    "term": "High Cohesion",
                    "domains": [
                      "quality attribute",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/high-cohesion"
                  },
                  {
                    "description": "Dependencies between units are few and explicit, so a change stays where it was made.",
                    "term": "Loose Coupling",
                    "domains": [
                      "quality attribute",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/low-coupling"
                  },
                  {
                    "description": "Internals are hidden behind an interface, and the interface is the only way in, but the system still ships with a live inspector, because hiding internals from callers is not the same as hiding them from the developer diagnosing the running system. Traded against [debuggability](/records/lexicon/debuggability): the [inspector](/records/tension/debuggability-encapsulation) is where the operating point sits.",
                    "term": "Encapsulation",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/encapsulation"
                  },
                  {
                    "description": "Complexity stays under a declared bound the gate reads, and stopping with a stated uncertainty is preferred to continuing with a silent incorrectness.",
                    "domains": [
                      "Human Factors"
                    ],
                    "term": "Bounded Complexity",
                    "href": "/records/layer/human-factors"
                  },
                  {
                    "description": "A modular system is built from independent, swappable units with [explicit boundaries](/records/architecture/explicit-boundaries), so a unit can be replaced without the rest knowing. Traded against [cross-cutting concerns](/records/lexicon/cross-cutting-concerns): a concern that [touches every unit](/records/tension/cross-cutting-concerns-modularity) is placed once, at the boundary, rather than spread through them.",
                    "term": "Modularity",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/modularity"
                  },
                  {
                    "description": "State is the asset and code is the replaceable part, so a design protects the state before it protects the code. Resolved by scope against Immutability: computed data is frozen, resource state is mutable but managed.",
                    "domains": [
                      "Evolution Principles"
                    ],
                    "term": "State Over Code",
                    "href": "/records/layer/evolution-principles"
                  },
                  {
                    "description": "An interface leaves room where the future is unknown, so a later feature is not blocked by an unneeded constraint. Resolved by scope against YAGNI: the restraint applies to implementation, the openness to interfaces.",
                    "domains": [
                      "Evolution Principles"
                    ],
                    "term": "Deliberate Under-Specification",
                    "href": "/records/layer/evolution-principles"
                  },
                  {
                    "description": "You are not going to need it, so nothing is built for a need that does not exist yet. Resolved by scope against Deliberate Under-Specification: no code for hypothetical features, and no constraint that would block one.",
                    "domains": [
                      "principle",
                      "Evolution Principles"
                    ],
                    "term": "YAGNI",
                    "href": "/records/lexicon/yagni"
                  },
                  {
                    "description": "Controls exist at every layer, so a single bypassed control exposes nothing on its own.",
                    "term": "Defense in Depth",
                    "domains": [
                      "principle",
                      "Security Core"
                    ],
                    "href": "/records/architecture/defense-in-depth"
                  },
                  {
                    "description": "Every actor holds the minimum authority its task needs, and anything not granted is denied.",
                    "term": "Least Privilege",
                    "domains": [
                      "principle",
                      "Security Core"
                    ],
                    "href": "/records/architecture/least-privilege"
                  },
                  {
                    "description": "The default configuration is the safe one, and opening something up is a deliberate act.",
                    "term": "Secure by Default",
                    "domains": [
                      "principle",
                      "Security Core"
                    ],
                    "href": "/records/architecture/secure-by-default"
                  },
                  {
                    "description": "A producer is bound to what its consumer can absorb, so load is refused or slowed at the source instead of piling up unseen. Traded against [throughput](/records/tension/backpressure-throughput): the bound is a measured point, never a reflex.",
                    "term": "Backpressure",
                    "domains": [
                      "mechanism",
                      "Correctness Core"
                    ],
                    "href": "/records/architecture/backpressure"
                  },
                  {
                    "description": "[Optimization](/records/architecture/optimization) follows measurement, so the bottleneck is profiled before anything is changed, and the change is judged by the measurement.",
                    "domains": [
                      "Performance Core"
                    ],
                    "term": "Profile First",
                    "href": "/records/layer/performance-core"
                  },
                  {
                    "description": "Configuration comes from the environment, is validated at boot, and has no fallback default that would hide a missing value.",
                    "term": "Configuration Externalization",
                    "domains": [
                      "principle",
                      "Resource Core"
                    ],
                    "href": "/records/architecture/configuration-externalization"
                  },
                  {
                    "description": "Every stated architectural invariant has an executable check that fails the build when it is broken.",
                    "term": "Policy as Code",
                    "domains": [
                      "mechanism",
                      "Security Core"
                    ],
                    "href": "/records/architecture/policy-as-code"
                  },
                  {
                    "description": "Preconditions, postconditions and invariants are stated and checked, never assumed.",
                    "term": "Design by Contract",
                    "domains": [
                      "principle",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/design-by-contract"
                  },
                  {
                    "description": "The contract is defined before the implementation, so consumers depend on the interface and not on the first thing that happened to work.",
                    "term": "Contract-First Design",
                    "domains": [
                      "principle",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/contract-first-design"
                  },
                  {
                    "description": "Types make invalid states unrepresentable, and every boundary validates its data against a schema.",
                    "term": "Type Safety",
                    "domains": [
                      "mechanism",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/type-safety"
                  },
                  {
                    "description": "Every view derives from one canonical model. Traded against [bounded context autonomy](/records/lexicon/bounded-context-autonomy): one model holds [where contexts share meaning](/records/tension/bounded-context-autonomy-canonical-model), and a translation stands where they do not.",
                    "term": "Canonical Model",
                    "domains": [
                      "principle",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/canonical-model"
                  },
                  {
                    "description": "Code and domain share one vocabulary, so a name in the code is a name the domain expert would use.",
                    "term": "Ubiquitous Language",
                    "domains": [
                      "activity",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/ubiquitous-language"
                  },
                  {
                    "description": "Behavior matches what a reasonable reader expects from the name, and a surprise is a defect.",
                    "term": "Principle of Least Surprise",
                    "domains": [
                      "principle",
                      "Contracts Core"
                    ],
                    "href": "/records/architecture/principle-of-least-surprise"
                  },
                  {
                    "description": "A change commits fully or not at all, within an explicit boundary.",
                    "term": "Atomicity",
                    "domains": [
                      "principle",
                      "Atomic Boundary"
                    ],
                    "href": "/records/architecture/atomicity"
                  },
                  {
                    "description": "Every invariant that held before a change holds after it. Traded against [availability](/records/lexicon/availability): strong inside one [transaction boundary](/records/architecture/transaction-boundary), eventual across [autonomy](/records/architecture/autonomy) boundaries, and [where the point sits](/records/tension/availability-consistency) is a measured choice.",
                    "term": "Consistency",
                    "domains": [
                      "quality attribute",
                      "Atomic Boundary"
                    ],
                    "href": "/records/architecture/consistency"
                  },
                  {
                    "description": "Mutable state is confined to its owner, and side effects are explicit, ordered and bounded.",
                    "term": "State Isolation",
                    "domains": [
                      "principle",
                      "Atomic Boundary"
                    ],
                    "href": "/records/architecture/state-isolation"
                  },
                  {
                    "description": "Asynchronous communication does not wait for a reply and is routed through a broker, so the availability and the pace of both sides are decoupled. Traded against [immediate consistency](/records/lexicon/immediate-consistency): [synchronous inside a trust boundary](/records/tension/asynchronous-communication-immediate-consistency), asynchronous across autonomy boundaries.",
                    "term": "Asynchronous Communication",
                    "domains": [
                      "principle",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/asynchronous-communication"
                  },
                  {
                    "description": "State is persisted as an immutable sequence of events, and the current state is a fold over them.",
                    "term": "Event Sourcing",
                    "domains": [
                      "pattern",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/event-sourcing"
                  },
                  {
                    "description": "Command query responsibility segregation keeps the write model and the read models separate, so each can take the shape its job needs.",
                    "term": "CQRS",
                    "domains": [
                      "pattern",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/command-query-responsibility-segregation"
                  },
                  {
                    "description": "Bounded staleness is accepted so that services stay independently available under partition. It is the availability side of the trade-off with Consistency, chosen where autonomy matters more than an immediate answer.",
                    "term": "Eventual Consistency",
                    "domains": [
                      "model",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/eventual-consistency"
                  },
                  {
                    "description": "A service owns its data and its availability, and depends on no other service being up to do its own work.",
                    "term": "Service Autonomy",
                    "domains": [
                      "principle",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/autonomy"
                  },
                  {
                    "description": "Order is defined by what depended on what, tracked with logical clocks, never by a wall clock.",
                    "term": "Causality",
                    "domains": [
                      "principle",
                      "Causality Core"
                    ],
                    "href": "/records/architecture/causality"
                  },
                  {
                    "description": "A running system emits machine-parseable signals, so its behavior is legible from outside.",
                    "term": "Observability",
                    "domains": [
                      "quality attribute",
                      "Observability"
                    ],
                    "href": "/records/architecture/observability"
                  },
                  {
                    "description": "The framework calls the code rather than the code calling the framework, so control flows from the outside in.",
                    "term": "Inversion of Control",
                    "code": "IoC",
                    "domains": [
                      "principle",
                      "Extensibility Core"
                    ],
                    "href": "/records/architecture/inversion-of-control"
                  },
                  {
                    "code": "DI",
                    "description": "Dependencies are handed to a unit rather than constructed inside it, so they are visible, replaceable and testable.",
                    "term": "Dependency Injection",
                    "domains": [
                      "pattern",
                      "Extensibility Core"
                    ],
                    "href": "/records/architecture/dependency-injection"
                  },
                  {
                    "description": "New behavior arrives as a plugin at a declared [extension point](/records/architecture/extension-points), and the core stays unchanged.",
                    "term": "Plugin Architecture",
                    "domains": [
                      "style",
                      "Extensibility Core"
                    ],
                    "href": "/records/architecture/plugin-architecture"
                  },
                  {
                    "description": "Capabilities are registered in one queryable place and discovered from it, never located through a hidden dependency. The registry is the one list, and adding a capability is registering it rather than editing every caller.",
                    "term": "Registry Pattern",
                    "domains": [
                      "pattern",
                      "Extensibility Core"
                    ],
                    "href": "/records/architecture/registry-pattern"
                  },
                  {
                    "description": "Configuration states what is wanted, and convention removes the boilerplate, so the only thing written down is the deviation from the default.",
                    "term": "Convention over Configuration",
                    "domains": [
                      "principle",
                      "Declarative Core"
                    ],
                    "href": "/records/architecture/convention-over-configuration"
                  },
                  {
                    "description": "Definitions are held as inspectable, transformable data, so the same tooling that reads data can read code. It is the practice that Homoiconicity makes possible.",
                    "term": "Code as Data",
                    "domains": [
                      "principle",
                      "Declarative Core"
                    ],
                    "href": "/records/architecture/code-as-data"
                  },
                  {
                    "description": "Software is structured around the domain rather than the framework, with the logic living in the model.",
                    "term": "Domain-Driven Design",
                    "code": "DDD",
                    "domains": [
                      "style",
                      "Domain Modeling"
                    ],
                    "href": "/records/architecture/domain-driven-design"
                  },
                  {
                    "description": "A bounded context is a boundary inside which one model and one language hold, and outside which they may not.",
                    "term": "Bounded Context",
                    "domains": [
                      "constraint",
                      "Domain Modeling"
                    ],
                    "href": "/records/architecture/bounded-context"
                  },
                  {
                    "description": "A translation sits at the edge of a context, so a foreign model cannot leak in and corrupt the local one.",
                    "term": "Anti-Corruption Layer",
                    "domains": [
                      "pattern",
                      "Domain Modeling"
                    ],
                    "href": "/records/architecture/anti-corruption-layer"
                  },
                  {
                    "description": "The domain core depends on nothing, and input, output and frameworks are adapters at the edge, which is dependency inversion at the scale of a system.",
                    "term": "Ports and Adapters Architecture",
                    "domains": [
                      "style",
                      "Structural Core"
                    ],
                    "href": "/records/architecture/ports-and-adapters-architecture"
                  },
                  {
                    "description": "A defined workflow is driven by one coordinating owner, which knows every step and is the one place the sequence can be read.",
                    "term": "Orchestration",
                    "domains": [
                      "mechanism",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/orchestration"
                  },
                  {
                    "description": "Parts react autonomously to events with no central conductor, which fits where they must stay independent and the sequence may emerge.",
                    "term": "Choreography",
                    "domains": [
                      "mechanism",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/choreography"
                  },
                  {
                    "description": "A named design pattern is applied only when the force it answers is present in the code, never speculatively. A pattern with no force behind it is accidental complexity.",
                    "domains": [
                      "Design Patterns Core"
                    ],
                    "term": "Pattern by Fit",
                    "href": "/records/layer/design-patterns-core"
                  },
                  {
                    "description": "A value is computed only when it is demanded, so nothing is materialized that nothing reads.",
                    "term": "Lazy Evaluation",
                    "domains": [
                      "approach",
                      "Execution Core"
                    ],
                    "href": "/records/architecture/lazy-evaluation"
                  },
                  {
                    "description": "The same inputs give the same outputs, and every source of nondeterminism is isolated and injected.",
                    "term": "Determinism",
                    "domains": [
                      "principle",
                      "Computation Core"
                    ],
                    "href": "/records/architecture/determinism"
                  },
                  {
                    "description": "An expression can be replaced by its value without changing the program.",
                    "term": "Referential Transparency",
                    "domains": [
                      "principle",
                      "Computation Core"
                    ],
                    "href": "/records/architecture/referential-transparency"
                  },
                  {
                    "description": "A pure function's only effect is its return value, so the core stays pure and the effects sit at the edge.",
                    "term": "Pure Functions",
                    "domains": [
                      "technique",
                      "Computation Core"
                    ],
                    "href": "/records/architecture/pure-functions"
                  }
                ],
                "kind": "glossary"
              }
            ],
            "icon": "bi-list-columns",
            "id": "architectural-principles",
            "intro": "This section lists the principles this page teaches, one term per entry, with its short code where one is in common use and the layer this page places it on. An entry that names a record in the canon is joined to it: its kind is read from the record, and the term opens it, where the record's own placement can be read. The rest are the core layers' own terms. Where two entries pull against each other on one construct, the entry names its counterpart and the mechanism that resolves the pair, by scope, by a measured trade-off, or by a rule, whether the canon records that resolution or the two layers derive it.",
            "subsections": [],
            "title": "Architectural rules and principles"
          }
        ]
      }
    ],
    "tone": "architecture"
  },
  "description": "The architecture page covers software architecture for code that an LLM writes. It models a system as a graph, types and relates its principles, traces each anti-pattern as a path of decay, derives coverage from a grid, and states every architectural intent as a condition a check can decide.",
  "id": "software-architecture",
  "label": "Architecture",
  "tab": null,
  "title": "Architecture — Bane's Lab",
  "url": "https://banes-lab.com/software-architecture"
}
