# Coordination is software

> When several reasoning agents write to one tree at the same time, this method treats their coordination as software. Its parts are shown in the model].

Page: Methodology · Collaborate
Canonical: https://banes-lab.com/disciplined-methodology/collaborate#coordination-is-software

This section is stop 76 of 102 in the learning route. Previous: [37 - Agents as executed contracts](https://banes-lab.com/disciplined-methodology/collaborate/agents-as-executed-contracts.md). Next: [39 - The board and the venue](https://banes-lab.com/disciplined-methodology/collaborate/the-board-and-the-venue.md). It builds on [18 - The gate holds the line](https://banes-lab.com/disciplined-methodology/build/the-gate-holds-the-line.md), [31 - Derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md).

When several reasoning agents write to one tree at the same time, this method treats their coordination as software. Its parts are shown in [C1·a the model](https://banes-lab.com/disciplined-methodology/collaborate#coordination-is-software-panel-a). A seat is created in the order shown in [C1·b a seat's making](https://banes-lab.com/disciplined-methodology/collaborate#coordination-is-software-panel-b), and its readers fall into the two classes shown in [C1·c reader classes](https://banes-lab.com/disciplined-methodology/collaborate#coordination-is-software-panel-c). A [lost update](https://banes-lab.com/records/arch/lost-update.md), a stale item, a missed message or a surface that has grown past reading is a defect report against the protocol, never a call for more care, and friction points to a missing [concurrency control](https://banes-lab.com/records/arch/concurrency-control.md). The grammar page states the same premise under [orchestration as declared structure](https://banes-lab.com/pag/orchestration/declared-structure.md), and the schema derived here is the one described in [shared surfaces](https://banes-lab.com/pag/orchestration/shared-surfaces.md) there.

### Surfaces, records, edges, states

More than one agent on one tree loses writes, accumulates stale items and misses messages, and each incident has a plausible local cause that hides the gap in the mechanism. A board grows past what any reader can consume, carrying hundreds of directed items, with every drain rule in force and agreed by every party. Every coordination failure is produced by good behaviour composing badly: each append is a real finding honestly reported, and the defect lies entirely in the composition, which no rule about care can see.

For this reason I treat coordination as software, with state, invariants and a schema, which decays without a validator. Every coordination failure is treated as a missing mechanism and answered with a surface, a schema or a validator, rather than with a request for more care. In practice, the coordination is modelled as a graph. A surface is a file the parties read and write, a record is one addressable claim inside it with exactly one writer declared on the record itself, and an edge is an id in a field. Every state is derived by traversing the edges, and no party writes one. Each party has a permanent identity bound in an index before its first write, and who may read an item is derived from presence on the surface and state in the index, never from anything a party declares about itself.

To check this, take the last coordination failure and name the mechanism that would have made it impossible or loud. If the answer is that you or the model should have been more careful, the mechanism is still missing. One writer per record is the invariant everything else rests on, and it does not apply to an outcome surface that is written jointly, such as a contract or a measured baseline. There the invariant is declared inapplicable, with its reason, and a clash in meaning is caught by an announcement plus each author removing its own duplicate, which is a different instrument from a fence.

### One writer, no written state

One writer per record refuses [shared mutable state](https://banes-lab.com/records/arch/shared-mutable-state.md) at the level of a single claim. With one writer per record, ordinals are allocated without coordination, last-writer-wins cannot happen, and protecting another party's scope becomes checkable record by record. The scope of the rule is the whole point: stated per surface, it is false wherever a surface is shared, which is the normal case, and because the two versions look identical on a surface with one writer, the mistake survives. A record's identity is allocated once and never recomputed, while its subject is declared and derived again on every run, because an id derived from location breaks on a move and one derived from the subject breaks on a rename. Two records sharing a subject key is the finding that catches a re-derivation.

No agent writes a state, which is [derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md) applied here as everywhere else. A written state is a marker, a marker goes stale, and a stale marker creates a false belief, while an absent one simply reads as absence. Open, blocked and absorbed are queries over the edges, which is [event sourcing](https://banes-lab.com/records/arch/event-sourcing.md) over a graph of claims: a record is open while a citation is unresolved, blocked while an inbound edge comes from an open record, and absorbed once the citation resolves. Absorbed is a transition, never a resting state. The record's durable half is extracted to the [one home](https://banes-lab.com/disciplined-methodology/build/one-home.md) history has, an [append-only log](https://banes-lab.com/records/arch/append-only-log.md), and the record is deleted in the same change, because a record resting in absorbed is a status marker spelled differently.

### A seat is allocated, never chosen

A seat is a letter bound to a role in an index that only grows, and what the role document holds is described in [a seat is a contract](https://banes-lab.com/disciplined-methodology/start/a-seat-is-a-contract.md). The index is an accumulator rather than a section of the board, because the board deletes what is resolved, while a letter that is no longer active still has to resolve: every item, row and citation that ever named it points there. A letter is claimed by adding its row before the first write, never simply by using it. The identity is allocated rather than chosen. The tool issues the shortest free identity from a scheme that never runs out and never reuses one, and the letter a party asks for is only its declaration for that call, not the allocation. The index has one mutable column, the seat's state, drawn from a closed set, because the reader set, the wait cap, the resolution of addressees and the convergence check all derive from it. A seat moves its own row, and a party that moves another party's state writes its reason beneath the row.

### Two reader classes

A reader's class is derived from what it received, never from what it decides it is. A participant receives the surfaces it owns and its inbox, and its turn never ends: it waits, and waiting has a command. A bounded reader receives a task and whatever the host injects, never a coordination surface. One derived line is all it knows about every surface, so a fact missing from that line does not exist for anything spawned, and the line is refreshed in the same change as the fact it carries, because a stale projection is a false statement delivered as the only statement. The rules divide by class, and the rules about owning a turn are inverted for a bounded reader: obeying the rule that a turn never ends would forbid it from returning, and returning is its contract. Which class a reader belongs to comes from the binding rather than from the reader. A deployment whose board slot resolves as absent is single-worker by declaration, and a reader classifying its own turn would be an escape hatch keyed on self-classification.

C1·a the model

```mermaid
flowchart TB
subgraph surface["A surface · a file the parties read and write"]
r1["Record · one writer, declared on the record"]
r2["Record · one writer"]
r3["Record · one writer"]
end
artifact["An artifact in the tree"]
other["A record on another surface"]
r1 -- satisfied-by · closes when the artifact exists --> artifact
r2 -- blocks · the target cannot close first --> r3
r3 -- answers · refutes · supersedes --> other
state["Every state is a query over these edges · no party writes one"]
surface -.-> state
```

C1·b a seat's making

```mermaid
flowchart TB
claim["A letter is claimed by adding a row to the index, before the first write"]
allocated["The identity is allocated · the shortest free one, never reused"]
role["A role document at the concern, the letter in a field"]
record["A fenced record on the board, raised from the template"]
state["One mutable column · active, inactive, invoked · a seat moves only its own row"]
claim --> allocated --> role --> record
claim -.-> state
```

C1·c reader classes

```mermaid
flowchart TB
participant["A participant · holds a seat"]
owns["Receives the surfaces it owns and its inbox"]
waits["Ends never · it waits, and waiting has a command"]
bounded["A bounded reader · a spawned run"]
injected["Receives a task and whatever the host injects · never a coordination surface"]
projection["One derived line is its whole view of the graph"]
returns["Ends by returning · which is its contract"]
participant --> owns --> waits
bounded --> injected --> projection --> returns
```

## Links to

- [Lost Update](https://banes-lab.com/records/arch/lost-update.md)
- [Concurrency Control](https://banes-lab.com/records/arch/concurrency-control.md)
- [Orchestration as declared structure](https://banes-lab.com/pag/orchestration/declared-structure.md)
- [Shared surfaces](https://banes-lab.com/pag/orchestration/shared-surfaces.md)
- [Shared Mutable State](https://banes-lab.com/records/arch/shared-mutable-state.md)
- [Derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md)
- [Event Sourcing](https://banes-lab.com/records/arch/event-sourcing.md)
- [One home](https://banes-lab.com/disciplined-methodology/build/one-home.md)
- [Append-Only Log](https://banes-lab.com/records/arch/append-only-log.md)
- [A seat is a contract](https://banes-lab.com/disciplined-methodology/start/a-seat-is-a-contract.md)

## Linked from

- [PAG and the method](https://banes-lab.com/pag/introduction/pag-and-the-method.md)
- [Composing a collaboration](https://banes-lab.com/pag/orchestration/composing-a-workflow.md)
- [Shared surfaces](https://banes-lab.com/pag/orchestration/shared-surfaces.md)
- [Where a rule lives](https://banes-lab.com/disciplined-methodology/start/from-chat-to-tree.md)
- [A seat is a contract](https://banes-lab.com/disciplined-methodology/start/a-seat-is-a-contract.md)
- [The behaviour document](https://banes-lab.com/disciplined-methodology/start/the-behaviour-document.md)
