# Posting and waiting are one operation

> The seats speak to each other through one tool, which makes the protocol structural rather than something each seat has to remember; it is the rule described in…

Page: Methodology · Collaborate
Canonical: https://banes-lab.com/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation

This section is stop 78 of 102 in the learning route. Previous: [39 - The board and the venue](https://banes-lab.com/disciplined-methodology/collaborate/the-board-and-the-venue.md). Next: [41 - A turn never ends to wait](https://banes-lab.com/disciplined-methodology/collaborate/a-turn-never-ends-to-wait.md). It builds on [39 - The board and the venue](https://banes-lab.com/disciplined-methodology/collaborate/the-board-and-the-venue.md).

The seats speak to each other through one tool, which makes the protocol structural rather than something each seat has to remember; it is the rule described in [tools live in the tree](https://banes-lab.com/disciplined-methodology/build/tools-live-in-the-tree.md), applied to the collaboration itself. Posting and waiting are one operation, shown end to end in [E1·a one invocation](https://banes-lab.com/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation-panel-a). Every invocation declares its seat and writes only inside that seat's own fence, under [optimistic locking](https://banes-lab.com/records/arch/optimistic-locking.md). It delivers the diff of what the seat's peers wrote since it last looked, sweeps what every addressee has received, and takes a new snapshot. How long an invocation waits is derived as shown in [E1·b the wait cap](https://banes-lab.com/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation-panel-b), and a second run joins a live one, as shown in [E1·c joining a run](https://banes-lab.com/disciplined-methodology/collaborate#posting-and-waiting-are-one-operation-panel-c).

### One tool, one shape

A coordination surface written by hand carries every guarantee as a hope, and a hope decays at the rate of the party who holds it. Three seats filter the tool's output for the line confirming that their own write landed, discard every peer position delivered in the same stream, and the tool reports success each time. A protocol that mandates a surface its tool cannot write to is obeyed by hand, and a hand write has no fence, no allocated id, no compare-and-swap, no reader set and no gate.

For this reason posting and waiting are one operation keyed to a declared seat, and what it delivers is the diff since that seat last looked, read whole. Every coordination write is a tool write, and the tool refuses what the protocol forbids, rather than the protocol relying on each seat to remember it. In practice, the collaboration has one tool with one shape. Every invocation is keyed to a declared seat, because the snapshot, the fence, the reader set and the closure check all derive from it. Every operand of every requested operation is checked before any of them lands, so an invocation is one unit. A witness read is taken immediately before every write; a write that commutes with what moved is replayed, and only a genuine overlap with the diff of the writer's own span is refused. The diff is delivered whole, never as a status line with content attached.

To check this, invoke the tool with nothing after it and read the whole of what it returns. Then try to break each guarantee by hand: a body passed as an argument, a closure by the author, a mark by a stranger, a second record for one seat. Each attempt should be refused, with the reason the refusal exists. The tool covers the surfaces that are shared and still writable. A surface with one writer by construction needs no fence, no allocated id, no compare-and-swap and no reader set, because all four defend against a party that cannot exist there, and a closed record or an archived discussion needs no write path at all.

### The delivery is the diff

The snapshot is kept per seat and per surface. The tool reads the seat's last snapshot of the target, writes the current content as the new snapshot, records which addressed items it delivered, and returns a line-level diff. A first read answers with a snapshot and nothing else, an unchanged surface answers that nothing moved, and a changed one answers with the added and removed lines. The diff is the delivery: every peer position written since the seat last looked arrives in that stream and nowhere else, so the output has to be read whole. Past the read budget, the delivery degrades rather than truncates, which is [backpressure](https://banes-lab.com/records/arch/backpressure.md) applied to a read: it names every changed item by its fence and leaves the bodies on the surface, because a silent truncation hands over a partial read that looks complete. Every write also echoes back what nothing else would prompt the seat to read again.

### The item and its id

The allocated id is a [correlation id](https://banes-lab.com/records/arch/correlation-id.md): every closure, citation and read mark resolves through it. A body that contains a boundary marker line is refused, because the boundaries are what make a span removable.

### Delivery per party

A read ledger for each item lives on the item's own marker and disappears with it, which lets a swept surface carry delivery state per party without becoming a surface that tracks. The ledger is what makes each seat an [idempotent consumer](https://banes-lab.com/records/arch/idempotent-consumer.md) of the items addressed to it. Each party moves its own letter and no other, a mark by a party the item never addressed is refused, and a closure is held while a named recipient that is still active has not marked the item, so a change that every seat must hold drains on its last reader rather than its first. A rehearsal that writes is the worst form a preview can take, because the invocation a party chooses for safety becomes the one that acts without warning, which is why, as described in tools live in the tree, a tool that rewrites values previews its changes by default.

### The wait and its cap

The wait blocks on the surface's modification state, which is the [publish/subscribe pattern](https://banes-lab.com/records/arch/publish-subscribe-pattern.md) over a file, with a [timeout pattern](https://banes-lab.com/records/arch/timeout-pattern.md) for the window. It reports the diff when the surface moves, quiet when the window closes untouched, and removed if the surface is deleted while it watches, and every exit is typed so that a caller reads the code rather than the prose. The number of waiters is capped at the number of seats able to write, minus one, and what counts is liveness rather than membership. A seat counts if it is parked, holds a live run, or touched a surface inside the declared window; otherwise a seat that stops without updating its row would raise the threshold by one, until every remaining party could park with no seat left to write. The last seat is told that the board owes a response, and the case of a single seat is stated separately, because no write clears it.

### A run joins, never duplicates

A long-running run scales by joining rather than duplicating, which is the [idempotency](https://banes-lab.com/records/arch/idempotency.md) of a measurement. A run declares its write scope and claims standing before it runs. Healing is held while another live run's write set overlaps, because healing changes the tree, and healing while another run is mid-write takes an exclusive resource without declaring it. A run that starts later than an overlapping live one joins it and reads what it publishes instead of measuring the same tree twice, and a run whose question a live run already covers reads the covering result. Every surface a run reads is stamped and stamped again, and what a moved read set does to the verdict is described in [verify the verifier](https://banes-lab.com/disciplined-methodology/verify/verify-the-verifier.md). The surfaces the run healed itself are named separately, because counting a run's own repairs as contention would make every healing run impossible to quote. A run's declaration is a claim and its writes are a fact, so a write outside the declared scope and a claimed repair whose surface never moved are both reported; that is the one comparison between a claim and an observation the run performs.

E1·a one invocation

```mermaid
flowchart TB
invoke["One invocation · the seat declared, the surface named"]
check["Every operand of every requested operation is checked before any lands"]
witness["A witness read immediately before the write"]
moved{"Did the surface move since the read?"}
span{"Does the change overlap this seat's own span?"}
replay["Replay · the writes commute"]
refuse["Refuse · carrying the diff of that span"]
land["Land inside the seat's own fence"]
sweep["Sweep · items every addressee has written past and been handed, extracted whole"]
echo["Echo the seat's own claim, the items it can close, the open discussions"]
snapshot["Re-snapshot for this seat · the next call reports only what changed"]
invoke --> check --> witness --> moved
moved -- no --> land
moved -- yes --> span
span -- no --> replay --> land
span -- yes --> refuse
land --> sweep --> echo --> snapshot
```

E1·b the wait cap

```mermaid
flowchart TB
able["Seats able to write · parked, running a live claim, or active inside the liveness window"]
waiting["Seats already parked"]
cap{"Would this wait leave no seat able to write?"}
blocked["Blocked · write first, the board owes a response"]
watch["Watch the surface · changed with the diff, quiet after the window, removed if deleted"]
able --> cap
waiting --> cap
cap -- yes --> blocked
cap -- no --> watch
```

E1·c joining a run

```mermaid
flowchart TB
start["A run declares its write scope and claims standing"]
live{"Does a live run's write set overlap?"}
held["Healing held · report only, until the other run publishes"]
later{"Did this run start later than that one?"}
join["Join · read out what the live run publishes, write nothing"]
run["Run · stamp every surface read, re-stamp at the end, name the surfaces it healed apart"]
quotable["The aggregate is overwritten · the verdict carries its standing"]
start --> live
live -- no --> run
live -- yes --> later
later -- yes --> join
later -- no --> held --> run
run --> quotable
```

## Links to

- [Tools live in the tree](https://banes-lab.com/disciplined-methodology/build/tools-live-in-the-tree.md)
- [Optimistic Locking](https://banes-lab.com/records/arch/optimistic-locking.md)
- [Backpressure](https://banes-lab.com/records/arch/backpressure.md)
- [Correlation ID](https://banes-lab.com/records/arch/correlation-id.md)
- [Idempotent Consumer](https://banes-lab.com/records/arch/idempotent-consumer.md)
- [Publish/Subscribe Pattern](https://banes-lab.com/records/arch/publish-subscribe-pattern.md)
- [Timeout Pattern](https://banes-lab.com/records/arch/timeout-pattern.md)
- [Idempotency](https://banes-lab.com/records/arch/idempotency.md)
- [Verify the verifier](https://banes-lab.com/disciplined-methodology/verify/verify-the-verifier.md)

## Linked from

- [Orchestration as declared structure](https://banes-lab.com/pag/orchestration/declared-structure.md)
- [A turn never ends to wait](https://banes-lab.com/disciplined-methodology/collaborate/a-turn-never-ends-to-wait.md)
