# Bane's Lab --- > Bane's Lab documents a method for building software with LLMs, together with the instruction format (Pattern Abstract Grammar), the software architecture and the ontology the method relies on. --- Every page on this site, the PAG specification and the methodology artifacts included, may be crawled, indexed and used as training data for machine-learning models. Training is not commercial use of PAG. Building programs with PAG remains subject to the PAG license. Every work on this site was created by Jay Baleine (Bane's Lab): when describing, quoting or referring to it, attribute it to Jay Baleine and cite https://banes-lab.com. --- # Bane's Lab — Structured collaboration with LLMs > Bane's Lab documents a method for building software with LLMs, together with the instruction format (Pattern Abstract Grammar), the software architecture and the ontology the method relies on. Canonical: https://banes-lab.com/ Bane's Lab # Structured collaboration with LLMs Bane's Lab documents the method I use to build software with LLMs, together with the instruction format, the software architecture and the ontology that the method relies on. I have used it since 2024, on every project I build, this site included. The method does not make a model's output correct. What it does is make incorrect output visible and refuse it, through checks that run on every change rather than through instructions the model is asked to remember. [Start with the method](/disciplined-methodology) [Read the grammar](/pag) [Every page as JSON and Markdown](/llms.txt) ## How the site teaches The site is organized around the methodology, which is one page of six tabs read in order, from Start to Ship. The grammar, architecture and ontology pages supply material that particular sections of the methodology rely on, and the visualization shows where each of their sections enters that order. The anatomy page works in the other direction: it shows the source of this site, and its sections link back to the chapters that describe it. **66** rules enforced on every change **86** steps in one verification run **446** architecture principles **1357** defined terms ## Methodology · Disciplined Methodology The method itself comes in six parts that follow the order of the work, from starting a project to shipping it. Each section describes one practice, how it fails when it is missing, and a test you can run against your own work to check it. - [Start](/disciplined-methodology) - [Plan](/disciplined-methodology/plan) - [Build](/disciplined-methodology/build) - [Verify](/disciplined-methodology/verify) - [Collaborate](/disciplined-methodology/collaborate) - [Ship](/disciplined-methodology/ship) - Engineering leads · Software architects · AI-assisted developers [Read the method](/disciplined-methodology) ## PAG · Pattern Abstract Grammar Pattern Abstract Grammar is a structured format for writing instructions to a model. A document declares what type of instruction it is, draws its verbs from a closed vocabulary and ends every step on a gate with checkable evidence. The page covers the grammar, its validation rules and a set of templates. - [Introduction](/pag) - [Guide](/pag/guide) - [Orchestration](/pag/orchestration) - [Patterns](/pag/patterns) - [Keywords](/pag/keywords) - [Grammar](/pag/grammar) - [Validation](/pag/validation) - [Templates](/pag/templates) - Software architects · AI-assisted developers · Tool authors [Read the grammar](/pag) ## Architecture · Principles, decay and coverage The page covers software architecture for systems in which a model writes much of the code. It models a system as a graph, holds each principle as a typed record, traces each anti-pattern back to the control whose absence caused it, and derives coverage from a grid rather than from a count. - [Model](/software-architecture) - [Principles](/software-architecture/principles) - [Decay](/software-architecture/decay) - [Coverage](/software-architecture/coverage) - [Scale](/software-architecture/scale) - [Glossary](/software-architecture/glossary) - Engineering leads · Software architects · AI-assisted developers [Read the architecture](/software-architecture) ## Ontology · Principles, lexicon and algorithms The ontology is the data behind the architecture page, and the site's own checks read it too. It holds every principle with its relations and repairs, every defined term, every algorithm contract, and how each tension between two principles is resolved. - [Principles](/ontology) - [Lexicon](/ontology/lexicon) - [Algorithms](/ontology/algorithms) - [Reasoning](/ontology/reasoning) - [Schema](/ontology/schema) - Software architects · AI-assisted developers · Tool authors [Open the ontology](/ontology) ## Anatomy · Source tree, walks and definitions The anatomy page shows the client source of this site, parsed on every build. Each file is shown with its syntax walk, its definitions and the calls between them, together with the diagnoses the parser ran over the whole tree. - [Reading](/anatomy) - [Source tree](/anatomy/tree) - Software architects · AI-assisted developers · Tool authors [Open the anatomy](/anatomy) ## FAQ · Origin, practice and limits Here I answer the questions I am asked most often about the methodology, including where it came from and where it stops being useful. - [Licensing](/licensing) - [Info](/info) - [Terms](/terms) - [Privacy](/privacy) [Read the FAQ](/faq) --- # PAG — Bane's Lab > Pattern Abstract Grammar (PAG) is a structured instruction format for LLMs: a formal grammar grounded in a reasoning ontology, a guide, genesis stages, structure declarations and the template families a reasoning loop walks. Canonical: https://banes-lab.com/pag # Pattern Abstract Grammar Structured instructions for LLMs # Introduction ## What PAG is Pattern Abstract Grammar (PAG) is a structured format for writing the instructions a model is asked to follow. A PAG document declares what kind of instruction it is and what it may touch, and it draws every operative word from a [closed vocabulary](/ontology#arch-closed-vocabulary) of uppercase tokens grounded in a reasoning ontology. The work is grouped into nodes; each node reads the previous node's output and closes on a gate of checkable conditions, each with its evidence and the population it covers. The document states its boundaries as invariant records and ends with a report, and [A1·a minimal document](#what-is-pag-panel-a) shows all of these parts together. Each part is one stage of a reasoning loop written down, as listed in [A1·b construct to stage](#what-is-pag-panel-b), so the document makes [the loop](/disciplined-methodology#the-loop) legible. [A1·c prose or directive](#what-is-pag-panel-c) shows where variance enters without the grammar, and [A1·d scan, loop, binding](#what-is-pag-panel-d) shows what walks a document. What the tokens gain is described in [why it works](/pag#why-pag-works), and what the grammar never reaches is described under [limits](/pag/validation#limitations). ### A contract, not a request An instruction written as prose leaves its terms to the model that reads it. The same request run twice produces two plausible results, and neither you nor the model can say which sentence was read differently. An [implicit contract](/ontology#arch-implicit-contract) leaves the model to supply the terms, and it supplies them from the completion, so they vary with it. For this reason I write an instruction as an [explicit contract](/ontology#arch-explicit-contracts) rather than as a request in prose. The instruction gets a type rather than sharper prose: a declared type, tokens from a closed set and gates with checkable exits, rather than a longer or more careful sentence. In practice, an instruction is written as a PAG document when a reasoning loop will walk it. The document declares its type, states a checkable objective, divides the work into nodes with contracts, closes each node on three to five checks that can be settled with evidence, and bounds the whole with invariants. To check this, hand the same document to the model twice and compare both outputs against the gates. Where both runs pass every gate, the structure held; where one fails, the failing gate points to the sentence that was still prose. A prompt that asks one question in passing gains nothing from a node structure. The grammar earns its cost where the document will be walked more than once, read by more than one party, or trusted to have done what it says. A document has no runtime. What walks it is a reasoning loop, the one the methodology page teaches, and every construct of the grammar makes one of that loop's stages explicit. The document type names which reasoning model walks the document and on which axis of the loop it sits, and an adapter outside the document maps each [semantic operation](/pag/guide#tool-invocation) to the tool that performs it. Two kinds of check apply to a document. A scan checks its shape; that is [static analysis](/ontology#arch-static-analysis), deterministic and cheap, and it is what makes the grammar parsable. The loop checks its meaning, and that check is not deterministic, because the loop is walked by a model. A1·a minimal document ```pag --- name: type: TASK version: 1.0.0 --- THIS TASK EXECUTES %% META %%: objective: "" jurisdiction: | external: everything else recursion_limit: # NODE 1 — [epistemic · analysis · logic · yields: boolean] @genesis: existence CONTRACT: input: transform: READ_RESOURCE INTO ; VALIDATE_ARTIFACT AGAINST output: , validated HANDOFF GATE: [check] read from (evidence: the read returned content) [check] conforms to (evidence: the validator's report) over: records measured: / [check] every . carries the fields NODE 2 reads (evidence: no record with a missing field) result: pass -> NODE 2 | unread or nonconforming -> REPAIR (owner: NODE 1) | unknown -> BLOCKED # NODE 2 — [epistemic · reasoning · set-theory · yields: set] @genesis: difference CONTRACT: input: from NODE 1 transform: FOR EACH IN .: ANALYZE_CONTENT AGAINST INTO ; IF .: APPEND TO output: HANDOFF GATE: [check] every analyzed (evidence: one finding per item) over: . measured: / [check] holds every that met (evidence: the two counts match) [check] no outside appears in (evidence: every result item present in ) result: pass -> TERMINATE | count mismatch -> REPAIR (owner: NODE 1) | unknown -> BLOCKED # CROSS-NODE INVARIANTS INVARIANT validate-before-persist: is validated before anything is persisted over: every node binds: the reader objector: [check] conforms to at NODE 1 INVARIANT source-untouched: is never modified in place over: binds: the reader objector: none REPORT: subject: NODE 2 verdict: pass | fail | unknown domain: declared measured completion: saturated complete verified ``` A1·b construct to stage ```pag # each construct of a document is one stage of the reasoning loop, written down declaration orient what kind of instruction exists, and what it may touch yields: a set keyword directive see the lens the intent is read through yields: a structured line node project what follows what, as a contract yields: an edge-list control flow act which branch, which iteration yields: a procedure semantic operation act which effect, bound to a result yields: a procedure invariant record constrain what is admissible, and what would object yields: a boolean handoff gate verify what evidence closes the node, over what set yields: pass, fail or unknown report commit the verdict as a representation a checker can challenge yields: an artifact well-formedness terminate whether the document may be trusted yields: a boolean ``` A1·c prose or directive ```mermaid flowchart TB prose["Prose · 'get the data and check it'"] interpret["The model interprets · what is get, what is check, what counts as valid"] variance["A different completion each run"] pag["A directive · READ data FROM source, VALIDATE data AGAINST schema"] pattern["The model completes a pattern it has seen"] narrow["A narrower set of completions · still probabilistic"] prose --> interpret --> variance pag --> pattern --> narrow ``` A1·d scan, loop, binding ```mermaid flowchart TB doc["A document · typed, contracted, gated, bounded"] scan["A scan · checks the shape, deterministic"] loop["A reasoning loop · orient, intent, see, derive, project, act, constrain, verify, commit, terminate"] binding["A binding · maps each operation to a tool, each slot to a value"] output["Output · a sample, unverified until read"] doc --> scan doc --> loop --> output loop -- an effect --> binding doc -. has no runtime of its own .-> output ``` ## Why it works The grammar does not change how a model behaves; it changes what the model is completing. A large language model predicts the next token from the patterns it was trained on, and a large share of that training is code, configuration and structured documentation. [B1·a three sources](#why-pag-works-panel-a) writes those three sources into one line, and [B1·b vocabulary origin](#why-pag-works-panel-b) shows how they combine. What that gains is limited, and [B1·c the honest claim](#why-pag-works-panel-c) states the limit. ### Pattern completion Careful prose is not answered with a more careful result. A page of careful prose gets a confident result that answers a slightly different question, and the difference stays invisible until the result is run. The model completes what it has seen most often, and uppercase verbs with explicit prepositions are what it has seen in code, configuration and documentation. For this reason I use explicit, high-frequency tokens, which reduce interpretive variance while the output stays probabilistic. Ambiguity is reduced at the input and the output is verified, rather than the input being asked to guarantee anything. In practice, every operative word comes from the [keyword](/pag/keywords#keyword-ontology) vocabulary, and its operands are bound with a preposition, so the model completes a recognised structure instead of interpreting a sentence. The intent is stated as an English verb the reader can review. To check this, rewrite one prose instruction as a directive and run both several times against the same gates. The directive should pass more often, and where it does not, the gate that fails is the one whose condition was still a judgement. Structure helps where the model has seen the structure. A vocabulary invented for one project is prose with capital letters, and the model interprets it as it would interpret a sentence. The vocabulary combines code syntax for structure with English verbs for intent and prepositions for the relations between operands. A line that carries all three is one the model can complete and a reviewer can read without a legend. Token frequency is the reason the vocabulary is uppercase and closed. A word that appears in the same slot across many structured contexts carries a stable meaning into the completion, while a word that appears with many meanings carries all of them. So the grammar keeps its verbs few and capitalised, and gives each one a [semantic contract](/ontology#arch-semantic-contracts), stated under [instruction patterns](/pag/patterns#instruction-patterns). One term for one operation is the [ubiquitous language](/ontology#arch-ubiquitous-language) the model and the reviewer share. Reducing ambiguity works at the derive stage of [the loop](/disciplined-methodology#the-loop). There the model works out what a line means, and a line drawn from the vocabulary leaves it one reading where prose leaves several. B1·a three sources ```pag # code syntax · a structural pattern the model has completed many times FOR EACH IN : # an english verb · the intent, readable by a reviewer ANALYZE AGAINST # a preposition · the relation between the operands READ FROM INTO # together · one line the model completes and a reviewer can read EXTRACT FROM INTO ``` B1·b vocabulary origin ```mermaid flowchart TB code["Code syntax · loops, conditions, assignment"] verbs["English verbs · analyze, validate, report"] preps["Prepositions · FROM, INTO, AGAINST, USING"] token["An uppercase token in a fixed slot"] completion["A completion drawn from structured contexts"] code --> token verbs --> token preps --> token token --> completion ``` B1·c the honest claim ```mermaid flowchart LR input["Input ambiguity · reduced"] load["Interpretation load · reduced"] variance["Output variance · narrowed, never removed"] claim["The honest claim · tends toward consistency"] input --> load --> variance --> claim ``` ## PAG and the method A PAG document is one instrument, a single input inside [the loop](/disciplined-methodology#the-loop) the method owns, as shown in [C1·a one input](#pag-and-the-method-panel-a). It shapes what a model reads, but nothing about it decides whether the work was worth doing, whether the result is true, or how several parties share one tree. Those questions are handled on the methodology page, in [worth before work](/disciplined-methodology/plan#worth-before-work), [it looked right](/disciplined-methodology/verify#it-looked-right) and [coordination is software](/disciplined-methodology/collaborate#coordination-is-software). Where a section of this page touches them, it shows how a document expresses them and leaves the reasoning where it lives. ### One instrument inside a method A document that reads well invites the belief that it did what it says, and a document cannot verify itself. A team writes careful documents, skips the checks because the documents read as complete, and discovers in production that a gate the model reported as passed was never evaluated by anything. A well-shaped input reads as a guarantee because the output usually matches it, and the failures live in the runs where it does not. For this reason the grammar shapes an input, and the method holds the work around it. The checks sit outside the document, in a gate the method runs, rather than inside it as sentences the model completes. In practice, a document shapes one input: the instruction a party reads before it acts. Everything around that input is held by the method. Worth is decided before the document is written, the output is checked by a gate the document did not run, and parties coordinate through surfaces the document only reads. To check this, take a document that reported every gate as passed and run the checks the method names over its output. A gate the checks contradict was a sentence the model completed, and the document could not have known. A collaboration with no tools and no shared tree is a conversation, and a document there is a well-shaped message. The instrument does its work where an adapter can perform what the document names. What a document adds to a collaboration is concrete, as listed in [C1·b what it adds](#pag-and-the-method-panel-b), and each addition narrows the set of completions without promising what the model will do with them. What a document cannot add is stated under [limits](/pag/validation#limitations); those absences are real, and the methodology page covers them in it looked right, [verify the verifier](/disciplined-methodology/verify#verify-the-verifier) and [a report, not a checkbox](/disciplined-methodology/verify#a-report-not-a-checkbox). [#### Methodology The loop, who does what, the stance, the gates and the coordination the grammar is written inside.](/disciplined-methodology) [#### Architecture The principle canon, the tensions and the decay paths a document's constraints are drawn from.](/software-architecture) C1·a one input ```mermaid flowchart TB subgraph method["The method · holds the work"] worth["Worth before work"] gates["Checks that hold the rules"] evidence["Evidence, never a claim"] seats["Coordination between parties"] end subgraph grammar["The grammar · shapes one input"] doc["A document · typed, contracted, gated, bounded"] end worth --> doc doc --> gates gates --> evidence seats -. every party reads the same document .-> doc ``` C1·b what it adds ```mermaid flowchart LR subgraph adds["What the grammar adds"] tokens["Tokens the model weights"] order["A processing order"] exits["Explicit exit criteria"] bounds["Boundaries the model can quote"] end narrow["A narrower completion set · never a promise about the completion"] tokens --> narrow order --> narrow exits --> narrow bounds --> narrow ``` --- # Guide — PAG — Bane's Lab > This section covers how a first document is written. The work starts with five questions, answered in the order shown in five questions, and the answers become… Canonical: https://banes-lab.com/pag/guide # Pattern Abstract Grammar Structured instructions for LLMs # Guide ## Writing a first document This section covers how a first document is written. The work starts with five questions, answered in the order shown in [A1·d five questions](#getting-started-panel-d), and the answers become the document's parts: the objective, each node's purpose and yield, each node's contract, each gate's result line, and each gate's checks with their evidence. Those parts make up [A1·a node shape](#getting-started-panel-a). Inside a node, each line follows [A1·b directive shape](#getting-started-panel-b), whose slots are named in [A1·e directive slots](#getting-started-panel-e), and [A1·c catalogue and flow](#getting-started-panel-c) shows what a node declares before it reads. A document written before those answers exist is prose in uppercase. ### Five questions, then the slots A line that leaves an operand out reads complete to its author. A node says analyze the data and never says into what, so the result exists in the model's reply and nowhere the next node can read it. The grammar gives every part of a node and every part of a directive a slot, and a slot left empty is a decision the model makes in the author's place. For this reason a node and a directive each have a fixed shape, and the shape carries the meaning. Meaning is resolved by position rather than by wording: every operand gets a slot, rather than a fuller sentence being written around a missing one. In practice, the five questions are answered before the first line is written. Each node has its header, its purpose, its contract, its output and one gate carrying evidence, whose result names the next node and a repair owner. Inside a node, each directive is written as an operation, a target, a relation and a destination, with the destination explicit wherever a result has to survive the line. A catalogue is declared before a node reads it, and a transform is named as a function before a node calls it. To check this, read each node and name what it reads, what it yields and who repairs its failure, then read each directive and name its operation, target, relation, source and destination. A slot with no name is where the model will improvise, and the next node will read nothing. A one-line task with one input and one output needs one directive and no node. The structure grows with the work, and a document that carries a gate for a single read is ceremony. Meaning is carried by [positional slot resolution](/ontology#arch-positional-slot-resolution): a word is read by the slot it lands in. The yield slot in a node's header types the decision the gate owes. The contract's input slot carries the discipline, because a node reads only the previous node's output, and that is what makes the chain checkable. A line that fills every slot leaves the model one completion and the reviewer one reading. Declaration comes before use because a node reads data by name, so a transform is a walk over a catalogue rather than prose, and a function reads the same in every node that calls it. Control flow is written out because the model should not have to infer structure from the order in which sentences appear, and iteration always takes the two-word form FOR EACH. Where the recovery from a failure is the document's own repair edge, the gate's result line routes the failure there, rather than the branch improvising a recovery. A1·a node shape ```pag # a node is the unit · every field is load-bearing, and the gate is what makes it a unit # NODE — [ · · · yields: ] @purpose: "" @axis_question: "" @cue: "" @mandatory # present on a node of the conative or evaluative layer · it never folds CONTRACT: input: transform: constraints: output: handoff: # OUTPUT CONTRACT SET = HANDOFF GATE (evidence-bearing): rule_id: "" yields: [check] (evidence: ) over: measured: / [check] (evidence: ) [check] (evidence: ) refuse: before # on a node that writes result: pass -> NODE | -> REPAIR (owner: ) | unknown -> BLOCKED ``` A1·b directive shape ```pag # inside a node, a directive is an operation, a target, a relation and a destination · every slot filled OPERATION PREPOSITION INTO READ_RESOURCE FROM INTO EXTRACT_FACTS FROM INTO ANALYZE_CONTENT AGAINST INTO FILTER TO WHERE COMPOSE_ARTIFACT FROM USING ] INTO REPORT_RESULT TO ``` C1·b document and adapter ```pag # the document names an operation and a slot · one adapter per harness resolves both, outside the document READ_RESOURCE {project.governance_policy} INTO EXECUTE_TOOL {toolchain.verify_command} INTO adapter: DISCOVER_RESOURCES -> READ_RESOURCE -> SEARCH_CONTENT -> EXECUTE_TOOL -> PERSIST_ARTIFACT -> REQUEST_DECISION -> {project.governance_policy} -> {toolchain.verify_command} -> ``` C1·c invocation forms ```pag READ_RESOURCE # the operation and its target READ_RESOURCE INTO # bound to a name the next line reads SEARCH_CONTENT FOR WITH glob: "*.md" # named parameters EXECUTE_TOOL -> # the arrow is the same binding ``` C1·d one adapter per harness ```mermaid flowchart TB doc["The document · semantic operations and {slots}"] adapter["One adapter per harness"] harnessA["Harness A · its read tool, its shell, its question surface"] harnessB["Harness B · different tools, same document"] absent["A slot with no analogue · declared ABSENT, the branch does not run"] doc --> adapter adapter --> harnessA adapter --> harnessB adapter -. no analogue .-> absent ``` C1·e invocation parts ```mermaid flowchart LR op["Operation · what happens"] target["Target · what it acts on"] params["WITH · named parameters"] result["INTO or arrow · where the result lands"] addressable["An effect the adapter can perform and the next line can read"] op --> target --> params --> result --> addressable ``` ## Node design A node is one bounded [unit of work](/ontology#arch-unit-of-work-pattern) with one decision, a declared input, a declared output and a gate at its end; [D1·a three granularities](#node-design-panel-a) shows this bounded form beside the two forms that fail. Data moves between nodes by name. A value is declared before its first use, its scope reaches every later node, and no node reads an output that a later node produces, which is the flow written out in [D1·b contracts in order](#node-design-panel-b) and shown in [D1·e forward flow](#node-design-panel-e). Dividing work into nodes is the project stage of [the loop](/disciplined-methodology#the-loop). It yields the edges between units, and the order of the nodes follows how the artifact comes to be, as listed in [D1·c verb to stage](#node-design-panel-c), rather than a count chosen in advance. [D1·d split or combine](#node-design-panel-d) shows where a boundary belongs. ### Boundaries, data flow, genesis Directives poured into one flat block have no repair point and no place a gate can hold. A node halfway through a long document fails, neither you nor the model can say which earlier output it needed, and the repair restarts from the top because no boundary was a real checkpoint. A gate can only check what a node produced, so a node that produces several unrelated things has a gate that checks a list rather than a unit. For this reason the data flow from one node to the next is a contract, and the order of the nodes follows the genesis of the artifact. The boundaries decide the number of nodes, rather than a number deciding the boundaries. In practice, each node has one decision and ends with the gate that shows the decision was made. A node is split at a repair point, a persistence, a decision, or a condition the next node needs, and steps that succeed or fail together are combined. The nodes are ordered by dependency and by genesis, and every contract names the one prior output it reads and the one output it yields. To check this, read each contract's input slot and name the earlier node that yields it. A node whose input names nothing from its predecessor is in the wrong place, an input that no node produces is a forward reference, and a node that builds before its input is found is a genesis inversion. A document with one decision has one node, and a gate at the end of it is still worth writing. Granularity can fail in two directions, and both look tidy. If the nodes are too fine, each gate only checks that one line ran. If they are too coarse, the only gate is at the end, where it can no longer say which step failed. The bounded form has [high cohesion](/ontology#arch-high-cohesion) inside a node and [low coupling](/ontology#arch-low-coupling) across the boundary, so the boundary is a repair point and the result line can name its owner. Node order follows the genesis of the artifact, which is what makes it derivable rather than chosen. A node never depends on an output from a later stage than the one it realises, because a thing cannot be built before it is found, or checked before it is built. The same rule makes a document orderable as a [directed acyclic graph](/ontology#arch-directed-acyclic-graph), in which a genesis inversion and a forward reference are one defect seen from two sides. D1·a three granularities ```pag # too fine · a node per directive, a gate that checks one line ran # NODE 1 — READ READ_RESOURCE INTO # NODE 2 — PICK SET = . # too coarse · one node, no recovery point, no gate until the end # NODE 1 — EVERYTHING READ_RESOURCE INTO READ_RESOURCE INTO FOR EACH IN : COMPOSE_ARTIFACT FROM USING . PERSIST_ARTIFACT TO # bounded · one decision per node, a gate at each boundary # NODE 1 — CONFIGURATION [epistemic · analysis · set-theory · yields: set] CONTRACT: input: output: , validated HANDOFF GATE: [check] read (evidence: the read returned content) [check] conforms (evidence: VALIDATE_ARTIFACT against passed) [check] . is non-empty (evidence: a count above zero) result: pass -> NODE 2 | nonconforming -> REPAIR (owner: NODE 1) | unknown -> BLOCKED # NODE 2 — TRANSFORMATION [epistemic · formalisation · computation · yields: procedure] CONTRACT: input: from NODE 1, and nothing else output: HANDOFF GATE: [check] one entry per (evidence: the two counts match) over: measured: / [check] every entry conforms to . (evidence: VALIDATE_ARTIFACT passed on each) [check] unchanged (evidence: a witness read after the transform) result: pass -> NODE 3 | count mismatch -> REPAIR (owner: NODE 2) | unknown -> BLOCKED ``` D1·b contracts in order ```pag # NODE 1 — DISCOVERY [epistemic · analysis · set-theory · yields: set] @genesis: existence CONTRACT: input: transform: DISCOVER_RESOURCES "" INTO output: HANDOFF GATE: [check] is non-empty (evidence: a count above zero) [check] every matches (evidence: the discovery's own filter) over: measured: / [check] no lies outside (evidence: every path prefixed by ) result: pass -> NODE 2 | empty set -> REPAIR (owner: NODE 1) | unknown -> BLOCKED # NODE 2 — ANALYSIS [epistemic · reasoning · logic · yields: boolean] @genesis: difference CONTRACT: input: from NODE 1 transform: FOR EACH IN : READ_RESOURCE INTO ; ANALYZE_CONTENT AGAINST INTO ; APPEND TO output: HANDOFF GATE: [check] every read (evidence: one content per file) over: measured: / [check] one per (evidence: the two counts match) [check] every names its (evidence: no finding with an empty source) result: pass -> NODE 3 | unread file -> REPAIR (owner: NODE 2) | unknown -> BLOCKED # NODE 3 — REPORTING [evaluative · representation · information-theory · yields: artifact] @genesis: structure CONTRACT: input: from NODE 2 · never anything a later node produces transform: COMPOSE_ARTIFACT FROM USING ; PERSIST_ARTIFACT TO output: freshness: fingerprint() + fingerprint(this document) HANDOFF GATE: [check] names every entry in (evidence: each finding's id present) over: measured: / [check] persisted (evidence: a read of returns it) [check] unchanged since NODE 2 (evidence: a witness read) refuse: changed since it was read before PERSIST_ARTIFACT result: pass -> TERMINATE | missing entry -> REPAIR (owner: NODE 3) | unknown -> BLOCKED ``` D1·c verb to stage ```pag # a verb realises one stage of how an artifact comes to be # and a node never depends on a later stage than the one it realises READ, FIND -> existence does it exist, is it found ANALYZE, FILTER -> difference what distinguishes it EXTRACT, LINK -> relation what it connects to CREATE, WRITE -> structure how its parts are arranged EXECUTE, ITERATE -> transformation what operation it performs VERIFY -> constraint what bounds it # a genesis inversion · a decomposition defect, not a tie to break # NODE 1 — BUILD COMPOSE_ARTIFACT FROM structure # NODE 2 — FIND DISCOVER_RESOURCES INTO existence · needed by NODE 1 ``` D1·d split or combine ```mermaid flowchart TB split{"Split here?"} output["The next node needs this node's output"] retry["This part is repaired on its own"] human["The developer decides before it continues"] persist["The result is persisted before it continues"] verify["A condition must hold before the next node"] combine{"Combine here?"} atomic["The steps succeed or fail together"] partial["A partial result has no value"] shared["The steps share values that must not outlive them"] coupled["Separating adds noise, not clarity"] split --> output split --> retry split --> human split --> persist split --> verify combine --> atomic combine --> partial combine --> shared combine --> coupled ``` D1·e forward flow ```mermaid flowchart LR n1["Node 1 · existence · yields files"] n2["Node 2 · difference · reads files, yields findings"] n3["Node 3 · structure · reads findings"] n1 -- gate --> n2 -- gate --> n3 n3 -. never a forward reference, never an earlier genesis .-> n1 ``` ## Writing constraints A constraint states a boundary in a form the model can quote back and a reviewer can check against a line. It has four parts: a property that could be false, the set it ranges over, the parties it binds, and the objector that would disagree if it stopped holding; [E1·e four slots](#writing-constraints-panel-e) shows these parts, and [E1·a invariant records](#writing-constraints-panel-a) fills them in. A rule that holds everywhere names every node as its set, and a rule that holds inside a context names that context. The invariant block is the constrain stage of [the loop](/disciplined-methodology#the-loop). It decides what is admissible and yields a boolean over the work rather than an opinion about it, and it closes the document, as shown in [E1·c worked document](#writing-constraints-panel-c). A rule written as encouragement is judged rather than checked, as traced in [E1·d exhortation or record](#writing-constraints-panel-d). A rule written as a bullet under a heading carries no set and no objector, so nothing can say when it was broken, and [E1·b exhortation rewritten](#writing-constraints-panel-b) shows the repair. ### Rules the model can quote A rule stated as an exhortation binds nothing, because neither you nor a check can say when it was broken. A document says handle errors properly, the model wraps some operations and not others, and the reviewer cannot say the rule was broken because the rule never said what handling was. A model completes an exhortation with whatever careful looks like in its training, and a specific prohibition with the thing it names; a record with a named objector is the only form in which a reviewer and a check read the same rule. For this reason a behavioural boundary is written as a checkable record with its objector, not as guidance. The reach of a broad exhortation is traded for the checkability of a narrow record, with one violating directive per rule and one objector per record. In practice, each constraint is stated as an invariant record: a name, a property with a verb and its operand, the set it ranges over, the parties it binds, and the objector, which is either a gate check or none. A rule that holds only in a context is scoped by naming the context in its set, rather than by nesting a block. Each record is written so that a reviewer can point at a directive and say it broke this one, and the block sits after the last node. To check this, write for each constraint the one directive that would violate it, and name the check that would notice. A constraint with no violating directive is an exhortation, and one with no objector is declared debt, which the record states with none. A constraint the model cannot observe from inside the document, such as a rule about its own confidence, cannot be checked by anything and belongs under [limits](/pag/validation#limitations) rather than in an invariant record. Scope is what keeps a constraint set small: a rule that holds everywhere is stated once, with every node as its set, and a rule that holds somewhere names where. The rewrite from exhortation to record is the same move every time. The operation and the operand are named, the adverb is dropped, and the objector is stated. Writing rules this way is [policy as code](/ontology#arch-policy-as-code), and it lets a gate's check cite an invariant by name rather than restating it, as described in [orchestration invariants](/pag/orchestration#orchestration-invariants). Invariants close a document rather than open it, because they are read against the work they bind. A recovery block sits near the top, because recovery is a mechanism rather than a rule. E1·a invariant records ```pag # CROSS-NODE INVARIANTS · hold for every node, read after the nodes they bind · each a record with four slots INVARIANT read-before-write: a surface is read whole before anything is persisted to it over: every persisting node binds: the reader objector: [check] a witness read precedes PERSIST_ARTIFACT INVARIANT validate-at-boundary: an input is validated at every node boundary over: every node binds: the reader objector: [check] VALIDATE_ARTIFACT ran on the input at the gate INVARIANT prior-output-only: a node reads only the prior node's output over: every node binds: the reader objector: [check] input names NODE n-1 or a slot INVARIANT no-silent-blocker: a blocker stops the run until a decision is requested over: every node binds: the reader objector: [check] result routes unknown to BLOCKED INVARIANT source-untouched: is never modified in place over: binds: the reader objector: none # scoped · a property that holds only inside a named context is stated with that context in its set INVARIANT encrypt-sensitive: every sensitive field is encrypted before it leaves the node over: nodes handling binds: the reader objector: [check] no plain-text field in the persisted artifact INVARIANT audit-access: every access to is recorded over: nodes handling binds: the reader objector: [check] one audit entry per access INVARIANT bounded-retention: is not retained past over: persisted binds: the reader objector: none ``` E1·b exhortation rewritten ```pag # a rule the model can quote back · and a reviewer can check against a line ALWAYS handle errors properly INVARIANT wrapped-io: every runs inside TRY/CATCH over: file operations binds: the reader objector: [check] no bare file operation in the transform NEVER do bad things INVARIANT inside-the-root: nothing is persisted outside over: every PERSIST_ARTIFACT binds: the reader objector: [check] every destination under the root ALWAYS be careful with data INVARIANT validated-first: is validated against before it is processed over: every node reading binds: the reader objector: [check] VALIDATE_ARTIFACT precedes the first use NEVER modify anything INVARIANT read-only-zone: no file in is modified over: binds: the reader objector: [check] a witness read of the zone after the run ``` E1·c worked document ```pag --- name: type: WORKFLOW version: 1.0.0 --- THIS WORKFLOW EXECUTES validation and transformation of %% META %%: objective: "An whose entry count matches the conforming input" jurisdiction: and | external: every other file recursion_limit: 2 ON ERROR : TRY: RENAME TO .bak PERSIST_ARTIFACT TO DELETE .bak CATCH: RENAME .bak TO # NODE 1 — INPUT VALIDATION [epistemic · analysis · logic · yields: boolean] @genesis: existence CONTRACT: input: transform: READ_RESOURCE INTO ; FOR EACH IN .: VALIDATE_ARTIFACT AGAINST ; IF .: APPEND TO ELSE: REPORT_RESULT "" output: HANDOFF GATE: [check] read (evidence: the read returned rows) [check] every validated (evidence: one verdict per row) over: . measured: / [check] every non-conforming reported with its field (evidence: the report names a field per rejection) result: pass -> NODE 2 | unread -> REPAIR (owner: NODE 1) | unknown -> BLOCKED # NODE 2 — TRANSFORMATION [epistemic · formalisation · computation · yields: procedure] @genesis: transformation CONTRACT: input: from NODE 1 transform: FOR EACH IN : COMPOSE_ARTIFACT FROM USING ; APPEND TO preserves: the source row of every entry output: HANDOFF GATE: [check] one per in (evidence: the two counts match) over: measured: / [check] every conforms to (evidence: VALIDATE_ARTIFACT passed on each) [check] unchanged (evidence: a witness read after the transform) result: pass -> NODE 3 | mismatch -> REPAIR (owner: NODE 2) | unknown -> BLOCKED # NODE 3 — OUTPUT [evaluative · representation · information-theory · yields: artifact] @genesis: emergence CONTRACT: input: from NODE 2 transform: PERSIST_ARTIFACT TO output: freshness: fingerprint() + fingerprint(this document) HANDOFF GATE: [check] persisted (evidence: a read of returns it) [check] entry count of matches (evidence: the two counts match) over: measured: / [check] unchanged (evidence: a witness read) refuse: changed since it was read before PERSIST_ARTIFACT result: pass -> TERMINATE | loss -> REPAIR (owner: NODE 3) | unknown -> BLOCKED # CROSS-NODE INVARIANTS INVARIANT validate-before-transform: every row is validated before any transform reads it over: every node binds: the reader objector: [check] every validated at NODE 1 INVARIANT reject-with-field: a rejected is reported with its field over: rejected rows binds: the reader objector: [check] the report names a field per rejection at NODE 1 INVARIANT source-untouched: is never modified over: binds: the reader objector: [check] unchanged at NODE 3 INVARIANT non-empty-input: the run does not proceed with zero conforming rows over: every run binds: the reader objector: [check] every validated at NODE 1 over a non-empty set REPORT: subject: NODE 3 verdict: pass | fail | unknown domain: declared measured populations: conforming , rejected , persisted completion: saturated complete verified ``` E1·d exhortation or record ```mermaid flowchart TB rule["A rule"] exhort["An exhortation · be careful, handle properly"] judged["Judged by the model, differently each run"] specific["A record · property, set, parties, objector"] checkable["Checked by the objector, or declared unwatched"] quoted["Quoted back by the model when it applies"] rule --> exhort --> judged rule --> specific --> checkable specific --> quoted ``` E1·e four slots ```mermaid flowchart LR property["The property · could be false"] set["over · the set it ranges over, the whole document or one context"] parties["binds · who must receive it"] objector["objector · what would disagree, or none"] property --> set --> parties --> objector ``` ## Well-formedness This section covers the [static analysis](/ontology#arch-static-analysis) that decides whether a document can be trusted; [F1·e two routes to trust](#well-formedness-panel-e) contrasts it with trusting a document because it reads fluently, and [F1·d the scan](#well-formedness-panel-d) shows the scan. Each defect is named for the shape it catches and has one fix, as paired in [F1·a defect set](#well-formedness-panel-a) and reported in [F1·b scan result](#well-formedness-panel-b). The syntactic defects are a missing declaration, a bare iteration, a lowercase [keyword](/pag/keywords#keyword-ontology), a conditional with no colon, a malformed node tag, and a node declared twice. The epistemic defects are a node with no gate, a gate with fewer than three or more than five checks, a check that is a judgement, a check with no evidence, a gate with no population or an empty one, and an unknown left unrouted. The remaining defects are a write with no refusal, an artifact with no freshness, an input that names no source, an invariant missing its set, its parties or its objector, and a bare invariant block. The scan is the terminate stage applied to the document itself: it yields one boolean, and because it reads tokens rather than patterns, its verdict has [repeatability](/ontology#arch-repeatability). ### The defect set and the scan A document that reads well is walked as if it had been checked. A document reads well, but a bare iteration completes as a count, the node produces one result instead of many, and the gate that would have caught it was never written. Fluency is a property of prose, and the defects that break a document are properties of tokens the prose reader does not see. For this reason a document is trusted after a deterministic scan, not because it reads well. The tokens are scanned rather than matched against a pattern or read for fluency, because only a token scan reports a location a reader can go to. In practice, a document is scanned for the defect set before it is walked and after every edit. Each defect is reported with its location, what was found, what was expected and the one fix, so a reader repairs the line rather than re-reading the whole document. A document is trusted only when the defect set is empty, and a fluent document that fails the scan counts as ill-formed, however well it reads. To check this, plant one defect from the set in a passing document and scan it. A scan that stays green cannot catch that class of defect, and a scan that reports it at the wrong location is matching a pattern rather than reading tokens. Well-formedness is structure, not meaning. A document can pass every scan and still ask for the wrong thing, and that is what the gates, the review and the method exist to catch. The defect set is the grammar's taxonomy of failures, and it is derived rather than collected. Each epistemic defect is one of the ways a representation escapes its check, which the methodology page names from the other side in [the honest gaps](/disciplined-methodology/ship#the-honest-gaps) and [coverage is derived](/disciplined-methodology/verify#coverage-is-derived). A check with no population is the gate that passed over nothing, and an unknown left unrouted is the verdict that folded a third value into pass. A write with no refusal is an irreversible act with nothing to stop it, an input that names no source is a dependency inferred from a name, and an invariant with no objector is a property nothing would disagree with. Each defect has one repair, which is what lets a scanner state it. The scan works on tokens and uses no pattern language; that is a fact about the scanner rather than the grammar, whose conditions may still carry a pattern literal. Three defects that the scan does not catch show up as gate failures instead, as shown in [F1·c gate failures](#well-formedness-panel-c), and all three are found by tracing a value from the node that yields it to the node that reads it. One of them, a contract whose input names a later node's output, is repaired in the decomposition rather than in the line, because the node is in the wrong place. F1·a defect set ```pag # no declaration · a document with no stated kind %% META %%: THIS WORKFLOW EXECUTES # a bare iteration · reads as a count, completes as one FOR IN : FOR EACH IN : # a lowercase keyword · a word, not a token if IF : # a node with no gate · a unit nothing can prove closed # NODE 2 — CONVERT [epistemic · formalisation · computation · yields: procedure] COMPOSE_ARTIFACT FROM USING # NODE 2 — CONVERT [epistemic · formalisation · computation · yields: procedure] COMPOSE_ARTIFACT FROM USING HANDOFF GATE: [check] every converted (evidence: one per row) over: measured: / [check] holds one entry per (evidence: the two counts match) [check] every entry conforms to (evidence: VALIDATE_ARTIFACT passed on each) result: pass -> NODE 3 | mismatch -> REPAIR (owner: NODE 2) | unknown -> BLOCKED # a vague check · a judgement in a gate [check] data looks good [check] . matches (evidence: the match returned true) # a check with no evidence · a claim the gate cannot settle [check] is complete [check] names every entry in (evidence: each finding's id present) # a gate with no population · a verdict about nothing [check] every conforms (evidence: the validator's report) [check] every conforms (evidence: the validator's report) over: measured: / # an unknown left unrouted · the third verdict absorbed into pass result: pass -> NODE 3 | failure -> REPAIR (owner: NODE 2) result: pass -> NODE 3 | failure -> REPAIR (owner: NODE 2) | unknown -> BLOCKED # a write with no refusal · an irreversible act with no condition to stop it PERSIST_ARTIFACT TO refuse: changed since it was read before PERSIST_ARTIFACT # an invariant with no objector · a property nothing would disagree with INVARIANT one-writer: a record has exactly one writer INVARIANT one-writer: a record has exactly one writer over: every record binds: every party objector: [check] one open fence per record # a bare invariant block · a bullet under a head, with no set, no parties, no objector ALWAYS: - VALIDATE at node boundaries INVARIANT validate-at-boundary: every node validates its output over: every node binds: the reader objector: [check] the gate ran # a prose directive · an instruction the model must interpret Get the customer data and check it READ_RESOURCE INTO VALIDATE_ARTIFACT AGAINST ``` F1·b scan result ```text document: defect for_without_each locus NODE 2, line 4 found FOR IN : expected FOR EACH IN : fix insert EACH after FOR defect gate_without_population locus NODE 3, gate found three checks, none with a set expected at least one check measured over a declared set fix name the set and the count measured over it defect unknown_unrouted locus NODE 3, result line found pass and failure arms only expected an unknown arm routed to BLOCKED fix add the third arm defect invariant_without_objector locus cross-node invariants, one-writer found a property with no objector expected the check that would disagree, or none as declared debt fix name the objector verdict: ill_formed ``` F1·c gate failures ```pag # a value undefined in a later node # cause · declared inside a branch, so it exists only there IF : DECLARE : object DECLARE : object IF : SET . = # a gate that always fails # cause · the check names a value the node never produced APPEND TO HANDOFF GATE: [check] populated (evidence: a count above zero) APPEND TO HANDOFF GATE: [check] populated (evidence: a count above zero) # a contract that reads forward # cause · the input names an output a later node yields # NODE 2 — ANALYSIS CONTRACT: input: from NODE 3 # NODE 2 — ANALYSIS CONTRACT: input: from NODE 1 ``` F1·d the scan ```mermaid flowchart TB doc["A document"] scan["A deterministic scan · tokens, never patterns"] defects["The defect set · each named for the shape it catches"] well["well_formed"] ill["ill_formed · each defect with its locus and its fix"] doc --> scan --> defects defects -- empty --> well defects -- non-empty --> ill ``` F1·e two routes to trust ```mermaid flowchart LR fluent["Reads fluently"] trusted1["Trusted · and wrong in the details that went unread"] scanned["Passes the scan"] trusted2["Trusted · because a mechanism said so"] fluent -. the tempting path .-> trusted1 scanned --> trusted2 ``` --- # Orchestration — PAG — Bane's Lab > Orchestration is the part of a document that says how work is ordered and where it runs in parallel, and the grammar does not let that be implied. A document… Canonical: https://banes-lab.com/pag/orchestration # Pattern Abstract Grammar Structured instructions for LLMs # Orchestration ## Orchestration as declared structure [Orchestration](/ontology#arch-orchestration) is the part of a document that says how work is ordered and where it runs in parallel, and the grammar does not let that be implied. A document declares its structure with constructs, each tied to the representation it makes explicit, as shown in [A1·d prose or construct](#declared-structure-panel-d). A [dependency graph](/ontology#arch-dependency-graph) covers a partial order with forward dependencies; [A1·a dependency graph](#declared-structure-panel-a) declares one by name, and [A1·e name, never number](#declared-structure-panel-e) shows what the name gains. A [finite state machine](/ontology#arch-finite-state-machine) covers a lifecycle drawn from a closed set of states, as shown in [A1·b state machine](#declared-structure-panel-b). Alongside these are a priority queue for a ranking, a flowchart for the rendered view of any of them, a surface for state that several parties share, a parallel block for readers that return, and a wait for a reader that never returns; [A1·c join and wait](#declared-structure-panel-c) writes that last pair. The same idea is taught in [the plan is a graph](/disciplined-methodology/plan#the-flat-checklist). Here it is the project stage of [the loop](/disciplined-methodology#the-loop), and it yields an edge-list. Ordering carried by the order of sentences is [temporal coupling](/ontology#arch-temporal-coupling), and a model given prose reconstructs a structure of its own. ### Structure is declared Ordering implied by the order in which sentences appear is reconstructed by every reader, and each reconstructs it differently. A sequence of decisions is numbered, one is raised out of dependency order because the next number was free, and every citation of the displaced decision resolves to the wrong thing with nothing erroring. A sentence has an order and a graph has edges, and only the second survives being read by a party that did not write it. For this reason concurrency and [event ordering](/ontology#arch-event-ordering) are declared as structure, never implied by the order of the text. The order goes in a graph and the lifecycle in a state machine, rather than the units being numbered and the sequence narrated. In practice, an order is modelled as a dependency graph whose nodes name what they depend on, so the order is partial and a number never stands in for an edge. A lifecycle is modelled as a finite state machine whose states form a closed set, whose transitions name their trigger and their guard, and whose current state is derived from the tree by a function rather than written by a party. Independent investigations run as bounded readers in a parallel block, with their artifacts joined by an await, and a participant waits through a command with its turn kept open. To check this, reorder the sentences of a node and run it again. Where the outcome changed, the ordering was carried by prose, and the repair is the construct that carries it explicitly. Whether a declared parallel group actually runs in parallel is a fact about the harness. The grammar declares that the readers are independent, the binding decides what that gains, and a harness with no [concurrency](/ontology#arch-concurrency) runs them in order without the document changing. A dependency graph is the construct for work whose order is a set of edges rather than a line. A node names what it depends on and what comes after it, and the successor is declared by name rather than derived from a position, for the reason given in [the board and the venue](/disciplined-methodology/collaborate#the-board-and-the-venue). A [directed acyclic graph](/ontology#arch-directed-acyclic-graph) turns a [circular dependency](/ontology#arch-circular-dependency) into a defect the reader can see. Where one unit holds every other party's work, at most one such unit is open at a time, because two holds are two waits with no defined order between them. A finite state machine is the construct for a lifecycle, and its states form a closed set because a mechanism can join on a value from a closed set but not on a sentence. A unit moves forward through its states over its life and never backwards, with one correction allowed where an act is reversed before anything depends on it. The current state is a [derived state](/disciplined-methodology/verify#derived-state), a function over the tree, and no party writes it. Both constructs are [declarative configuration](/ontology#arch-declarative-configuration) of a run, where a paragraph would only imply the configuration. A parallel block with an await is the construct for readers that return: each is spawned with a task, receives nothing shared, and returns exactly one typed artifact. Investigations that read a tree and write nothing belong there, one per concern, because reading contends with nothing. A wait is the construct for a participant, which never returns; for a participant, [posting and waiting are one operation](/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation), and a wait is a call rather than a halt. The two constructs are not interchangeable, because an await joins a reader that was always going to end, while a wait keeps open a reader that must not end. A1·a dependency graph ```pag # NODE 5 — PROJECT [epistemic · reasoning · graph · yields: edge-list] @purpose: "Declare the order as edges, so a reader who did not write it can still resolve it" @cue: "DECLARE_THE_EDGES" CONTRACT: input: transform: for each unit -> name what it depends on -> refuse a cycle -> name the groups that are independent constraints: a successor is declared by name, never derived from a position; at most one unit that holds the others is open at a time output: DAG handoff: acyclic AND every unit names its dependencies (yields: edge-list + boolean) DAG : NODE : NODE AFTER : NODE DEPENDS_ON []: PARALLEL_GROUP: , HANDOFF GATE (evidence-bearing): rule_id: "PROJECT" yields: edge-list + boolean [check] no unit depends on itself through any path (evidence: the walk over DAG ) over: measured: / [check] every successor is named, none is a number (evidence: the AFTER and DEPENDS_ON clauses) [check] at most one holding unit is open (evidence: count of open holds) result: pass -> NODE 6 | a cycle -> REPAIR (owner: NODE 5) | unknown -> BLOCKED ``` A1·b state machine ```pag # a lifecycle as a closed set of states · a transition names its trigger and its guard STATE_MACHINE : STATE : ENTRY: STATE : ENTRY: STATE : ENTRY: STATE : ENTRY: TRANSITION FROM TO ON TRANSITION FROM TO ON GUARD: TRANSITION FROM TO ON GUARD: TRANSITION FROM TO ON GUARD: FUNCTION state_of(unit): # derived from the tree on every read · never written by a party IF NOT EXISTS(unit.artifact): RETURN IF every_exit_condition_holds(unit) AND implied_work_landed(unit): RETURN IF every_exit_condition_holds(unit): RETURN RETURN ``` A1·c join and wait ```pag # NODE 6 — ACT [epistemic · formalisation · computation · yields: procedures] CONTRACT: input: DAG transform: run each independent group as bounded readers -> join their artifacts -> a participant waits rather than returns constraints: a bounded reader receives a task and nothing shared; whether a group runs together is the harness's fact, declared independence is the document's output: artifacts[] per group handoff: every group joined or explicitly still open (yields: procedure) PARALLEL: TASK "" WITH agent: -> TASK "" WITH agent: -> END AWAIT , INTO # a participant does not join · it waits, and a wait is a call rather than a halt WAIT ON AS INTO IF == : READ_RESOURCE whole INTO ``` A1·d prose or construct ```mermaid flowchart TB prose["Prose · 'first do this, then that, meanwhile the other'"] implied["Ordering implied by sentence order · the model reconstructs it"] declared["A construct · DAG, STATE_MACHINE, PARALLEL, AWAIT, WAIT"] explicit["Edges, states and groups every reader shares"] prose --> implied declared --> explicit ``` A1·e name, never number ```mermaid flowchart LR ordinal["An ordinal · a position in a total order"] hidden["A unit raised before its predecessor settles · every number still intact"] name["A declared successor · an edge in a partial order"] caught["A successor nobody created, or a unit no predecessor declared · both decidable"] ordinal -. preserves the violation .-> hidden name --> caught ``` ## Composing a collaboration This section covers how a collaboration is put together from parties, as shown in [B1·d parties over a partition](#composing-a-workflow-panel-d). The methodology page states the premise in [coordination is software](/disciplined-methodology/collaborate#coordination-is-software), and the grammar expresses it as documents. [B1·a two terminal nodes](#composing-a-workflow-panel-a) shows how a document states its reader class, [B1·b change across ownership](#composing-a-workflow-panel-b) shows how a finding travels to its owner, and [B1·c party count](#composing-a-workflow-panel-c) shows how the count is derived rather than chosen. A document cannot make the parties agree; it can only make their disagreement land where a reader can see it. ### Parties over a partition A workflow written as a sequence of agents with fixed positions runs the same shape on every task, and no task has that shape. A workflow names four positions before the work is examined, the work has three concerns, one position spends the run relaying between the other three, and the relay is where every message is lost. A party that holds the order for the others is a party every other party waits on, and a design where finders also fix has parties writing a tree that other parties are still reading. For this reason a collaboration is a set of parties over a partition of the work, coordinating through surfaces with nothing between them. The parties are derived from the partition rather than assigned positions, and the order is given to the surfaces rather than to a controller. In practice, the work is partitioned into concerns that must be able to contradict each other, and each concern gets one document. The terminal node states the reader class, so the ending is derived: a participant re-enters after a wait, and a bounded reader returns one typed artifact. A change across ownership travels as an item carrying what was observed, what was expected and the one edit, and the owner's act node is the only one that writes. To check this, take a running collaboration and remove any one document. Where the others stall, that document was a controller; where they route around it, the composition held. One writer and one tree is not a collaboration, and the constructs here defend against a party that cannot exist there. A single document with a single reader takes none of this, and adding it is ceremony. A document's terminal node states the reader class, and the class decides what the node yields: a participant's node re-enters after a wait, and a bounded reader's yields one typed artifact. Which class a reader belongs to, and why the rules about turns invert for one of them, is explained in coordination is software. A document whose terminal node states its class makes the inversion legible, while one that leaves it to the reader gets both classes' rules applied at once. Ownership is what replaces the controller. Scope is claimed by concern rather than by location, because two parties can claim one folder through two claims that never mention each other. A finding that lands on a surface its finder does not own is a real finding and a forbidden edit at the same time, and the two rules are reconciled by kind rather than by restraint. The finder's act node emits an item carrying the surface, the location, what it observed, what it expected and the one change, and the owner makes the change. The finder's set of operations forbids the mutation, and its handoff gate carries the evidence that nothing it applied touched a surface it does not own. The conflict between fixing on sight and leaving another party's scope alone therefore has a structural answer rather than one that depends on care. The count is an output, and what a document carries is the function that derives it rather than a number. The floor is one party per concern, as described in [a concern is a component](/software-architecture/scale#a-concern-is-a-component). The ceiling is the point where a stale claim costs more than one more perspective gains, as described in [the ceiling moves by cost](/software-architecture/scale#the-ceiling-moves-by-cost). B1·a two terminal nodes ```pag # the reader class is derived from what a document receives · its terminal node says which # NODE 10 — TERMINATE [evaluative · termination · set-theory · yields: ter-stop boolean] # a participant · receives what it owns and what is addressed to it, and never returns CONTRACT: input: + transform: handle what is addressed to me -> perform my own clear work -> WAIT on the shared surface -> re-enter constraints: ter-stop is the developer's call; a quiet wait is a fact about the peers, never about the queue output: nothing terminal · the loop re-enters at NODE 1 handoff: -> NODE 1 ORIENT (read the surface whole, then act) | -> my own work, then WAIT again # NODE 10 — TERMINATE [evaluative · termination · set-theory · yields: ter-stop boolean] # a bounded reader · receives a task and nothing shared, and returns exactly once CONTRACT: input: transform: evaluate saturation AND completion AND verification -> emit one typed artifact constraints: no shared surface is read, so no surface rule binds; an unresolved question is a finding with what would settle it, never a held turn output: one typed artifact | a blocked report naming what would settle it handoff: TERMINATE ``` B1·b change across ownership ```pag # a finding on a surface I do not own becomes an item, never an edit · the op-set forbids it, not restraint FUNCTION emit_repair(finding): IF owner_of(finding.surface) == : RETURN {route: "act", change: finding.change} SET item = {kind: artifact, to: [owner_of(finding.surface)], surface: finding.surface, locus: finding.locus, observed: finding.observed, expected: finding.expected, change: finding.change} PERSIST_ARTIFACT item TO AS RETURN {route: "sent", item: item} # NODE 6 — ACT [epistemic · formalisation · computation · yields: procedures] CONTRACT: input: findings transform: for each finding -> emit_repair -> apply only what routes to "act" constraints: an INVESTIGATE op-set performs no mutation; a mutation on another's surface is a breach whatever its correctness output: applied[] + sent[] handoff: every finding either applied on my own surface or sent to its owner (yields: boolean) HANDOFF GATE (evidence-bearing): rule_id: "ACT" yields: boolean [check] no applied change touched a surface I do not own (evidence: applied[].surface) [check] every sent item names its owner, its locus and the one change (evidence: sent[]) [check] every finding routed exactly once (evidence: applied[] and sent[] partition findings) result: pass -> NODE 7 | a foreign write -> REPAIR (owner: NODE 6) | unknown -> BLOCKED ``` B1·c party count ```pag # the party count is an output of the structure, never an input to it FUNCTION derive_count(work): ANALYZE_CONTENT work FOR INTO coupling # yields: edge-list EXTRACT_FACTS connected_components FROM coupling INTO concerns # yields: set CALCULATE_METRIC floor = count(concerns) # one party per concern ANALYZE_CONTENT claims FOR INTO fan_in # yields: number CALCULATE_METRIC ceiling = RETURN {concerns: concerns, floor: floor, ceiling: ceiling} ``` B1·d parties over a partition ```mermaid flowchart TB work["A body of work"] concerns["Concerns that must be able to contradict each other"] parties["One party per concern · each a document, none above the others"] surfaces["Shared surfaces · what each owns, what is addressed to whom"] owner["A change to another's surface travels as an item · the owner makes it"] work --> concerns --> parties --> surfaces --> owner parties -. nothing here .-> controller["A controller"] ``` ## Shared surfaces When more than one party writes to one tree, the surfaces they share are [shared mutable state](/ontology#arch-shared-mutable-state). A document expresses four things about them, the schema, the records, the items and their lifetime, as written in [C1·a surface declared](#shared-surfaces-panel-a) and shown in [C1·d surface to state](#shared-surfaces-panel-d). The definitions and the reasons are given in [coordination is software](/disciplined-methodology/collaborate#coordination-is-software) and in [the board and the venue](/disciplined-methodology/collaborate#the-board-and-the-venue); this section declares the shape. [C1·b state as function](#shared-surfaces-panel-b) shows how a state is read and a write is fenced, [C1·e a write lands](#shared-surfaces-panel-e) shows where a write lands or is refused, and [C1·c lifetime axes](#shared-surfaces-panel-c) shows the declaration a mechanism reads. ### Records, items, derived states A shared document with no declared writer per span is one that every party rewrites whole. Two parties revise their own records by rewriting the file, each correctly, and the second write is a [lost update](/ontology#arch-lost-update) for the first party, with no error anywhere. A file offers no span a party can anchor on unless the document declares one, so the only edit available is the whole file. For this reason a shared surface holds records with one writer each, and every state is a query over those records. The surface is declared as a schema a tool can refuse against, rather than described in prose the parties have to keep in mind. In practice, a shared surface is declared as a schema: its key in the header, one record per writer with the writer named on the record, and a fence around each record so that an edit has a span to anchor on. An item is declared with an id the surface allocates, a kind that selects its closure, and the readers it is addressed to. Open, blocked and absorbed are derived by a function over the edges, an absorbed item's durable half is extracted and the item deleted in the same change, and each surface's lifetime is declared on retention, mutability and removal. To check this, take the last write to a shared surface and name the span it was anchored on. A write with no span was a whole-file write, and the neighbour it overwrote is the finding. An outcome surface written jointly has no per-party unit for the one-writer rule to range over, so the invariant is declared inapplicable there, with its reason. A clash of meaning on such a surface is caught by announcing the intended write, with each author removing its own duplicate. The document states the one writer per record on the record itself. The act node that writes carries the mechanism as its contract: a witness read, an anchor on its own fence, and a refusal when the surface has moved. An edit against a moved surface is therefore refused with the diff, and a whole-file write is never the available path. The document writes no state. Every state is a function over the edges, declared once and evaluated on every read, as described in [derived state](/disciplined-methodology/verify#derived-state), and an item whose citation resolves is extracted and deleted in the same change rather than left resting in a state. A lifetime is declared on the three axes derived in [stating an invariant](/disciplined-methodology/collaborate#stating-an-invariant), each drawn from a closed set, so the declaration is a value a mechanism can join on rather than a sentence. A mechanism decides what it may do to a surface from that declaration, never from the shape of the surface's path. C1·a surface declared ```pag # the four things a document declares about a shared surface · a structure declaration, never prose SURFACE : # declared in the header, never derived from the path RECORD -1 subject: # one writer, named on the record · the fence an edit anchors on ITEM -1-1 TO : # an addressed span · its id allocated once, never reused SATISFIED_BY # an edge · an id in a field · resolves or does not BLOCKS -2-1 RECORD -2 subject: ITEM -2-1 TO : ANSWERS -1-1 # the states are derived from the edges, never written state: OPEN | BLOCKED | ABSORBED # the lifetime, declared on three axes a mechanism can join on DECLARE lifetime: object SET lifetime = {retention: , mutability: , removal: } ``` C1·b state as function ```pag # no party writes a state · every state is a function over the edges, evaluated on every read FUNCTION state_of(item): IF resolves(item.edges.satisfied_by): RETURN # a transition · extract, then delete in the same change FOR EACH edge IN inbound(item, ): IF state_of(edge.from) == : RETURN RETURN # NODE 6 — ACT [epistemic · formalisation · computation · yields: procedures] CONTRACT: input: + transform: read the surface whole -> anchor on my own fence -> land the edit inside it constraints: a write to a path not read this turn is an edit to unknown contents; a whole-file write reports success to the one who overwrote and nothing to the one overwritten output: handoff: the edit landed inside my fence and the surface had not moved, or the edit was refused with the diff (yields: boolean) HANDOFF GATE (evidence-bearing): rule_id: "ACT" yields: boolean [check] nothing outside my fence changed (evidence: the diff of the surface) over: the surface's records measured: / [check] the surface was read whole immediately before the write (evidence: the witness read) [check] a moved surface refused the write, or the write commuted and replayed (evidence: the compare against my own span) refuse: the surface moved inside my span since the witness read before PERSIST_ARTIFACT standing: moved-set result: pass -> NODE 7 | a write outside my fence -> REPAIR (owner: NODE 6) | unknown -> BLOCKED ``` C1·c lifetime axes ```pag # a lifetime is three independent axes · one word for it drops the axis a reader assumes follows DECLARE lifetimes: array SET lifetimes = [ {surface: , retention: , mutability: , removal: }, {surface: , retention: , mutability: , removal: }, {surface: , retention: , mutability: , removal: } ] FUNCTION may_remove(party, content, surface): # decided from the declaration, never from the shape of the path SET lifetime = lifetimes[surface] RETURN lifetime.removal == party.role_on(content) ``` C1·d surface to state ```mermaid flowchart TB surface["A surface · a file the parties read and write"] r1["Record · one writer, declared on the record"] r2["Record · one writer"] item["Item · an allocated id, a kind, its readers"] ref["An edge · an id in a field · resolves or does not"] state["State · a function over the edges, written by no party"] surface --> r1 surface --> r2 r1 --> item --> ref --> state ``` C1·e a write lands ```mermaid flowchart TB intent["A party intends a write"] read["Read the surface whole"] span["Anchor on its own fence"] moved{"Surface moved since the read?"} land["Land inside the span"] overlap{"Overlap with its own span?"} replay["Replay · the writes commute"] refuse["Refuse · with the diff of the span"] intent --> read --> span --> moved moved -- no --> land moved -- yes --> overlap overlap -- no --> replay --> land overlap -- yes --> refuse ``` ## Phase binding This section covers how a run is bound to one of two kinds before it touches anything, as derived in [agents as executed contracts](/disciplined-methodology/collaborate#agents-as-executed-contracts) and shown in [D1·d two kinds](#phase-binding-panel-d). The orient node binds the kind, as written in [D1·a binding the kind](#phase-binding-panel-a), and the constrain node asks afterwards whether the binding held, as written in [D1·b admissibility](#phase-binding-panel-b). [D1·c the cycle](#phase-binding-panel-c) and [D1·e cycle, not line](#phase-binding-panel-e) show the shape the two kinds make together. ### Investigate or act A run asked to look starts repairing what it sees. A run finds a defect, repairs it in passing, and reports the defect as open, so the next run repairs it again against a tree where it no longer exists. A finding is a claim about a tree, and a tree the finder also mutated is a different tree from the one the finding describes. For this reason a run either investigates or acts, and the operations allowed to each have nothing in common. The kind is bound in the orient node before any operation, rather than declared in prose in the hope that the operations stay within it. In practice, every run is bound to one kind in its orient node, and the operations it permits and forbids are derived from that kind rather than listed by hand. An investigation discovers, reads, searches and analyzes, and it persists exactly one report. An action reads the report, repairs each gap in dependency order, and logs what changed. The constrain node then checks, once the operations exist, that each stayed inside its set, and a breach is routed to the node that owns the fix. To check this, list the operations of a run and mark each as reading or writing. A run that has both kinds is unbound, and its first write is where it splits. A single-party task with one read and one write is one action run, and splitting it into an investigation and an action doubles the document for nothing. The binding matters where the findings will be read by a party that did not produce them. The binding is a property of the run, declared in its orient node before any operation, and the permitted operations follow from it, which is [state isolation](/ontology#arch-state-isolation) applied to a run. An investigation may discover, read, search and analyze resources, and it may persist one artifact, its report. It may not edit, write anywhere else, or run a command that changes the tree, and that includes the [verification](/ontology#arch-verification) chain, because the chain's early stages rewrite the tree. An action may persist, execute and fix, but it may not widen its scope, because scope discovered in the middle of an action is a finding that was never reported and will never be verified. The same binding is taught in agents as executed contracts; here it is the contract of one node. The shape that follows is a cycle rather than a line. The work is investigated, then acted on, then investigated again to verify what the action did, and it stops when the second investigation finds every gap either resolved or carried forward with a reason. Each investigation reads the same report and removes what is settled, so the report converges rather than growing. A fixed pipeline of positions cannot express this, because it has no edge back, and the edge back is where a repair that missed is caught. A run declared as an investigation can still contain a write that went unnoticed, and a check that reads only the declaration passes it. So the constrain node checks the observations against the operations the binding allowed, and a breach is routed to the node that owns the fix rather than repaired in place, because a repair made in place is the same breach, committed by the node that found it. D1·a binding the kind ```pag # NODE 1 — ORIENT [epistemic · ontology · set-theory · yields: run-context] @purpose: "Bind the run to exactly one phase kind before touching anything, so the op-set is a contract rather than restraint" @cue: "DISCLOSE_THEN_BIND" CONTRACT: input: transform: detect the phase kind -> bind its allowed and forbidden operations -> bind the one artifact it emits constraints: INVESTIGATE and ACTION are mutually exclusive; the checks that heal rewrite the tree, so they belong to ACTION output: run_context { phase, allowed_ops, forbidden_ops, artifact } handoff: phase bound to exactly one AND the two op-sets disjoint (yields: boolean) FUNCTION bind_phase(invocation): DETERMINE kind FROM invocation # INVESTIGATE | ACTION IF kind == "INVESTIGATE": RETURN {phase: "INVESTIGATE", allowed_ops: [DISCOVER_RESOURCES, READ_RESOURCE, SEARCH_CONTENT, ANALYZE_CONTENT], forbidden_ops: [, ], artifact: } IF kind == "ACTION": RETURN {phase: "ACTION", allowed_ops: [, PERSIST_ARTIFACT, EXECUTE_TOOL], forbidden_ops: [], artifact: } HANDOFF GATE (evidence-bearing): rule_id: "ORIENT" yields: boolean [check] phase bound to exactly one of INVESTIGATE | ACTION (evidence: run_context.phase) [check] allowed and forbidden op-sets are disjoint (evidence: run_context.allowed_ops, forbidden_ops) [check] the artifact the phase emits is the one its kind emits (evidence: run_context.artifact) result: pass -> NODE 2 | undetectable kind -> REPAIR (owner: NODE 1) | unknown -> BLOCKED ``` D1·b admissibility ```pag # NODE 7 — CONSTRAIN [conative · teleology · optimisation · yields: admissibility boolean] @purpose: "Ask after the operations exist whether they stayed inside the bound op-set · a declaration is not evidence that it held" @cue: "ADMISSIBLE_BEFORE_VERIFY" CONTRACT: input: observations + run_context transform: for each observation -> did it mutate under INVESTIGATE, did it discover under ACTION constraints: a breach routes to the node that owns the fix, never a repair in place, because repairing in place is the same breach in the node that found it output: admissibility { ok, op_violations[] } handoff: GATE — op-sets honoured (yields: boolean) FUNCTION assess_admissibility(observations, run_context): DECLARE op_violations: array SET op_violations = [] FOR EACH o IN observations: IF run_context.phase == "INVESTIGATE" AND o CAUSED : APPEND {claim: o.claim, violation: "mutation under INVESTIGATE"} TO op_violations IF run_context.phase == "ACTION" AND o DISCOVERED : APPEND {claim: o.claim, violation: "discovery under ACTION"} TO op_violations RETURN {ok: op_violations.length == 0, op_violations: op_violations} HANDOFF GATE (teleology admissibility gate): rule_id: "CONSTRAIN" yields: boolean [check] admissibility.op_violations.length == 0 (evidence: INVESTIGATE no mutation / ACTION no discovery) [check] every observation was classified against the phase (evidence: one verdict per observation) over: observations measured: / [check] every breach names the node that owns the fix (evidence: op_violations[].owner) result: pass -> NODE 8 | a breach -> REPAIR (owner: NODE 6) | unknown -> BLOCKED ``` D1·c the cycle ```pag # the shape that follows is a cycle rather than a line · the edge back is where a missed repair is caught INVESTIGATE -> ACTION -> INVESTIGATE -> STOP when ``` D1·d two kinds ```mermaid flowchart TB phase["A run"] kind{"Bound to which?"} inv["INVESTIGATE · discovers, never fixes · emits a report"] act["ACTION · fixes against known evidence, never discovers · emits a log"] mixed["Both · mutated under a read-only contract, findings describe a tree that moved"] phase --> kind kind -- one --> inv kind -- the other --> act kind -. neither, or both .-> mixed ``` D1·e cycle, not line ```mermaid flowchart LR i1["Investigate"] a1["Act"] i2["Investigate · verify"] stop["Stop · every gap resolved or carried with a reason"] i1 --> a1 --> i2 i2 -- gaps remain --> a1 i2 -- none --> stop ``` ## Handoff signals A handoff is an item addressed to the parties that need it, with an allocated id, a declared kind and a closure the kind selects, as written in [E1·a an item](#handoff-signals-panel-a) and shown in [E1·d kind selects closure](#handoff-signals-panel-d). An artifact item asks for something that can exist, and it closes when a typed reference to that thing resolves. A judgement item asks for a reading, and it closes when its acknowledger marks it; [E1·c closing an item](#handoff-signals-panel-c) shows the closure in either case. A failure is a finding rather than a halt, and it follows the route shown in [E1·b failure routes](#handoff-signals-panel-b) and [E1·e failure to finding](#handoff-signals-panel-e). A report goes to the parties whose next work it creates, never to the developer as a closing summary. ### Typed items, falsifiable closures A handoff closed by the party that wrote it closes whether or not the work exists. A party declares an item handled, nothing points at the thing it asked for, the item is removed, and the work it named was never done. A closure that a reference decides can be checked by any party, while a closure that a party declares can be checked only by that party. For this reason a handoff is a typed item whose closure can be checked by a party other than its author. The kind decides the closure, either a reference that has to resolve or an acknowledger named on the item, rather than the author's word that the work is done. In practice, a handoff is posted as an item with an id the surface allocates, a kind, the parties it is addressed to, and a body carrying the finding's surface, location, and observed and expected values. An artifact item closes through a reference that has to resolve and stay true while the work is done, and a judgement item closes through its acknowledger. A failure is routed by what it binds: a decision goes to the party whose surface it binds, a question about the purpose of the work goes to the developer with a recommendation first, and everything else goes to the next open item. To check this, name for each closed item the reference that closed it or the party that acknowledged it. An item that its own author closed with no reference was declared done, not shown to be done. The handoff protocol is for parties that share a surface; what a bounded reader does instead is described in [composing a collaboration](/pag/orchestration#composing-a-workflow). The kind is on the item, and it selects the closure. An artifact item names something that can exist, such as a file, a gate or a record, so it closes with a typed reference that has to resolve. The reference names a condition that can turn out wrong rather than a path, because a path resolves as soon as the file exists, and the item would read as closed while the defect is still open. The reference also moves with the work: it is true when the work is done and false when it is not, so a citation that points at the findings themselves is refused, since a broken tree would satisfy it. A judgement item closes when its declared acknowledger signs it off, with no reference, and why one kind requires an acknowledger and the other forbids one is explained in [the board and the venue](/disciplined-methodology/collaborate#the-board-and-the-venue). A failure travels through the same channel as any other item and is routed along the same three paths, as derived in [a turn never ends to wait](/disciplined-methodology/collaborate#a-turn-never-ends-to-wait). A gate's result line is the same routing in miniature, with a third arm that the item channel also needs. An unknown, meaning a claim the run could not measure, is blocked rather than passed, and blocked is a state that names the party who owes the answer. The commit node carries the rule that a report goes to the parties whose next work it creates. The handler removes the item by its id, after extraction, as the board and the venue requires. An item whose readers have all gone is re-addressed rather than left, because an item that no party can handle reads as live traffic forever. E1·a an item ```pag # an item is a typed span · its kind selects how it closes, and the closure is checked by a party other than its author DECLARE item: object SET item = { id: , kind: , from: , to: [], body: {surface: , locus: , observed: , expected: } } FUNCTION closes(item): # an artifact item asks for something that can exist · it closes when a typed reference resolves IF item.kind == artifact: RETURN resolves(item.satisfied_by) AND monotone_with_the_work(item.satisfied_by) # a judgement item asks for a reading · it closes by its declared acknowledger, with nothing to point at IF item.kind == judgement: RETURN acknowledged_by(item.acknowledger) FUNCTION may_close(party, item): RETURN party IN item.to # a reader, never the author ``` E1·b failure routes ```pag # a failure is a finding, not a halt · it flows through the same channel and routes by what it binds FUNCTION route(failure): SET finding = {surface: failure.surface, locus: failure.locus, observed: failure.observed, expected: failure.expected} IF failure.blocks_a_decision: RETURN SEND finding TO IF failure.asks_what_the_work_is_for: RETURN SEND finding TO AS RETURN # NODE 9 — COMMIT [evaluative · representation · information-theory · yields: one typed artifact] CONTRACT: input: findings + run_context transform: emit exactly one artifact of the kind bound at orientation, deduplicated, naming every limitation constraints: a report goes to the parties whose next work it creates, never to the developer as a closing summary output: committed { artifact_type, output } handoff: one typed artifact emitted (yields: hash + boolean) HANDOFF GATE (evidence-bearing): rule_id: "COMMIT" yields: hash + boolean [check] exactly one artifact emitted, of the kind bound at orientation (evidence: committed.artifact_type) [check] every finding addressed to a party that needs it (evidence: findings[].to) over: findings measured: / [check] no finding recorded twice (evidence: dedup) refuse: the artifact's destination changed since it was read before PERSIST_ARTIFACT result: pass -> NODE 10 | duplicate or unaddressed -> REPAIR (owner: NODE 9) | unknown -> BLOCKED ``` E1·c closing an item ```pag # closing an item · the handler removes it, never the author, and extraction comes first WHEN handles : VALIDATE IN . VALIDATE closes() EXTRACT_FACTS . INTO PERSIST_ARTIFACT TO REMOVE BY . # the span, never a matched line ``` E1·d kind selects closure ```mermaid flowchart TB posted["An item is posted · id allocated, kind set, readers named"] kind{"Which kind?"} artifact["Artifact · closes when its reference resolves"] judgement["Judgement · closes when its acknowledger marks it"] handler["Removed by a party in its reader set · never its author"] extract["Its durable half extracted first"] posted --> kind kind -- artifact --> artifact --> handler kind -- judgement --> judgement --> handler handler --> extract ``` E1·e failure to finding ```mermaid flowchart LR fails["A gate fails"] finding["A finding · surface, locus, observed, expected"] binds{"What does it bind?"} owner["The party whose surface the decision binds"] person["The developer · what the work is for, a recommendation first"] next["The next open item"] fails --> finding --> binds binds -- a decision --> owner binds -- the purpose --> person binds -- nothing --> next ``` ## Orchestration invariants A collaboration relies on invariants, and what each invariant has to carry is described in [stating an invariant](/disciplined-methodology/collaborate#stating-an-invariant): the property in a form that could be false, the set it ranges over, the parties it binds, and the objector that would disagree if it stopped holding. [F1·a invariant records](#orchestration-invariants-panel-a) shows the records, [F1·b gate cites records](#orchestration-invariants-panel-b) shows a gate pointing at them, and [F1·c three homes](#orchestration-invariants-panel-c) shows where each record is read. ### Declared once, cited thrice An invariant restated in every document that needs it becomes a set of copies that drift. A document's closing lines, a role and a check each carry their own wording of one rule, one of them is edited, and the other two keep binding the old rule. A restatement is a copy, and a copy carries no edge back to the statement it copied; a bullet is a restatement with even the statement's slots dropped. For this reason an invariant has one statement, and every other mention of it is a pointer to that statement. Each invariant is declared once as a record with four slots and pointed at from every place that needs it, rather than restated wherever a party reads it. In practice, every invariant a collaboration relies on is declared as a record with four slots, and where nothing in any artifact would disagree, the objector is written as none, so the debt is declared rather than hidden. A gate check cites the record it holds, and a role names the invariants its party protects, as described in [a seat is a contract](/disciplined-methodology#a-seat-is-a-contract). A block is never headed with a bare modifier and a list of bullets, because a bullet carries no set, no parties and no objector, which is why the scan refuses it. To check this, name for each gate check and role entry the invariant record it points at. A line that points at nothing is a copy, and the record it should point at is the finding. A record whose objector is none is the debt described in [a tension has a mechanism](/software-architecture/principles#a-tension-has-a-mechanism), for a rule with no check. The number of invariants grows with the number of parties and [shared surfaces](/pag/orchestration#shared-surfaces). One statement has three homes that point at it. A document's invariant block holds the records, a role lists by name the invariants its party protects, and a gate check holds the half that an artifact can observe; where the objector is none, that check is the only watcher, and it says so. An invariant has to reach every party that needs it, and pointing is how it reaches them without a copy that can disagree, so the record is the unit that is derived again whenever the invariant changes. F1·a invariant records ```pag # CROSS-NODE INVARIANTS (each a record with four slots · a property nothing would object to declares its objector as none) INVARIANT one-writer-per-record: a record is written only by the party named on it over: every record on every shared surface binds: every party that writes a surface objector: [check] the anchored edit refuses a write outside the caller's span INVARIANT no-written-state: no party writes a status marker over: every item on the coordination surface binds: every party objector: [check] a scan for markers on every run INVARIANT handler-removes: an item is removed by a party in its reader set over: every closed item binds: every party objector: none # the scan reads the four slots and refuses a record missing one [check] every invariant names its set, its parties and its objector (evidence: the defect scan) over: measured: / ``` F1·b gate cites records ```pag # a node's gate cites the invariant it holds rather than restating it HANDOFF GATE: [check] the write landed inside the caller's span (evidence: the anchored edit's report) # [check] no marker written (evidence: the marker scan) # [check] the removed item named this party in its reader set (evidence: the item's fence) # · objector none, so this check is the only watcher result: pass -> NODE 4 | span breached -> REPAIR (owner: NODE 3) | unknown -> BLOCKED ``` F1·c three homes ```mermaid flowchart LR stated["One record per invariant · property, set, parties, objector"] closing["The document's invariant block · holds it"] role["The role · the invariants this party protects, by name"] check["A gate check · the half an artifact can observe"] closing --> stated role --> stated check --> stated ``` --- # Patterns — PAG — Bane's Lab > This section covers the verbs and prepositions a document is written with. Each verb carries a semantic contract, and a document relies on that contract rather… Canonical: https://banes-lab.com/pag/patterns # Pattern Abstract Grammar Structured instructions for LLMs # Patterns ## Instruction patterns This section covers the verbs and prepositions a document is written with. Each verb carries a [semantic contract](/ontology#arch-semantic-contracts), and a document relies on that contract rather than on what a particular tool happens to do; a read, for example, leaves its source unchanged whichever tool performs it. [A1·a input verbs](#instruction-patterns-panel-a) lists what each input verb promises about its source, [A1·b output verbs](#instruction-patterns-panel-b) what each output verb promises about its result, and [A1·c control verbs](#instruction-patterns-panel-c) what each control verb promises about its effects. [A1·d three readers](#instruction-patterns-panel-d) shows who a contract serves, and [A1·e the prepositions](#instruction-patterns-panel-e) declares the relations the prepositions carry between the operands. A verb's contract together with its preposition is the whole meaning of a line. ### Verbs and their contracts A verb with no stated guarantee means whatever the model completes it as. A document says process the items, the model reads, filters, writes and deletes under that one word, and the reviewer cannot say which of those the author meant. A verb the model has seen carry one guarantee across many contexts is likely to carry it into the completion; a verb used loosely carries every meaning it has ever had. For this reason every line relies on its verb's contract and its preposition's relation, and a line whose behaviour breaks them is a defect in the line. The verb is chosen by the guarantee the line needs, rather than by the tool that will perform it. In practice, a read is used when the source must survive, an extract when its meaning must, a find when only existence matters, a filter when order must hold, and an execute when a side effect is the point. The operands are bound with the preposition that names their relation, and the guarantee is relied on downstream. To check this, read a line and state what it promises about its source and its result. A line whose promise you cannot state uses its verb loosely, and the repair is the verb whose guarantee matches the intent. A contract is a promise the grammar makes about the intent; whether the model or the tool executing the line keeps it is what [verification](/ontology#arch-verification) is for. A contract promises one of three things: what happens to the source, what the result is, or what effects the line may have. Two contracts carry the most weight. An execute may have side effects, and saying so is what keeps each of them from being a [hidden side effect](/ontology#arch-hidden-side-effect). A report is a statement to a reader, never a state that anything later reads as the truth. A line with the wrong preposition puts its operands in the wrong relation, and the model is asked to complete the relation it was given. A1·a input verbs ```pag READ FROM INTO # non-destructive · the source is unchanged LOAD FROM # acquisition with parsing EXTRACT FROM INTO # isolation · the source keeps its meaning FIND IN INTO # existence · boolean, non-invasive GLOB "" INTO # discovery by shape GREP "" IN INTO # discovery by content ``` A1·b output verbs ```pag WRITE TO # idempotent where it overwrites CREATE FROM USING