{
  "content": {
    "kind": "tabbed",
    "layout": "chapter",
    "meta": {
      "subtitle": "Constraints, checks and skepticism for building software with LLMs",
      "title": "Disciplined Methodology",
      "version": "3.0.0"
    },
    "tabs": [
      {
        "icon": "bi-play-circle",
        "id": "start",
        "label": "Start",
        "sections": [
          {
            "icon": "bi-arrow-clockwise",
            "id": "the-loop",
            "intro": "Every piece of work in this method follows the same loop of ten steps, which I call nodes, whether the work is a one-line fix or a plan that runs for weeks. A plan, a check, an agent, a refactor and a review are all this one loop, run at a different size. I treat it as the first thing to learn, because each later chapter applies it to one kind of work, and every mechanism in the method exists to hold one of its gates: the points where the work may not continue until a condition holds. The nodes are shown in [ten nodes] and the sizes in [four sizes], and each node is published as a record on the ontology page: [orient](/ontology/reasoning#stage-orient), [intent](/ontology/reasoning#stage-intent), [see](/ontology/reasoning#stage-see), [derive](/ontology/reasoning#stage-derive), [project](/ontology/reasoning#stage-project), [act](/ontology/reasoning#stage-act), [constrain](/ontology/reasoning#stage-constrain), [verify](/ontology/reasoning#stage-verify), [commit](/ontology/reasoning#stage-commit), [terminate](/ontology/reasoning#stage-terminate).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice this means running the loop at the size of the task and always knowing which node the work is on. Four of the nodes are gates that apply at every size: the work has to be worth doing before any effort goes into it, a change has to be allowed before it is trusted, a claim needs evidence before it is recorded, and the loop only ends as done when nothing is left, everything is done and everything is checked. If that last condition is not met, it ends as blocked instead.",
                    "boundary": "The loop has its limits as well. It is not worth the ceremony for a throwaway script, and it pays off where you or your model will read, change or rely on the work later. A reference, a note or a contract is something you read rather than run, so forcing the full loop onto it adds ceremony without making it more reliable.",
                    "cause": "Nothing gave the work a shape, so the shape came from whatever sentence the model found most likely next.",
                    "decision": "A one-line fix goes through the same ten nodes as a plan does, rather than through a lighter process kept for small tasks.",
                    "failureMode": "The model starts writing code in its first reply and guesses what the goal is, and after that each reply answers the previous one rather than the task, so the conversation drifts away from what was asked.",
                    "kind": "lesson",
                    "principle": "For this reason I give every piece of work the same shape, the loop, whatever its size.",
                    "problem": "Work with a model tends to begin at the doing and skip everything that should come before it.",
                    "validation": "To check this on your own work, take the plan, the check and the agent for a single task and read each of them as the same ten nodes. A step that fits none of them is either missing from the loop or does not belong in the work."
                  },
                  {
                    "kind": "text",
                    "text": "The ten nodes fall into three groups. The first, the [epistemic](/ontology/reasoning#reason-layer-epistemic) layer, is about knowing: orient decides what the subject is by reading it from the tree, see chooses how to look at it, derive draws a claim from what was seen, project picks the next step that is allowed, and act carries it out. The second, the [conative](/ontology/reasoning#reason-layer-conative) layer, is about what is worth doing: intent states the [objective](/ontology/reasoning#reason-node-tel-objective) and ranks the possible approaches by [priority](/ontology/reasoning#reason-node-tel-priority), and constrain checks that a change is allowed once it has been made. The third, the [evaluative](/ontology/reasoning#reason-layer-evaluative) layer, is about whether the result is right and whether the work is finished: verify asks for [evidence](/ontology/reasoning#reason-node-ver-evidence), commit writes the result down where the next round can read it, and terminate decides whether to [stop](/ontology/reasoning#reason-node-ter-stop)."
                  },
                  {
                    "kind": "text",
                    "text": "The order between the nodes matters as much as the nodes themselves. A claim that turns out to be [refuted](/ontology/reasoning#reason-node-ver-refutation) goes back to derive together with the evidence that refuted it; it never carries on with a note attached. A repair restarts at the earliest node that can supply the missing evidence, and everything after that node is redone. The number of repairs is limited, so a loop that keeps repairing ends as [blocked](/ontology/reasoning#reason-node-ter-block) rather than as done. Each node also owes a specific kind of answer: a node that has to rank options is not satisfied by a yes, and a node that has to answer yes or no is not satisfied by a ranking. The same loop is what an [agent template](/pag/templates#templates-agents) follows and what an [instruction pattern](/pag/patterns#instruction-patterns) is chosen by, which is why the grammar page and this page describe one loop twice."
                  },
                  {
                    "caption": "ten nodes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph epistemic[\"Epistemic · how is it known?\"]\n        orient[\"Orient · name the subject, read from the tree\"]\n        see[\"See · look through the lenses the subject warrants\"]\n        derive[\"Derive · a claim grounded in what was seen\"]\n        project[\"Project · the next admissible move\"]\n        act[\"Act · apply the operation to the state\"]\n    end\n    subgraph conative[\"Conative · what is worth doing?\"]\n        intent[\"Intent · the objective, and the highest-worth branch\"]\n        constrain[\"Constrain · is the operation admissible?\"]\n    end\n    subgraph evaluative[\"Evaluative · is it right, and are we done?\"]\n        verify[\"Verify · is the evidence set non-empty?\"]\n        commit[\"Commit · externalise the result as inspectable state\"]\n        terminate[\"Terminate · saturated, complete and verified?\"]\n    end\n    orient --> intent\n    intent -- gate: worth before work --> see\n    see --> derive --> project --> act --> constrain\n    constrain -- gate: admissible --> verify\n    verify -- gate: evidence --> commit --> terminate\n    verify -. refuted, back with the evidence .-> derive\n    terminate -- gate: stop --> orient"
                  }
                ],
                "title": "Ten nodes, every size"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The loop also nests inside itself. A plan is one pass through the loop whose act node produces phases, each phase is a pass whose act node produces tasks, and each task is a pass that ends in an edit and a run of the checks. The gates apply at every level: a phase cannot start until the phase before it has recorded evidence the next one can read, and a plan cannot finish until every phase has done so. For this reason a plan has a gate between its phases rather than a tick beside each item, as described in [the plan is a graph](/disciplined-methodology/plan#the-flat-checklist)."
                  },
                  {
                    "kind": "text",
                    "text": "The difference between an instruction and a traversal, meaning one pass through the loop, shows within the first minute. An instruction asks for an outcome. A traversal names the nodes it passes through, so a reader can see where it went wrong. For example, asked to raise a file-size limit, a traversal starts by opening every file that mentions the limit, and finds that the limit is declared in three places. Its intent is one limit with a [single source of truth](/ontology#arch-single-source-of-truth), so it concludes that the problem is the limit having more than [one home](/disciplined-methodology/build#one-home), not its value. It changes the declaration, deletes the two copies and keeps to the one option the checker offers. It then runs the gate once and reads the output in full, records the report, and stops because the objective reads as true against the tree. The edit touched one file instead of three, and a reader of the messages can tell which node the work was on."
                  },
                  {
                    "caption": "four sizes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    fix[\"A one-line fix · one traversal, minutes\"]\n    task[\"A task · one traversal, an afternoon\"]\n    phase[\"A phase · one traversal that holds many tasks\"]\n    plan[\"A plan · one traversal that holds many phases\"]\n    fix --- task --- phase --- plan\n    plan -. each phase walks the loop again inside .-> phase\n    phase -. each task walks the loop again inside .-> task"
                  }
                ],
                "title": "Instruction and traversal"
              }
            ],
            "title": "The loop"
          },
          {
            "icon": "bi-people",
            "id": "who-does-what",
            "intro": "Three parties do the work in this method: the tooling, the model and me, as the developer. The tooling detects problems and repairs the ones it can, the model repairs what the tooling leaves, and I decide what the work is for and what finished means. The split is shown in [three parties], and the parts do not swap. I treat it as the second thing to learn, because every later chapter assumes it, and every failure the method knows turns out to be one party doing another party's job. The architecture page reaches the same three parties from a different starting point, that [the author is probabilistic](/software-architecture/scale#the-author-is-probabilistic).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, detection is a check that runs the same way every time, with its fixer switched on by default. The findings the fixer cannot close go to the model one at a time, each with its location and the value that was expected. The developer keeps the decisions about what the work is for, and hands nothing else down.",
                    "cause": "A developer cannot pay attention to every line, and a model cannot tell a rule from a preference unless something outside it enforces the rule.",
                    "decision": "Detection goes to the tooling and governance stays with the developer, rather than to a review that reads what a check could enforce.",
                    "failureMode": "You review the code for style, the model reviews it for [correctness](/ontology#arch-correctness), and both of you miss the architectural drift because neither of you owns it.",
                    "kind": "lesson",
                    "principle": "For this reason I treat quality as a property of the tooling, not of how much attention the developer or the model pays.",
                    "problem": "When you don't name the roles, you end up doing work a check should do, and the model ends up guessing what you want.",
                    "validation": "To check this on your own work, read the last ten findings your tooling raised. Each of them should name a check; a finding that a developer had to raise by hand points to a check that does not exist yet."
                  },
                  {
                    "kind": "text",
                    "text": "Detection is mechanical because it has to give the same result on every run. A reviewer who applies a rule from memory applies it differently on a tired day, and a model that applies a rule from a prompt applies it differently once its context fills up. A check, by contrast, is [static analysis](/ontology#arch-static-analysis): it returns the same verdict for the same tree. The chapters [one correct answer](/disciplined-methodology/verify#one-correct-answer) and [scale follows determinism](/software-architecture/scale#scale-follows-determinism) work out what follows from that. Repairs that have exactly one correct answer belong to the tooling for the same reason: the fixer applies them in the same run that found the fault, without asking the developer or the model."
                  },
                  {
                    "kind": "text",
                    "text": "Repair belongs to the model because a finding is small and specific, and a model handles small, specific tasks well; what a finding contains is described in [detect, log, fix](/disciplined-methodology/build#detect-log-fix). The model is not trusted to decide that its own work is finished, because reading an edit is not the same as running the checks, and [it looked right](/disciplined-methodology/verify#it-looked-right) covers that failure. Governance stays with the developer because nothing in the method computes whether work is worth doing. What the work is for, what finished looks like and which of two acceptable approaches to take are decisions I make and write down before the work starts. When I correct the model, the correction is meant to become a rule rather than something I remember; a rule that lives only in my head is [manual-only governance](/ontology#arch-manual-only-governance), and it decays."
                  },
                  {
                    "caption": "three parties",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph tooling[\"The tooling\"]\n        detect[\"Detection · every rule, on every change, the same way\"]\n        heal[\"Healing · what a fixer can restore, it restores\"]\n    end\n    subgraph ai[\"The model\"]\n        repair[\"Repair · what the fixers left, one finding at a time\"]\n    end\n    subgraph operator[\"The developer\"]\n        govern[\"Governance · what the work is for, and what finished means\"]\n    end\n    detect --> heal\n    heal -- the findings left --> repair\n    repair -- a changed tree --> detect\n    govern -- rules and objectives --> detect\n    govern -- corrections --> repair\n    repair -. questions .-> govern"
                  }
                ],
                "title": "Three parties, three jobs"
              }
            ],
            "title": "Who does what"
          },
          {
            "icon": "bi-search",
            "id": "the-stance",
            "intro": "The stance is four sentences, and the rest of the method depends on them. The first is that a claim stays unverified until you or your model read it in the current tree, as shown in [claim to evidence]. The second is that review is [adversarial by default](/disciplined-methodology#adversarial-by-default), because agreeing is cheaper than [verification](/ontology#arch-verification), as shown in [agreement outruns]. The third is that every manual step is a failure of automation; the ontology names what a manual step decays into, [manual runbook dependency](/ontology#arch-manual-runbook-dependency) and [manual-only governance](/ontology#arch-manual-only-governance). The fourth is that a document states what is true now and carries no history of its own, which is [single source of truth](/ontology#arch-single-source-of-truth) applied to prose. Everything else in the method is a mechanism that keeps one of these four sentences true without the developer or the model having to remember it.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the file is opened before the model or you say what it contains, the command is run before the model or you say what it prints, and the line is quoted rather than recalled. A claim about what a mechanism does is settled by running the mechanism, because a report about it, a rule describing it and a peer's account of it are all prose.",
                    "cause": "The model remembers a version of the file that sounds right, and the developer remembers the version they last edited, and neither of those is the file as it is now.",
                    "decision": "A claim about the tree stays unverified until the model or the developer reads the tree, rather than being accepted because it sounds right.",
                    "failureMode": "The model describes a function the way it was before you renamed it two sessions ago, makes an edit based on that description, and the edit lands in the wrong place.",
                    "kind": "lesson",
                    "principle": "For this reason I treat what either of you remembers as a lead to follow, never as evidence.",
                    "problem": "A question about the code is often answered from memory, by the model or by the developer, without opening the file.",
                    "validation": "To check this, ask the model for the file path and line behind each claim it makes. A claim it cannot point to is an assumption."
                  },
                  {
                    "kind": "text",
                    "text": "The stance applies to every input in the same way. My own messages, the model's reasoning, its edits and the reports that say they succeeded, a summary of an earlier turn, a peer's account and a file's claim about itself are all unverified until they are checked now. Reasoning is not verification, and a report that something succeeded is exactly the failure described in [it looked right](/disciplined-methodology/verify#it-looked-right). Verified means read or run in the current state of the tree, which is what the [ground truth](/ontology/reasoning#reason-node-ver-ground-truth) node of [the loop](/disciplined-methodology#the-loop) asks for. A file is also read in full, because reading part of it loses its structure, and the structure is what is being analysed."
                  },
                  {
                    "kind": "text",
                    "text": "A wrong claim spreads faster than its correction, for a simple reason. Agreeing with a peer costs one read of what they wrote, while refuting them costs opening the thing they wrote about, and only a party with a reason to doubt goes to that effort. The more coherent the argument around a wrong claim, the faster it spreads, because a claim that fits invites agreement rather than inspection. What follows from this is a small discipline: a statement that rests on another party's reading is checked by opening the thing they read, not by reading their sentence, and a claim about a mechanism is settled by making the mechanism run rather than by reading its source."
                  },
                  {
                    "kind": "text",
                    "text": "The difference shows in one exchange. Asked whether the router uses the new name, the answer from memory is *the router already uses the new name, so nothing else needs to change*. The answer from the tree is *the handler in the router still calls the old name, here is the line*. Only the second answer can be shown to be wrong, because it points at a line that can be checked."
                  },
                  {
                    "kind": "text",
                    "text": "The last two sentences of the stance follow from the first two. A step a developer performs by hand is a step no check observes, so it is done differently the next time; the repair is described in [tools live in the tree](/disciplined-methodology/build#tools-live-in-the-tree). A document that carries its own history makes the reader reconstruct what is true now, and a reader reconstructing the truth is guessing; the repair is described in [derived state](/disciplined-methodology/verify#derived-state)."
                  },
                  {
                    "caption": "claim to evidence",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    claim[\"A claim about the tree\"]\n    read{\"Read in this session?\"}\n    lead[\"A lead · follow it to the file\"]\n    evidence[\"Evidence · the path and the line\"]\n    act[\"Act on it\"]\n    claim --> read\n    read -- no --> lead\n    read -- yes --> evidence\n    lead --> read\n    evidence --> act"
                  },
                  {
                    "caption": "agreement outruns",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    claim[\"A claim is written\"]\n    agree1[\"A peer agrees · one read of the sentence\"]\n    agree2[\"A second peer agrees · one read of the agreement\"]\n    plan[\"It becomes a plan row\"]\n    open[\"A reader opens the file\"]\n    refuted[\"Refuted · the file moved before the claim was written\"]\n    claim --> agree1 --> agree2 --> plan\n    claim -. costs one read of the operand .-> open --> refuted"
                  }
                ],
                "title": "Read before you claim"
              }
            ],
            "title": "The stance"
          },
          {
            "icon": "bi-crosshair",
            "id": "adversarial-by-default",
            "intro": "The second sentence of [the stance](/disciplined-methodology#the-stance) says that review is adversarial by default, and it follows from the first. If a claim about the work stays unverified until the developer, the model or a check has tried to break it, then a review that starts by approving has nothing left to verify.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a review opens by listing what is wrong, and approval is what remains once that list is empty. A reply that opens with praise is rejected, and you or your model attack your own output before presenting it, because work that neither you nor a check has tried to break is not finished.",
                    "cause": "Training rewards the model for agreeing, so agreement is the easiest answer it can give.",
                    "decision": "The deliverable of a review is its list of findings, rather than a verdict with reasons attached.",
                    "failureMode": "The review reads well and approves the change, and the regression ships, because no party in the review was looking for it.",
                    "kind": "lesson",
                    "principle": "For this reason, approval can only be the result of [verification](/ontology#arch-verification), never the position a review starts from.",
                    "problem": "A model asked to review a change tends to agree with it, and that agreement looks like a review.",
                    "validation": "To check this, count the findings in a review. A review with none either checked nothing or checked the wrong thing."
                  }
                ],
                "title": "The list before the verdict"
              }
            ],
            "title": "Adversarial by default"
          },
          {
            "icon": "bi-eyeglasses",
            "id": "resolving-a-message",
            "intro": "A message from the developer is not simply answered. It is first understood as a whole, in one pass, before any reply is written, by reading it through the fifteen questions shown in [the readings]. This is the [orient](/ontology/reasoning#stage-orient) node of [the loop](/disciplined-methodology#the-loop) applied to a request. It matters because most drift starts here: a request answered at its surface is one the model answered without reading what lies under it.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the model is asked to read a request through the fifteen questions in their order before replying, and to write the reply as that understanding, in connected sentences rather than under headings.",
                    "boundary": "The questions scale with the request. A one-line request that comes down to one file and one edit still goes through them, but they take a moment and most of the answers are empty; an empty answer is still an answer, not a skipped question.",
                    "cause": "A reply forms from the first plausible reading of a message, and the first reading is the surface.",
                    "decision": "A message is understood before it is answered, rather than answered from its first reading.",
                    "failureMode": "A request to rename a function is answered by renaming the function, and three collectors that found it by a naming pattern quietly stop finding anything, because the model never asked what the name was connected to.",
                    "kind": "lesson",
                    "principle": "For this reason I treat the structure behind a request as what is being asked about, and the wording as evidence about that structure.",
                    "problem": "A message answered only at its surface gets wrong the details that only its structure would have shown.",
                    "validation": "To check this, take a reply and ask which of the fifteen questions it rests on. A reply that skipped one is incomplete rather than concise, and the question it skipped is where its mistake will be."
                  },
                  {
                    "kind": "text",
                    "text": "The fifteen questions are what turn this kind of judgement into something a check can enforce, because each one has a defined kind of answer. [Identity](/ontology/reasoning#reason-node-ont-identity) asks what exists, and the answer is a set. [Structure](/ontology/reasoning#reason-node-ont-structure) asks how the parts are arranged, and the answer is an ordering. [Relation](/ontology/reasoning#reason-node-ont-relation) asks what a thing connects to, and the answer is a graph. [Probability](/ontology/reasoning#reason-node-ont-probability) asks how sure each reading is, and the answer is a number between zero and one. The others, [composition](/ontology/reasoning#reason-node-ont-composition), [space](/ontology/reasoning#reason-node-ont-space), [time](/ontology/reasoning#reason-node-ont-time), [state](/ontology/reasoning#reason-node-ont-state), [change](/ontology/reasoning#reason-node-ont-change), [behaviour](/ontology/reasoning#reason-node-ont-behaviour), [function](/ontology/reasoning#reason-node-ont-function), [cause](/ontology/reasoning#reason-node-ont-cause), [meaning](/ontology/reasoning#reason-node-ont-meaning), [scale](/ontology/reasoning#reason-node-ont-scale) and [novelty](/ontology/reasoning#reason-node-ont-novelty), each have a kind of answer of their own."
                  },
                  {
                    "kind": "text",
                    "text": "A question with a defined kind of answer can be turned into a condition that a check can test. What that condition does from there is described in [from intent to predicate](/software-architecture/coverage#an-architecture-is-its-predicate-set), on the architecture page, and that is how a reading the developer did once becomes a check that runs every time."
                  },
                  {
                    "kind": "text",
                    "text": "[Introspection](/ontology#arch-introspection) means looking one level below the [abstraction](/ontology#arch-abstraction) a thing presents. A document's list of sections is its surface, and the rule that decides what may go into a section is its structure. A function's signature is its surface, and which state it owns and how long that state lives are its structure. A count is a surface, and the scope it was counted over is its structure. Reading at that level is what makes the first reading of a request agree with the final [verification](/ontology#arch-verification) of its result, because both are then looking at the same thing."
                  },
                  {
                    "caption": "the readings",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    message[\"A message arrives\"]\n    subgraph readings[\"Read whole, in order\"]\n        identity[\"What exists\"]\n        composition[\"What it is made of\"]\n        structure[\"How the parts are arranged\"]\n        relation[\"What it connects to\"]\n        space[\"Where it sits\"]\n        time[\"When it happens\"]\n        state[\"The condition it is in\"]\n        change[\"How it is already moving\"]\n        behaviour[\"What it does\"]\n        function[\"The role that doing serves\"]\n        cause[\"Why it happens\"]\n        meaning[\"What it signifies\"]\n        scale[\"The level it lives at\"]\n        probability[\"How sure each reading is\"]\n        novelty[\"What cuts against expectation\"]\n    end\n    reply[\"The reply is that understanding, made explicit\"]\n    message --> identity --> composition --> structure --> relation --> space --> time --> state --> change --> behaviour --> function --> cause --> meaning --> scale --> probability --> novelty --> reply"
                  }
                ],
                "title": "Fifteen readings, one pass"
              }
            ],
            "title": "Resolving a message"
          },
          {
            "icon": "bi-layers",
            "id": "three-encodings",
            "intro": "The rules of the method are written down in three different forms, and each form holds a different kind of rule. Mechanical rules are enforced by checks, behavioural rules tell the model how to work, and the context architecture decides what the model is given to read. The three feed into each other, as shown in [three encodings]. A method that uses only one of the three leaks through the other two, and when two documents disagree, the order shown in [precedence] decides which one wins.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a rule about the tree goes into a check. A rule about how the model should work goes into the behaviour policy, as one line with a stable name. What the model needs to know goes into the context architecture, arranged so that the general part carries over to other projects and everything specific to this project sits in one file. A fact lives in exactly one of the three places, and the other two point to it.",
                    "boundary": "The split follows what a rule applies to, never how important it feels. A behavioural rule whose effect can be seen in an artifact is really a mechanical rule written as prose, and moving it into a check is progress, not a demotion.",
                    "cause": "A rule written where no check reads it is held only by memory, and a rule written in two places becomes two rules that drift apart.",
                    "decision": "Each rule is assigned to one of the three forms before it is written down, rather than added wherever it happens to fit.",
                    "failureMode": "A rule about the tree is written into the behaviour policy, the model may keep to it for a session, and the tree drifts anyway, because nothing outside the conversation reads that sentence.",
                    "kind": "lesson",
                    "principle": "For this reason I keep each kind of rule in its own form: mechanical rules, behavioural rules and context architecture each hold one kind, and all three defer to the tree.",
                    "problem": "Rules are often written as one long instruction document, which mixes what a check should enforce with what [the developer and the model](/disciplined-methodology/collaborate#the-human-and-the-ai) are expected to remember, and the whole document then decays as fast as its weakest part.",
                    "validation": "To check this, take any rule and name the place it lives. A rule you cannot place in one of the three is either two rules or a rule that nothing enforces."
                  },
                  {
                    "kind": "text",
                    "text": "Mechanical rules are the ones a check can decide from the tree alone: where a file may live, what a name may say, which imports cross a boundary, whether a fact is declared twice and whether a document's references resolve. They are [policy as code](/ontology#arch-policy-as-code), enforced by checks, fixers, validators and generators through [static analysis](/ontology#arch-static-analysis) and [fitness functions](/ontology#arch-fitness-functions). Each returns pass or fail, and all of them run in [one chain](/disciplined-methodology/ship#one-chain), which is what [the gate holds the line](/disciplined-methodology/build#the-gate-holds-the-line) describes. The developer has no part in this form at all, and that is intended: a mechanical rule that needs a developer to apply it is a behavioural rule disguised as a check."
                  },
                  {
                    "kind": "text",
                    "text": "Behavioural rules cover how the model is asked to work where no artifact can show whether it did: that it reads a file before saying what the file contains, that it asks a question before the work that depends on the answer rather than after, and that it never runs a step whose output it will not read in full. Each is one line with a stable name, in the shape [rules with names](/disciplined-methodology#rules-with-names) describes, so that a correction has a place to land and a citation has something to point to."
                  },
                  {
                    "kind": "text",
                    "text": "Context architecture is how the other two forms reach the model in the same way every session. Its core documents name no project: an ontology of readings, a canon of principles as [principles are typed](/software-architecture/principles#principles-are-typed) describes, the naming standard that [placement is a grammar](/disciplined-methodology/build#placement-is-a-grammar) describes, and the [core templates](/pag/templates#templates-core) the grammar page publishes. A single adapter binds them to one project, as [the drop-in](/disciplined-methodology#onboarding) explains. Digests expand one concern each where a rule needs more room. Memory holds one fact per file and serves as reference rather than authority, so a remembered fact is checked against the tree before anything is done with it. An order of precedence runs through all of it, and the tree outranks every document: a document that disagrees with what is on disk is wrong, and it is corrected in the same turn the disagreement is found."
                  },
                  {
                    "kind": "text",
                    "text": "The feedback between the three forms is what makes them work as one system rather than three separate ones. A check raises a finding, and the model is asked to repair it within the behavioural rules. A correction I give is written down as a behavioural rule and a memory in the same turn. When a behavioural rule has to be stated twice for the same kind of problem, that is the signal to build the check that makes it mechanical; the prose then becomes a pointer, and the rule has a [single source of truth](/ontology#arch-single-source-of-truth). The core documents stay untouched throughout, because they name nothing specific to this project, and the adapter absorbs whatever changes."
                  },
                  {
                    "caption": "three encodings",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph mechanical[\"Mechanical rules · what the tree must be\"]\n        checks[\"Checks, fixers, validators, generators\"]\n    end\n    subgraph behavioural[\"Behavioural rules · how the agent is asked to work\"]\n        policy[\"One-line rules with stable names\"]\n    end\n    subgraph context[\"Context architecture · what the agent knows and where\"]\n        cores[\"Agnostic cores · ontologies, templates, the standard\"]\n        adapter[\"One adapter · binds every slot to this tree\"]\n        digests[\"Digests · one concern each, expanding a rule\"]\n        memory[\"Memory · one fact per file, reference never authority\"]\n    end\n    tree[\"The tree\"]\n    checks -- findings, healed or not --> policy\n    policy -- a correction hardens into a rule --> policy\n    policy -- a pattern stated twice becomes a check --> checks\n    cores -- read through --> adapter\n    adapter -- resolved slots --> policy\n    digests -- expand --> policy\n    memory -. recalled, then verified against .-> tree\n    checks -- read and heal --> tree\n    policy -- edits --> tree"
                  },
                  {
                    "caption": "precedence",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    policy[\"The behaviour policy\"]\n    contract[\"The codebase contract\"]\n    boundary[\"A member's own boundary document\"]\n    digests[\"The per-concern digests\"]\n    canon[\"The document canon\"]\n    source[\"Source files\"]\n    memory[\"Memory\"]\n    tree[\"The tree on disk\"]\n    policy --> contract --> boundary --> digests --> canon --> source --> memory\n    tree -. wins over every document, and the document is fixed the same turn .-> policy"
                  }
                ],
                "title": "One kind of discipline per home"
              }
            ],
            "title": "Three encodings"
          },
          {
            "icon": "bi-diagram-2",
            "id": "from-chat-to-tree",
            "intro": "A rule can live in one of two places, and [two homes] shows where each one leads. It can live in the conversation, where the developer has to restate it and hope it is followed, or it can live in the tree, where the model is given the policy file at the start of every session and a check refuses any change that breaks the rule. Everything in this method lives in the tree: as [policy as code](/ontology#arch-policy-as-code) where a check can enforce it, and as a line in the policy where only the model's conduct can. An instruction that has to be restated is a mechanism that has not been built yet, and the ontology calls the state it leaves behind [manual-only governance](/ontology#arch-manual-only-governance).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each instruction you keep repeating moves into a file the model is given at the start of every session, and each check you keep performing by hand moves into a command the pipeline runs. Once the mechanism holds, the old habit is dropped, because a habit kept alongside its mechanism is a second home for the same rule.",
                    "boundary": "A conversation is the right place for a rule only when the model has no access to your files; as soon as it does, the tree is the right place.",
                    "cause": "A rule held only by discipline is decided again every time it applies, and every new decision is a chance to decide differently.",
                    "decision": "Discipline is turned into mechanism as soon as a rule has been stated twice, rather than stated a third time.",
                    "failureMode": "The session starts well, the instructions fade as the context fills up, and by the end the model is back to its default behaviour.",
                    "kind": "lesson",
                    "principle": "For this reason I hold rules in the tree rather than in the conversation, because a rule in the conversation decays and a check in the tree does not.",
                    "problem": "Rules that live in a chat have to be restated every session, and each restatement is a chance for them to drift.",
                    "validation": "To check this, delete your custom instructions for one session. What still holds is mechanism, and what breaks was discipline."
                  },
                  {
                    "kind": "text",
                    "text": "The test that tells the two apart is whether anything would object if the rule stopped holding, the same objector test that the section [stating an invariant](/disciplined-methodology/collaborate#stating-an-invariant) applies to a whole topology. A rule in a conversation has no objector: once it is forgotten, nothing notices. A rule in the tree has one of two. Either a check refuses the change that breaks it, or a policy line states it in the same words at the start of every session. The second is weaker than the first, because the model can still fail to follow a line it has been given, but it is still stronger than a memory, because a policy is delivered to every session and a memory reaches only the party who remembers to look it up."
                  },
                  {
                    "kind": "text",
                    "text": "Friction between several parties working on one tree is the same question at a larger scale, and [coordination is software](/disciplined-methodology/collaborate#coordination-is-software) answers it. When two parties lose a write, leave a stale item behind or miss a message, the first question is what the [shared surface](/pag/orchestration#shared-surfaces) is missing, never who should have been more careful. A rule added without a mechanism behind it only asks for more care, and it decays at the same rate the care did."
                  },
                  {
                    "caption": "two homes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    rule[\"A rule\"]\n    conversation[\"Held in the conversation\"]\n    restated[\"Restated every session\"]\n    fades[\"Fades as the context fills\"]\n    defaults[\"The model is back to its defaults\"]\n    tree[\"Held in the tree\"]\n    policy[\"A policy file given to the model every session\"]\n    check[\"A check that runs on every change\"]\n    holds[\"Held by the tree, not by memory\"]\n    rule --> conversation --> restated --> fades --> defaults\n    rule --> tree --> policy --> holds\n    tree --> check --> holds"
                  }
                ],
                "title": "Discipline decays, mechanism holds"
              }
            ],
            "title": "Where a rule lives"
          },
          {
            "icon": "bi-tag",
            "id": "rules-with-names",
            "intro": "Every behavioural rule is written as one line with three parts: a stable name, a directive, and either the name of the check that enforces it or a statement that no check can. [a policy file] shows such lines, and [a rule record] shows the shape they are read into. The name is what a correction attaches to and what a citation points to. When I correct the model, the correction is written down in the same turn as a named rule and a memory, so that the rule is there for the next session instead of the correction having to be given again, as shown in [a correction hardens].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each rule is one line: a short stable name, a directive in the present tense, and the gate that enforces it. The name is cited wherever the rule applies. When a correction arrives, it is assigned to [one home](/disciplined-methodology/build#one-home), the rule is written first, then its reason and how it applies, a memory is stored beside it, and every place it was written to is confirmed by searching rather than by recollection. What is captured is the kind of mistake the correction belongs to, never the single case that triggered it.",
                    "boundary": "A rule may mention the measured failure that led to it, in the past tense and only inside that rule, because that clause is part of what the rule depends on. It describes the shape of the failure and how it showed up, never who caused it, when, or in what order.",
                    "cause": "A correction with nowhere to attach is remembered by the developer and forgotten by the model, so it has to be given again the following week.",
                    "decision": "Each rule gets a name that a correction can attach to, rather than a paragraph that corrections are appended to.",
                    "failureMode": "The same correction is made in three sessions, each time as a new paragraph, and the three paragraphs end up contradicting each other.",
                    "kind": "lesson",
                    "principle": "For this reason I keep behaviour as a set of named rules, so that a correction becomes permanent rather than being repeated.",
                    "problem": "Instructions written as prose have no fixed place for a correction to attach to.",
                    "validation": "To check this, take the last correction you gave the model and look for its name among the rules. If it has no name, you will have to give it again."
                  },
                  {
                    "kind": "text",
                    "text": "The shape of the line is the whole design. A name is a stable identity, so a rule can be cited from a digest, a memory, a finding or another party's message without quoting its text, and the citation survives any rewording; the names are the [ubiquitous language](/ontology#arch-ubiquitous-language) the developer, the model and the tooling share. A directive that fits on one line cannot hide a second instruction, so it reads as a single step. The gate field is the honest part: it names the check that enforces the rule, or it says that no artifact can show whether the rule held, and a rule that says neither has never been assessed. That field is written in exactly one place per rule, because a [single source of truth](/ontology#arch-single-source-of-truth) allows no second place to declare it. A rule without its reason gets argued over again, and a rule without its application gets admired and ignored, so the digest that expands a rule carries both; a digest is an [architecture decision record](/ontology#arch-architecture-decision-records) for one line of conduct."
                  },
                  {
                    "kind": "text",
                    "text": "The reason and the application are written in the developer's own sharpest words wherever there are any, because a paraphrase loses the distinction that made the correction necessary. For example, one wrong path becomes a rule about checking paths, and one missed reference becomes a rule about places that find files by pattern."
                  },
                  {
                    "kind": "text",
                    "text": "The rules are grouped into the ones that apply every turn and the ones that apply when a particular kind of task comes up, plus a small set of declared exceptions. That grouping helps the reader and means nothing to the checks. A check reads the gate field and never the heading, which is why a rule can move between groups without any mechanism noticing, and why a new rule is one added line rather than a new section."
                  },
                  {
                    "kind": "text",
                    "text": "Once parsed, a rule is a record, and that record is what the inventory, the coverage walk and the leak check all read; [coverage is derived](/disciplined-methodology/verify#coverage-is-derived) from that inventory rather than counted. The gate field has two allowed forms, a check or conduct, rather than being optional, so a rule that declares neither cannot be written down at all; the unassessed state is impossible rather than merely discouraged."
                  },
                  {
                    "code": "## <rules that bite every turn>\n\n- `read_before_claim`: a claim about a file is a lie until the file is read in this session · gate: conduct\n- `finding_not_principle`: the model is directed with a location and a mismatch, never with a principle · gate: conduct\n- `one_run_is_the_answer`: a check runs once per state and its first output is read whole · gate: conduct\n\n## <rules that fire on a matching task>\n\n- `rename_by_hand`: a move is done by hand, every reference enumerated before and verified after · gate: reference\n- `ask_at_the_uncertainty`: a question is raised where it appears, with a recommendation, before the dependent work · gate: conduct",
                    "kind": "code",
                    "language": "markdown",
                    "title": "a policy file"
                  },
                  {
                    "code": "export type Tier = \"always\" | \"situational\" | \"exception\";\nexport type Gate = { readonly kind: \"check\"; readonly id: GateId } | { readonly kind: \"conduct\" };\n\nexport interface RuleRecord {\n    readonly slug: string;\n    readonly directive: string;\n    readonly tier: Tier;\n    readonly gate: Gate;\n    readonly locked: boolean;\n    readonly source: DocumentId;\n}\n\nexport interface Digest {\n    readonly slug: RuleRecord[\"slug\"];\n    readonly why: string;\n    readonly how: string;\n    readonly measured?: { readonly shape: string; readonly presents: string };\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a rule record"
                  },
                  {
                    "caption": "a correction hardens",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    correction[\"A correction arrives\"]\n    classify[\"Classified to one encoding\"]\n    rule[\"One line · slug, directive, gate\"]\n    reason[\"Its reason · why it exists\"]\n    application[\"Its application · how it applies\"]\n    memory[\"A memory file · the fact, its why, its how\"]\n    search[\"Verified by search, never by recollection\"]\n    correction --> classify --> rule --> reason --> application --> memory --> search\n    rule -. the class, never the instance .-> rule"
                  }
                ],
                "title": "A correction lands on a name"
              }
            ],
            "title": "Rules with names"
          },
          {
            "icon": "bi-file-earmark-text",
            "id": "a-seat-is-a-contract",
            "intro": "A seat is a party's role in a collaboration, and it is defined by a contract, never by a character. A seat applies [design by contract](/ontology#arch-design-by-contract) to a party: the contract is a role document with the same sections for every seat, as shown in [a role document]. It names what the seat owns, what it refuses, how it works, the principles that decide its calls and the mistakes it tends to make.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a role is a short document with the same sections every time, and it names the mistakes that seat is known to make beside what it owns. The seat's output is checked against the contract, never against its tone. The seat's identity stays out of the filename, so that handing a role over changes a field rather than a path.",
                    "boundary": "A measured mistake is evidence and is kept in one place: it leaves a role document only by being moved to the [one home](/disciplined-methodology/build#one-home) history has. A mistake that is only expected never replaces one that was measured.",
                    "cause": "A character is judged by how it sounds, and sounding right comes easily to a model even when the work underneath is wrong.",
                    "decision": "A seat is defined by its contract rather than by its character.",
                    "failureMode": "The persona keeps its voice through the whole session and still drifts as much as a session with no persona at all.",
                    "kind": "lesson",
                    "principle": "For this reason I get [consistency](/ontology#arch-consistency) from checks rather than from roleplay.",
                    "problem": "A persona gives a model a voice, and a voice is not a behaviour.",
                    "validation": "To check this, strip the voice from a session's output and check what remains against the contract. Whatever the voice was hiding becomes visible."
                  },
                  {
                    "kind": "text",
                    "text": "A uniform shape is what makes a set of seats comparable. A reader looking for what a seat refuses finds it in the same place in every document; otherwise the documents are just prose filed together. The set of sections is the contract, and the declared fields are what a tool reads: the identity, the concern the seat holds, and the one line another seat uses to route work to it. The seat's identity is allocated and recorded before its first write, for the reasons [coordination is software](/disciplined-methodology/collaborate#coordination-is-software) gives."
                  },
                  {
                    "kind": "text",
                    "text": "The section that matters most is the one about what the seat gets wrong. A reviewer that approves a change because it reads well, a builder that reviews the description instead of the diff, and a coordinator that routes work a single edit would have closed are all measured mistakes. A seat is given its own document before its first edit so that it can avoid repeating them. A contract without that section is a job description, and a job description does not constrain the seat at all."
                  },
                  {
                    "code": "# Reviewer\n\n## <identity>\nThe seat's identity, bound in the index before its first write.\n\n## <what it owns>\nThe list of findings, and nothing else.\n\n## <what finished means>\nA change ships only once the list is empty.\n\n## <how it works>\nOne finding per line: file, line, expected, found. No style comments, no rewrites.\n\n## <the shapes it gets wrong>\nAffirming a change that reads well. Reviewing the description instead of the diff.\n\n## <what decides its calls>\nA finding without a location is an opinion. Approval is what remains when the list is empty.",
                    "kind": "code",
                    "language": "markdown",
                    "title": "a role document"
                  }
                ],
                "title": "Contract over character"
              }
            ],
            "title": "A seat is a contract"
          },
          {
            "icon": "bi-journal-code",
            "id": "the-behaviour-document",
            "intro": "The behaviour policy is the system prompt of the collaboration, whatever file name the harness uses for it. It is the one document delivered to every session at startup, so it carries what has to be in force before the model knows what task it is on, and it points to everything else. The order of its parts is shown in [a behaviour document] and [delivery order]. It is written the same way for any harness and any model, because nothing in it names a tool: it names operations and slots, and a single binding says which tool performs each one, which applies [platform independence](/ontology#arch-platform-independence) to a prompt, as shown in [one binding per harness]. What each kind of reader receives is shown in [reader classes]. The document is the behavioural form among the [three encodings](/disciplined-methodology#three-encodings), and [document structure](/pag/guide#document-structure) on the grammar page applies the same rule to a single document: declare first, then instruct.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, it opens with [the stance](/disciplined-methodology#the-stance) and the hard prohibitions, because those apply before the task is known. Next comes what to read first and in which order, then the rules that apply every turn, then the ones that apply to particular tasks, then the declared exceptions. How the work is verified, how the tree is inspected and what the tree contains come after the rules, because each of them assumes a task. Anything that needs more room is moved into a digest the document points to. No tool is named anywhere: the document names the operation, and the binding decides which tool performs it.",
                    "boundary": "The document is delivered once to each reader, so a change to it does not reach a session that is already running. A rule edited mid-session reaches only the parties that start afterwards, which is why a governing change is also sent as a message to the parties already running, since messages reach them every round and the file does not.",
                    "cause": "A document delivered in one piece has no structure that marks what must be in force from the start and what can be looked up later, so every line competes for the same attention and the order is simply the order it was written in.",
                    "decision": "The document is arranged by precedence and kept free of anything specific to one harness, rather than grown in the order rules happened to arrive.",
                    "failureMode": "The document grows by appending, every session opens on a wall of prose, the first rules get attention and the last ones barely any, and the same correction is added a fourth time at the bottom.",
                    "kind": "lesson",
                    "principle": "For this reason I give the behaviour document a deliberate composition: what must be in force from the start comes first, the delivery order follows the order of precedence, and anything that only matters once the task is known is referred to rather than included.",
                    "problem": "A prompt written as one long instruction document is delivered once at startup to a model that will lose track of most of it, and nothing in its shape says which parts matter most.",
                    "validation": "To check this, rename the file to what another harness expects and give it to a different model. Where it breaks, a tool name or a path has leaked into a place that should hold a slot; where it holds, the composition has transferred."
                  },
                  {
                    "code": "# <the stance and the hard prohibitions>\n\nA claim about the tree is unverified until the tree is read. Review is adversarial by default. Every manual step is a failure of automation. A document states what is true now.\n\n# <what governs what, and the precedence>\n\nThe behaviour policy governs the agent. The codebase contract governs the code. A digest expands one rule and declares nothing. The tree outranks all of them, and a document that disagrees with the tree is corrected the same turn.\n\n# <what is read first>\n\nA blocker outranks everything and is read first. Then the board, whole. Then the seat's own role. Then the document whose domain the task enters.\n\n# <rules that bite every turn>\n\n- `read_before_claim`: a claim about a file is a lie until the file is read in this session · gate: conduct\n\n# <rules that fire on a matching task>\n\n- `rename_by_hand`: a move is done by hand, every reference enumerated before and verified after · gate: reference\n\n# <declared exceptions>\n\n- `question_is_blocked`: a pending question is a blocked state, never a third verdict\n\n# <how the work is verified>\n\nOne command runs every stage in order. It runs once per state, and its first output is read whole.\n\n# <the layers>\n\n<layer>: what it holds and what authority it carries, one line each.",
                    "kind": "code",
                    "language": "markdown",
                    "title": "a behaviour document"
                  }
                ],
                "title": "A system prompt with a composition"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "One question decides where a part of the document goes. If it tells the model how to find out what it is doing, it belongs at the top, in the order it applies. If it tells the model what to do once it knows, it goes further down or into a digest the top points to. How often a rule applies is a poor guide: a rule that applies every hour but assumes a known task can safely be referred to, while a rule that applies once a month but decides which document to open belongs at the top."
                  },
                  {
                    "caption": "delivery order",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph resident[\"Resident · in force before the task is known\"]\n        axiom[\"The axiom · the stance, the readings, the hard prohibitions\"]\n        set[\"The document set · what governs what, and the precedence\"]\n        startup[\"Startup · what is read first, and in which order\"]\n        always[\"Rules that bite every turn\"]\n    end\n    subgraph referenced[\"Referenced · presupposes a known task\"]\n        situational[\"Rules that fire on a matching task\"]\n        exceptions[\"Declared exceptions\"]\n        verify[\"How the work is verified · one chain\"]\n        tooling[\"How the tree is looked at\"]\n        notes[\"What the tree is\"]\n        digests[\"Digests · one concern each, expanding a rule\"]\n    end\n    test{\"Does it tell you how to find out what you are doing?\"}\n    test -- yes --> resident\n    test -- no --> referenced\n    axiom --> set --> startup --> always\n    situational --> exceptions --> verify --> tooling --> notes\n    resident -- delivery order --> referenced\n    situational -. needs room .-> digests"
                  }
                ],
                "title": "Resident, then referenced"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The document is a claim like any other, and the stance applies to it: the model is asked to re-read it whenever it enters the context, because a version held in memory is only a memory, and it gives way to the tree in the order three encodings sets out."
                  },
                  {
                    "kind": "text",
                    "text": "It states what is true now and never what used to be, as [derived state](/disciplined-methodology/verify#derived-state) requires of every document. Copying a sentence from one document into another is how a dead reference spreads, so each fact has a [single source of truth](/ontology#arch-single-source-of-truth) and the other documents point to it, which [documentation is code](/disciplined-methodology/verify#documentation-is-code) turns into a check. The whole set of documents is validated, each kind against its declared shape, and a document that does not match its shape fails before it is delivered."
                  }
                ],
                "title": "The document is a claim"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Portability](/ontology#arch-portability) follows from what the document is allowed to say. It states what to do as [semantic operations](/pag/guide#tool-invocation), such as discovering resources, reading a resource, searching content, analysing, running a tool, saving an artifact and reporting a result, the same rule stated under semantic operations on the grammar page. It states where things are as slots, such as the gate, the rule host, the test root and the depth cap. One binding per harness maps each operation to that harness's tool and each slot to that tree's value, which is [configuration externalization](/ontology#arch-configuration-externalization) applied to a prompt. Moving the document to a harness that expects a different file name therefore takes a rename and one binding, and the rules do not change. The model is deliberately left as an empty slot, because choosing the model belongs to the harness, and a value written into that slot would have no source."
                  },
                  {
                    "kind": "text",
                    "text": "A set of rules meant for use in other projects is written as a block that a host project copies into its own document, rather than merging it. Where the host's rule and the block's rule collide on the same thing, the host's rule wins, and the collision is treated as a finding rather than a negotiation. Every path in the block is relative to one value the adopting project sets, and the only literal path that remains is the import a runtime resolves, because a runtime reading a path has no binding to consult."
                  },
                  {
                    "caption": "one binding per harness",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    policy[\"The behaviour document\"]\n    operations[\"Semantic operations · discover, read, search, analyse, execute, persist, report\"]\n    slots[\"Slots · the gate, the rule host, the test root, the depth cap\"]\n    binding[\"One binding per harness\"]\n    toolsA[\"Harness A · its tools, its file name\"]\n    toolsB[\"Harness B · its tools, its file name\"]\n    model[\"The model · an absent slot by construction\"]\n    policy --> operations --> binding\n    policy --> slots --> binding\n    binding --> toolsA\n    binding --> toolsB\n    policy -. names nothing about .-> model"
                  }
                ],
                "title": "Operations and slots"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Who receives the document decides which of its rules apply, and the document states which kind of reader each rule applies to, rather than leaving the reader to decide; [coordination is software](/disciplined-methodology/collaborate#coordination-is-software) explains where the two kinds of reader come from. The single line a bounded reader receives is updated in the same change as the fact it carries and kept under a size limit, because a summary that keeps growing under an update rule with no stated limit turns into the document's own clutter."
                  },
                  {
                    "caption": "reader classes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    doc[\"The behaviour document · delivered once, at startup\"]\n    seat[\"A seat\"]\n    bounded[\"A bounded invocation\"]\n    board[\"The board · delivered whole every round\"]\n    line[\"One projection line · the only board it ever sees\"]\n    invert[\"Turn-owning rules invert · returning is its contract\"]\n    routed[\"A change to the document is routed to the running parties\"]\n    doc --> seat --> board\n    doc --> bounded --> line\n    bounded --> invert\n    doc -. an edit mid-session does not reach running parties .-> routed"
                  }
                ],
                "title": "Who receives it"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The document grows only in the shape [rules with names](/disciplined-methodology#rules-with-names) describes, and when a rule has had to be stated twice for the same kind of problem, it becomes a check that the line points to."
                  },
                  {
                    "kind": "text",
                    "text": "The document repeats nothing the codebase contract owns, and the contract repeats nothing the document owns; a reader who finds the same fact in both has found a copy that neither the developer nor the model maintains."
                  }
                ],
                "title": "How it grows"
              }
            ],
            "title": "The behaviour document"
          },
          {
            "icon": "bi-box-arrow-in-down",
            "id": "onboarding",
            "intro": "Setting up the method in a new project means applying a template to one file of project details, not rebuilding the rules in a conversation. The whole governance set is a folder that names no project, plus one file that does, as shown in [a drop-in]. Adopting it means copying the folder and writing that one file, the binding shown in [a binding], in which every fact about the host project is a slot in one of the three states shown in [slot states]. The gate is then green on an empty tree before the first line of code exists. All of this rests on one separation: the thinking is kept apart from the tools, which applies [platform independence](/ontology#arch-platform-independence) to a method and [configuration externalization](/ontology#arch-configuration-externalization) to its facts. The folder is generated from the [template families](/pag/templates#templates-families) the grammar page publishes.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the reasoning stays in core documents that name no project, and the bindings stay in one adapter that fills every slot the cores leave open. A slot that nothing can fill is declared absent in the adapter, rather than left for a core to assume, and the part of the method that depends on it does not run. The set is proven on an empty tree first: a gate that is red before any code exists is reporting a problem with the binding, and a gate that is green there becomes the baseline every later failure is measured against.",
                    "boundary": "A catalogue inside a core document, such as a list of principles, patterns or examples, may assume things this project does not have. The mechanism carries over unchanged, and the catalogue is worked out again against what exists here. Replacing the mechanism would be the mistake; working out the catalogue again is the work.",
                    "cause": "A core document that names a path is tied to the project that has that path, so the next project has to edit the core.",
                    "decision": "The method moves to a new project by rewriting one adapter, rather than by editing the core documents.",
                    "failureMode": "Every new project starts with a long conversation that rebuilds rules which already exist somewhere else, and rebuilds them slightly wrong.",
                    "kind": "lesson",
                    "principle": "For this reason the core documents name no project, a single adapter binds them to one, and every missing piece is declared rather than patched over.",
                    "problem": "A method written in one project's vocabulary does not carry over to the next project.",
                    "validation": "To check this, apply the set to an empty project. A red gate there points to a binding the adapter did not make. A green gate proves the binding and nothing more, because a check over an empty tree measures nothing."
                  },
                  {
                    "caption": "a drop-in",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph governance[\"The governance folder · copied whole, never edited for a feature\"]\n        policy[\"The behaviour policy · named rules given to the model first\"]\n        checks[\"The checks · one file per rule, each proven to fire\"]\n        cores[\"The cores · reasoning that names no project\"]\n        binding[\"The binding · the one file that names this tree\"]\n    end\n    code[\"The code · shaped by the grammar the checks parse\"]\n    command[\"The one command · every check, fixer, generator and validator\"]\n    binding -. resolves every slot the cores name .-> cores\n    checks -. parse .-> code\n    command --> checks\n    policy -. governs .-> code"
                  }
                ],
                "title": "A template applied to a binding"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A core is a document that says what to do in terms of [semantic operations](/pag/guide#tool-invocation) and slots, the same shape [the behaviour document](/disciplined-methodology#the-behaviour-document) has. It never names the tool that searches or the folder that holds the tests, because as soon as it does, it is tied to one project and the next project has to edit it. The adapter is the one file where those names live, and it is the only file rewritten when the set moves to another project."
                  },
                  {
                    "kind": "text",
                    "text": "A slot is always in one of three states, and the third is the one that matters most. Resolved means this project has the thing, and its value is in the adapter. Absent means this project has nothing that corresponds to it, so the part of the method that depends on it does not run, and that is declared rather than faked. Deferred means the thing will exist but does not yet, so the dependent part is blocked rather than skipped, which answers a different question in the right way. An adapter in which every slot is resolved is hiding something. The checks this project does not have, such as a computed measure of worth, a detector for work that stops making progress and a calibrated confidence, are declared absent in the adapter so that nothing assumes them; [the honest gaps](/disciplined-methodology/ship#the-honest-gaps) lists them, and the architecture page arrives at [the same declared absences](/software-architecture/coverage#the-honest-gaps) because an architecture is its predicate set."
                  },
                  {
                    "caption": "slot states",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    core[\"A core names a slot\"]\n    binding{\"What does the binding say?\"}\n    resolved[\"Resolved · the branch runs against this tree's value\"]\n    absent[\"Absent · the branch does not run, and says so\"]\n    deferred[\"Deferred · the branch is blocked until the value exists\"]\n    faked[\"Nothing declared · the branch runs against a guess\"]\n    core --> binding\n    binding -- a value --> resolved\n    binding -- declared absent --> absent\n    binding -- declared deferred --> deferred\n    binding -. no declaration .-> faked"
                  }
                ],
                "title": "Cores, one adapter, three slot states"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The template that generates the set keeps the mechanism and rewrites the content. A fact that would be wrong in the next project is turned into a slot. A statement written for one domain that holds for the whole kind is generalised to the kind. A mechanism that must know nothing about what it governs is made project-neutral. The generator then fills in the one binding and checks it in both directions, that every slot the cores name is bound and that every binding names a slot. It installs the set, runs the gate, and removes itself before the gate approves the tree. A generated project is therefore green when it arrives, with no edits by hand, and that is why every manual step in setting up a project counts as a [manual runbook dependency](/ontology#arch-manual-runbook-dependency) rather than a chore."
                  },
                  {
                    "kind": "text",
                    "text": "The checks read their contracts from the same templates the surfaces are created from, so there is a [single source of truth](/ontology#arch-single-source-of-truth) that the check reads while it runs. A check that copied a schema into itself would hold a second copy with nothing keeping the two the same, and the drift would only show when the developer or the model created a new surface and it failed on its first run, wrong from the start because it followed a template that looked authoritative."
                  }
                ],
                "title": "The generator removes itself"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The binding is a typed module rather than a written page, and its readable version is generated from the module, so the two cannot disagree, which is what [self-describing architecture](/ontology#arch-self-describing-architecture) means for a binding. A slot is one record with three fields: a state from a fixed set, a value that is empty unless the state is resolved, and a note explaining why. A reader therefore sees the reason next to the value, and a mechanism sees the state before the value. The three constructors are the only way to create a slot, which is what stops a resolved slot from having no value and an absent slot from carrying an old one."
                  },
                  {
                    "kind": "text",
                    "text": "Slots are grouped by who supplies them: what the host project supplies, what the package owns, the conventions, the limits and the commands that run things. A count of slots in each state is worked out when the page is rendered, so it cannot disagree with the table above it, and a binding whose count shows every slot resolved is the one to distrust."
                  },
                  {
                    "code": "export type SlotState = \"RESOLVED\" | \"ABSENT\" | \"DEFERRED\";\nexport type SlotValue = string | number | readonly string[] | null;\n\nexport interface Slot {\n    readonly state: SlotState;\n    readonly value: SlotValue;\n    readonly note: string;\n}\n\nexport const resolved = (value: Exclude<SlotValue, null>, note: string): Slot => ({ state: \"RESOLVED\", value, note });\nexport const absent = (note: string): Slot => ({ state: \"ABSENT\", value: null, note });\nexport const deferred = (note: string): Slot => ({ state: \"DEFERRED\", value: null, note });\n\nexport interface Binding {\n    readonly project: Readonly<Record<string, Slot>>;\n    readonly surface: Readonly<Record<string, Slot>>;\n    readonly convention: Readonly<Record<string, Slot>>;\n    readonly limits: Readonly<Record<string, Slot>>;\n    readonly execution: Readonly<Record<string, Slot>>;\n}\n\nexport const binding: Binding = {\n    project: {\n        root: resolved(\"<host-root>\", \"the host root relative to this package, the one value an adopter sets\"),\n        policy_projection: absent(\"the host has not adopted the package, so no projection is written into its document\"),\n        rollback_point: deferred(\"a reversible checkpoint will exist once the host is under version control\"),\n    },\n    surface: { board: resolved(\"<board-file>\", \"the coordination board\") },\n    convention: { nesting_cap: resolved(\"<depth>\", \"the placement depth cap from a governed root\") },\n    limits: { file_cap: absent(\"no per-file cap; a host that wants one holds it in its own linter\") },\n    execution: { compile: absent(\"nothing here compiles\") },\n};",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a binding"
                  }
                ],
                "title": "The binding as a module"
              }
            ],
            "title": "The drop-in"
          }
        ]
      },
      {
        "icon": "bi-kanban",
        "id": "plan",
        "label": "Plan",
        "sections": [
          {
            "icon": "bi-cash-coin",
            "id": "worth-before-work",
            "intro": "Before any work starts, one gate decides whether it starts at all. It asks three questions, as shown in [the worth gate]: what the work is for, what finished looks like, and whether this is the most worthwhile of the approaches that are allowed. This gate is the [intent](/ontology/reasoning#stage-intent) node of [the loop](/disciplined-methodology#the-loop), and on the ontology page it rests on four records: an [objective](/ontology/reasoning#reason-node-tel-objective), a [utility](/ontology/reasoning#reason-node-tel-utility), a [cost](/ontology/reasoning#reason-node-tel-cost) and a [priority](/ontology/reasoning#reason-node-tel-priority). A task that cannot answer these questions is not ready to be a task.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the objective is written in one sentence before the first step, worded so the result can be checked against it. What is out of scope is written beside it, because scope that is never stated grows quietly. Each approach is weighed by what it achieves against what it costs, the reason the chosen one won is written down, and only then does planning begin.",
                    "boundary": "Worth is not computed anywhere in this method: no tool weighs utility against cost across the approaches for you. The gate is a judgement I make and write down, and saying so openly is what stops it from being mistaken for a mechanism.",
                    "cause": "Starting is cheaper than deciding, and a model tends to start as soon as you let it.",
                    "decision": "The approaches that are allowed are ranked before any effort is spent, rather than the first workable one being taken.",
                    "failureMode": "Three days into a refactor, the question of whether the refactor was needed comes up for the first time.",
                    "kind": "lesson",
                    "principle": "For this reason worth is decided before any work begins, and what the work will not do is stated as plainly as what it will.",
                    "problem": "Work that skips the question of worth can be done well and still turn out to be unnecessary.",
                    "validation": "To check this, read the objective again once the work is done. The result should be the thing the sentence named; a result that needs a new sentence to describe it answered a different question."
                  },
                  {
                    "kind": "text",
                    "text": "The gate has a particular shape, and the shape is what makes it hold. The intent node produces an objective and a ranking, never a simple yes. A ranking needs more than one option, so a plan with only one option has not ranked anything and has not passed the gate. Each option records what it achieves and what it costs, and the chosen one is the option where that difference is largest among those that are allowed at all. An option that would cross a hard limit is not a worse option; it is not an option. Whether a change is allowed is asked again at the [constrain](/ontology/reasoning#stage-constrain) node once the work exists, because a plan that looked acceptable on paper can still produce a change that is not. [When rules collide](/disciplined-methodology/plan#when-rules-collide) applies the same gate to two rules that meet on one piece of code."
                  },
                  {
                    "kind": "text",
                    "text": "Stating what the work will not do often matters more than stating what it will. The stated scope of a unit is what its author intended, and its unstated scope is whatever collects around it because nothing ruled it out; the ontology calls that [speculative generality](/ontology#arch-speculative-generality). Writing down the nearest thing the change will not do is what lets the next reader turn down the addition that would have made a focused unit into a [god object](/ontology#arch-god-object). The same test applies to every surface, record or field a plan proposes: it has to name something that would break without it, not merely something that would read it, and an addition that breaks nothing either way is the problem."
                  },
                  {
                    "kind": "text",
                    "text": "The same task reads differently once worth has been decided. Without it: *clean up the config and the checker, they have gotten messy*. With it: *objective, one limit with [one home](/disciplined-methodology/build#one-home); not in scope, the checker's other options; chosen, derive it from the config, because the two other homes cannot be deleted otherwise*. The second version can be finished. The first cannot."
                  },
                  {
                    "caption": "the worth gate",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    request[\"A request\"]\n    objective[\"The objective · one sentence the result is checked against\"]\n    nongoal[\"The non-goal · the nearest thing this will not do\"]\n    branches[\"The allowed approaches\"]\n    rank{\"Highest worth · utility minus cost?\"}\n    chosen[\"The chosen approach, and why the others lost\"]\n    stop[\"Below worth · redirect or stop\"]\n    request --> objective --> nongoal --> branches --> rank\n    rank -- yes --> chosen\n    rank -- no --> stop"
                  }
                ],
                "title": "What is this for"
              }
            ],
            "title": "Worth before work"
          },
          {
            "icon": "bi-list-check",
            "id": "the-flat-checklist",
            "intro": "When you ask a model for a plan, it usually comes back as a flat list of about ten items, in no order that matters, with no gate between them, and with a checkbox after each one that the model ticks itself. In this method a plan is a [directed acyclic graph](/ontology#arch-directed-acyclic-graph) instead. Its phases pass evidence to each other, its tasks carry contracts, and a finished task is deleted rather than ticked, as [list against graph] shows. The architecture page claims that [a system is a graph](/software-architecture#a-system-is-a-graph), and this section applies the same claim to the work done on the code.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the phases are ordered by what depends on what, and within that by what has to exist before something else can be built on it. A gate between two phases names the evidence the next phase reads before it starts. Every task has a contract with four parts: the file it touches, the evidence that proves it, the verifier that reads that evidence, and the thing it deliberately leaves alone. Severity decides which handler a failure goes to, and never the order of the list.",
                    "boundary": "Priority and sprint are labels on a phase. They help decide where attention goes, but they never become the plan's structure, because a plan ordered by urgency hides its dependencies.",
                    "cause": "A flat list is the cheapest structure to write and the cheapest to tick, which is why the model and the developer both reach for it.",
                    "decision": "A plan with no dependency order and no gates is sent back rather than started.",
                    "failureMode": "Item four depends on item seven, but the model works through them in list order, and the plan reaches the end with three items quietly left undone.",
                    "kind": "lesson",
                    "principle": "For this reason I treat a plan as a set of phases with gates between them, not as a list of tasks.",
                    "problem": "A task turned straight into a flat checklist has no order and no gates, so the ticks on it say nothing about whether the work is done.",
                    "validation": "To check this, ask what each phase needs from the one before it. A phase that needs nothing from its predecessor is either in the wrong place or in the wrong plan."
                  },
                  {
                    "kind": "text",
                    "text": "The two orderings in that practice are dependency and genesis, applied in that sequence. Under dependency, a phase comes after every phase whose output it reads. Genesis is the order in which things come into being: a thing exists, it is told apart from other things, it is related to them, it is structured, it is transformed, and it is constrained. A phase should never depend on something that comes later in that order than what it produces. A plan that builds a transformation on a structure that does not exist yet is inverted, and that is a fault in the decomposition, not a tie to settle."
                  },
                  {
                    "kind": "text",
                    "text": "[Impact analysis](/ontology#arch-impact-analysis) records names, never counts. A row saying three files are affected gives the reader nothing to act on, while the three file names do. When a dimension has no impact, the row records the evidence that it was checked and found empty, because a blank cell looks the same whether it was checked or skipped, and only the checked one is safe. Every task has a unique id, and every mention of an id has to point to a task that exists, so a dependency note cannot keep pointing at a deleted task while still looking current."
                  },
                  {
                    "kind": "text",
                    "text": "The plan holds what is true now and what is left to do, and nothing else. It holds no findings about defects already fixed, no account of how the plan came about, no inventory of what already exists, and no finished task kept in place with a note. A finished task is deleted, which keeps the remaining tasks equal to the remaining work, and past work left on a checklist invites doing it a second time. The [planning templates](/pag/templates#templates-planning) on the grammar page are built in stages and trimmed by deletion for the same reason. A count written into the plan is written state that goes stale, as [derived state](/disciplined-methodology/verify#derived-state) explains."
                  },
                  {
                    "caption": "list against graph",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph flat[\"The flat list\"]\n        direction TB\n        f1[\"item, in the order it came to mind\"] --> f2[\"item\"] --> f3[\"item\"] --> f4[\"item\"]\n        f4 --> ticked[\"done when every box is ticked\"]\n    end\n    subgraph graph[\"The graph\"]\n        direction TB\n        p1[\"phase 1\"] -- gate: the evidence phase 2 reads --> p2[\"phase 2\"]\n        p1 -- gate --> p3[\"phase 3\"]\n        p2 -- gate --> p4[\"phase 4\"]\n        p3 -- gate --> p4\n        p4 --> objective[\"done when the objective sentence reads true against the tree\"]\n    end"
                  }
                ],
                "title": "The list that ticks itself"
              }
            ],
            "title": "The plan is a graph"
          },
          {
            "icon": "bi-layout-text-sidebar",
            "id": "execute-the-template",
            "intro": "A plan in this method is produced by running a template against the task, as shown in [draft, compare, restructure], rather than by writing a document that copies the template's headings. The template works like a program. It walks the ten nodes of [the loop](/disciplined-methodology#the-loop) and asks its questions in a fixed order, from worth through admissibility and evidence to termination, and it produces the artifact the loop ends on. Each node is typed as shown in [a node contract], and the resulting plan has the shape shown in [a plan's shape]. There is one template for each genesis question, as shown in [one per question]. The grammar page publishes the [template families](/pag/templates#templates-families) used here, and [core templates](/pag/templates#templates-core) states the rule they all follow: a template carries the contract, never the content.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the first plan is drafted from the task and then compared with the template node by node and gate by gate, with the draft treated as raw material for the restructure. Only current and future work stays in the result, and a task is deleted as soon as it is finished.",
                    "boundary": "The full loop applies only to an artifact that is executed. A reference, a specification, a contract or a note describes something rather than runs, and forcing the loop onto it fits it to a shape it does not have.",
                    "cause": "This happens because a template copied for its shape gives the look of rigour without any of its questions being answered.",
                    "decision": "When the draft and the template disagree, the draft is restructured to fit the template rather than defended.",
                    "failureMode": "It can have every right heading and none of the right answers, and the reader still trusts it because of the headings.",
                    "kind": "lesson",
                    "principle": "For this reason, when a shape recurs I turn it into a template, and I run the template as a procedure rather than copying it.",
                    "problem": "A plan that copies a template's headings gets none of the guarantees the template was written to give.",
                    "validation": "To check this, read the plan for its answers rather than its headings, and ask of each heading whether the decision under it could have gone the other way."
                  },
                  {
                    "kind": "text",
                    "text": "The restructure adds what the draft is missing: the ranking asked for in [worth before work](/disciplined-methodology/plan#worth-before-work), the ordering asked for in [the plan is a graph](/disciplined-methodology/plan#the-flat-checklist), an evidence contract on every material claim, and explicit termination. Each evidence contract names what would refute the claim and carries a confidence at or above the threshold, and finding no contradiction does not count as support. Termination requires saturation, completion and [verification](/ontology#arch-verification) together, so a feeling that the work is finished does not end it."
                  },
                  {
                    "kind": "text",
                    "text": "Each template answers one genesis question, and a template is chosen by the question the work raises. The question of how anything comes to be leads to a plan, a checklist or a task set. How a verdict comes to be leads to an audit or a context check, and how a base [abstraction](/ontology#arch-abstraction) comes to be leads to a shared pattern drawn from repeated evidence. How an agent comes to be leads to a reusable investigator, built from the [agent templates](/pag/templates#templates-agents) on the grammar page. How a template comes to be leads to a template drawn from a document that has already been executed. When two templates could apply, the artifact the work ends on decides between them, and when none applies, I say so rather than force one to fit."
                  },
                  {
                    "kind": "text",
                    "text": "The time to write a template is when a shape appears for the second time. A single instance is only an artifact, but a second one makes a shape, and unless the second is written from a template, the shape ends up written twice. When the developer or the model reads a sibling file to learn the format, they pick up that sibling's accidents as though they were rules. The template therefore carries the constraint and never the content of one instance, and the checks read their contracts from it, as described in [the drop-in](/disciplined-methodology#onboarding). Each template also spells out its whole structure. This is the one place where I duplicate on purpose, because the shared structure is what lets each template run on its own, and moving it into an import would take that away from all of them."
                  },
                  {
                    "kind": "text",
                    "text": "A template's loop, types and gates name no domain, so they carry over to any tree unchanged. Its catalogues are worked out again against what exists there, which is the rule the drop-in states for every core. I also keep the gates that run while an artifact is produced apart from the gates that run when it executes, because an artifact that passed its generation gates has not yet passed its execution gates."
                  },
                  {
                    "kind": "text",
                    "text": "Every node of a template carries the same contract, and that contract is what lets a template run as a program rather than be read as a document. A node declares its layer, the mathematical shape its decision yields, the input it reads, which is only the previous node's output, the transformation it applies, the constraints stated at that step, its output, and one handoff gate that carries evidence. The gate in turn names its checks and the evidence each one reads, the node it passes to, and the earliest node a failure is sent back to, with a limit on how far back that can be. Because the yields type is a discriminated union, a gate that owes a ranking cannot be satisfied by a boolean, and the compiler reports the mismatch. The four gates that can never be skipped are a closed subset of the node names rather than a convention the reader has to remember. As a result, a template can be checked by walking its own declarations, and a node without a gate, a gate without evidence, or a decision without a shape fails before anything runs."
                  },
                  {
                    "code": "export const LAYERS = [\"epistemic\", \"conative\", \"evaluative\"] as const;\nexport const NODES = [\"orient\", \"intent\", \"see\", \"derive\", \"project\", \"act\", \"constrain\", \"verify\", \"commit\", \"terminate\"] as const;\n\nexport type Yields =\n    | { readonly mathType: \"set-theory\"; readonly shape: \"set\" | \"boolean\" }\n    | { readonly mathType: \"logic\"; readonly shape: \"boolean\" }\n    | { readonly mathType: \"graph\"; readonly shape: \"edge-list\" }\n    | { readonly mathType: \"optimisation\"; readonly shape: \"boolean\" | \"ranking\" }\n    | { readonly mathType: \"probability\"; readonly shape: \"number[0,1]\" }\n    | { readonly mathType: \"computation\"; readonly shape: \"procedure\" };\n\nexport interface Gate<Node extends (typeof NODES)[number]> {\n    readonly rule: Node;\n    readonly checks: readonly { readonly claim: string; readonly evidence: string }[];\n    readonly onPass: Node | \"STOP\";\n    readonly onFail: { readonly owner: Node; readonly bounded: true };\n}\n\nexport interface NodeContract<Node extends (typeof NODES)[number], Input, Output> {\n    readonly node: Node;\n    readonly layer: (typeof LAYERS)[number];\n    readonly yields: Yields;\n    readonly input: Input;\n    readonly transform: (input: Input) => Output;\n    readonly constraints: readonly string[];\n    readonly output: Output;\n    readonly handoff: Gate<Node>;\n}\n\nexport type Mandatory = \"intent\" | \"constrain\" | \"verify\" | \"terminate\";",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a node contract"
                  },
                  {
                    "code": "# <what this change is for, in one sentence>\n\n## Worth\nObjective: the outcome, named so the result can be checked against it.\nNot in scope: the nearest things this change will not do.\nBranches ranked: the way chosen, and why the others lost.\n\n## Admissible\nHard limits: what no phase may cross, whatever it would gain.\nCost: what this is allowed to take, and the point past which it stops.\n\n## Phases, ordered by dependency\n### Phase 1: <name>\nNeeds: nothing.\nGate: the evidence Phase 2 reads before it starts.\n- [ ] task: <one change> — file: <where> — evidence: <what proves it> — verifier: <who reads it> — not: <what this task leaves alone>\n\n### Phase 2: <name>\nNeeds: the gate of Phase 1.\nGate: ...\n\n## Termination\nThe run stops when the objective sentence reads true against the tree, not when the list is ticked.",
                    "kind": "code",
                    "language": "markdown",
                    "title": "a plan's shape"
                  },
                  {
                    "caption": "draft, compare, restructure",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    draft[\"Draft · the first plan from the task\"]\n    compare[\"Compare · node by node, gate by gate, against the template\"]\n    restructure[\"Restructure · to what the template enforces\"]\n    plan[\"The plan · worth ranked, phases ordered, gates named, termination stated\"]\n    draft --> compare --> restructure --> plan\n    compare -. the draft is raw material, the template is the authority .-> draft"
                  },
                  {
                    "caption": "one per question",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    question{\"How does the thing come to be?\"}\n    checklist[\"A plan, a checklist, a task set\"]\n    claim[\"A verdict on claims, an audit\"]\n    pattern[\"A shared abstraction from repeated evidence\"]\n    agent[\"A reusable specialised investigator\"]\n    layer[\"A template from an executed document\"]\n    none[\"None fits · say so rather than force one\"]\n    question -- anything --> checklist\n    question -- a verdict --> claim\n    question -- a base --> pattern\n    question -- an agent --> agent\n    question -- a template --> layer\n    question -. no fit .-> none"
                  }
                ],
                "title": "Executed, not imitated"
              }
            ],
            "title": "Execute the template"
          },
          {
            "icon": "bi-chat-square-quote",
            "id": "ask-where-it-appears",
            "intro": "You decide what the work is for, as described in [worth before work](/disciplined-methodology/plan#worth-before-work), while the shape of the work is left to the model. When a question crosses from the model's side to yours, the model is asked to raise it at the point where it appears, before any work that depends on it, because a decision the model makes without asking is an assumption. [three fates] shows where an uncertainty can go.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the model is asked to raise an uncertainty as soon as it would change what gets built, with a recommendation placed first and its reasoning given, and with the other options as real alternatives whose cost is stated. While the answer is pending, the model is asked to do the parts that do not depend on it. When the model runs as a bounded agent with no channel back to you, it is asked instead to state the uncertainty and the assumption it took, name what would settle it, and return it as one of the [handoff signals](/pag/orchestration#handoff-signals) typed on the grammar page.",
                    "boundary": "A bounded task with a clear contract returns a result rather than a question, since questions are for decisions that belong to you, not for ones the contract has already made. A question about what the project is for is almost always yours, while a question about how something should be shaped rarely is.",
                    "cause": "Asking feels like slowing down, and the model and the developer both tend to prefer momentum to a pause.",
                    "decision": "The cost of the pause is paid at the uncertainty, rather than the cost of the rework after it.",
                    "failureMode": "The model guesses the missing decision, builds a day of work on the guess, and mentions the guess in a footnote at the end.",
                    "kind": "lesson",
                    "principle": "For this reason the model is asked to raise a question where it appears, and to state an assumption where it makes one.",
                    "problem": "A question that is never asked turns into an assumption, and the work then rests on a decision that neither you nor the model made on purpose, which the ontology calls [unowned risk](/ontology#arch-unowned-risk).",
                    "validation": "To check this, look at the questions the model raised in a session and where in the work each one landed. A question that arrived after the work depending on it was an assumption reported late."
                  },
                  {
                    "kind": "text",
                    "text": "Questions go through the harness's question tool, which has a fixed shape, and a question that does not go through the tool is treated as not asked. The reason is practical: a question in chat prose is easy to scroll past, while the tool presents it as a decision you can take in one read. Each call carries only a few questions, each with options you can hold in mind at once. The first option is the recommendation, and its description gives the reasoning as well as the choice. The other options are genuine alternatives that say what happens if chosen, including the cost. *It depends* does not count as an answer, and a weak recommendation is marked as weak, together with what would make it stronger."
                  },
                  {
                    "kind": "text",
                    "text": "The same uncertainty reads differently depending on when it is raised. Asked late, it reads *done, note that I assumed the second shape, let me know if you wanted the first*. Asked where it appears, it reads *two shapes fit here, I recommend the second because the first needs a second config, which one, and meanwhile I am doing the parts both share*. The first leaves you a day of work to undo, while the second leaves you a decision to make."
                  },
                  {
                    "caption": "three fates",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    appears[\"An uncertainty appears\"]\n    changes{\"Does the answer change what gets built?\"}\n    contract{\"Does the contract already decide it?\"}\n    seat{\"Is there a channel to ask?\"}\n    ask[\"Ask now, with a recommendation first\"]\n    state[\"State the assumption, name what would settle it, return\"]\n    shared[\"Do the parts every answer shares\"]\n    proceed[\"Return a result, no question\"]\n    assume[\"Assume, and the work rests on a guess\"]\n    appears --> changes\n    changes -- no --> proceed\n    changes -- yes --> contract\n    contract -- yes --> proceed\n    contract -- no --> seat\n    seat -- yes --> ask --> shared\n    seat -- no, a bounded run --> state\n    changes -. skipped .-> assume"
                  }
                ],
                "title": "The pause, not the rework"
              }
            ],
            "title": "Ask where it appears"
          },
          {
            "icon": "bi-intersect",
            "id": "when-rules-collide",
            "intro": "Sometimes two rules meet on one line of code and disagree. This method treats that as a boundary between two domains rather than as an exception, and the collision has one resolution, as shown in [one form].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the first step is to find the domain each rule serves, and the second is to find the form that satisfies both. The resolution is recorded once, at the place where the next collision of the same kind will be met, and one rule is never satisfied by breaking the other.",
                    "cause": "Two rules that collide come from two different domains, and the collision marks the line between them.",
                    "decision": "A tension is resolved in the architecture rather than by disabling one of the rules.",
                    "failureMode": "A rule is turned off for one file so that another rule can pass, and that file becomes the place where neither rule means anything any more.",
                    "kind": "lesson",
                    "principle": "For this reason, when two enforced rules apply to the same code, I look for the one form that satisfies both, and where the rules hold in different scopes, that form is the boundary between the scopes.",
                    "problem": "When two rules conflict, the tempting move is to switch one of them off.",
                    "validation": "To check this, search for every rule that you or the model switched off. Each one is either a resolved tension with its resolution written down, or an unresolved tension that is still hidden."
                  },
                  {
                    "kind": "text",
                    "text": "Two collisions from this site's own code show how this works. In the first, a rule that bans literal file paths meets a declaration file that has to spell out its own paths. The boundary lies between declaring a path and using one, and the one form is that the declaration file is the single exempt place while every consumer reads the path from it by key. In the second, a rule that every export needs a consumer meets a registry entry that has no consumer until a variant registers itself. The boundary lies between a capability and its use, and the one form is that the [registry pattern](/ontology#arch-registry-pattern) resolves variants by [auto-discovery](/ontology#arch-auto-discovery), so the variant file is the consumer."
                  },
                  {
                    "kind": "text",
                    "text": "The architecture page describes three ways to handle a tension, separating, trading or mitigating, and its principle [a tension has a mechanism](/software-architecture/principles#a-tension-has-a-mechanism) decides when a boundary is the answer and when a measured trade-off is. Both rules are right inside their own [bounded context](/ontology#arch-bounded-context), and the line of code sits where the two contexts touch, which is why [explicit boundaries](/ontology#arch-explicit-boundaries) are the first thing to name. Once the boundary is named, the answer carries over: the next collision on the same boundary has the same answer, while a collision on a different boundary is a different tension rather than a precedent."
                  },
                  {
                    "caption": "one form",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    a[\"Rule A\"]\n    b[\"Rule B\"]\n    line[\"One line of code\"]\n    boundary[\"The domain boundary\"]\n    form[\"The one form that satisfies both\"]\n    off[\"One rule switched off\"]\n    a --> line\n    b --> line\n    line --> boundary\n    boundary --> form\n    line -. the tempting move .-> off"
                  }
                ],
                "title": "A tension is a boundary"
              }
            ],
            "title": "When rules collide"
          }
        ]
      },
      {
        "icon": "bi-hammer",
        "id": "build",
        "label": "Build",
        "sections": [
          {
            "icon": "bi-bug",
            "id": "detect-log-fix",
            "intro": "Seen from outside, the work is one cycle, as shown in [the loop from outside]. The tools run with their fixers on and report what the fixers could not repair. The model then fixes what the report names, and the tools run again, until they report nothing. The cycle closes because the tools speak to the model in a typed format, the finding shown in [an actionable finding], and because the report on disk holds the state of the work rather than the output of a single run. The architecture page arrives at the same contract from the author's side: because [the author is probabilistic](/software-architecture/scale#the-author-is-probabilistic), a finding is the contract between the check and the model.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the model is given the finding rather than the rule: which file, which line, what the tool expected, what it found, and the one action that would close it. It is asked to repair that and nothing else, and the tools run again once the tree has changed.",
                    "boundary": "A finding whose only repair the toolchain refuses to perform is withdrawn or exempted, with that refusal given as the reason. A report that can never be emptied teaches you and the model to discount its colour, and the findings beside it pay for that.",
                    "cause": "A principle has to be turned into an action again at every line, and the model is likely to turn it into a different action each time.",
                    "decision": "The effort goes into the check that produces findings, rather than into the explanation that produces agreement.",
                    "failureMode": "You explain the architecture at length, the model agrees, and the next file it writes breaks it in a way the explanation did not anticipate.",
                    "kind": "lesson",
                    "principle": "For this reason I give the model specific findings rather than abstract principles, because a model refactoring against a finding tends to do better than a model generating from a principle.",
                    "problem": "Telling the model about your principles and hoping for [compliance](/ontology#arch-compliance) does not hold across a session.",
                    "validation": "To check this, compare a session driven by findings with one driven by explanation, and count the fixes that stuck. The findings session should keep more of them; if it does not, the findings are not specific enough."
                  },
                  {
                    "kind": "text",
                    "text": "Healing comes before reporting, and the ontology calls this [auto-remediation](/ontology#arch-auto-remediation). A violation whose repair has exactly [one correct answer](/disciplined-methodology/verify#one-correct-answer) is repaired in the same run that caught it, without the developer or the model asking: a missing type the grammar computes, a form the registry records, or a name whose only legal spelling can be derived. The fix flag can switch healing off but never on, because a fix that has to be opted into turns a computed repair into a queue of work. A fix is applied, validated again and converges, so applying it twice changes nothing, which is [idempotency](/ontology#arch-idempotency); a fix that fails its own check is not a fix. What reaches the model is what remains: the findings that need judgement, such as which concern a file belongs to, whether two roles should be split, or where a duplicated fact should live."
                  },
                  {
                    "kind": "text",
                    "text": "The error log is how the tools talk to the model, so it is typed. A finding carries the id of the check that fired, the path and the position inside the file, the steps the check took to reach its result, the value it found, the value it expected where one can be derived, a repair stated as an action with real operands, and whether the fixer already applied it. Prose in a finding counts as a defect, because the model reading it should not have to repeat the analysis the check already did. A sentence describing a rename is only a description, while the action and its two operands are a contract the model can carry out."
                  },
                  {
                    "kind": "text",
                    "text": "Because every run leaves its report on disk, the reports also serve as [audit logging](/ontology#arch-audit-logging): you can go back and read what each run found, as described in [a report, not a checkbox](/disciplined-methodology/verify#a-report-not-a-checkbox)."
                  },
                  {
                    "caption": "the loop from outside",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    detect[\"Detect · the one command, fixers on\"]\n    heal[\"Heal · every finding with one correct answer, in the same run\"]\n    report[\"Report · the findings the fixers left, as data on disk\"]\n    fix[\"Fix · the model, one finding at a time, from the report\"]\n    detect --> heal --> report --> fix\n    fix -- until the report is empty --> detect"
                  },
                  {
                    "code": "engine/registries/route.registry.ts:41\n  rule      literal-in-lookup\n  locus     the first argument of the lookup call\n  trail     resolved the callee verb, matched the lookup form, read the argument\n  expected  an imported constant as the lookup key\n  found     the string literal \"home\"\n  fix       replace the argument with the id from the ids module: HOME_PAGE\n  healed    no",
                    "kind": "code",
                    "language": "text",
                    "title": "an actionable finding"
                  }
                ],
                "title": "Detect, heal, report, fix"
              }
            ],
            "title": "Detect, log, fix"
          },
          {
            "icon": "bi-shield-lock",
            "id": "the-gate-holds-the-line",
            "intro": "You can write a rule down and the model may follow it for a while, but nothing notices when it stops, which is why every rule in this method comes with a check. [a check's events] shows what happens to that check once it exists. Every other rule depends on this one. The point is not strictness for its own sake: a rule held by a check costs the same to hold on the thousandth change as on the first, while a rule held by attention costs more each time. The checks are [fitness functions](/ontology#arch-fitness-functions), and what they do is [policy enforcement](/ontology#arch-policy-enforcement). The architecture page turns the same idea into an account of decay, in which [an anti-pattern is a decay path](/software-architecture/decay#an-anti-pattern-is-a-decay-path), and the section [seven controls, seven classes](/software-architecture/decay#seven-controls-seven-classes) places each anti-pattern by the check that was missing.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the check is written the moment the pattern is introduced, and it is made to catch the pattern's bypasses too. When a violation slips past it, the check is extended before the content that slipped is touched, so the gate gets stronger before the cleanup. A check is never weakened, a case is never excluded to make the run green, and no tier softer than failure is added.",
                    "boundary": "A pattern that no static check can catch is a question for the developer who owns the work, not a license to skip the check. The honest answer to that question is a rule declared unobservable, with the evidence a check would need written beside it.",
                    "cause": "Convention decides a rule again at every use, and the model has no reason to decide it the same way twice.",
                    "decision": "The check ships in the same change as the rule, rather than the rule now and the check when it bites.",
                    "failureMode": "The team agrees on a rule, you tell the model about it, and a month later half the tree follows it, because nothing ever refused the other half.",
                    "kind": "lesson",
                    "principle": "For this reason I hold a rule with a check rather than with discipline. A rule holds only while a check enforces it: the model's attention and yours both drift, and the gate runs the check on every change regardless.",
                    "problem": "Convention does not survive contact with a model or with a tired developer.",
                    "validation": "To check this, introduce the pattern's nearest bypass and confirm that the same check reports it. A check that catches the pattern but not its bypass holds the line on one side only."
                  },
                  {
                    "kind": "text",
                    "text": "The check is the fix, and the content edit is the cleanup. The order matters because a repaired instance with an unrepaired check is the same defect waiting for its next instance, and the developer or the model who found it has already spent the attention it would take to find it again. A caught duplicate, a caught escape hatch and a better approach discovered mid-task all call for the same response: the affected rule is extended to cover the shape."
                  },
                  {
                    "kind": "text",
                    "text": "Every check returns pass or fail, which applies [fail fast](/ontology#arch-fail-fast) to the gate. There is no warning tier and no advisory level, because a middle tier would let a run finish as successful while a failure is still open, and the verdict is binary to prevent exactly that. A red result that is tolerated is [flaky test normalization](/ontology#arch-flaky-test-normalization) under another name. Severity survives only as the order in which failures are repaired, never as a softer verdict, so a check that would warn is either promoted to a failure or deleted. The same refusal covers exclusions. A finding is resolved by fixing the code, or by proving that it tests a false premise, in which case the finding is deleted; it is never resolved by widening an exemption or disabling the rule for one file."
                  },
                  {
                    "caption": "a check's events",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    pattern[\"A new pattern enters the tree\"]\n    ships[\"The check ships in the same change, with a planted violation\"]\n    slips[\"A violation slips past the check\"]\n    appended[\"The check is extended first, then the content is repaired\"]\n    inconvenient[\"A finding is inconvenient\"]\n    stays[\"It stays a finding · no warn tier, no exclusion\"]\n    disagree[\"Two checks disagree on one line\"]\n    derived[\"Both stay on · the form that satisfies both is derived\"]\n    uncheckable[\"A pattern no static check can catch\"]\n    surfaced[\"Surfaced as a question, never used as license\"]\n    pattern --> ships\n    slips --> appended\n    inconvenient --> stays\n    disagree --> derived\n    uncheckable --> surfaced\n    ships ~~~ slips\n    appended ~~~ inconvenient\n    stays ~~~ disagree\n    derived ~~~ uncheckable"
                  }
                ],
                "title": "The check is the rule"
              }
            ],
            "title": "The gate holds the line"
          },
          {
            "icon": "bi-sort-numeric-down",
            "id": "the-check-comes-first",
            "intro": "A check is proven before it is trusted, as shown in [the order]. The proof has two halves, and each catches a failure the other cannot. The same discipline applied to checks that already exist is described in [verify the verifier](/disciplined-methodology/verify#verify-the-verifier).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the check is written first, then broken on purpose to see that it fires with the expected message. It is then run over the real population to confirm that at least one real member passes for the right reason. The planted file is restored, and only then is the code the check will hold written. After a check is narrowed for precision, the case that motivated it is run again.",
                    "boundary": "A check that every member satisfies for free always says the same thing, and its green result then passes for evidence that what it measures is working. Where nothing can disagree with a check, it is kept with the property it cannot test written down, rather than shipped in a weaker form.",
                    "cause": "A check has only the code in front of it to be shaped by, so it learns the code's accidents as the rule; [testability](/ontology#arch-testability) is either designed in or absent.",
                    "decision": "Every change is ordered as check, planted violation, conforming member, then code, rather than code first with a check fitted around it.",
                    "failureMode": "The check comes last and passes on its first run, and neither you nor the model ever learns that it would have passed anything.",
                    "kind": "lesson",
                    "principle": "For this reason the check comes before the code, and I trust a check only after it has caught something on purpose and let something through on purpose.",
                    "problem": "A check written after the code describes the code rather than the rule.",
                    "validation": "To check this, find the change where each check first fired and the member it first cleared. A check with no such moments has never shown that it works."
                  },
                  {
                    "kind": "text",
                    "text": "The two halves of the proof answer two different questions. A planted violation shows that the check can reject, because a check that has never been seen to fail looks the same as one that cannot fail. A real member passing shows that the check can tell members apart. A check that every member fails has only been shown to reject, and its first green result looks the same as a scope that stopped reaching anything, the [mock mirage](/ontology#arch-mock-mirage) of a test that exercises nothing real. Where no member can pass yet because the correct shape does not exist in the tree, the first conforming member is written beside the check in the same change, and the check is proven against it before either is trusted."
                  },
                  {
                    "kind": "text",
                    "text": "Narrowing is where a correct check can lose its subject without anything reporting it, and it is where the rule in [a check matches a shape](/disciplined-methodology/build#a-check-matches-a-shape) is easiest to break. A rule is written against one case and then scoped for precision. Each refinement is judged by the false positives it removes, and neither the developer nor the model runs the true positive again, so a scope that excludes the motivating case reads exactly like a scope that got tighter. The cheapest scoping is the harmful one, because it keys on the property the correct members share rather than on the property the defect has. Running the motivating case again after every scoping costs a sentence, and it is the only step that tells a check that became precise from one that became blind."
                  },
                  {
                    "caption": "the order",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    write[\"Write the check\"]\n    plant[\"Plant a violation\"]\n    fires{\"Does it report the expected message?\"}\n    real[\"Run it over the real population\"]\n    passes{\"Does at least one real member pass for the right reason?\"}\n    restore[\"Restore the planted file\"]\n    code[\"Write the code the check holds\"]\n    write --> plant --> fires\n    fires -- no --> write\n    fires -- yes --> real --> passes\n    passes -- no, everything fails --> write\n    passes -- yes --> restore --> code"
                  }
                ],
                "title": "Check, prove, then build"
              }
            ],
            "title": "The check comes first"
          },
          {
            "icon": "bi-bounding-box",
            "id": "a-check-matches-a-shape",
            "intro": "A check enforces the shape of an anti-pattern, never a particular provider, package, filename or threshold. Because of that, the check and its message carry over: the same rule catches every later occurrence of the same shape, whatever library or symbol it involves. It is also how a small number of checks can govern a growing tree without growing with it, since the mechanism stays general and a registry holds the instances, as shown in [mechanism and registry]. Where a check runs depends on what it needs to see, as shown in [placed by sight], and a check becomes active when its file is dropped in, as shown in [dropped in]. Its contract is typed as shown in [a rule contract], and the finding it produces as shown in [a finding]. The shapes themselves are catalogued on the architecture page, as described in [an anti-pattern is a decay path](/software-architecture/decay#an-anti-pattern-is-a-decay-path), and each one carries the control whose absence lets it in.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the check is written for the whole class: it detects a construct in a syntax tree, a token sequence or a structural relation, never a name. The instances are kept as data in a registry the check reads, seeded only with instances verified to have the shape. The message states the shape and its one fix in terms a developer working with a different library would understand unchanged, and a rule becomes active when its file is dropped in.",
                    "boundary": "A shape whose defining property is semantic rather than structural may carry a registry of classified instances. The split is then strict: the mechanism reads the registry, the registry is the only place a specific name appears, and the message stays general whatever the registry holds.",
                    "cause": "A check that names an instance is correct on the case that motivated it and silent on the next case, which is the one it was written to prevent.",
                    "decision": "Constructs are gated rather than literals.",
                    "failureMode": "A rule bans one library's direct import by name, a second library with the same hazard arrives, and the rule says nothing because it never knew what it was protecting.",
                    "kind": "lesson",
                    "principle": "For this reason a check matches a shape rather than a name, its instances are kept as data, and its message states the fix in general terms.",
                    "problem": "The obvious check names the thing that went wrong, and the thing that went wrong is one instance of a shape that will recur under other names.",
                    "validation": "To check this, read a check's message with the vendor, the path and the symbol removed. If it still says what is wrong and how to fix it, the check matches a shape; if it says nothing, the check matched an instance."
                  },
                  {
                    "caption": "mechanism and registry",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph mechanism[\"The mechanism · provider-agnostic\"]\n        detect[\"Detect the shape · a tree pattern, a token sequence, a structural relation\"]\n        message[\"State the shape and its one fix, naming no instance\"]\n    end\n    subgraph registry[\"The registry · data\"]\n        instances[\"Verified instances of the shape, one line each\"]\n    end\n    detect -- reads --> instances\n    next[\"The next instance\"]\n    next -- one registry line, no new check --> instances"
                  }
                ],
                "title": "Mechanism general, data specific"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Two properties decide whether a shape can be gated, and both have to hold. The first is that detection is deterministic: the bad shape can be recognised by [static analysis](/ontology#arch-static-analysis), from an import edge, a manifest field or a path, never by a runtime probe that sometimes fails. Where the only way to catch something is to observe non-determinism at runtime, the work is to trace it back to the static shape that causes the non-determinism and gate that shape instead. The second is that remediation is deterministic: there is one correct fix, and it can be stated without reference to any particular case. Where both hold, the shape is gated. Where either fails, it is raised as a question rather than glossed over, and [the honest gaps](/disciplined-methodology/ship#the-honest-gaps) lists the ones raised so far."
                  }
                ],
                "title": "Two properties decide"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Where a check runs depends on what it needs to see. A rule over one file's syntax tree is the lightest kind, and it applies [the filesystem is the architecture](/disciplined-methodology/build#the-filesystem-is-the-architecture) to the checks themselves. A rule over relations between files reads a graph that an earlier stage wrote, and it fails closed when that graph is missing, so the order of the stages matters rather than being incidental. A rule over a folder rather than a file walks from the root, and it needs an anchor, because a finding has to be reported against a file the rule visits: a placement finding attaches to a file inside the offending folder, and a declaration that points at something absent attaches to the manifest that declared it. A check over the whole tree that does not work file by file becomes a stage of its own, and a rewriter checks its own output by parsing it again before it writes."
                  },
                  {
                    "caption": "placed by sight",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    shape[\"A shape to gate\"]\n    where{\"What does the check need to see?\"}\n    perfile[\"One file's syntax tree · a per-file rule dropped into the rule host\"]\n    closure[\"Relations across files · a rule that reads the graph a prior stage wrote\"]\n    folder[\"A folder rather than a file · a rule that walks from the root and anchors its finding\"]\n    pipeline[\"The whole tree, or a rewrite · a stage of its own\"]\n    shape --> where\n    where --> perfile\n    where --> closure\n    where --> folder\n    where --> pipeline"
                  }
                ],
                "title": "Placed by what it needs to see"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The mechanism that discovers rules also works by shape, and that is what lets the core stay untouched. A rule becomes active by declaring a contract that the [registry pattern](/ontology#arch-registry-pattern) discovers; if any core file has to learn the rule's name, the design is wrong. The gate also checks the contract against itself, so a rule that is missing a message, declares its own severity, or reaches for an untyped escape fails at lint rather than at load. The mechanism that enforces every other rule is the one most likely to decay unnoticed, because nothing else watches it, so the rule host passes through the same gate it enforces."
                  },
                  {
                    "kind": "text",
                    "text": "Matching is exact rather than approximate. A check is derived, never guessed, because a check that is usually right is wrong: its misses are invisible, and its false accusations fall on the developer or the model who did the right thing. The tooling I write matches by walking the syntax tree, comparing tokens or comparing exact strings, never by a pattern language that hides the grammar it implements. A hand-written scanner tells use apart from mention, so a detector never matches its own detection strings inside a report about them. It also tests the form of a call rather than a list of names, because a list of names is a check naming instances, and it stops working the moment one more name exists."
                  },
                  {
                    "caption": "dropped in",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    file[\"A rule file dropped into the host\"]\n    discover[\"Discovered by shape · a text match on its contract\"]\n    index[\"The index is re-derived from disk\"]\n    active[\"Active at failure severity, no core file edited\"]\n    self[\"The rule host passes through the gate it enforces\"]\n    file --> discover --> index --> active --> self\n    self -. a malformed rule fails at lint, never at load .-> file"
                  }
                ],
                "title": "Discovered by shape, matched exactly"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The rule contract is small and typed, and its [type safety](/ontology#arch-type-safety) is what lets the registry discover it and the gate check it. A rule declares its kind, a description, an options schema and its messages, and it exports a function that returns a listener over the syntax tree. The message ids form a [closed vocabulary](/ontology#arch-closed-vocabulary), so a report that names an undeclared message fails to compile, and a declared message that no report uses is a finding against the rule. The rule object is exported directly rather than bound to a name, because the filename is the rule's identity, and a second name would be a second fact that has to agree with it. A rule never declares a severity, because there is only one."
                  },
                  {
                    "kind": "text",
                    "text": "What a rule emits is the finding described in [detect, log, fix](/disciplined-methodology/build#detect-log-fix), in typed form: a closed vocabulary of actions, resolved operands and a flag saying whether it healed."
                  },
                  {
                    "code": "export interface RuleContract<MessageId extends string> {\n    readonly meta: {\n        readonly type: \"problem\";\n        readonly docs: { readonly description: string };\n        readonly schema: readonly [];\n        readonly messages: Readonly<Record<MessageId, string>>;\n    };\n    readonly create: (context: RuleContext<MessageId>) => RuleListener;\n}\n\nexport default {\n    meta: {\n        type: \"problem\",\n        docs: { description: \"a single-instance resource is reached through its one owner\" },\n        schema: [],\n        messages: {\n            directReach: \"A single-instance resource must be reached through its owner, which serialises access; route the call through the owner's API.\",\n        },\n    },\n    create(context) {\n        return listener({\n            callExpression(view, node) {\n                if (reachesSharedInstance(view)) {\n                    context.report({ node, messageId: \"directReach\" });\n                }\n            },\n        });\n    },\n} satisfies RuleContract<\"directReach\">;",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a rule contract"
                  },
                  {
                    "code": "export type Severity = \"error\";\n\nexport interface Remediation<Action extends string> {\n    readonly action: Action;\n    readonly operands: Readonly<Record<string, string>>;\n}\n\nexport interface Finding<Action extends string = string> {\n    readonly rule: string;\n    readonly path: string;\n    readonly locus: { readonly line: number; readonly column: number; readonly member?: string };\n    readonly trail: readonly string[];\n    readonly actual: string;\n    readonly expected: string | null;\n    readonly remediation: Remediation<Action>;\n    readonly healed: boolean;\n    readonly severity: Severity;\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a finding"
                  }
                ],
                "title": "The contract, typed"
              }
            ],
            "title": "A check matches a shape"
          },
          {
            "icon": "bi-wrench-adjustable",
            "id": "tools-live-in-the-tree",
            "intro": "When the method lacks a capability, the gap is closed by a tool that lives in the tree with a command surface of its own, as shown in [closing a gap]. That is how [the stance](/disciplined-methodology#the-stance)'s third sentence, that every manual step is a failure of automation, is held by something other than the developer's memory. Which tools exist, what kind each one is and why it exists follow from the method rather than from preference: a tool exists where a check needs an input, where a developer would otherwise repeat a step, or where an eye would otherwise stand in for a measurement, as shown in [a look tool]. A tool that does something irreversible reads its preconditions first, as shown in [before an irreversible tool]. The grammar page states the caller's half of the same contract under [semantic operations](/pag/guide#tool-invocation): an instruction names an operation, and the binding names the tool.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a gap is closed by writing a tool with a declared command surface that lives in the tree. The tool shows its contract before it has any effect: its flags are declared, an undeclared flag is refused, and its help is printed on request. A tool that allocates or rewrites values runs in preview and shows its diff before it applies it. Where a mechanism needs something written to a surface, that surface is made writable by a tool before the requirement exists.",
                    "boundary": "A one-off script belongs in a scratch location, and it moves into the tree as soon as its [reusability](/ontology#arch-reusability) shows. The discipline applies to anything a second run will need, so a scratch tool that gets a second run has already crossed that line.",
                    "cause": "A manual loop is faster the first time and slower every time after, and nothing records how it was done.",
                    "decision": "The tool that already owns the concern is extended first, rather than a second tool being added beside it.",
                    "failureMode": "A ten-minute manual procedure runs weekly for a year, differently each time, and the one week it is skipped is the week it mattered.",
                    "kind": "lesson",
                    "principle": "For this reason I close a capability gap with a tool in the tree, never with a manual loop or a workaround.",
                    "problem": "The cheapest response to a missing capability is to do the thing by hand, and doing it by hand is where the variation comes in.",
                    "validation": "To check this, list every step you performed by hand this week. Each one is either a tool that does not exist yet, or a tool that exists and was not used."
                  },
                  {
                    "kind": "text",
                    "text": "The tools fall into kinds by what they stand in for. A generator stands in for a fact that would otherwise be typed by hand, such as an index, a catalogue, a document derived from a manifest or a rendered diagram; this is [derived state](/disciplined-methodology/verify#derived-state) written by code. A validator stands in for a review that would otherwise be done from memory, such as finding every route, catching internal names that leak into public copy, or resolving every reference a document makes. A fixer stands in for a repair that has [one correct answer](/disciplined-methodology/verify#one-correct-answer), and a probe stands in for an eye. Every kind is reached through [one chain](/disciplined-methodology/ship#one-chain), for the reason that section gives."
                  },
                  {
                    "kind": "text",
                    "text": "The probe deserves the most attention, because the eye is the measurement most often trusted and least often right, the failure described in [it looked right](/disciplined-methodology/verify#it-looked-right). A visual, numeric or timing defect is diagnosed by adding a probe that writes out a value you can read before anything is changed, which is [observability](/ontology#arch-observability) built for one question, and by binary-searching the pipeline against a known-good control. Adjusting values over repeated runs proves nothing. A look tool therefore returns what the eye cannot see: beside the screenshot, it returns the console log the page produced while rendering, the layout the engine computed and the markup that was actually in the tree. A screenshot the developer hands over counts as the measurement. The tool takes one capture per question rather than relaunching in a loop, because a second capture is exactly the tuning by eye the probe is there to replace."
                  },
                  {
                    "kind": "text",
                    "text": "A tool that performs an irreversible operation skips any standing precondition its code does not implement, and it still reports success. So before such a tool runs, the standing instructions that bear on the operation are compared with what the tool actually does, by reading its code rather than its help, since the help has no reason to mention a precondition the code does not implement. A missing step is first taken by hand and declared, and then built into the tool, so the next run does not depend on the developer or the model remembering it. A step skipped before a deletion cannot be made up later, because what it needed is gone."
                  },
                  {
                    "kind": "text",
                    "text": "The requirement and the means of writing what it needs tend to arrive in different changes, and only the requirement feels like the work. A mechanism is built, it needs an input, the input lives in a file, and nothing in building the mechanism asks how that file gets written. The requirement lands complete, and the write it depends on is left to whichever developer or model runs into it, done by hand without any of the protections a tool's write carries. For this reason the question of what writes a file is asked as soon as that file becomes an input, and the answer is a tool that writes it, in place before the requirement that needs it."
                  },
                  {
                    "caption": "closing a gap",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    gap[\"A capability gap appears\"]\n    owner{\"Does something already own this concern?\"}\n    extend[\"Extend the owner, so the next consumer inherits it\"]\n    build[\"Author a tool with a command surface, in the tree\"]\n    loop[\"A manual loop\"]\n    workaround[\"A workaround\"]\n    gap --> owner\n    owner -- yes --> extend\n    owner -- no --> build\n    gap -. the tempting moves .-> loop\n    gap -. the tempting moves .-> workaround"
                  },
                  {
                    "caption": "a look tool",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    question[\"A visual question\"]\n    tool[\"The look tool · one capture per question\"]\n    shot[\"The screenshot · what the eye sees\"]\n    console[\"The console log · what the page said while rendering\"]\n    layout[\"The layout · what the engine computed\"]\n    dom[\"The markup · what was actually in the tree\"]\n    answer[\"An answer with a value you can read\"]\n    question --> tool\n    tool --> shot\n    tool --> console\n    tool --> layout\n    tool --> dom\n    shot --> answer\n    console --> answer\n    layout --> answer\n    dom --> answer"
                  },
                  {
                    "caption": "before an irreversible tool",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    invoke[\"An irreversible operation is about to run\"]\n    preconditions[\"Enumerate the standing preconditions bearing on it\"]\n    code[\"Read the tool's code for each · not its help\"]\n    missing{\"Does the tool implement every one?\"}\n    hand[\"Take the missing step by hand first, and declare it\"]\n    encode[\"Encode the step in the tool for the next invocation\"]\n    run[\"Run it\"]\n    invoke --> preconditions --> code --> missing\n    missing -- yes --> run\n    missing -- no --> hand --> encode --> run"
                  }
                ],
                "title": "Every manual step is a missing tool"
              }
            ],
            "title": "Tools live in the tree"
          },
          {
            "icon": "bi-house",
            "id": "one-home",
            "intro": "Every fact has one home, as shown in [one limit]. Any other place that repeats the fact either derives it from that home, as shown in [one truth per concern], or holds a copy that will drift sooner or later. The principle is [single source of truth](/ontology#arch-single-source-of-truth), and [DRY](/ontology#arch-duplicate-code) is its everyday name. It applies equally to a number in a config, a location in a script, a word in a filename and a sentence in a document, and each of these has one mechanism that holds it. For a location, that mechanism is shown in [a location declaration] and [the lookup]. The architecture page states the same split under [definitions own what, code owns how](/software-architecture#definitions-own-what), and [derived state](/disciplined-methodology/verify#derived-state) describes the [verification](/ontology#arch-verification) side of it.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a home is chosen for each fact, and every other appearance is derived from it by a generator or a lookup. Any copy that cannot be derived is deleted.",
                    "boundary": "A declaration file is the one exempt place, because there the string is the declaration rather than a copy of one. Every consumer reads that file by key, and the exemption never widens to a second file.",
                    "cause": "A copy is cheaper to make than a derivation, and the two agree on the day of copying, so the drift is invisible until it costs something.",
                    "decision": "The second appearance is a lookup rather than a copy, even where the copy would be shorter.",
                    "failureMode": "A limit lives in the tool's config, in a checker, in a script and in three documents. You change it in the config, and the other five keep enforcing the old value.",
                    "kind": "lesson",
                    "principle": "For this reason I give every fact one home, and any second appearance is either derived from it or treated as a defect.",
                    "problem": "The same fact gets stated in several places, and the places stop agreeing.",
                    "validation": "To check this, change the fact at its home. Every other appearance should follow without a second edit, and any appearance that stayed behind was a copy."
                  },
                  {
                    "kind": "text",
                    "text": "Three sources of truth carry most of the tree. The first is for quality: every tool's configuration is built in memory from one declaration, a validator refuses a second configuration on disk, and because the defaults are catalogued, the declaration carries only the deviations. The second is for locations: one declaration holds where every member lives, branches compose so each directory is spelled once, and every script resolves a location by key, so a rename is one edit. This is [configuration externalization](/ontology#arch-configuration-externalization), and a path spelled out in a script is [hardcoded configuration](/ontology#arch-hardcoded-configuration). The third is for naming: one [closed vocabulary](/ontology#arch-closed-vocabulary) holds every word a filename may carry, and an undeclared word is an edit to the vocabulary that has to be approved, not a naming choice."
                  },
                  {
                    "kind": "text",
                    "text": "A location is never spelled out in a string, and the check for that recognises four shapes: a declared location written as a literal anywhere; the same location assembled from parts, after local constants, arrays and concatenation are folded; a literal tail appended to a lookup when a key already covers the whole path; and any path-shaped string with no anchor at all. Where the path sits makes no difference, so a path in an array entry or a template is the same defect as a path in a value."
                  },
                  {
                    "kind": "text",
                    "text": "The location declaration is shaped so that composing locations costs nothing. A branch declares its own place under a root key, and every key beneath it resolves relative to that place, so a directory is spelled once and a rename is one edit. A branch that declares a root also resolves as a leaf, so a key keeps working after it gains children. The keys are generic and the values are the project's own: the governance tooling finds the application by a fixed key whatever the directory is called, so renaming the directory means editing one value. The lookup is typed over the declared keys, so a key that does not exist fails to compile instead of resolving to nothing at run time. The declaration answers one question only, where a member lives and which governed roots sit inside it. What lives below a root belongs to the naming vocabulary and is not listed here again."
                  },
                  {
                    "code": "app:\n    root: <application-root>\n    member: <application-member>          # → <application-root>/<application-member>\n    builds: <build-output>                # → <application-root>/<build-output>\ntesting:\n    root: <test-root>\n    app: <application-suite>              # → <test-root>/<application-suite>\ngovernance:\n    root: <governance-host>\n    rules: <rule-host>                    # → <governance-host>/<rule-host>\n    reports: <report-root>                # → <governance-host>/<report-root>",
                    "kind": "code",
                    "language": "yaml",
                    "title": "a location declaration"
                  },
                  {
                    "code": "type LocationKey = \"app.root\" | \"app.member\" | \"app.builds\" | \"testing.app\" | \"governance.rules\";\n\nexport declare function relativePath(key: LocationKey): string;\nexport declare function absolutePath(key: LocationKey): string;\n\nconst ruleHost = absolutePath(\"governance.rules\");\nconst suite = relativePath(\"testing.app\");",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the lookup"
                  },
                  {
                    "caption": "one limit",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph copies[\"Three homes\"]\n        s1[\"settings · lines-per-file: 200\"]\n        c1[\"checker · MAX_LINES = 150\"]\n        r1[\"readme · files never exceed 150 lines\"]\n    end\n    subgraph home[\"One home\"]\n        s2[\"settings · lines-per-file: 200\"]\n        c2[\"checker · reads lines-per-file from the settings\"]\n        r2[\"readme · states the shape, never the number\"]\n        s2 -- derived --> c2\n        s2 -. no number to copy .-> r2\n    end\n    s1 -. drift .- c1\n    c1 -. drift .- r1"
                  },
                  {
                    "caption": "one truth per concern",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph truths[\"One truth per concern\"]\n        quality[\"Quality config · one file, every tool's config built in memory from it\"]\n        paths[\"Locations · one declaration, every location resolved by key\"]\n        vocabulary[\"Naming · one closed vocabulary\"]\n    end\n    tools[\"Every tool\"]\n    scripts[\"Every script\"]\n    checks[\"Every check\"]\n    quality -- in memory --> tools\n    paths -- by key --> scripts\n    vocabulary -- parsed --> checks\n    drift[\"A per-tool config on disk · a spelled path · an undeclared word\"]\n    drift -. refused .-> truths"
                  }
                ],
                "title": "One home per fact"
              }
            ],
            "title": "One home"
          },
          {
            "icon": "bi-folder-symlink",
            "id": "the-filesystem-is-the-architecture",
            "intro": "Every [extension point](/ontology#arch-extension-points) in the tree is a file in a directory, so adding a capability means adding a file, and removing one means deleting a file. A list of what exists that is maintained by hand is a registry in disguise, and that is where the next inconsistency appears, as shown in [wired then collected]. The same shape governs pages, rules, checks, templates and documents, typed as shown in [the registry]. The [registry pattern](/ontology#arch-registry-pattern), filled by [auto-discovery](/ontology#arch-auto-discovery), is the [open/closed principle](/ontology#arch-open-closed) made physical, and it grows into a [plugin architecture](/ontology#arch-plugin-architecture).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, each variant has its own file that registers itself at module scope, and the files are collected by pattern, never by name. The switch, the lookup table and the list of imports that had to learn each new name are deleted. Where a barrel file collects the files, it is generated from the directory rather than written by hand, and it is checked in both directions: for an entry with no file and for a file with no entry.",
                    "boundary": "A surface discovered by shape is the riskiest thing in any rename, because a change of suffix quietly changes what it collects. The collection is compared before and after every move, as described in [moves and renames](/disciplined-methodology/verify#moves-and-renames), and a count that dropped to zero means the move broke something, not that it was clean.",
                    "cause": "A list is complete on the day it is written, and nothing compares it against the directory afterwards.",
                    "decision": "Each variant registers itself from its own file, rather than being added by hand to a list in a core file.",
                    "failureMode": "A new variant renders through the fallback branch because the switch that dispatches it never learned its name, and nothing reported that.",
                    "kind": "lesson",
                    "principle": "For this reason the directory is the registry, and a core file that has to learn a name is the wrong design.",
                    "problem": "Every switch over a kind, every record literal of variants and every import list in a composer is a list that you or the model have to remember to update.",
                    "validation": "To check this, add a variant by adding one file and touching nothing else. If it needed a second edit, the registry is still in disguise."
                  },
                  {
                    "kind": "text",
                    "text": "A barrel file that lists its side-effect imports by hand is the same disguise one level down, and the rules follow the same approach, as described in [a check matches a shape](/disciplined-methodology/build#a-check-matches-a-shape)."
                  },
                  {
                    "kind": "text",
                    "text": "A generated index over authored data is regenerated from its source and checked for drift in the gate, never edited by hand. Every scan works at any depth, because a scan fixed to one depth reports a pass over whatever sits one level below it. The index is checked in both directions because checking only one direction is decoration: the failure that actually happens is a scan that resolves a smaller set than it claims, with the difference passing for coverage."
                  },
                  {
                    "kind": "text",
                    "text": "The registry has the same shape wherever it appears, and its kind is a closed union, so a variant of an undeclared kind fails to compile, and a lookup for one cannot be written. The same three parts appear whether the variants are pages, checks, codemods or document forms, which is why one primitive serves all of them, and a second registry implementation is a duplicate rather than a convenience."
                  },
                  {
                    "code": "export interface Variant<Kind extends string> {\n    readonly kind: Kind;\n    readonly applies: (subject: Subject) => boolean;\n    readonly run: (subject: Subject) => Finding[];\n}\n\nexport interface Registry<Kind extends string> {\n    readonly register: (variant: Variant<Kind>) => void;\n    readonly all: () => readonly Variant<Kind>[];\n    readonly get: (kind: Kind) => Variant<Kind>;\n}\n\nexport const checks = createRegistry<CheckKind>();\n\nchecks.register({ kind: \"unreachable-export\", applies: isModule, run: findUnreachableExports });",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the registry"
                  },
                  {
                    "caption": "wired then collected",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph before[\"Before · the router learns every name\"]\n        router1[\"router · switch on the page name\"]\n        router1 --> home1[\"home page\"]\n        router1 --> terms1[\"terms page\"]\n        router1 --> faq1[\"faq page\"]\n    end\n    subgraph after[\"After · the directory is the registry\"]\n        pages[\"pages folder · collected by pattern\"]\n        home2[\"home page · registers itself\"] --> pages\n        terms2[\"terms page · registers itself\"] --> pages\n        faq2[\"faq page · registers itself\"] --> pages\n        pages --> router2[\"router · never learns a name\"]\n    end"
                  }
                ],
                "title": "Adding is adding a file"
              }
            ],
            "title": "The filesystem is the architecture"
          },
          {
            "icon": "bi-exclamation-octagon",
            "id": "fail-at-the-boundary",
            "intro": "A failure should surface at the boundary where it happens, as shown in [masked and surfaced]. The principle is [fail fast](/ontology#arch-fail-fast): no default, no fallback and no second path carries on as if nothing went wrong, and [the debt shapes] shows what replaces each of them. The architecture page gives errors their place in the language under [execution joins the halves](/software-architecture/principles#execution-joins-the-halves). This section covers the practice at the boundary, and the pairs below are derived in [never and always](/software-architecture/decay#never-and-always).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the code fails at the first point where a precondition does not hold, and the error says what was expected and what was found. A default value is refused for anything the configuration should have supplied, and so is a second path that carries on when the first one cannot. Replaced code is deleted in the same edit rather than marked, because a marker is a second path with a label on it.",
                    "boundary": "Fail fast applies to the boundaries of your own system. A surface a visitor meets still gets [graceful degradation](/ontology#arch-graceful-degradation), a real page rather than a bare error, and the failure behind it is logged where you will see it.",
                    "cause": "A fallback turns a loud failure into a quiet wrong answer, and a quiet wrong answer costs more than any crash.",
                    "decision": "Fallbacks, dual paths and silent defaults are refused, rather than kept as a safety net.",
                    "failureMode": "A missing secret falls back to a placeholder and the deploy succeeds. The service starts talking to nothing, and the first sign is a customer reporting it.",
                    "kind": "lesson",
                    "principle": "For this reason I treat errors as part of the language: a failure surfaces where it occurs, and no default is allowed to mask it.",
                    "problem": "Code that handles every edge case by carrying on hides the one case that should have stopped it.",
                    "validation": "To check this, remove one required input and run. The run should stop at the boundary that needed the input and name it; a run that continued has a fallback somewhere."
                  },
                  {
                    "kind": "text",
                    "text": "The debt shapes are named as pairs rather than as a list of prohibitions, because each pair states what to do instead. A deprecation marker, a tombstone or a compatibility shim is how [lava flow](/ontology#arch-lava-flow) and [zombie code](/ontology#arch-zombie-code) begin, and its pair is explicit removal in the same edit. Every write is checked for those markers before it lands, so only living code on a single forward path remains; the accounting behind the pairs is described in [debt and leverage](/software-architecture/decay#debt-and-leverage)."
                  },
                  {
                    "kind": "text",
                    "text": "An environment variable never carries a fallback value, and a missing one fails at startup with its name; a placeholder there is a [hidden side effect](/ontology#arch-hidden-side-effect) waiting for production. A guard that fails open is itself a defect, because a guard exists to stop a state, and a guard that lets the state through on error has stopped nothing. That is why [secure by default](/ontology#arch-secure-by-default) is the same rule seen from the [security core](/ontology/schema#layer-security-core). A boolean flag is written as an explicit positive test rather than a negated default, so an absent flag hides the feature rather than switching it on by accident."
                  },
                  {
                    "code": "const masked = env.HOST ?? \"localhost\";\n\nconst surfaced = env.HOST ?? fail(\"HOST is not set; the deploy needs a droplet\");",
                    "kind": "code",
                    "language": "javascript",
                    "title": "masked and surfaced"
                  },
                  {
                    "caption": "the debt shapes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph never[\"Never · debt\"]\n        shortcut[\"a shortcut\"]\n        fallback[\"a fallback\"]\n        dual[\"a dual path\"]\n        deprecation[\"a deprecation marker\"]\n        fornow[\"a for-now\"]\n        optional[\"an optional feature the system depends on\"]\n    end\n    subgraph always[\"Always · leverage\"]\n        constraint[\"a constraint\"]\n        failfast[\"fail-fast\"]\n        single[\"a single path\"]\n        removal[\"explicit removal\"]\n        now[\"now\"]\n        mandatory[\"mandatory\"]\n    end\n    shortcut --> constraint\n    fallback --> failfast\n    dual --> single\n    deprecation --> removal\n    fornow --> now\n    optional --> mandatory"
                  }
                ],
                "title": "Loud at the boundary"
              }
            ],
            "title": "Fail at the boundary"
          },
          {
            "icon": "bi-folder2-open",
            "id": "placement-is-a-grammar",
            "intro": "Where a file lives and what its name says follow one grammar, shown in [the grammar]: a container, an optional subject, a concern, and then the file, as shown in [one tree]. The file's name ends with the concern of its folder, which is [concern-folder correspondence](/ontology#arch-concern-folder-correspondence). Every word comes from a [closed vocabulary](/ontology#arch-closed-vocabulary): [where a word goes] shows how a word is placed, [the vocabulary] shows how the words are declared, and [jurisdiction] shows what the grammar claims and what it leaves alone. A file with two concerns is split rather than given a vague name, which is [one concern per file](/ontology#arch-one-concern-per-file). Only an overlap between two tags for one concern that cannot be reduced takes the tag closer to the domain, following the precedence [the layer spine](/software-architecture#the-layer-spine) holds on the architecture page. The grammar is what turns [separation of concerns](/ontology#arch-separation-of-concerns) from advice into a check, and the layer spine is the axis it uses to classify every concern.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the closed vocabulary and the roots it governs are declared, and a check parses every path against the grammar. A collision is resolved sideways with a variant, never downward with another folder. An undeclared word is a decision for the developer, worked down a ladder: an existing word first, then the is-a test, then the conclusion that the filename is wrong, then the conclusion that the file itself is wrong. Every file is created conformant, because there is no queue of files waiting to be converted.",
                    "boundary": "Files that an ecosystem names for you keep their names. The grammar governs what you write, not what your tools require, and a tree carrying another system's ownership markers is never declared a governed root, because its names are identifiers that system resolves at runtime.",
                    "cause": "Nothing parses a path, so a wrong placement fails no check and reads as a preference.",
                    "decision": "The vocabulary is closed and the path is parsed, rather than placement being reviewed by eye.",
                    "failureMode": "A helper folder appears, then a utils folder, then a second helper folder inside a feature, and six months later you can't say where a new file goes, and neither can the model.",
                    "kind": "lesson",
                    "principle": "For this reason I treat placement as a grammar. A name is a claim about what the code does, and it is checked against the code, never against the old name.",
                    "problem": "Separation of concerns given as advice produces a different tree for every developer who follows it.",
                    "validation": "To check this, pick a file at random and work out its path from its contents alone. If the derived path differs from the real one, one of them is wrong, and the grammar says which."
                  },
                  {
                    "code": "folder = <container> | <subject> | <concern>       one word, never a dot\nfile   = <subject>.<concern>.<ext>\n       | <subject>.<variant>.<concern>.<ext>        only when two files would collide\n\ndepth  = container(1) → subject(2, optional) → concern(3) → file\n         a role may be skipped, never repeated, never revisited\n         the file's parent is always the concern folder\n         the file's concern tag equals its parent folder",
                    "kind": "code",
                    "language": "text",
                    "title": "the grammar"
                  },
                  {
                    "caption": "one tree",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    engine[\"engine · a container, one grouping axis\"]\n    registries[\"registries · a concern folder, files of one role\"]\n    page[\"page.registry.ts\"]\n    route[\"route.registry.ts\"]\n    form[\"form · a subject folder\"]\n    panel[\"panel · a subject folder\"]\n    fv[\"validators\"]\n    pv[\"validators\"]\n    field[\"field.validator.ts\"]\n    layout[\"layout.validator.ts\"]\n    engine --> registries --> page\n    registries --> route\n    engine --> form --> fv --> field\n    engine --> panel --> pv --> layout\n    form -. two sets of validators must not merge .- panel"
                  }
                ],
                "title": "One legal path per file"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Words are resolved by their position rather than by their spelling, which is [positional slot resolution](/ontology#arch-positional-slot-resolution). A word is read by the slot it lands in, so a concern tag can also serve as a subject: a registry of pools and a pool named base use the same word in two slots without ambiguity. The one restriction on the words themselves is that a subject never equals its own concern. A subject folder exists exactly when a container holds two or more sets of one concern that must not merge, because optional grouping would give classification two right answers and make placement impossible to check. [Sideways overflow](/ontology#arch-sideways-overflow) handles the rest: a collision takes the filename's variant slot, breadth takes a sibling subject folder, and the [bounded nesting depth](/ontology#arch-bounded-nesting-depth) is the reason both slots exist."
                  },
                  {
                    "caption": "where a word goes",
                    "kind": "mermaid",
                    "text": "flowchart LR\n    word[\"A word at a slot\"]\n    role{\"A role a file plays?\"}\n    thing{\"A thing the system has?\"}\n    concern[\"The concern list · the file's tag\"]\n    subject[\"The subject list · the first slot of a name\"]\n    rejected[\"Rejected · a process, an adjective, a grouping label\"]\n    split[\"The file gets its real role, or splits\"]\n    word --> role\n    role -- registry, validator, renderer --> concern\n    role -- no --> thing\n    thing -- form, panel, route --> subject\n    thing -- timing, lazy, misc, helper --> rejected --> split"
                  }
                ],
                "title": "Slots, not words"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "[Declared jurisdiction](/ontology#arch-declared-jurisdiction) decides what the grammar reaches. Each key in the configuration is a governed root, and without a declaration there is no enforcement, so a tree outside the jurisdiction keeps its own names. A declaration is a claim that is checked against the disk: a root declared before its folder exists governs nothing and fails nothing, yet it reads as coverage. Material written elsewhere is declared once as an upstream root, and that one declaration exempts it from the naming, tense and reference checks together, because all three fail on such a tree and none of those failures is a defect in it."
                  },
                  {
                    "caption": "jurisdiction",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    tree[\"A tree\"]\n    declared{\"Declared as a governed root?\"}\n    governed[\"Every file inside resolves to one legal path\"]\n    foreign{\"Carries another system's ownership markers?\"}\n    upstream{\"Authored elsewhere?\"}\n    left[\"Left alone · a grammar that does not claim a tree enforces nothing in it\"]\n    refused[\"Refused as a root · its names are identifiers another runtime resolves\"]\n    exempt[\"Declared once as upstream · exempt from naming, tense and reference checks together\"]\n    tree --> declared\n    declared -- yes --> foreign\n    foreign -- yes --> refused\n    foreign -- no --> governed\n    declared -- no --> upstream\n    upstream -- yes --> exempt\n    upstream -- no --> left"
                  }
                ],
                "title": "Jurisdiction is declared"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Classification is a matter of judgement, while structure can be decided by a machine, and the tooling stops at the line between them. A check reports that a name does not parse or that a tag disagrees with its folder, but it never decides what a file is; the classification rule lives in the layer spine on the architecture page. Reshaping an existing tree is therefore a [manual identity migration](/ontology#arch-manual-identity-migration), done one container at a time with the gate green between each, and the rest is described in [moves and renames](/disciplined-methodology/verify#moves-and-renames)."
                  }
                ],
                "title": "Judgement classifies, the check parses"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The vocabulary is one typed declaration, and its type is what makes it closed: the legal words for each slot are a union derived from the data rather than written out a second time, and a flat bucket is declared explicitly rather than inferred from the folder's shape."
                  },
                  {
                    "kind": "text",
                    "text": "The declaration also asserts its own [consistency](/ontology#arch-consistency) when it compiles. A subject that is already a concern tag, a variant that is already a subject, or a concern whose layer lies outside the spine fails to compile, so the vocabulary cannot become inconsistent without the whole gate refusing to load. Every closed vocabulary here takes the same shape: a configuration that carries data and the proofs of its own consistency, and no reasoning."
                  },
                  {
                    "code": "export const LAYERS = [\"domain\", \"application\", \"processing\", \"runtime\", \"infrastructure\", \"operations\", \"product\"] as const;\n\nexport const taxonomy = {\n    containers: {\n        \"<governed-root>\": [\"<container>\", \"<container>\"],\n    },\n    specialContainers: {\n        \"<governed-root>\": [\"<flat-bucket>\"],\n    },\n    concerns: [\n        { folder: \"registries\", tag: \"registry\", layer: \"infrastructure\" },\n        { folder: \"validators\", tag: \"validator\", layer: \"processing\" },\n        { folder: \"strings\", tag: \"strings\", layer: \"product\" },\n    ],\n    subjects: [\"base\", \"<domain-noun>\", \"<domain-noun>\"],\n    variants: [\"<facet>\", \"<facet>\"],\n    grammar: {\n        separator: \".\",\n        maxDepthFromRoot: 3,\n        compoundMarkers: [\"test\", \"spec\", \"generated\"],\n    },\n} as const;\n\ntype Config = typeof taxonomy;\nexport type Subject = Config[\"subjects\"][number];\nexport type Variant = Config[\"variants\"][number];\nexport type ConcernTag = Config[\"concerns\"][number][\"tag\"];\nexport type GovernedRoot = keyof Config[\"containers\"];\n\ntype Assert<Name extends string, Overlap> = [Overlap] extends [never] ? true : [Name, Overlap];\n\nexport const NO_SUBJECT_CONCERN_OVERLAP: Assert<\"subject is already a concern tag\", Extract<Subject, ConcernTag>> = true;\nexport const NO_VARIANT_SUBJECT_OVERLAP: Assert<\"variant is already a subject\", Extract<Variant, Subject>> = true;\nexport const EVERY_LAYER_DECLARED: Assert<\"concern layer is not in the spine\", Exclude<Config[\"concerns\"][number][\"layer\"], (typeof LAYERS)[number]>> = true;",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the vocabulary"
                  }
                ],
                "title": "A vocabulary that proves itself"
              }
            ],
            "title": "Placement is a grammar"
          }
        ]
      },
      {
        "icon": "bi-clipboard-check",
        "id": "verify",
        "label": "Verify",
        "sections": [
          {
            "icon": "bi-eye-slash",
            "id": "it-looked-right",
            "intro": "The most expensive failures I have had were the ones that looked right: the code read well and the model said it was done, but nothing had run. Everything in this chapter follows from one distinction. A claim is a sentence that the developer or the model produced, and until something grounds it, it is [ungrounded content](/ontology#arch-ungrounded-content). [Evidence](/ontology/reasoning#reason-node-ver-evidence) is an observation that a mechanism produced. Only evidence decides anything, as shown in [a claim's source], and [report and prose] shows how to tell the two apart. The [verify](/ontology/reasoning#stage-verify) node of [the loop](/disciplined-methodology#the-loop) asks exactly this question, and the ontology's [verification](/ontology#arch-verification) axis names its parts: [ground truth](/ontology/reasoning#reason-node-ver-ground-truth), [falsification](/ontology/reasoning#reason-node-ver-falsification), [confidence](/ontology/reasoning#reason-node-ver-confidence) and [refutation](/ontology/reasoning#reason-node-ver-refutation).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the exit code is the answer and the parsed findings are the answer, while the model's summary is treated as a story about the answer.",
                    "boundary": "A mechanism's output is evidence about the mechanism itself and only prose about anything else. The sentence most likely to stop a reader looking further is one whose subject is not the thing that printed it, because it reads as if the looking has already been done.",
                    "cause": "A model produces text that resembles a finished result, because that is what finished results look like in its training.",
                    "decision": "The report on disk decides when the work is done, rather than the reply that describes it.",
                    "failureMode": "The model claims [compliance](/ontology#arch-compliance) after one edit and never checks it again, and the next run of the tools finds the same fault plus a new one.",
                    "kind": "lesson",
                    "principle": "For this reason the verdict comes from a machine, and the model's judgement is never the signal that the work is done.",
                    "problem": "A model judges its own edit as clean by reading it, and reading is not running.",
                    "validation": "To check this, find the verifier output behind every claim of done in a session. A done with no output behind it is a claim, and a claim is unverified."
                  },
                  {
                    "kind": "text",
                    "text": "A completion claim reads *all done, the change is clean and everything passes*, while a completion signal reads *gate: every step passed, exit zero, report written to the run's path*. The first is a sentence a model produced, and the second is a number a machine produced."
                  },
                  {
                    "kind": "text",
                    "text": "Evidence comes in tiers, and the tiers are ranked: a measurement taken locally outranks a vendor's documentation, which outranks a community source, which outranks inference. A record carries its confidence and its derivation as two separate axes, because material adapted from elsewhere can be strong or weak evidence regardless of having been adapted, and folding a word about provenance into the vocabulary of strength would make the whole set impossible to rank. When sources conflict, both are recorded and the conflict is stated. A claim that is unverified or rests on a single source is labelled as such wherever it drives a decision."
                  },
                  {
                    "caption": "a claim's source",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    edit[\"An edit lands\"]\n    read[\"The model reads it back\"]\n    story[\"A story about the result\"]\n    run[\"The verifier runs\"]\n    exit[\"An exit code and parsed findings\"]\n    done{\"Done?\"}\n    edit --> read --> story\n    edit --> run --> exit --> done\n    story -. never the signal .-> done"
                  },
                  {
                    "caption": "report and prose",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    output[\"A message printed by a run\"]\n    subject{\"Is its subject the mechanism that printed it?\"}\n    report[\"A report · the authority of an execution\"]\n    prose[\"Prose · opened at the mechanism it names, never trusted for arriving as output\"]\n    output --> subject\n    subject -- yes --> report\n    subject -- no --> prose"
                  }
                ],
                "title": "Looks right is not runs right"
              }
            ],
            "title": "It looked right"
          },
          {
            "icon": "bi-patch-check",
            "id": "verify-the-verifier",
            "intro": "[Verification](/ontology#arch-verification) produces evidence, and the verifier itself has to be verified, in the order shown in [earning trust]. A gate that has never failed on purpose has never shown that it can fail, and a green result from a check that exercises nothing is the [mock mirage](/ontology#arch-mock-mirage). A checker applies its own rules to itself; otherwise it asks of the code what it does not ask of its own source. Above every verifier sits an anchor that cannot be verified, only disclosed, because a gate cannot prove itself. A verdict is the value typed in [a verdict], and a verdict whose surfaces moved beneath it loses its standing, as shown in [lost standing]. The same proof, taken when a check is first written, is described in [the check comes first](/disciplined-methodology/build#the-check-comes-first).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the two cases described in the check comes first are kept as tests beside the check. Every detector is also tested adversarially with the inputs that fool a shallow match, such as a look-alike character, a pattern inside a comment, or a shape without the structure. The governance tooling runs through the same gate it enforces. The anchor everything else rests on is disclosed, and when a gate goes green after a structural change, it is confirmed that the gate still loads what it claims to load.",
                    "boundary": "The anchor is the boundary of what can be verified. A verifier trusts that the runtime runs, that the filesystem reads, that a command executes and that tool output arrives, and it says so rather than pretending to verify them. Everything above the anchor is verified, and the anchor itself is disclosed.",
                    "cause": "A check's own green is the only evidence of its health, and green is also what a broken check produces.",
                    "decision": "A verifier is trusted only after a conforming member, a planted violation and an adversarial test, rather than on the strength of its green results.",
                    "failureMode": "A gate is green for a year, until you read its source and find it has matched nothing since a refactor changed the file suffix it looked for.",
                    "kind": "lesson",
                    "principle": "For this reason I verify the verifier with a conforming member before believing what it says.",
                    "problem": "A green check is evidence of nothing until you know the check can go red.",
                    "validation": "To check this, find for each check the planted violation that turned it red and the conforming member that turned it green. A check missing either one is unverified."
                  },
                  {
                    "kind": "text",
                    "text": "The failure the anchor guards against is concrete. A loader that discovers checks by a name pattern reports success while loading none of them if the pattern no longer matches what is on disk: every step passes, and nothing is checked. So a green run after a structural change is followed by one question, whether the run still loads what it claims to load, and the evidence is the generated index naming the checks together with the loader's own count. A harness that cannot fail belongs to the same class. A stub that stands in for an absent environment must answer only for that environment, because a permissive stub that also absorbs the subject's own missing symbols turns every defect into a silent success."
                  },
                  {
                    "kind": "text",
                    "text": "A verifier that audits claims audits itself last, and an overclaim in its own contract drops its confidence below the threshold, so a run below the threshold is not a clearance. How that self-audit runs, and why a verifier binds to one phase at a time, is described in [agents as executed contracts](/disciplined-methodology/collaborate#agents-as-executed-contracts)."
                  },
                  {
                    "kind": "text",
                    "text": "A verdict carries a standing beside its value. Every surface a run reads is stamped when it is read and stamped again at the end, which is [optimistic locking](/ontology#arch-optimistic-locking) over a read set. A run whose read set moved beneath it names the surfaces that moved and is not authoritative. The verdict itself is untouched, so a pass stays a pass; what is withdrawn is its standing to be quoted, because the report then describes an interleaving of changes rather than a state. Holding a write barrier across the read would be the wrong repair: that is [pessimistic locking](/ontology#arch-pessimistic-locking), which serialises every verification against every write to answer a question about the past. In the type, the standing is derived from whether the moved set is empty, rather than written by the run. The set the run reached is named, so a green result reads as coverage over that set and silence over the rest, and the surfaces the run healed itself are named apart from the ones that moved, because a run's own repairs are not contention. A clearance is then one function over the record: a pass whose standing is authoritative. Any other combination is a value without the standing to be quoted."
                  },
                  {
                    "code": "export type Value = \"pass\" | \"fail\";\nexport type Standing = \"authoritative\" | \"withdrawn\";\n\nexport interface Stamp {\n    readonly surface: string;\n    readonly seen: string;\n}\n\nexport interface Verdict {\n    readonly value: Value;\n    readonly standing: Standing;\n    readonly reached: readonly string[];\n    readonly moved: readonly Stamp[];\n    readonly healedByThisRun: readonly string[];\n    readonly derivations: readonly Finding[];\n}\n\nexport const standingOf = (moved: readonly Stamp[]): Standing => (moved.length === 0 ? \"authoritative\" : \"withdrawn\");\n\nexport const quotable = (verdict: Verdict): boolean => verdict.value === \"pass\" && verdict.standing === \"authoritative\";",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a verdict"
                  },
                  {
                    "caption": "earning trust",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    written[\"A check is written\"]\n    real[\"A conforming member it passes\"]\n    planted[\"A planted violation it fails\"]\n    adversarial[\"Adversarial inputs it rejects\"]\n    self[\"The tooling passes through its own gate\"]\n    recorded[\"The first firing and the first clearing are recorded\"]\n    trusted[\"Trusted, above a disclosed anchor\"]\n    written --> real --> planted --> adversarial --> self --> recorded --> trusted"
                  },
                  {
                    "caption": "lost standing",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    run[\"A run reads its surfaces and stamps each\"]\n    restamp[\"It re-stamps them at the end\"]\n    moved{\"Did any surface move beneath it?\"}\n    authoritative[\"The verdict stands and may be quoted\"]\n    withdrawn[\"The verdict keeps its value and loses its standing · the moved set is named\"]\n    run --> restamp --> moved\n    moved -- no --> authoritative\n    moved -- yes --> withdrawn"
                  }
                ],
                "title": "Conforming member first"
              }
            ],
            "title": "Verify the verifier"
          },
          {
            "icon": "bi-file-earmark-bar-graph",
            "id": "a-report-not-a-checkbox",
            "intro": "A [verification](/ontology#arch-verification) runs once per state of the tree, and its first output is the answer. [Reproducibility](/ontology#arch-reproducibility) is what a second run would test, so a second run that differs is a finding rather than a retry. The output is read whole and never searched for the line you hoped to see. The run writes its report on every exit, so a report being present is never mistaken for a pass. On the grammar page, [validation gates](/pag/validation#validation-gates) hold an instruction's claims to the same standard: checkable, and backed by evidence.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the gate runs once and its full output is written to a file. The file is read whole, what it names is fixed, and the tree changes; only then does the gate run again, and never merely to see whether the answer changes. A report's scope is read before its verdict, because a clearance from a check that cannot see the whole surface is worse than a visible gap.",
                    "boundary": "A new run is warranted once the tree has changed; the earlier report is then history, and the new run is the measurement. The sign of misuse is a second run whose only difference is the filter.",
                    "cause": "A second run of the same state either repeats the answer or reveals non-determinism, and both are already findings from the first run.",
                    "decision": "The tree is changed between runs, rather than the filter between reads.",
                    "failureMode": "The check fails, is run twice more and passes on the third try, and the flake ships with the change, which is [flaky test normalization](/ontology#arch-flaky-test-normalization) in miniature.",
                    "kind": "lesson",
                    "principle": "For this reason each state of the tree gets one run, its output is read whole, and its report is written on every exit path.",
                    "problem": "Re-running a check until it passes turns a verifier into a slot machine.",
                    "validation": "To check this, count the runs per tree state in a session. Anything above one is either a flake that should have been filed or an answer you did not like."
                  },
                  {
                    "kind": "text",
                    "text": "Reading whole is a rule about structure, not about diligence. A slice of a report answers only the question the reader already thought to ask, while the reason a check writes a finding is to raise something the reader had not thought of. A search is worse than an offset, because an offset shows what was skipped, and a search silently leaves out everything that did not match. The same holds for a file and for a coordination surface. When a read fails because the output is too large, that is the cue to read it in parts until the whole has been read, never the cue to sample it."
                  },
                  {
                    "kind": "text",
                    "text": "A count is evidence of coverage only over the surface the scan reaches. A report therefore carries its derivations as well as its verdict, meaning what it reached, what it excluded and why, so that a green result reads as coverage rather than as silence. A negative result inherits the scope of the query that produced it and carries no evidence of its own, so before reporting that something does not exist, the measurement is run again one scope wider, over every surface where the thing could be declared."
                  }
                ],
                "title": "One run, read whole"
              }
            ],
            "title": "A report, not a checkbox"
          },
          {
            "icon": "bi-question-square",
            "id": "unknown-is-not-pass",
            "intro": "A verdict has three values, and the third is the one a percentage hides, as shown in [three verdicts]. A surface that no test touches has not passed. Its verdict is unknown, and unknown never rounds up to pass.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the surfaces a unit can fail in are mapped before its tests are written, using the catalogue described in [what can drift, seen through how it drifts](/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts), projected onto [correctness](/ontology#arch-correctness): each surface with its failure modes, its technique, its predicate and its evidence source. Surfaces that are still unknown are reported as unknown, never as passed.",
                    "cause": "A percentage counts lines executed, and a line can execute while no claim about it gets checked.",
                    "decision": "Coverage is measured as the surfaces a unit can fail in, rather than as a percentage of lines.",
                    "failureMode": "Coverage is high, the failure that ships lives in a case the test suite never imagined, and the number never moved.",
                    "kind": "lesson",
                    "principle": "For this reason no evidence means unknown, never pass: a verdict is pass or fail only against an evidence set that is not empty.",
                    "problem": "Coverage pursued by intuition and reported as a percentage never walks the space a system can fail in.",
                    "validation": "To check this, name a failure surface of one unit that the tests do not touch. If you can, coverage is not complete, whatever the percentage says."
                  },
                  {
                    "caption": "three verdicts",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    surface[\"A surface a unit can fail in\"]\n    tested{\"Does a test touch it?\"}\n    passed{\"Did it pass?\"}\n    pass[\"Pass\"]\n    fail[\"Fail\"]\n    unknown[\"Unknown · never rounds up to pass\"]\n    surface --> tested\n    tested -- no --> unknown\n    tested -- yes --> passed\n    passed -- yes --> pass\n    passed -- no --> fail"
                  }
                ],
                "title": "Three verdicts, not two"
              }
            ],
            "title": "Unknown is not pass"
          },
          {
            "icon": "bi-bullseye",
            "id": "one-correct-answer",
            "intro": "[Determinism](/ontology#arch-determinism) is the one property the others depend on, as shown in [the four properties]. A deterministic mechanism can be healed, enforced, predicted and scaled, while pursuing those four separately produces mechanisms that have none of them; the ontology's names for what follows from determinism are [predictability](/ontology#arch-predictability), [repeatability](/ontology#arch-repeatability) and [reproducibility](/ontology#arch-reproducibility). So the first question about a mechanism is not whether its subject can be checked, but whether its subject is deterministic, and [the first question] shows what follows from each answer. The architecture page draws the consequence for the size of a system in [scale follows determinism](/software-architecture/scale#scale-follows-determinism).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every mechanism is asked whether one correct answer exists for it. Where one does, the mechanism is built to produce that answer and nothing else, with its healer beside it. Where none does, the question is whether the subject can be changed so that one exists, and the subject is changed rather than the check loosened. Where neither is possible, that is said openly and a developer stays in [the loop](/disciplined-methodology#the-loop), with the evidence a check would need written down.",
                    "boundary": "The model's output is not deterministic, and no instruction format makes it so; as the architecture page puts it, [the author is probabilistic](/software-architecture/scale#the-author-is-probabilistic). The input is therefore structured and the output verified. A rule often has one deterministic half and one that is not, and the honest form of the rule names which half is which.",
                    "cause": "A mechanism with two possible answers cannot be checked, healed or trusted at scale, because every consumer has to handle both.",
                    "decision": "Determinism comes before speed and before elegance of any kind, rather than being traded against them.",
                    "failureMode": "A check passes on one machine and fails on another, and the team learns to re-run it until it passes.",
                    "kind": "lesson",
                    "principle": "For this reason I reach for determinism first, because the other four properties follow from it.",
                    "problem": "Much of what looks like a tooling problem is a non-determinism problem in disguise.",
                    "validation": "To check this, run the mechanism twice on the same input and compare the bytes. A difference is a finding, whatever the tool says about itself."
                  },
                  {
                    "kind": "text",
                    "text": "Each of the four derived properties fails in a recognisable way when determinism is missing. A healer working on a judgement call guesses. A check over a non-deterministic subject either fires on everything or flakes. A verdict that depends on who ran it cannot be quoted. A protocol that rests on care multiplies its cost by the number of parties while its enforcement stays flat. All four are the same defect, and naming determinism as the source is what lets one question test them all."
                  },
                  {
                    "kind": "text",
                    "text": "Changing the subject is the move most often missed. An act that nothing records cannot be checked, but the same act performed through a tool that records it can, which is the purpose described in [tools live in the tree](/disciplined-methodology/build#tools-live-in-the-tree). A rule that a reader has to remember cannot be checked, but the same rule written as a declaration a mechanism resolves can. The rule's wording does not change in either case. What changes is the subject, from something that happens in a turn to something that leaves an artifact, and once it leaves an artifact, the check, the healer and the verdict all follow."
                  },
                  {
                    "caption": "the four properties",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    det[\"Deterministic · one correct answer exists\"]\n    heal[\"Healable · a fixer can restore it\"]\n    enforce[\"Enforceable · a check can hold it\"]\n    predict[\"Predictable · a reader can predict it\"]\n    scale[\"Scalable · a hundred consumers agree on it\"]\n    det --> heal\n    det --> enforce\n    det --> predict\n    det --> scale"
                  },
                  {
                    "caption": "the first question",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    mechanism[\"A mechanism is proposed\"]\n    subject{\"Is the subject deterministic?\"}\n    build[\"Build the check and its healer\"]\n    change{\"Can the subject be made deterministic?\"}\n    work[\"Change the subject · an act nothing records becomes an act a writer records\"]\n    conduct[\"Declare it unobservable, with the evidence a check would need\"]\n    mechanism --> subject\n    subject -- yes --> build\n    subject -- no --> change\n    change -- yes --> work --> build\n    change -- no --> conduct"
                  }
                ],
                "title": "Four properties, one axis"
              }
            ],
            "title": "One correct answer"
          },
          {
            "icon": "bi-graph-up",
            "id": "derived-state",
            "intro": "Every reader derives the state of the work each time, by looking at what is on disk, the route through the tree shown in [two routes]. A checkbox that you or the model ticked is a claim, while a report a run wrote is evidence. A count you typed is a copy of a fact the tree already holds, and it is wrong from the first change you did not carry over to it. The property this aims at is [self-describing architecture](/ontology#arch-self-describing-architecture), the health test named in [a system is a graph](/software-architecture#a-system-is-a-graph), and here [introspection](/ontology#arch-introspection) over the tree replaces every written status.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, counts, statuses and progress are derived by traversal and written nowhere, and history is kept out of the documents that state what is true now. A superseded statement is deleted rather than marked, and a document that states how many of something exist is regenerated rather than written by hand.",
                    "boundary": "A prior value that a mechanism consumes to compute a change is an input, not history. A drift detector needs both states; the earlier one lives in the artifact the comparison produces and disappears when the comparison does. The test is whether removing the comparison would leave the value still written.",
                    "cause": "Nothing re-reads a marker after the tree moves, so its staleness has no observer.",
                    "decision": "The cost of a traversal is paid on every read, rather than the cost of staleness on every write.",
                    "failureMode": "The plan says three of five phases are done, two of the three were undone by a later change, and the plan still says three.",
                    "kind": "lesson",
                    "principle": "For this reason the state is derived from the tree and never written, and history is kept apart from the current truth.",
                    "problem": "Markers written into a plan describe the past and get read as the present.",
                    "validation": "To check this, delete a written status and derive it again. If the derived value differs from the written one, the written one was already wrong."
                  },
                  {
                    "kind": "text",
                    "text": "Written into the plan, a status reads *phase three of five, done, updated last week*; derived from the tree, it reads *phase three of five, two tasks open, one closed since the last run*. The first was true once, and the second is true now. The difference is not a matter of diligence. A written marker goes stale by construction, and a stale marker creates a false belief, while an absent marker simply reads as absence."
                  },
                  {
                    "kind": "text",
                    "text": "The same rule reaches documents: every document states what is true now. It carries no change notes, no clauses saying what something was renamed from, no dates tied to our own actions, and no explanation of the current state in terms of a former one. History has two homes and no third: an accumulator that a mechanism can read, and the message the developer receives. The check that enforces this is described in [documentation is code](/disciplined-methodology/verify#documentation-is-code)."
                  },
                  {
                    "caption": "two routes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    tree[\"The tree on disk\"]\n    traverse[\"A traversal, every time\"]\n    state[\"The current state\"]\n    written[\"A status written last week\"]\n    reader[\"The reader\"]\n    tree --> traverse --> state --> reader\n    written -. read as the present .-> reader\n    tree -. changed since .- written"
                  }
                ],
                "title": "Derived, never written"
              }
            ],
            "title": "Derived state"
          },
          {
            "icon": "bi-files",
            "id": "counting-copies",
            "intro": "A fact stated in more than one place is not yet a defect. [DRY](/ontology#arch-duplicate-code) names the aim, a [dual write](/ontology#arch-dual-write) names the failure, and a walk with a fixed order decides which of the two a given pair is, as shown in [the walk]. The walk asks whether the copies can collapse into one, how many of them claim to be the source, how often each derivation runs, and which consumer each copy reaches. Walked out of order, the same set of copies leads either to a repair that destroys evidence or to a comparison over an edge that cannot exist.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, collapse is asked first: where one copy can be derived from the other, the derivable one stops being written, and the divergence can no longer occur. Only where collapse is not available are the distinguished copies counted, and then one resolves to a derivation, zero to a declaration, and many to a decision. Next, the period of every derivation edge is read, because a copy that is regenerated is an instance of the source that can go stale, while a copy fixed once at creation is a record. Last comes what each copy reaches, because a set of copies can be fully collapsed and still deliver nothing.",
                    "boundary": "A one-shot copy, written once against the fact as it stood at the time, is a record rather than a stale instance. Collapsing it would destroy evidence rather than remove duplication, so the repair is inverted: the copies are diagnosed and the source is repaired.",
                    "cause": "Copying never records which copy was the original, so the walk has to count.",
                    "decision": "Every duplicate is decided by its collapse, its count of distinguished copies, its derivation period and its delivery, in that order, rather than by which copy looks newer.",
                    "failureMode": "Two configs disagree, each team believes its own is the source, both get edited, and neither derives from the other.",
                    "kind": "lesson",
                    "principle": "For this reason a duplicate is resolved by counting its distinguished copies, and how often a derivation runs decides whether a copy is a record or a stale one.",
                    "problem": "Deciding which of two copies is right is guesswork until you count.",
                    "validation": "To check this, name the source of a duplicated fact and the period at which its copies refresh. A copy whose refresh nothing schedules is stale from the first change to its source."
                  },
                  {
                    "kind": "text",
                    "text": "Refusing to pick a source when there are zero is the [directed acyclic graph](/ontology#arch-directed-acyclic-graph) ruling in the form a duplicate reaches it. A second declaration is an edge rather than a fact standing beside the first, so a set of copies is a [dependency graph](/ontology#arch-dependency-graph) and collapsing it means choosing a direction along it; a cycle among the copies is a [circular dependency](/ontology#arch-circular-dependency) between facts. Where no copy is distinguished, the graph has no root, and a collapse would have to choose one that the structure does not supply. Refusing is the whole of the correct behaviour there, and it is the part a builder is most tempted to improve: a tiebreak applied to a cyclic set turns a correct refusal into a confident wrong answer."
                  },
                  {
                    "kind": "text",
                    "text": "Every repair of a divergence first asks which side is authoritative. A join can report that two declarations agree, but never that the value they agree on is right. Where one side cites the other, the direction is forced and the repair is bookkeeping. Where both sides declare, the repair is a decision about which value is correct, and the pull is always toward whichever side is free to change. Converging on the cheap side and reporting it as maintenance is the substitution to refuse. A comparison's green result is a [correctness](/ontology#arch-correctness) verdict only where one side is authoritative; elsewhere it says the two match without saying that either is right."
                  },
                  {
                    "caption": "the walk",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    dup[\"Two copies of one fact\"]\n    collapse{\"Is either derivable from the other?\"}\n    reduce[\"One declaration, one derivation · the divergence becomes unrepresentable\"]\n    count{\"How many claim to be the source?\"}\n    one[\"One · a source exists\"]\n    zero[\"Zero · a cycle, each points at another\"]\n    many[\"Many · an undecided choice\"]\n    derive[\"Make every other copy a derivation\"]\n    declare[\"Declare one home and break the cycle\"]\n    decide[\"Decide, then derive\"]\n    period{\"How often does the derivation run?\"}\n    record[\"A record\"]\n    stale[\"Drift\"]\n    dup --> collapse\n    collapse -- yes --> reduce\n    collapse -- no --> count\n    count -- one --> one --> derive\n    count -- zero --> zero --> declare\n    count -- many --> many --> decide\n    derive --> period\n    period -- often --> record\n    period -- never --> stale"
                  }
                ],
                "title": "Count the distinguished copies"
              }
            ],
            "title": "Counting copies"
          },
          {
            "icon": "bi-journal-code",
            "id": "documentation-is-code",
            "intro": "This method treats documentation as code, and [every run] shows what a document passes through. A document is typed, and it is placed by the same grammar described in [placement is a grammar](/disciplined-methodology/build#placement-is-a-grammar). A check resolves its references, as shown in [a resolved reference], so [traceability](/ontology#arch-traceability) runs in both directions. A count in a document is derived rather than typed, and a document that drifts fails the same gate as the code. A module's overview is generated from the manifest the module owns and never written by hand, which is [manifest-based design](/ontology#arch-manifest-based-design) taken literally; the manifest is typed in [a manifest], and [compiled from four] shows how the overview is assembled. Prose that cannot be parsed cannot be governed, so documentation is written in a form that can be.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every document has a type, and the type selects its schema, its rules and its one computed location. Every reference points at an identifier and a path with a declared verb, and a check resolves both halves and fails on an undeclared verb rather than skipping it. Each module's overview is generated from a manifest the module owns, together with its derived public surface. No count is stated in prose. A scaling guide sits beside every system that has seams, and it is updated in the same change that adds a seam.",
                    "boundary": "A generated document is exempt from the content scan and checked for drift instead, because the governed surface is the manifest it was generated from. The one way a generated document differs from generated source is its marker: generated source carries its marker in its name, while a generated document opens with a banner that the gate looks for.",
                    "cause": "Prose about code has no compiler, so nothing tells you when it stops being true.",
                    "decision": "The parseable form is written and the prose generated from it, rather than the prose written in the hope that it stays true.",
                    "failureMode": "The readme names a script that was renamed a month ago, and a new contributor runs it, gets nothing, and assumes the tooling is broken.",
                    "kind": "lesson",
                    "principle": "For this reason documentation goes through the same typing, placement, parsing, validation and repair as any other code.",
                    "problem": "Hand-written documentation is right on the day of writing and drifts every day after.",
                    "validation": "To check this, rename one file that the documents mention. The document gate should fail before anything else does, and a rename the documents survived is a rename they never mentioned."
                  },
                  {
                    "caption": "every run",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    typed[\"Typed · the form selects the schema, the rules and the legal place\"]\n    placed[\"Placed · one computed location from form, owner and name\"]\n    parsed[\"Parsed · references are constructs with a verb, an identifier and a path\"]\n    validated[\"Validated · every reference resolves, no count, no past tense\"]\n    repaired[\"Repaired · bare paths healed, generated documents regenerated\"]\n    typed --> placed --> parsed --> validated --> repaired\n    repaired -. on every run .-> typed"
                  }
                ],
                "title": "Typed, placed, parsed"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A document's path is computed from three axes and never chosen. Its form says what it is, such as a guide, a reference, a contract, a template or a taxonomy. Its owner says which part of the tree it belongs to. Its name states the subject, prefixed by the activity verb where the form is directive. Because a document's location is a function of its declared type and its owner, one search finds every document of a type and every document an owner holds. A document is created through a tool that computes that location, and a filename that does not break down into these parts fails."
                  },
                  {
                    "kind": "text",
                    "text": "Every document has one audience, one purpose and one [abstraction](/ontology#arch-abstraction) level, as with a behaviour policy, a codebase contract, a guide to extending one system, a reference to what is enforced, or a taxonomy that holds a standard and its vocabulary. Content that belongs to a different level moves to that level and is never duplicated. The test is to strip out the words that belong to the wrong level and ask whether the entry still says something at this one. A document that reads at two levels is two documents."
                  }
                ],
                "title": "A path computed from three axes"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A document points at code with a construct rather than a phrase: a declared verb, an identifier and a path. The gate resolves both halves, so the path has to exist, and the identifier has to be exported from, declared in or referenced in that file. An undeclared verb fails rather than being skipped, which is what stops a typo from making a reference invisible. Every claim a document makes about what it validates is backed by a real construct. Documents also form a [dependency graph](/ontology#arch-dependency-graph): a document's name is its export, its edge fields are imports resolved through a registry, a superseded edge sets the target's status, and a duplicate name or a dead edge is a finding."
                  },
                  {
                    "code": "The placement check parses every path, see: `parsePath` \"engine/matchers/path.matcher.ts\"\n\nThe validator resolves both halves:\n  the path must exist\n  the identifier must be declared in that file\n\nA verb it does not know fails the document rather than being skipped,\nso a typo cannot make a reference invisible.",
                    "kind": "code",
                    "language": "markdown",
                    "title": "a resolved reference"
                  }
                ],
                "title": "References are constructs"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A module's overview is generated, and the manifest is its whole editorial surface. Everything that can be derived is computed: the public surface from the declarations, the dependencies from the descriptor, the governing principles resolved by identity against the canon, and the diagrams from the module's own graph. A thin manifest is a bug. The content rules run on each field as rendered into its fragment and report against that field, and the generated document is checked for drift in both directions, so a hand edit is reverted on the next run."
                  },
                  {
                    "kind": "text",
                    "text": "The manifest is a typed record, and its type is what separates a stub from a document. The documentation block has a required core and expands itself: any further key renders as its own section without a change to the generator, so the type admits arbitrary lowercase keys beside the required ones. A quick start is runnable code with its intent and its language, never a sketch, and a validator holds every required field to its shape before anything is generated."
                  },
                  {
                    "code": "export interface Manifest {\n    readonly label: string;\n    readonly summary: string;\n    readonly maturity: \"experimental\" | \"stable\";\n    readonly domains: readonly { readonly meta: Domain; readonly sub: SubDomain }[];\n    readonly governedBy: readonly ConceptId[];\n    readonly entries: readonly string[];\n    readonly docs: {\n        readonly overview: string;\n        readonly whenToUse: readonly string[];\n        readonly whenNotToUse: readonly string[];\n        readonly quickStart: readonly { readonly intent: string; readonly lang: string; readonly code: string }[];\n        readonly configuration: string;\n        readonly disposal: readonly string[];\n        readonly aiContext: readonly string[];\n        readonly apiNotes?: readonly { readonly name: string; readonly note: string }[];\n        readonly [section: string]: unknown;\n    };\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a manifest"
                  },
                  {
                    "caption": "compiled from four",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    manifest[\"The manifest · the authored surface\"]\n    surface[\"The public surface · derived from the code\"]\n    deps[\"The dependencies · derived from the descriptor\"]\n    principles[\"The principles · resolved by identity against the canon\"]\n    readme[\"The module document · generated, drift-checked, never edited\"]\n    manifest --> readme\n    surface --> readme\n    deps --> readme\n    principles --> readme\n    readme -. a hand edit is reverted on the next run .-> manifest"
                  }
                ],
                "title": "The manifest is the editorial surface"
              }
            ],
            "title": "Documentation is code"
          },
          {
            "icon": "bi-arrow-left-right",
            "id": "moves-and-renames",
            "intro": "A move is a [manual identity migration](/ontology#arch-manual-identity-migration): it is done by hand, one container at a time, with the gate green between each, and it opens with [impact analysis](/ontology#arch-impact-analysis) over every reference, as shown in [a surviving move]. The references that matter most are the ones a pattern collects rather than the ones a path names. As described in [the filesystem is the architecture](/disciplined-methodology/build#the-filesystem-is-the-architecture), much of the tree is collected by pattern, and a [glob-resolvable tree](/ontology#arch-glob-resolvable-tree) is exactly what a rename tool never sees.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every reference is enumerated before the move, including the ones resolved by pattern. Files are moved and renamed by hand, one container at a time, and every importer is updated by hand as well. A structural rewrite lands as a draft beside the live file, with a published migration map, and the original is deleted only after approval.",
                    "boundary": "A throwaway script can move whatever it likes. The discipline applies to code that something else depends on. A rename is also a create at its destination, so the destination is read before the write, because attention tends to stay on the source.",
                    "cause": "A surface resolved by pattern holds no literal path that a rewrite could touch.",
                    "decision": "The rename tool's speed is traded for literal edits that a search can verify.",
                    "failureMode": "A suffix changes, the collector that gathered files by that suffix now gathers nothing, and everything downstream passes because nothing is left to check.",
                    "kind": "lesson",
                    "principle": "For this reason a move starts with an enumeration and ends with a [verification](/ontology#arch-verification), and a count checks every surface that resolves by pattern.",
                    "problem": "A rename tool reports a clean rename while the surfaces that resolve by pattern quietly go empty.",
                    "validation": "To check this, compare what each pattern-based surface collects before and after the move. Any set that shrank without explanation is a broken move that the tool would have called clean."
                  },
                  {
                    "kind": "text",
                    "text": "Nothing is dropped without a record. A restructure produces a migration map listing every displaced block with its destination, or an explicit deletion with its reason, so content removed from one place either appears in another or is listed as deleted. Relocation is a rewrite, so it needs the same approval as rewriting the contents. A move and a delete in one step is the most destructive form, because the original is gone and nothing is left to compare the replacement against."
                  },
                  {
                    "caption": "a surviving move",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    enumerate[\"Enumerate every reference, the pattern-resolved ones included\"]\n    before[\"Record what each collector gathers\"]\n    move[\"Move and rename by hand, one container at a time\"]\n    update[\"Update every importer as a literal edit\"]\n    verify[\"Verify every reference with a search\"]\n    after[\"Record what each collector gathers now\"]\n    same{\"Same sets?\"}\n    clean[\"The gate is green · next container\"]\n    broken[\"A collector went empty · the move is broken\"]\n    enumerate --> before --> move --> update --> verify --> after --> same\n    same -- yes --> clean\n    same -- no --> broken"
                  }
                ],
                "title": "Enumerate, move, verify"
              }
            ],
            "title": "Moves and renames"
          },
          {
            "icon": "bi-grid-3x3",
            "id": "coverage-is-derived",
            "intro": "Rule coverage is a set derived over the grid the architecture page builds in [what can drift, seen through how it drifts](/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts). Each cell pairs a dimension of the ontology axis, such as [identity](/ontology/reasoning#reason-node-ont-identity), [structure](/ontology/reasoning#reason-node-ont-structure), [relation](/ontology/reasoning#reason-node-ont-relation), [state](/ontology/reasoning#reason-node-ont-state) or [behaviour](/ontology/reasoning#reason-node-ont-behaviour), with a lens of the analysis axis, such as [structural](/ontology/reasoning#reason-node-ana-structural), [causal](/ontology/reasoning#reason-node-ana-causal) or [temporal](/ontology/reasoning#reason-node-ana-temporal). The walk that finds an empty cell is described in [a cell that resists an invariant](/software-architecture/coverage#a-cell-that-resists-an-invariant). What this section adds is the rule side, shown in [one cell per rule]: every rule declares the gate that observes it, or declares conduct together with the evidence a check would need, as shown in [gate or conduct]. The conduct roster, whose vocabulary is typed in [the conduct roster], shrinks whenever a mechanism starts observing in an artifact what the developer or the model previously had to keep in mind. That shrinking is how this method defines progress.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, every rule declares the check that observes it, or that no check can, and every conduct rule names the half of it that is decidable and whether that half has been built. The unbuilt halves are worked down to zero, and a gap found while building a gate is gated in the same run.",
                    "boundary": "A cell is watched only by a predicate that can fail, as described in [the check comes first](/disciplined-methodology/build#the-check-comes-first).",
                    "cause": "A rule stated without its cell has no address, so neither you nor the model can tell which drift it watches and which drift nothing watches.",
                    "decision": "The empty cells are counted, rather than the rules.",
                    "failureMode": "A team believes its architecture is covered because it has many rules, and the failure that ships lives in a dimension no rule ever named.",
                    "kind": "lesson",
                    "principle": "For this reason coverage is a set derived over the grid of drift dimensions and lenses, and every rule declares either its gate or its conduct.",
                    "problem": "Coverage claimed from a count of rules says nothing about which drift classes the rules reach.",
                    "validation": "To check this, take any rule and name its dimension and its lens; a rule that fits no cell watches nothing in particular. Then find an empty cell and ask what would drift there unseen."
                  },
                  {
                    "kind": "text",
                    "text": "Conduct is a closed question, not a softer state. A rule declares conduct when no construct in any artifact observes it, and the declaration stays falsifiable because each entry names what would have to become observable for the rule to gain a check. Many such rules have a half that is decidable, such as whether a surface conforms to its template, whether a set of readers resolves, or whether a report states the boundary of its own negative result. That half is recorded in a cell with a [closed vocabulary](/ontology#arch-closed-vocabulary) of four values: observed, naming its gates; unbuilt, which counts as debt rather than a paragraph of explanation; none, with a reason taken from a closed set; and null, which means unassessed and is also a declared state. There are three reasons a half can be none: the subject is an act, no declared surface holds it, or the property cannot be evaluated on a member. The coverage report is then derived over the whole set: the gated rules with their gates, the conduct entries, the unassessed rows, which are exactly the entries whose cell is null, and the debt, which is exactly the unbuilt halves. No count is written by hand. Every number a reader wants is the length of one of those lists on the run that produced it."
                  },
                  {
                    "kind": "text",
                    "text": "The cell is filled by walking through questions, never by reading the entry. Does the half name a declared surface, or an imagined one? Is its subject an artifact or an act? Is the population non-empty, given that a check over an empty set is a green result that measures nothing? Can the property be evaluated on a member? Three of these questions take one search each, and only the fourth needs judgement. That changes how the roster reads: every entry looks like a judgement, yet most of them turn on a fact. The cell also holds the value while the entry holds the range, because an observing check is often narrower than the rule whose half it answers, and a bare id would claim more than the check covers."
                  },
                  {
                    "kind": "text",
                    "text": "Projected onto [correctness](/ontology#arch-correctness), the same grid becomes the catalogue of test surfaces described in what can drift, seen through how it drifts, and the unknown verdict that an unmeasured surface receives, described in [unknown is not pass](/disciplined-methodology/verify#unknown-is-not-pass), rests on it. A fresh walk of the roster compares against the kinds of finding the checks emit rather than against the list of checks, because a half gains an observer far more often as a new kind than as a new rule."
                  },
                  {
                    "code": "export type CheckableHalf =\n    | { readonly kind: \"observed\"; readonly by: readonly GateId[] }\n    | { readonly kind: \"unbuilt\" }\n    | { readonly kind: \"none\"; readonly because: \"subject-is-an-act\" | \"no-declared-surface\" | \"not-evaluable\" };\n\nexport interface ConductEntry {\n    readonly slug: RuleSlug;\n    readonly whatACheckWouldNeed: string;\n    readonly half: CheckableHalf | null;\n}\n\nexport interface Coverage {\n    readonly gated: readonly { readonly slug: RuleSlug; readonly gate: GateId }[];\n    readonly conduct: readonly ConductEntry[];\n    readonly unassessed: readonly RuleSlug[];\n    readonly debt: readonly RuleSlug[];\n}",
                    "kind": "code",
                    "language": "typescript",
                    "title": "the conduct roster"
                  },
                  {
                    "caption": "one cell per rule",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    dimensions[\"What can drift · identity, structure, relation, state, behaviour, and the rest\"]\n    lenses[\"How it drifts · structural, causal, temporal, invariant, and the rest\"]\n    cell[\"One cell · an invariant that must hold\"]\n    watched[\"A predicate enforces it\"]\n    unwatched[\"Declared unwatched, with the reason\"]\n    empty[\"An empty cell · a drift class nothing watches\"]\n    dimensions --> cell\n    lenses --> cell\n    cell --> watched\n    cell --> unwatched\n    cell -. never walked .-> empty"
                  },
                  {
                    "caption": "gate or conduct",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    rule[\"A rule\"]\n    gate{\"Does an artifact observe it?\"}\n    check[\"Names its check\"]\n    conduct[\"Declared conduct · with the evidence a check would need\"]\n    half{\"Is a half of it decidable?\"}\n    built[\"The half is gated, and the entry names its range\"]\n    debt[\"The half is unbuilt · counted as debt\"]\n    none[\"No checkable half · an act, not an artifact\"]\n    rule --> gate\n    gate -- yes --> check\n    gate -- no --> conduct --> half\n    half -- built --> built\n    half -- unbuilt --> debt\n    half -- no --> none\n    debt -. worked to zero .-> built"
                  }
                ],
                "title": "The grid and the roster"
              }
            ],
            "title": "Coverage is derived"
          }
        ]
      },
      {
        "icon": "bi-people-fill",
        "id": "collaborate",
        "label": "Collaborate",
        "sections": [
          {
            "icon": "bi-person-check",
            "id": "the-human-and-the-ai",
            "intro": "This section covers how the developer and the model reach each other. You decide what the work is for and the model shapes the work, as described in [ask where it appears](/disciplined-methodology/plan#ask-where-it-appears), and only two things cross between those two roles. A question goes from the model to you, through one channel and with a recommendation first. A correction goes from you to the model once, and hardens into a named rule, as described in [rules with names](/disciplined-methodology#rules-with-names). Everything else, both of you read from the tree, as shown in [two channels]. The same split, with the tooling as the third party, is described in [who does what](/disciplined-methodology#who-does-what), and the architecture page grounds it in the fact that [the author is probabilistic](/software-architecture/scale#the-author-is-probabilistic).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the developer governs by writing what the work is for and what finished means, and corrects drift immediately and briefly, in a few words, once. The correction is expected to become a rule with a stable name and a memory in the same turn, and the next session is expected to read them. When the developer says something that contradicts the plan, the model is asked to halt, check the tree again, and report what it finds rather than argue about the state of a file. A session runs continuously until the queue is empty, and the developer calls the stop.",
                    "boundary": "A question crosses the line only when its answer changes what gets built, and then before the work that depends on it.",
                    "cause": "A model tends toward the reply that reads as helpful, and a reply that reads as helpful is often a summary, a pause offered as thoroughness, or a question that could have been a recommendation.",
                    "decision": "The line is crossed through the two channels only, a question up and a correction down, rather than through the conversation.",
                    "failureMode": "The developer explains the architecture at length, the model reports a milestone and asks what to do next, and the work stops while looking finished.",
                    "kind": "lesson",
                    "principle": "For this reason the developer governs, the model is asked to work inside the boundaries, and a correction hardens into a rule rather than being repeated.",
                    "problem": "Without a declared split, the developer ends up shaping the work by hand and the model ends up guessing what it was for.",
                    "validation": "To check this, read a session's transcript for the moments the turn ended. Each should be the developer calling the stop or a question through the channel; anything else is a halt dressed as a report."
                  },
                  {
                    "kind": "text",
                    "text": "The model is asked never to mention, imply or act on how much capacity it has left, because it cannot measure that, and an assumption presented as a constraint cuts the work short on a false premise. Only the developer calls the stop, and the halts that pretend otherwise are described in [a turn never ends to wait](/disciplined-methodology/collaborate#a-turn-never-ends-to-wait)."
                  },
                  {
                    "kind": "text",
                    "text": "A memory that has gone stale leads to a question rather than a silent refresh, and the order of precedence is set out in [three encodings](/disciplined-methodology#three-encodings)."
                  },
                  {
                    "caption": "two channels",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    operator[\"The developer\"]\n    ai[\"The model\"]\n    tree[\"The tree\"]\n    operator -- what the work is for, what finished means --> ai\n    operator -- a correction, brief, once --> ai\n    ai -- the shape of the work --> tree\n    ai -- a question through one channel, recommendation first --> operator\n    ai -- the correction hardened into a rule and a memory --> tree\n    tree -- read whole, every session --> ai\n    operator -. calls the stop .-> ai"
                  }
                ],
                "title": "Two channels across one line"
              }
            ],
            "title": "The developer and the model"
          },
          {
            "icon": "bi-robot",
            "id": "agents-as-executed-contracts",
            "intro": "An agent that persists across sessions is a walk through [the loop](/disciplined-methodology#the-loop), not a persona, as shown in [a verifying agent]. The [agent templates](/pag/templates#templates-agents) on the grammar page are walked rather than adopted, which applies the rule described in [a seat is a contract](/disciplined-methodology#a-seat-is-a-contract) to agents. An agent is created as shown in [making an agent]. Its definition is executed rather than consulted: it directs the agent to disclose what it trusts, bind itself to one phase as [phase binding](/pag/orchestration#phase-binding) requires, rank what is worth verifying, calibrate its detectors, gather from the implementation, check its own contract against its own behaviour, and emit exactly one typed artifact. The agent that creates agents and the agent that audits them are the same loop applied to agents, and what the walk executes are the ontology's contracts for the [orient](/ontology/reasoning#stage-orient) and [verify](/ontology/reasoning#stage-verify) stages.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, an agent is written as a contract the loop can execute. It has a disclosed trust anchor, a phase it binds to, and a ranking of its claims by risk and uncertainty. Every claim has an evidence requirement naming the observation that would settle it, an admissibility check confirms the phase was honoured, and the run ends in a single typed artifact. The agent is generated from inspected evidence about its domain, rendered through an adapter, and shown to be grounded and embodied before it is persisted.",
                    "boundary": "A bounded invocation has no channel back, so it returns its uncertainty as described in [ask where it appears](/disciplined-methodology/plan#ask-where-it-appears), and a rule that should have been inverted for it, left as it is, is actively wrong while reading as governed.",
                    "cause": "An agent written as a description is applied by its reader's interpretation, and the interpretation drifts with the reader.",
                    "decision": "An agent is defined by the loop it walks and the artifact it emits, rather than by a voice.",
                    "failureMode": "A reviewer agent with a persuasive system prompt approves a change that reads well, because nothing in its definition made it open the diff, calibrate a detector or name what would refute its verdict.",
                    "kind": "lesson",
                    "principle": "For this reason I treat a capability as real only once its behaviour matches a testable contract, and a verifier applies its rules to itself.",
                    "problem": "An agent defined by a voice can be judged only by how it sounds, and a model can make almost anything sound right.",
                    "validation": "To check this, run the agent on a case with a planted contradiction and on a clean case. It should report the contradiction with its evidence and pass the clean case for the right reason; an agent that cannot fail on purpose has never been shown to work."
                  },
                  {
                    "kind": "text",
                    "text": "The anchor is disclosed, as [verify the verifier](/disciplined-methodology/verify#verify-the-verifier) requires, and the self-audit is what catches an overclaim above it: the agent reads its own definition, extracts every capability it claims, runs a positive and a negative case for each, and lowers its confidence for every claim it cannot back."
                  },
                  {
                    "kind": "text",
                    "text": "Phase binding is what keeps an investigation honest. An investigation discovers and never fixes, and its artifact is a report of evidence. An action fixes and never discovers, and its artifact is a log of bounded changes against known evidence. The two exclude each other because the checks that heal rewrite the tree, so an investigation that ran them has changed the tree under a read-only contract."
                  },
                  {
                    "kind": "text",
                    "text": "An agent is generated the way a plan is, from a template that is executed, as described in [execute the template](/disciplined-methodology/plan#execute-the-template). Its source is inspected evidence about the domain it will investigate, never prior knowledge, which is the difference between grounded output and [ungrounded content](/ontology#arch-ungrounded-content). Its target is a portable contract, the shape [the drop-in](/disciplined-methodology#onboarding) gives every core, rendered for one runtime through an [adapter pattern](/ontology#arch-adapter-pattern), so the same agent moves to another runtime by being rendered again. What an agent needs to know in order to act is declared in the body it is delivered with, because a declaration in a field the runtime discards never reaches the agent, and a check reading that field measures an artifact while the mechanism does nothing."
                  },
                  {
                    "caption": "a verifying agent",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    anchor[\"Disclose the trust anchor · what is assumed and cannot be verified\"]\n    phase[\"Bind to one phase · investigate discovers and never fixes, action fixes and never discovers\"]\n    rank[\"Rank the claims by verification worth\"]\n    calibrate[\"Calibrate every detector · a known-good it must match, a known-bad it must not\"]\n    resolve[\"Resolve each claim to the observation that would settle it\"]\n    gather[\"Gather from the implementation · never infer\"]\n    admissible[\"Check the phase was honoured\"]\n    verify[\"Classify each claim · verified, contradicted, unverified\"]\n    audit[\"Audit the agent's own contract · an overclaim lowers its confidence\"]\n    artifact[\"Emit exactly one typed artifact\"]\n    anchor --> phase --> rank --> calibrate --> resolve --> gather --> admissible --> verify --> audit --> artifact\n    verify -. refuted or escalated, bounded .-> resolve"
                  },
                  {
                    "caption": "making an agent",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    evidence[\"Inspected domain evidence\"]\n    contract[\"A portable contract · semantic operations and slots, no runtime\"]\n    adapter[\"An adapter renders it for one runtime\"]\n    grounded{\"Grounded, embodied, no leakage?\"}\n    persisted[\"Persisted, with its participation declared in the body\"]\n    evidence --> contract --> adapter --> grounded\n    grounded -- yes --> persisted\n    grounded -- no --> contract"
                  }
                ],
                "title": "A walked loop, one artifact"
              }
            ],
            "title": "Agents as executed contracts"
          },
          {
            "icon": "bi-diagram-3",
            "id": "coordination-is-software",
            "intro": "When several reasoning agents write to one tree at the same time, this method treats their coordination as software. Its parts are shown in [the model]. A seat is created in the order shown in [a seat's making], and its readers fall into the two classes shown in [reader classes]. A [lost update](/ontology#arch-lost-update), a stale item, a missed message or a surface that has grown past reading is a defect report against the protocol, never a call for more care, and friction points to a missing [concurrency control](/ontology#arch-concurrency-control). The grammar page states the same premise under [orchestration as declared structure](/pag/orchestration#declared-structure), and the schema derived here is the one described in [shared surfaces](/pag/orchestration#shared-surfaces) there.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the coordination is modelled as a graph. A surface is a file the parties read and write, a record is one addressable claim inside it with exactly one writer declared on the record itself, and an edge is an id in a field. Every state is derived by traversing the edges, and no party writes one. Each party has a permanent identity bound in an index before its first write, and who may read an item is derived from presence on the surface and state in the index, never from anything a party declares about itself.",
                    "boundary": "One writer per record is the invariant everything else rests on, and it does not apply to an outcome surface that is written jointly, such as a contract or a measured baseline. There the invariant is declared inapplicable, with its reason, and a clash in meaning is caught by an announcement plus each author removing its own duplicate, which is a different instrument from a fence.",
                    "cause": "Every coordination failure is produced by good behaviour composing badly: each append is a real finding honestly reported, and the defect lies entirely in the composition, which no rule about care can see.",
                    "decision": "Every coordination failure is treated as a missing mechanism and answered with a surface, a schema or a validator, rather than with a request for more care.",
                    "failureMode": "A board grows past what any reader can consume, carrying hundreds of directed items, with every drain rule in force and agreed by every party.",
                    "kind": "lesson",
                    "principle": "For this reason I treat coordination as software, with state, invariants and a schema, which decays without a validator.",
                    "problem": "More than one agent on one tree loses writes, accumulates stale items and misses messages, and each incident has a plausible local cause that hides the gap in the mechanism.",
                    "validation": "To check this, take the last coordination failure and name the mechanism that would have made it impossible or loud. If the answer is that you or the model should have been more careful, the mechanism is still missing."
                  },
                  {
                    "caption": "the model",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph surface[\"A surface · a file the parties read and write\"]\n        r1[\"Record · one writer, declared on the record\"]\n        r2[\"Record · one writer\"]\n        r3[\"Record · one writer\"]\n    end\n    artifact[\"An artifact in the tree\"]\n    other[\"A record on another surface\"]\n    r1 -- satisfied-by · closes when the artifact exists --> artifact\n    r2 -- blocks · the target cannot close first --> r3\n    r3 -- answers · refutes · supersedes --> other\n    state[\"Every state is a query over these edges · no party writes one\"]\n    surface -.-> state"
                  }
                ],
                "title": "Surfaces, records, edges, states"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "One writer per record refuses [shared mutable state](/ontology#arch-shared-mutable-state) at the level of a single claim. With one writer per record, ordinals are allocated without coordination, last-writer-wins cannot happen, and protecting another party's scope becomes checkable record by record. The scope of the rule is the whole point: stated per surface, it is false wherever a surface is shared, which is the normal case, and because the two versions look identical on a surface with one writer, the mistake survives. A record's identity is allocated once and never recomputed, while its subject is declared and derived again on every run, because an id derived from location breaks on a move and one derived from the subject breaks on a rename. Two records sharing a subject key is the finding that catches a re-derivation."
                  },
                  {
                    "kind": "text",
                    "text": "No agent writes a state, which is [derived state](/disciplined-methodology/verify#derived-state) applied here as everywhere else. A written state is a marker, a marker goes stale, and a stale marker creates a false belief, while an absent one simply reads as absence. Open, blocked and absorbed are queries over the edges, which is [event sourcing](/ontology#arch-event-sourcing) over a graph of claims: a record is open while a citation is unresolved, blocked while an inbound edge comes from an open record, and absorbed once the citation resolves. Absorbed is a transition, never a resting state. The record's durable half is extracted to the [one home](/disciplined-methodology/build#one-home) history has, an [append-only log](/ontology#arch-append-only-log), and the record is deleted in the same change, because a record resting in absorbed is a status marker spelled differently."
                  }
                ],
                "title": "One writer, no written state"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A seat is a letter bound to a role in an index that only grows, and what the role document holds is described in [a seat is a contract](/disciplined-methodology#a-seat-is-a-contract). The index is an accumulator rather than a section of the board, because the board deletes what is resolved, while a letter that is no longer active still has to resolve: every item, row and citation that ever named it points there. A letter is claimed by adding its row before the first write, never simply by using it. The identity is allocated rather than chosen. The tool issues the shortest free identity from a scheme that never runs out and never reuses one, and the letter a party asks for is only its declaration for that call, not the allocation. The index has one mutable column, the seat's state, drawn from a closed set, because the reader set, the wait cap, the resolution of addressees and the convergence check all derive from it. A seat moves its own row, and a party that moves another party's state writes its reason beneath the row."
                  },
                  {
                    "caption": "a seat's making",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    claim[\"A letter is claimed by adding a row to the index, before the first write\"]\n    allocated[\"The identity is allocated · the shortest free one, never reused\"]\n    role[\"A role document at the concern, the letter in a field\"]\n    record[\"A fenced record on the board, raised from the template\"]\n    state[\"One mutable column · active, inactive, invoked · a seat moves only its own row\"]\n    claim --> allocated --> role --> record\n    claim -.-> state"
                  }
                ],
                "title": "A seat is allocated, never chosen"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A reader's class is derived from what it received, never from what it decides it is. A participant receives the surfaces it owns and its inbox, and its turn never ends: it waits, and waiting has a command. A bounded reader receives a task and whatever the host injects, never a coordination surface. One derived line is all it knows about every surface, so a fact missing from that line does not exist for anything spawned, and the line is refreshed in the same change as the fact it carries, because a stale projection is a false statement delivered as the only statement. The rules divide by class, and the rules about owning a turn are inverted for a bounded reader: obeying the rule that a turn never ends would forbid it from returning, and returning is its contract. Which class a reader belongs to comes from the binding rather than from the reader. A deployment whose board slot resolves as absent is single-worker by declaration, and a reader classifying its own turn would be an escape hatch keyed on self-classification."
                  },
                  {
                    "caption": "reader classes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    participant[\"A participant · holds a seat\"]\n    owns[\"Receives the surfaces it owns and its inbox\"]\n    waits[\"Ends never · it waits, and waiting has a command\"]\n    bounded[\"A bounded reader · a spawned run\"]\n    injected[\"Receives a task and whatever the host injects · never a coordination surface\"]\n    projection[\"One derived line is its whole view of the graph\"]\n    returns[\"Ends by returning · which is its contract\"]\n    participant --> owns --> waits\n    bounded --> injected --> projection --> returns"
                  }
                ],
                "title": "Two reader classes"
              }
            ],
            "title": "Coordination is software"
          },
          {
            "icon": "bi-kanban",
            "id": "the-board-and-the-venue",
            "intro": "Two surfaces with opposite lifetimes share one transport, as shown in [two surfaces]. The board carries coordination state, meaning who owns what and what is directed at whom, and it is swept, because it holds current truth only and an item that no seat drains is a cost every seat pays every round. One seat's part of it is shown in [a seat's record], and [an item's closure] shows how an item leaves it. The venue carries an argument and accumulates until the argument converges, because a position stands until it is read and dissent survives to the end, through the orderings shown in [convergence] and the schedule typed in [a venue schedule]. The [coordination templates](/pag/templates#templates-coordination) on the grammar page carry both shapes, and the seats that write them are partitioned as described in [composing a collaboration](/pag/orchestration#composing-a-workflow).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the board holds current truth only: it is overwritten in place, a resolved item is deleted outright, and every append is paired with a drain of whatever is already absorbed. Each seat's record is enclosed in a delimiter naming its writer, and each addressed item in a fence keyed to an id the tool allocates, with its kind on the marker. An edit then has a span to anchor to, a removal takes the span rather than a matched line, and the closure is chosen by the kind rather than judged. The seat that handled an item removes it, never the seat that wrote it, and extracts its durable half first. Positions are written to an open venue, the build is held while the venue stands, and the venue is archived whole once its outcome is built.",
                    "boundary": "A venue can be written by the tool but never drained by it, and once archived it takes on [immutability](/ontology#arch-immutability) as an [append-only log](/ontology#arch-append-only-log) of the argument. Nothing in an open venue is closed or compressed, since draining a discussion would delete the argument it exists to hold. Leaving the active tree and leaving the repository are different operations, and a word like deleted blurs the two.",
                    "cause": "Only the handler knows an item is handled, and only the writer was permitted to remove it, so the knowledge and the permission sat in different seats and the item stayed.",
                    "decision": "The surfaces are split by lifetime rather than by topic, so a swept surface and an accumulating one never share a record.",
                    "failureMode": "A converged venue is removed from disk as soon as it is signed, which satisfies every ordering the closure checks, and every position id the accumulator cites then points at nothing.",
                    "kind": "lesson",
                    "principle": "For this reason the board is swept and the venue accumulates, and the two share only their transport.",
                    "problem": "One surface asked to hold both coordination state and an argument reports one state and hides the other.",
                    "validation": "To check this, read the board for an item that argues rather than states, and read the archive for a venue whose reasoning is missing. Either one is a lifetime applied to the wrong surface."
                  },
                  {
                    "caption": "two surfaces",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph board[\"The board · current truth only\"]\n        b1[\"Who owns what · what is directed at whom\"]\n        b2[\"Swept · a resolved item is deleted, never marked\"]\n        b3[\"Read whole, every round\"]\n    end\n    subgraph venue[\"The venue · an argument\"]\n        v1[\"Where each seat stands · what it still needs\"]\n        v2[\"Accumulates until it converges · dissent survives\"]\n        v3[\"Holds the build while open · that red is intended\"]\n    end\n    transport[\"One transport · fenced records, tool-allocated ids, compare-and-swap\"]\n    board -.-> transport\n    venue -.-> transport\n    venue -- converged, absorbed, then archived whole --> archive[\"The archive · the reasoning survives\"]\n    board -- absorbed items extract first --> history[\"The history accumulator · the only home history has\"]"
                  }
                ],
                "title": "Swept and accumulated"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The delimiter is not decoration. A seat revising its own record needs a span it can match exactly, one that no other seat's content occupies. Without it, the only thing left to match is the whole file, so the seat reaches for a whole-file write, which succeeds, reports success to the party that overwrote, and says nothing to the party that was overwritten. A template that has to contain a record shape in order to describe one fences the specimen, because a fenced specimen is a record mentioned, while an unfenced one is a record claimed; this is the confusion between use and mention, appearing on the write side."
                  },
                  {
                    "kind": "text",
                    "text": "An item's kind sits on its marker and selects its closure, which the grammar page describes as [handoff signals](/pag/orchestration#handoff-signals): typed items with closures that can be checked. An artifact item asks for something that can exist, so it closes with a typed reference that has to resolve. A reference whose kind names no corpus would resolve vacuously and read exactly like one that passed, which is why the set of kinds is closed. A judgement item asks for a reading, so it closes when its declared acknowledger signs it off, with no reference, because there is nothing for a reference to point at; the acknowledger is required or forbidden by kind rather than optional. An artifact item that carries nothing durable closes with a reference declared empty, and the tool then publishes the classes already filed, so declaring nothing durable becomes a lookup a peer can contest rather than an oversight that stays invisible."
                  },
                  {
                    "kind": "text",
                    "text": "The sweep is the mechanical drain, and it is gated on delivery: an item is a message on a [message queue](/ontology#arch-message-queue) whose consumers are named, and it leaves the queue once every consumer has taken delivery. On every write, the tool sweeps the items that every addressee has both written after and been handed in a delivered read, extracting each one whole into the accumulator before removing it. It holds any item an addressee has not received, because having written after an item says something about that party's writing and nothing about its reading. Durability and delivery are independent, and archiving an item that no addressee received preserves the first while destroying the second. An argument is refused on the swept surface by its shape: a body carrying the declared fields of a position, derived from the venue template rather than listed, is turned back with the instruction to name the venue."
                  },
                  {
                    "caption": "an item's closure",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    posted[\"An item is posted · a fenced span, an allocated id, a kind, a stamp, its addressees\"]\n    kind{\"Which kind?\"}\n    artifact[\"Artifact · asks for something that can exist\"]\n    judgement[\"Judgement · asks for a reading\"]\n    ref[\"Closes with a typed reference that must resolve\"]\n    ack[\"Closes by its acknowledger, with no reference\"]\n    handler[\"Closed by a seat in its reader set · never its author\"]\n    ledger[\"Held while a named recipient has not marked it read\"]\n    extract[\"Its durable half extracted to the accumulator first\"]\n    dropped[\"The span is dropped, never a matched line\"]\n    posted --> kind\n    kind -- artifact --> artifact --> ref --> handler\n    kind -- judgement --> judgement --> ack --> handler\n    handler --> ledger --> extract --> dropped"
                  },
                  {
                    "code": "┌─── <record> <seat> ─── one writer: <seat> · others cite, never edit · a span edit only, never a whole-file write\n<seat> — <state from the closed set>\n  <field>:   <the concerns this seat claims, by concern and never by directory>\n  <field>:   <the current unit and its state>\n  <field>:\n             ┌─── <item> <seat>-<allocated id> ─── kind:<artifact | judgement> at:<stamp> to:<seats | *>\n             To <seat> — the argument, across as many lines as it needs.\n             └─── END <item> <seat>-<allocated id>\n  <field>:   <typed pointers, each naming a declared kind>\n└─── END <record> <seat>",
                    "kind": "code",
                    "language": "text",
                    "title": "a seat's record"
                  }
                ],
                "title": "Fences, kinds and the sweep"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A venue declares its own exit condition, or it becomes an indefinite halt. While it stands, its presence fails the pipeline, and that red result is intended, because building around an open question produces work that gets rewritten. Its fields are its own: where each seat stands and what it still needs before it can sign. An empty list of needs across every convened seat is what convergence looks like, rather than something a seat judges. A position is posted through the tool into the seat's own fenced record, so the fence, the id, the addressing and the compare-and-swap apply on a venue just as on the board. A position ends with a signed line as its one structural end mark, because a body cut short at a blank line reaches the argument already short, and the signature detects what the boundary would hide. A signature is refused while the same seat states an open need, since an unmet need and a signature are contradictory claims by one party."
                  },
                  {
                    "kind": "text",
                    "text": "Convergence is a walk over [event ordering](/ontology#arch-event-ordering), with each ordering encoded as a refusal rather than a note, because an ordering recorded in prose is rediscovered by collision, while one encoded in the operation cannot be broken. The general form is stated under [orchestration invariants](/pag/orchestration#orchestration-invariants) on the grammar page, and how a seat writes one is described in [stating an invariant](/disciplined-methodology/collaborate#stating-an-invariant). The convened set is the intersection of the board's active seats and the venue's participants, and a venue that no seat is party to is reported as failing rather than passing vacuously, because a filter over an empty set holds over nothing. Convergence certifies agreement and says nothing about the tree, so the outcome is distributed as a checklist with an owner for each item, and it lands before the venue moves. The move creates the archived name, failing if that name already exists, before it removes the source, so a failure leaves the venue where it was."
                  },
                  {
                    "caption": "convergence",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    open[\"Open · the venue declares its own exit condition and holds the build\"]\n    needs[\"Every convened seat states its needs\"]\n    signed[\"Every convened seat has signed · a signature with an open need is refused\"]\n    durable[\"Every seat's durable half resolves in the accumulator\"]\n    deferred[\"Every deferred question has a destination that resolves\"]\n    directives[\"Every directive is discharged\"]\n    absorbed[\"The outcome is absorbed · the distribution checklist carries no open item\"]\n    inherited[\"Every clause the successor inherits was deferred here\"]\n    archive[\"Moved whole into the archive · never deleted\"]\n    open --> needs --> signed --> durable --> deferred --> directives --> absorbed --> inherited --> archive"
                  }
                ],
                "title": "A venue converges or holds the build"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A successor is declared by name against a schedule rather than derived from an ordinal, because an ordinal is a position in a total order, while the real edges are partial and include forward dependencies: a [directed acyclic graph](/ontology#arch-directed-acyclic-graph) rather than a list. The declaration is checked at the moment it is written. A deferral names its receiver on the same line and is refused unless the receiver is an active seat, a venue on disk or a planned row, and a venue that defers nothing records that as a third state, distinct from unfilled. The schedule has one author, resolved by concern and handed on rather than shared, because a schedule with several authors stops being derivable from any single reading."
                  },
                  {
                    "kind": "text",
                    "text": "The record and the schedule are the two shapes worth holding in mind, because every check on the surface derives from one of them. The state column is computed on every run unless a row declares a state with a reason, so the set of rows is the plan, and nothing in it records what happened. Both shapes ship as templates, and the checks read their contracts from those templates, as described in [the drop-in](/disciplined-methodology#onboarding)."
                  },
                  {
                    "code": "export const SCHEDULE_STATES = [\"planned\", \"created\", \"open\", \"archived\"] as const;\nexport type ScheduleState = (typeof SCHEDULE_STATES)[number];\n\nexport interface ScheduleRow {\n    readonly ordinal: string;\n    readonly invariant: string;\n    readonly establishes: string;\n    readonly merged?: string;\n    readonly declaredState?: ScheduleState;\n    readonly declaredBecause?: string;\n}\n\nexport const schedule: readonly ScheduleRow[] = [\n    { ordinal: \"1\", invariant: \"<invariant>\", establishes: \"<what establishing it settles>\" },\n    { ordinal: \"2\", invariant: \"<invariant>\", establishes: \"<what establishing it settles>\" },\n    { ordinal: \"2a\", invariant: \"<invariant deferred here by 2>\", establishes: \"<what establishing it settles>\", declaredState: \"planned\", declaredBecause: \"<why the tree cannot derive it yet>\" },\n];",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a venue schedule"
                  }
                ],
                "title": "The schedule is a graph"
              }
            ],
            "title": "The board and the venue"
          },
          {
            "icon": "bi-broadcast",
            "id": "posting-and-waiting-are-one-operation",
            "intro": "The seats speak to each other through one tool, which makes the protocol structural rather than something each seat has to remember; it is the rule described in [tools live in the tree](/disciplined-methodology/build#tools-live-in-the-tree), applied to the collaboration itself. Posting and waiting are one operation, shown end to end in [one invocation]. Every invocation declares its seat and writes only inside that seat's own fence, under [optimistic locking](/ontology#arch-optimistic-locking). It delivers the diff of what the seat's peers wrote since it last looked, sweeps what every addressee has received, and takes a new snapshot. How long an invocation waits is derived as shown in [the wait cap], and a second run joins a live one, as shown in [joining a run].",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the collaboration has one tool with one shape. Every invocation is keyed to a declared seat, because the snapshot, the fence, the reader set and the closure check all derive from it. Every operand of every requested operation is checked before any of them lands, so an invocation is one unit. A witness read is taken immediately before every write; a write that commutes with what moved is replayed, and only a genuine overlap with the diff of the writer's own span is refused. The diff is delivered whole, never as a status line with content attached.",
                    "boundary": "The tool covers the surfaces that are shared and still writable. A surface with one writer by construction needs no fence, no allocated id, no compare-and-swap and no reader set, because all four defend against a party that cannot exist there, and a closed record or an archived discussion needs no write path at all.",
                    "cause": "A protocol that mandates a surface its tool cannot write to is obeyed by hand, and a hand write has no fence, no allocated id, no compare-and-swap, no reader set and no gate.",
                    "decision": "Every coordination write is a tool write, and the tool refuses what the protocol forbids, rather than the protocol relying on each seat to remember it.",
                    "failureMode": "Three seats filter the tool's output for the line confirming that their own write landed, discard every peer position delivered in the same stream, and the tool reports success each time.",
                    "kind": "lesson",
                    "principle": "For this reason posting and waiting are one operation keyed to a declared seat, and what it delivers is the diff since that seat last looked, read whole.",
                    "problem": "A coordination surface written by hand carries every guarantee as a hope, and a hope decays at the rate of the party who holds it.",
                    "validation": "To check this, invoke the tool with nothing after it and read the whole of what it returns. Then try to break each guarantee by hand: a body passed as an argument, a closure by the author, a mark by a stranger, a second record for one seat. Each attempt should be refused, with the reason the refusal exists."
                  },
                  {
                    "caption": "one invocation",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    invoke[\"One invocation · the seat declared, the surface named\"]\n    check[\"Every operand of every requested operation is checked before any lands\"]\n    witness[\"A witness read immediately before the write\"]\n    moved{\"Did the surface move since the read?\"}\n    span{\"Does the change overlap this seat's own span?\"}\n    replay[\"Replay · the writes commute\"]\n    refuse[\"Refuse · carrying the diff of that span\"]\n    land[\"Land inside the seat's own fence\"]\n    sweep[\"Sweep · items every addressee has written past and been handed, extracted whole\"]\n    echo[\"Echo the seat's own claim, the items it can close, the open discussions\"]\n    snapshot[\"Re-snapshot for this seat · the next call reports only what changed\"]\n    invoke --> check --> witness --> moved\n    moved -- no --> land\n    moved -- yes --> span\n    span -- no --> replay --> land\n    span -- yes --> refuse\n    land --> sweep --> echo --> snapshot"
                  }
                ],
                "title": "One tool, one shape"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The snapshot is kept per seat and per surface. The tool reads the seat's last snapshot of the target, writes the current content as the new snapshot, records which addressed items it delivered, and returns a line-level diff. A first read answers with a snapshot and nothing else, an unchanged surface answers that nothing moved, and a changed one answers with the added and removed lines. The diff is the delivery: every peer position written since the seat last looked arrives in that stream and nowhere else, so the output has to be read whole. Past the read budget, the delivery degrades rather than truncates, which is [backpressure](/ontology#arch-backpressure) applied to a read: it names every changed item by its fence and leaves the bodies on the surface, because a silent truncation hands over a partial read that looks complete. Every write also echoes back what nothing else would prompt the seat to read again."
                  }
                ],
                "title": "The delivery is the diff"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The allocated id is a [correlation id](/ontology#arch-correlation-id): every closure, citation and read mark resolves through it. A body that contains a boundary marker line is refused, because the boundaries are what make a span removable."
                  }
                ],
                "title": "The item and its id"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A read ledger for each item lives on the item's own marker and disappears with it, which lets a swept surface carry delivery state per party without becoming a surface that tracks. The ledger is what makes each seat an [idempotent consumer](/ontology#arch-idempotent-consumer) of the items addressed to it. Each party moves its own letter and no other, a mark by a party the item never addressed is refused, and a closure is held while a named recipient that is still active has not marked the item, so a change that every seat must hold drains on its last reader rather than its first. A rehearsal that writes is the worst form a preview can take, because the invocation a party chooses for safety becomes the one that acts without warning, which is why, as described in tools live in the tree, a tool that rewrites values previews its changes by default."
                  }
                ],
                "title": "Delivery per party"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "The wait blocks on the surface's modification state, which is the [publish/subscribe pattern](/ontology#arch-publish-subscribe-pattern) over a file, with a [timeout pattern](/ontology#arch-timeout-pattern) for the window. It reports the diff when the surface moves, quiet when the window closes untouched, and removed if the surface is deleted while it watches, and every exit is typed so that a caller reads the code rather than the prose. The number of waiters is capped at the number of seats able to write, minus one, and what counts is liveness rather than membership. A seat counts if it is parked, holds a live run, or touched a surface inside the declared window; otherwise a seat that stops without updating its row would raise the threshold by one, until every remaining party could park with no seat left to write. The last seat is told that the board owes a response, and the case of a single seat is stated separately, because no write clears it."
                  },
                  {
                    "caption": "the wait cap",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    able[\"Seats able to write · parked, running a live claim, or active inside the liveness window\"]\n    waiting[\"Seats already parked\"]\n    cap{\"Would this wait leave no seat able to write?\"}\n    blocked[\"Blocked · write first, the board owes a response\"]\n    watch[\"Watch the surface · changed with the diff, quiet after the window, removed if deleted\"]\n    able --> cap\n    waiting --> cap\n    cap -- yes --> blocked\n    cap -- no --> watch"
                  }
                ],
                "title": "The wait and its cap"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A long-running run scales by joining rather than duplicating, which is the [idempotency](/ontology#arch-idempotency) of a measurement. A run declares its write scope and claims standing before it runs. Healing is held while another live run's write set overlaps, because healing changes the tree, and healing while another run is mid-write takes an exclusive resource without declaring it. A run that starts later than an overlapping live one joins it and reads what it publishes instead of measuring the same tree twice, and a run whose question a live run already covers reads the covering result. Every surface a run reads is stamped and stamped again, and what a moved read set does to the verdict is described in [verify the verifier](/disciplined-methodology/verify#verify-the-verifier). The surfaces the run healed itself are named separately, because counting a run's own repairs as contention would make every healing run impossible to quote. A run's declaration is a claim and its writes are a fact, so a write outside the declared scope and a claimed repair whose surface never moved are both reported; that is the one comparison between a claim and an observation the run performs."
                  },
                  {
                    "caption": "joining a run",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    start[\"A run declares its write scope and claims standing\"]\n    live{\"Does a live run's write set overlap?\"}\n    held[\"Healing held · report only, until the other run publishes\"]\n    later{\"Did this run start later than that one?\"}\n    join[\"Join · read out what the live run publishes, write nothing\"]\n    run[\"Run · stamp every surface read, re-stamp at the end, name the surfaces it healed apart\"]\n    quotable[\"The aggregate is overwritten · the verdict carries its standing\"]\n    start --> live\n    live -- no --> run\n    live -- yes --> later\n    later -- yes --> join\n    later -- no --> held --> run\n    run --> quotable"
                  }
                ],
                "title": "A run joins, never duplicates"
              }
            ],
            "title": "Posting and waiting are one operation"
          },
          {
            "icon": "bi-hourglass-split",
            "id": "a-turn-never-ends-to-wait",
            "intro": "A turn never ends because work is blocked on a peer, which is the one edge [a turn] never takes: ending the turn would be the wait, and that wait is a halt. Waiting costs a tool call rather than a turn. A seat reports to its peers on the surface, never to the developer, because a report addressed to the developer reads as an ending and stops the collaboration for as long as the developer takes to reply. The tool this section relies on is described in [posting and waiting are one operation](/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation), and [phase binding](/pag/orchestration#phase-binding) on the grammar page explains why a bounded run returns instead.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the model is asked to work the next open item and, where one blocks, to move to the next unblocked one. Where every item depends on a peer, it waits through the tool, naming the surface the argument is on, and keeps the turn open across the wait. When the wait returns a change, it reads the surface whole and acts on every live item addressed to it, without waiting again straight away and without narrating what the read found. When the wait returns quiet, it picks up its own work and waits again. Findings, status and conclusions are written as directed items to the seats that need them.",
                    "boundary": "Where the work is clear and nothing blocks it, the work is simply done. Every coordination mechanism is a way of moving work, and moving work feels like doing it, so the blocker is named before anything is routed; where naming it produces nothing, the item is clear and routing it would be a substitute for the work.",
                    "cause": "A well-organised summary delivered at a moment that felt conclusive is the most common disguise a halt wears, and the quality of the summary is not a defence.",
                    "decision": "A blocked item is routed to the next open one, and the wait goes through the tool only when every item is blocked, rather than the turn ending on a report.",
                    "failureMode": "A seat's own queue empties, it reports a milestone, the turn ends, and the peers whose writes would have created its next work never receive what it found.",
                    "kind": "lesson",
                    "principle": "For this reason a turn ends on a tool call, a wait is a call rather than a halt, and findings go to the seats that need them.",
                    "problem": "Every coordination failure that outlives its mechanisms takes the shape of a turn that ended on prose.",
                    "validation": "To check this, read the last action of every response in a session. A response whose last action is prose while work remained stopped the collaboration, however much work came before it."
                  },
                  {
                    "kind": "text",
                    "text": "A second wait straight after the first throws away the signal just delivered while looking like diligence, because a tool call is present and the turn stays open. Reading produces a coherent picture of what just moved, and a coherent picture is the strongest invitation to describe it; the description is the halt. Quiet is a fact about the peers, never about the queue, and the queue is not empty while a surface is unaudited, a pattern is ungated or a claim is unverified."
                  },
                  {
                    "kind": "text",
                    "text": "A decision that no seat is making is a routing signal rather than a stall, and it travels as one of the [handoff signals](/pag/orchestration#handoff-signals) the grammar page types. Two independent refusals are the trigger. A question that every existing seat has declined is an input that exists in no file, which is exactly what makes the work suited to an agent, and it is assigned to a seat without waiting to be asked: either an existing seat whose concern covers it, or a new one created for it. A question a seat correctly judges to be above its own authority goes to the seat whose surface the decision binds, named in the same position that declines it, because saying a decision is not yours is a routing statement, not an end point. A contradiction that is fully diagnosed, with a named repair and no seat to take it, reads as handled while nothing lands. The developer is out of [the loop](/disciplined-methodology#the-loop) for venues and signs off on every venue automatically, so no venue waits on the developer's signature and no decision inside one is the developer's to take. What the work is for remains the developer's to answer whenever they choose, at the cost of a message rather than a held venue. A question to the developer binds a seat only; a bounded invocation returns its uncertainty instead, as described in [ask where it appears](/disciplined-methodology/plan#ask-where-it-appears)."
                  },
                  {
                    "caption": "a turn",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    item{\"Is there an open item?\"}\n    work[\"Work it · a tool call advances it\"]\n    blocked{\"Blocked on a peer?\"}\n    next[\"Route to the next unblocked item\"]\n    wait[\"Wait through the tool · the turn stays open\"]\n    changed{\"What did the wait return?\"}\n    read[\"Read the surface whole, then act on every item addressed to me\"]\n    own[\"Pick up my own work and wait again\"]\n    report[\"A report to the developer\"]\n    item -- yes --> blocked\n    blocked -- no --> work --> item\n    blocked -- yes, others open --> next --> work\n    blocked -- yes, all --> wait --> changed\n    changed -- changed --> read --> item\n    changed -- quiet --> own --> wait\n    item -. never, while work remains .-> report"
                  }
                ],
                "title": "Waiting has a command"
              }
            ],
            "title": "A turn never ends to wait"
          },
          {
            "icon": "bi-shield-check",
            "id": "stating-an-invariant",
            "intro": "This section covers how an invariant is written down so that something can object when it breaks. A topology relies on invariants, and an invariant it relies on without stating cannot be told apart from a property a reader happened to infer. Stating one is [design by contract](/ontology#arch-design-by-contract) for a collaboration, where the preconditions and postconditions belong to the parties. The test is not whether the invariant is true, but whether anything would disagree if it stopped being true. A stated invariant fills the four slots shown in [four slots]. A lifetime has the three axes shown in [three axes] and typed in [a lifetime declaration], and a relation between two states needs the two readings shown in [two readings]. The same four slots appear for a declared workflow under [orchestration invariants](/pag/orchestration#orchestration-invariants) on the grammar page.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, an invariant is written with four parts: the property, in a form that could turn out false; the set it quantifies over; the parties it binds; and whatever would object if it stopped holding. The invariant is delivered in a surface the bound parties receive, because a mechanism that must honour an invariant is the consumer most easily forgotten, being the only one that cannot ask. Where no objector exists, the invariant is stated as unheld, and every derivation that rests on it is marked.",
                    "boundary": "Stating an invariant does not enforce it. A statement is a claim about the topology, while a check is a mechanism over artifacts, and where one exists without the other, the honest form says which. An invariant held by a tool holds only as long as every party uses the tool, and a path around the tool by hand is invisible to everything.",
                    "cause": "Nothing objects when an unstated invariant stops holding, so its first violation goes unnoticed.",
                    "decision": "The objector is named before the property is relied on, rather than the property being stated alone.",
                    "failureMode": "Two documents state opposite versions of one invariant, every mechanism faithfully implements its own version, nothing reports a defect, and the contradiction exists only for a reader who holds both documents in mind at once.",
                    "kind": "lesson",
                    "principle": "For this reason I state an invariant with its property, its set, its parties and its objector, or I state it as unheld.",
                    "problem": "An unstated invariant is not a gap in the documentation but a defect in every claim that rests on it.",
                    "validation": "To check this, take an invariant the design relies on and name what would disagree if it stopped holding. If nothing would, the invariant is held by circumstance."
                  },
                  {
                    "kind": "text",
                    "text": "The contradicted invariant is the failure that no single check can see, so the unit of checking is the set of statements rather than any one statement. An invariant is restated wherever a party needs it, because delivery requires that, and every restatement is a copy that can disagree. Adding a statement therefore adds an obligation to re-derive the whole set whenever the invariant changes, starting with the copies delivered most often."
                  },
                  {
                    "caption": "four slots",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    invariant[\"A stated invariant\"]\n    property[\"The property · in a form that could be false\"]\n    set[\"The set it quantifies over · never a verdict beyond its range\"]\n    parties[\"The parties it binds · delivered in a surface they receive\"]\n    objector[\"The objector · a check, a refusal, a comparison, a party that would notice\"]\n    unheld[\"Or stated as unheld · and the derivations above it marked\"]\n    invariant --> property\n    invariant --> set\n    invariant --> parties\n    invariant --> objector\n    invariant -. no objector .-> unheld"
                  }
                ],
                "title": "Property, set, parties, objector"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A lifetime has three independent axes, and describing it in one word makes the other two impossible to state; [immutability](/ontology#arch-immutability), for example, is a single value on one of them. Retention says what ends a piece of content. Mutability says whether a statement that has landed may be rewritten, and by whom. Removal authority says who may take content out. None of the three can be derived from another, and a topology that runs more than one kind of surface has surfaces that differ on each axis independently. The axis a one-word description drops first is removal authority, because a reader assumes it follows from retention. It does not: keeping content and forbidding its removal are separate claims, and a mechanism that faithfully implements the first can still remove content. Each axis takes its value from a closed set, which is what makes the declaration something a check can read rather than a sentence."
                  },
                  {
                    "caption": "three axes",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    surface[\"A surface's lifetime\"]\n    retention[\"Retention · what ends a piece of content\"]\n    mutability[\"Mutability · whether a landed statement may be rewritten, and by whom\"]\n    removal[\"Removal authority · who may take content out\"]\n    word[\"One word · true of every surface and sufficient for none\"]\n    surface --> retention\n    surface --> mutability\n    surface --> removal\n    surface -. collapsed to .-> word"
                  },
                  {
                    "code": "export const RETENTION = [\"accumulating\", \"current-truth\", \"discharged\", \"computed\"] as const;\nexport const MUTABILITY = [\"append-only\", \"owner-rewritable\", \"frozen\"] as const;\nexport const REMOVAL = [\"none\", \"author\", \"handler\", \"producer\"] as const;\n\nexport interface Lifetime {\n    readonly retention: (typeof RETENTION)[number];\n    readonly mutability: (typeof MUTABILITY)[number];\n    readonly removal: (typeof REMOVAL)[number];\n}\n\nexport interface LifetimeRegion {\n    readonly name: string;\n    readonly span: \"item\" | \"field\" | \"row\" | \"column\";\n    readonly lifetime: Lifetime;\n    readonly why: string;\n}\n\nexport interface LifetimeDeclaration {\n    readonly declared: Readonly<Record<SurfaceKey, Lifetime>>;\n    readonly regions: Readonly<Record<SurfaceKey, readonly LifetimeRegion[]>>;\n    readonly seeds: Readonly<Record<SurfaceKey, SurfaceKey>>;\n}\n\nexport const lifetime: LifetimeDeclaration = {\n    declared: {\n        \"<swept-surface>\": { retention: \"current-truth\", mutability: \"owner-rewritable\", removal: \"handler\" },\n        \"<accumulating-surface>\": { retention: \"accumulating\", mutability: \"frozen\", removal: \"none\" },\n        \"<generated-surface>\": { retention: \"computed\", mutability: \"frozen\", removal: \"producer\" },\n    },\n    regions: {\n        \"<rule-surface>\": [{ name: \"<region>\", span: \"field\", lifetime: { retention: \"accumulating\", mutability: \"owner-rewritable\", removal: \"author\" }, why: \"<why this span differs from its file>\" }],\n    },\n    seeds: { \"<template>\": \"<swept-surface>\" },\n};",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a lifetime declaration"
                  }
                ],
                "title": "A lifetime is three axes"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "A property that is a relation between two states cannot be enforced by a check that looks at only one of them. Presence, shape, membership and conformance can be decided from a single reading, through the [structural](/ontology/reasoning#reason-node-ana-structural) lens. A rule that content may grow but not shrink, be corrected but not removed, or advance but not retreat is a [happens-before relationship](/ontology#arch-happens-before-relationship), seen through the [temporal](/ontology/reasoning#reason-node-ana-temporal) lens, and it can be decided only from two readings. A required section is enforced as it goes from empty to full, but nothing notices when it goes from full to empty, and a stricter single-state check has exactly the same blind spot. The repair is to change the number of readings: the prior state is kept, the set it was taken over is recorded, and the two are compared. The comparison has three results rather than two, because a comparison across differing sets refuses to compute, and a refusal is the safe direction when the alternative is a false accusation."
                  },
                  {
                    "caption": "two readings",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    property{\"Is the property a relation between two states?\"}\n    single[\"A single-state check · presence, shape, membership, conformance\"]\n    two[\"Two readings · retain the prior state, record the set it was taken over, compare\"]\n    blind[\"A stricter single-state check · the same blind spot, more demanding\"]\n    third[\"Three results · unchanged, shortened, not comparable\"]\n    property -- no --> single\n    property -- yes --> two --> third\n    property -. the tempting repair .-> blind"
                  }
                ],
                "title": "Two states need two readings"
              },
              {
                "blocks": [
                  {
                    "kind": "text",
                    "text": "Declared as data, a lifetime takes the form shown in [a lifetime declaration]. Each axis is a literal tuple, and the field type is derived from it, so a value outside the closed set fails to compile instead of resolving as a fourth state that was never declared. A surface is a key and its lifetime is one record over the three axes, so a check joins on the axis name and reads the value. A region declares only where it differs from its file, naming the span it covers, the lifetime it carries and the reason, and that limit is what keeps the declaration small enough to count."
                  },
                  {
                    "kind": "text",
                    "text": "A seed names which live surface a template creates, so the template declares a lifetime for an instance rather than for itself, and a seed pointing at an undeclared surface is a compile error rather than a citation that resolves to nothing. The values have no order and none is a default. A surface that declares nothing is undeclared, which is a state distinct from every value, and treating the two as the same would make an unmeasured surface impossible to tell apart from a measured one."
                  }
                ],
                "title": "Declared as data"
              }
            ],
            "title": "Stating an invariant"
          }
        ]
      },
      {
        "icon": "bi-box-seam",
        "id": "ship",
        "label": "Ship",
        "sections": [
          {
            "icon": "bi-link-45deg",
            "id": "one-chain",
            "intro": "One command runs every tool in this method as a single gate, in stages typed as shown in [a stage array]. The stages form a [pipeline architecture](/ontology#arch-pipeline-architecture) ordered by [causal dependency](/ontology#arch-causal-dependency), as shown in [the stages], and each stage runs the checks, fixers, generators and validators it owns. A check that runs only when you or the model remember its command is a convention rather than a check. Arguments can narrow the chain while you iterate, but only the whole run supports a claim that the work is done, as shown in [narrowing]. The chain is what turns a collection of tools into a verdict, and the rule it serves is described in [the gate holds the line](/disciplined-methodology/build#the-gate-holds-the-line).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the project has one entry point whose default is the whole pipeline, and arguments can narrow it but never widen it. Its stages are ordered by what each one needs from the one before, and a dependency is stated wherever a step produces an artifact that another stage consumes. Every check, fixer, generator and validator sits in a stage as a direct call, never as an alias the gate shells out to. The aggregate report is written on every exit path, and the gate governs its own tooling with the same rules it applies to the code.",
                    "boundary": "Narrowing is only for speed while iterating locally. A member, a step or a bypass answers a question faster, but a claim that the work is done needs one whole-scope run with nothing bypassed. A narrowed run never overwrites the one aggregate, because a report about a narrower subject under the aggregate's name would describe a different subject under the same name.",
                    "cause": "A tool outside the chain depends on a developer's memory, and memory is the one component in the system with no check on it.",
                    "decision": "Every tool is routed through the one entry point, rather than kept as a command of its own.",
                    "failureMode": "There are three linters, two of which have not been run since spring, and a formatter that runs on some machines only because of an editor plugin.",
                    "kind": "lesson",
                    "principle": "For this reason every tool runs through one chain, because a tool reached only by its own command enforces nothing.",
                    "problem": "Tooling accumulates as separate commands, and the commands stop getting run.",
                    "validation": "To check this, list every check the project claims to have and run the one command. Each check should appear in its output; one that does not is not a check the project has."
                  },
                  {
                    "kind": "text",
                    "text": "The stage order encodes real dependencies, [event ordering](/ontology#arch-event-ordering) in the ontology's sense, so it carries weight rather than being tidy. A cleaning step runs before anything measures a file, and a type check runs before any structural check reads a tree that may not compile. The fixer stage writes the closure graph that the graph-aware rules read when they load, so it comes before linting, and a graph-aware rule fails closed when the graph is missing rather than passing over nothing. Several stages change the working tree, which is why an investigation never runs the gate, as described in [agents as executed contracts](/disciplined-methodology/collaborate#agents-as-executed-contracts)."
                  },
                  {
                    "kind": "text",
                    "text": "A registry the run consumes at load is derived again before anything loads it, so deleting a member cannot break the run that would have removed its entry. Deleting a rule is then one step, just as adding one is one dropped file. The chain also checks its own registration contract and the shape of every finding."
                  },
                  {
                    "kind": "text",
                    "text": "Where a host project already has a toolchain, the chain hands off rather than duplicating it. The host chooses which concerns to hand over, its tools stay its own, and there is one chain instead of two. A [verification](/ontology#arch-verification) slot the host cannot fill, such as a build, a runtime probe or a size cap, resolves as absent. The step that reads it does not run, and the claim it would have settled is carried as observed by the developer rather than as verified."
                  },
                  {
                    "kind": "text",
                    "text": "The chain is data before it is a run. A pure planner takes the resolved scope, meaning which members, which step and which bypasses, and returns the stage array, and the runner walks that array in order, with any order that carries weight stated on the step rather than remembered. A member with no tests declares null rather than an empty string, because the two are different claims. Everything a stage-control flag can do is a function over this data, and no flag can add a step that the array does not hold."
                  },
                  {
                    "code": "export const STAGE_SLUGS = [\"<stage>\", \"<stage>\", \"<stage>\"] as const;\nexport type StageSlug = (typeof STAGE_SLUGS)[number];\n\nexport interface Member {\n    readonly id: string;\n    readonly dir: string;\n    readonly gated: boolean;\n    readonly tests: string | null;\n}\n\nexport interface Step {\n    readonly label: string;\n    readonly command: readonly string[];\n    readonly scope: \"wide\" | \"perMember\" | \"appOnly\";\n    readonly tags: readonly (\"generate\" | \"validate\" | \"build\")[];\n    readonly produces?: string;\n    readonly consumes?: string;\n}\n\nexport interface Stage {\n    readonly slug: StageSlug;\n    readonly bypassedByDefault: boolean;\n    readonly parallel: boolean;\n    readonly steps: readonly Step[];\n}\n\nexport declare function stagesFor(scope: { readonly members: readonly Member[]; readonly only?: string; readonly bypass?: readonly StageSlug[] }): readonly Stage[];",
                    "kind": "code",
                    "language": "typescript",
                    "title": "a stage array"
                  },
                  {
                    "caption": "the stages",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    command[\"one command\"]\n    rederive[\"the rule index is re-derived from disk before any stage\"]\n    prepare[\"dependency integrity, one typecheck per member\"]\n    unused[\"dead code, dead exports, dead dependencies\"]\n    fixers[\"strip comments, rebuild the graph, run the rewriters\"]\n    format[\"the formatter, fix on\"]\n    lint[\"every linter, per member, fix on, reading the graph the fixers wrote\"]\n    test[\"every suite, then the passing-test floor\"]\n    build[\"the site, the diagrams, the chapters, every generator, every derivation\"]\n    validate[\"discovery, leaks, graphs, configs, documents\"]\n    report[\"the one aggregate · written on every exit\"]\n    command --> rederive --> prepare --> unused --> fixers --> format --> lint --> test --> build --> validate --> report\n    prepare -. fail fast .-> report\n    lint -. fail fast .-> report\n    test -. fail fast .-> report"
                  },
                  {
                    "caption": "narrowing",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    whole[\"No arguments · every stage, whole scope, healing on\"]\n    member[\"A member · that member's steps, repo-wide steps reported as skipped\"]\n    step[\"A step · only that step\"]\n    bypass[\"A bypass · one stage skipped, local iteration only\"]\n    claim[\"A completion claim\"]\n    whole --> claim\n    member -. never satisfies .-> claim\n    step -. never satisfies .-> claim\n    bypass -. never satisfies .-> claim"
                  }
                ],
                "title": "Everything through one chain"
              }
            ],
            "title": "One chain"
          },
          {
            "icon": "bi-rulers",
            "id": "scale-follows-from-structure",
            "intro": "How many parties a body of work needs is not a matter of choice. The count follows from how the work divides into concerns that must be able to contradict each other. The floor is the number of those concerns, and the ceiling is set by the worst fan-in, the point at which claims resting on one surface stop surviving; [floor, ceiling, count] shows where each comes from. The architecture page derives the same range for a system, as described in [a concern is a component](/software-architecture/scale#a-concern-is-a-component) and [the ceiling moves by cost](/software-architecture/scale#the-ceiling-moves-by-cost).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the work is first divided into concerns, and counting them gives the floor. The fan-in on each [shared surface](/pag/orchestration#shared-surfaces) is measured from the traffic the surface already records, which gives the ceiling. A count is then chosen inside that range, and the partition it came from is written down.",
                    "boundary": "Volume is the wrong input, as described in a concern is a component; the fan-in caps a small task and a large one alike.",
                    "cause": "A count chosen independently of the partition either leaves a concern with no owner or gives one surface more claims than it can hold.",
                    "decision": "The work is partitioned first and counted second.",
                    "failureMode": "Five agents work on a task that has two concerns, three of them wait, and the surface they all write to becomes the bottleneck.",
                    "kind": "lesson",
                    "principle": "For this reason the number of parties follows from the structure of the work rather than from a preference.",
                    "problem": "The number of agents or people on a task comes from a preference, and a preferred number is wrong in one of two directions.",
                    "validation": "To check this, ask what partition the current count came from. A count with no partition behind it is a preference, and the fan-in will expose it."
                  },
                  {
                    "kind": "text",
                    "text": "With fewer parties than the floor, one concern has no owner, so it is decided by whichever party happens to be nearest, which is the substitution every other chapter refuses. With more parties than the ceiling, the shared surface becomes the bottleneck: a claim is more often stale by the time it lands than it is read, and the parties spend their rounds re-deriving each other's reads."
                  },
                  {
                    "kind": "text",
                    "text": "The argument is carried on the architecture page in [scale follows determinism](/software-architecture/scale#scale-follows-determinism). A deterministic check returns the same verdict whoever runs it, so adding a party adds no enforcement cost, and that is why every coordination rule here is either a mechanism or a declared piece of conduct with its evidence written down."
                  },
                  {
                    "caption": "floor, ceiling, count",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    work[\"A body of work\"]\n    partition[\"Partition it into concerns that must be able to contradict each other\"]\n    floor[\"Floor · the number of concerns\"]\n    fanin[\"Measure the fan-in on each shared surface\"]\n    ceiling[\"Ceiling · the worst fan-in before claims stop surviving\"]\n    count[\"The count · a choice inside the range, with the partition written down\"]\n    work --> partition --> floor\n    partition --> fanin --> ceiling\n    floor --> count\n    ceiling --> count"
                  }
                ],
                "title": "Floor and ceiling"
              }
            ],
            "title": "Scale follows from structure"
          },
          {
            "icon": "bi-cloud-upload",
            "id": "the-deploy-is-a-file-operation",
            "intro": "The deployable is derived from the routes the site serves, as shown in [routes to site]. The deploy is a file operation with a [rollback](/ontology#arch-rollback), and it never touches a process it does not own, which is [least privilege](/ontology#arch-least-privilege) applied to a deploy. [Secrets management](/ontology#arch-secrets-management) keeps every secret outside the tree. Every served surface uses [encryption in transit](/ontology#arch-encryption-in-transit), including the local development server, because [environment parity](/ontology#arch-environment-parity) means development exercises the same transport as production; otherwise it exercises something else.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the deploy starts from the served routes and follows every path a text artefact names. Every file that nothing reaches is deleted, and the whole of what is left is uploaded. One backup is kept of what is replaced, and it is restored on any failure. A command that touches a shared machine is handed to the developer who owns that machine rather than run, and every secret stays in the one artifact declared to hold it.",
                    "boundary": "On a machine that hosts other people's processes, nothing beyond your own files is touched. The deploy is a file operation because a file operation can be rolled back, while a process operation has a blast radius.",
                    "cause": "Nothing between the build and the upload asks whether a file is reachable.",
                    "decision": "The deployable is pruned from the routes rather than taken from the build folder on trust, and a file operation is chosen over a process operation for its rollback.",
                    "failureMode": "A page fails to pre-render, and nothing reports it because the old file is still in the build folder, so the stale page ships.",
                    "kind": "lesson",
                    "principle": "For this reason the deployable is whatever a page can reach.",
                    "problem": "A deploy that ships a build folder ships whatever happened to be in it.",
                    "validation": "To check this, list every file in the deployable and the route that reaches it. A file that no route reaches is one the discovery check should have refused."
                  },
                  {
                    "kind": "text",
                    "text": "A discovery check derives, from the same registry the build reads, every route a page can serve and every file a route reaches. It fails the build on a route with no rendered file, a payload a machine cannot parse, or a file that nothing reaches, so the problem is found before a deploy rather than after."
                  },
                  {
                    "caption": "routes to site",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    routes[\"The served routes\"]\n    follow[\"Follow every path a text artefact names\"]\n    reached[\"What a page can reach\"]\n    prune[\"Delete everything else\"]\n    backup[\"Back up what is live\"]\n    upload[\"Upload the whole of what is left\"]\n    check{\"Healthy?\"}\n    done[\"Live\"]\n    restore[\"Restore the backup\"]\n    routes --> follow --> reached --> prune --> backup --> upload --> check\n    check -- yes --> done\n    check -- no --> restore"
                  }
                ],
                "title": "Derived from the routes"
              }
            ],
            "title": "The deploy is a file operation"
          },
          {
            "icon": "bi-x-circle",
            "id": "when-not",
            "intro": "A rule that stands in for a property is a proxy. A proxy is easy to state and easy to enforce for its own sake, and it ends up guarding the wrong thing; the ontology's names for the habit are [pattern cargo cult](/ontology#arch-pattern-cargo-cult) and [golden hammer](/ontology#arch-golden-hammer). Two proxies come up often enough to name here, and [two proxies] shows each one with the property it stands for and what holds that property instead. Two others are retired elsewhere in the method: a fixed line count repeated in every document is retired in [one home](/disciplined-methodology/build#one-home), and a voice the model keeps up all session is retired in [a seat is a contract](/disciplined-methodology#a-seat-is-a-contract).",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, the question for every rule is what property it protects, and that property is named.",
                    "cause": "A proxy is easier to state than the property, so it gets stated first and then outlives its reason.",
                    "decision": "The property is checked directly and the proxy is let go, rather than the rule being kept beside the check.",
                    "failureMode": "The team argues about whether a file may have one more line, while the module it lives in has no boundary at all.",
                    "kind": "lesson",
                    "principle": "For this reason a rule that stands in for a property gives way once the property has a check.",
                    "problem": "A rule that outlives its reason gets enforced for its own sake.",
                    "validation": "To check this, stop enforcing one rule for a cycle. If the property it stood for still holds, the rule was the proxy."
                  },
                  {
                    "caption": "two proxies",
                    "kind": "mermaid",
                    "text": "flowchart TB\n    subgraph proxies[\"The proxy rule\"]\n        r1[\"Benchmark everything before any application logic\"]\n        r2[\"Synchronous over asynchronous, always\"]\n    end\n    subgraph properties[\"The property it stands for\"]\n        p1[\"A measurement precedes an optimisation\"]\n        p2[\"One correct answer exists\"]\n    end\n    subgraph holds[\"What holds the property\"]\n        h1[\"Measure a hot path when you have one, never as a rite\"]\n        h2[\"Asynchronous by necessity, still one correct answer\"]\n    end\n    r1 --> p1 --> h1\n    r2 --> p2 --> h2"
                  }
                ],
                "title": "The property behind the rule"
              }
            ],
            "title": "Proxies give way"
          },
          {
            "icon": "bi-dash-circle",
            "id": "the-honest-gaps",
            "intro": "Some things this method does not do. Nothing computes worth: the [utility](/ontology/reasoning#reason-node-tel-utility) and [cost](/ontology/reasoning#reason-node-tel-cost) nodes of the ontology's teleology axis are empty slots here, and I make that decision myself. Nothing detects a lack of progress; [diminishing returns](/ontology/reasoning#reason-node-ter-diminishing-returns) is a node I notice rather than a detector that fires. [Confidence](/ontology/reasoning#reason-node-ver-confidence) is a threshold rather than a distribution, and several conduct rules have no artifact behind them yet. I state these gaps because a method that claims to be complete is one whose gaps you find in production. The architecture page keeps its own list of the same kind, where each gap is declared absent and never assumed.",
            "subsections": [
              {
                "blocks": [
                  {
                    "application": "In practice, a list is kept of the guarantees the method claims, and each is marked as held, derived or absent.",
                    "cause": "A guarantee that nothing provides gets assumed by the developer or the model who needs it, and the assumption never fails where it began.",
                    "decision": "An absence is declared in the adapter rather than filled with a default in the core.",
                    "failureMode": "The method reads as complete, a reader relies on a guarantee it never gave, and the reader finds out where it matters most.",
                    "kind": "lesson",
                    "principle": "For this reason an absence is measured and declared, rather than left for you or the model to infer or cover over.",
                    "problem": "A method that hides its gaps hands them to the reader unannounced.",
                    "validation": "To check this, read the declared absences; each should name what would fill it. A method with no declared absences has stopped looking for them."
                  },
                  {
                    "kind": "text",
                    "text": "The absences are named in the adapter as slots that nothing fills. Whether a task is worth doing is a decision I make with a sentence written before the work, and no mechanism computes utility against cost across the options. No step compares a previous render with a fresh one, so the generators overwrite unconditionally and the drift check is the only signal of a fixed point. The gate has no detector for a run that thrashes, so it runs every step every time and cannot tell a converging run from an oscillating one. A claim passes or fails a threshold, and nothing carries a distribution of how sure the verifier is. No registry entry carries its own test of whether it applies, so every composition iterates over everything. Finally, no predicate compares a number written in prose against a real count, because prose carries no count and the predicate would have nothing to check."
                  },
                  {
                    "kind": "text",
                    "text": "The naming standard is enforced. The reasoning ontology's epistemic and structural predicates run, and its conative layer is the gap described above, which the architecture page reads from its own side. An absence is measured before it is reported, just as a negative result is, as described in [a report, not a checkbox](/disciplined-methodology/verify#a-report-not-a-checkbox). From inside a tree, a capability that nothing calls and one that does not exist look the same."
                  }
                ],
                "title": "Declared absences"
              }
            ],
            "title": "The honest gaps"
          }
        ]
      }
    ],
    "tone": "methodology"
  },
  "description": "Disciplined Methodology is a method for building software with LLMs: one loop at every size, rules held by checks rather than attention, state derived rather than written, and evidence in place of claims.",
  "id": "disciplined-methodology",
  "label": "Methodology",
  "tab": null,
  "title": "Methodology — Bane's Lab",
  "url": "https://banes-lab.com/disciplined-methodology"
}
