Files
hq/00-META/process/07-feature-branches.md
T
jschoubben a2da2a3e74
mesh/check checking a2da2a3e7451 on 87f2901f556b
mesh/delivery merged: source.main moved to novox/hq@87f2901f556b
Let the lead answer every design question against the principles
The operator replaced the instruction on implementing a design on
2026-11-11 about 21:48 CET: the lead answers each question met while
building in one line against the principles, and only one no principle
settles goes on, to the operator when it changes what they see or how
they work, removes data or needs their terminal, otherwise to the design
writer as a design line. Playbooks 02, 07 and 08, the glossary's design
question, AGENTS.md, the code reviewer and the drawn overview still said
only the operator or the design writer answers; they now say the rule.

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-11 23:53:03 +01:00

925 lines
91 KiB
Markdown

# Playbook 07 — Features
**Trigger.** A feature: work that changes code in one repository or several (`mesh-sdk`, `mesh-controller`,
`mesh-catalog`, `mesh-host`, `mesh-lab`, and `hq` when a design rides along), too large to be one small fix.
A small fix (one repository, one issue, about an hour of work) follows
[playbook 08](08-small-fixes.md) instead.
**Who runs it.** Anyone who writes code, engineers and agents alike. Agents follow it exactly.
## The failures it prevents
- **Pull requests as scratchpads.** A feature worked as one pull request per unit of thought left sixteen
stacked pull requests unmerged, consolidated by hand afterwards. A pull request is the end of a feature,
not a step in it.
- **Waiting on checks mid-feature.** A feature worked as one pull request per issue into protected
branches spent most of a day waiting for merge checks while the code was ready.
- **Context bought again and again.** A fresh agent per small issue spends most of its run reading the
playbook, the issue and the code before it writes a line. On 2026-10-14 an issue sized for five to ten
minutes took forty-one.
- **Finished work that never ships.** A feature that kept taking new issues held thirteen landed issues
undelivered for a day: an issue done at 21:09 was still not on the machines at 15:00 the next day.
- **Work that waits and nobody notices.** Most lost time was not work at all, but a check, a delivery
or an agent waiting on something that had stopped, unseen.
- **Review that keeps hardening.** One fix went through seven review rounds in five and a half hours, each
asking for more hardening than its issue asked (issue 704, 2026-10-14). A round is for what makes the
change wrong; everything else is an issue of its own.
- **The first check after the whole branch is written.** A feature's catalog branch, pushed once after
hours of local work, met its first check on 2026-10-16 and failed on 29 problems, TypeScript errors among
them, that a unit suite run continuously while working finds at once.
- **A green pull request nobody marks.** An approved, green pull request that was not marked ready waited
12 h 17 min for someone to merge it (mesh-catalog #300, 2026-10-14). There is no ready mark since ADR 0421:
the operator's Approve is asked as soon as the checks pass.
- **Review rounds spent on what a run or a search would have shown.** On 2026-10-19 milestone R3b of design 47
took two review rounds and one more cycle after a failed try. A test that "failed first" only by not compiling
proved nothing, and dropping the field it was for passed every test. A reader of the changed record that the
survey never listed ended a module's conditions at each sync. The reviewer judged the bus tests by reasoning, and
wrongly, because they ran only after the review.
- **A check asked again and again.** Build capacity is the mesh's scarcest resource ("we don't have more
processing power", the operator, 2026-10-26), and a release that ran a try before its review, a try after it
and a check per fix round on an open pull request spent it several times over: every push to an open pull
request asks a new check, of every member for a group. A release runs one check ("every release should only
run 1 check or 1 try", the operator, 2026-10-26; ADR 0548).
- **A node agent's bus reads, proven only by review.** On 2026-10-27 a change widened what every node agent watches
on the bus; two reviews read the code, no test ran it under a node's real permissions, and once it was live every
node's agent was refused that read and stopped composing (issue 1126). How-we-build's rule "A bus permission is
proven under the real permission" (ADR 0560) is what the review now asks for.
- **A change built on what was remembered, not on what runs.** In the days up to 2026-11-02 a release took the
controller's jobs apart from the records and the survey alone. Jobs nobody had named surfaced only after the
delivery, a moved module's wiring and a changed failure label's readers were never read, and every check found one
more fault. Each layer had checked the layer before it; none had read the running code. Step 0 item 3a is the answer.
- **Implementation that decided.** On 2026-11-10 one milestone was prepared and developed from a design of more
than 400 KB, by agents told to start from the knowledge base and to report what was not mesh-shaped. The prepare
wrote its own findings and a file of about 40 rulings by its two leads, a third layer of truth between the design
and the code; a developer refused an event the design names; and an audit found seven rulings against the records
or the design (among them a store kept twice and a copy of another part's data) and 29 questions the design never
answered, all found in develop. The design is now the only input to the prepare and to develop, the prepare's only
output is where each design line lands and what the design does not answer, and develop starts only when it is all
answered (step 0b, *Design complete*). Since 2026-11-11 the lead answers each such question in one line against the
principles, and only one no principle settles goes further (step 0, *Who answers a design question*).
- **A design that met the code only in develop.** On 2026-11-11, in the develop step of milestone 47/G, the lead
answered over 100 questions, most of them a design line meeting the code: a line naming a form the code cannot
take, or assuming a part already built that was not. The prepare had read the design alone. It now reads the code
each design line lands in as well, and lists every place where the two disagree before any developer starts
(step 0, items 3 and 10; the operator, 2026-11-11).
- **A module proven only after it reached the machines.** The mail modules were delivered with unit tests
only, then failed live three times (issues 859, 865, 868) and took five more hours of fixes.
## The shape
One feature is **one branch name**, **one worktree per repository**, **one pull request per repository**,
opened **once**, after the review, and **one check** (ADR 0548). It runs in five steps, with the design completed between the first two (step 0b), and its time is bounded. A milestone has no phases
(the operator, 2026-10-17): these are its steps, and a report names the step it is in:
| Step | What happens | Bound |
|---|---|---|
| 0. Prepare | from the milestone part and the design's main file, read whole, then the code each design line lands in: where each line lands, what exists there today and what relies on it, as one build map per repository; every design question, the design's silences, listed; and every place where a design line and the code disagree, listed | 15 minutes, longer when what exists is large: code never starts on an incomplete answer |
| 0b. Design complete | every design question and every place where design and code disagree is answered: by the lead in one line against the principles, or, where no principle settles it, by the operator or `hq-design-writer` (step 0); each answer is written down (the lead's in the milestone's lead-answers file, the others into the milestone part, playbook 02) and its build map rows added | until the list is empty: develop never starts before |
| 1. Develop | one fixing agent per repository builds every design line of its build map locally, each commit citing the lines it builds, the whole unit suite before every commit, the integration tests compiled, and once per head it reports those of the packages it touched and their importers run against an embedded bus (below); nothing is pushed | the milestone's issues, 30 minutes each |
| 2. Review | one reviewer reads all of it, the local commits, judging the integration tests by reading them against the code; reports go both ways; at most 3 rounds | 15 minutes |
| 3. Check | push the reviewed heads once and open the pull requests together; the checker's one check runs the integration tests; no further review unless the check fails | one check run |
| 4. Deliver | merge; the source revision moves, each module is built once and wanted on its nodes, its canary first | until the view says the source revision `delivered` |
**One milestone is one release** (the operator, 2026-10-17). A milestone is developed whole, reviewed once,
pushed once, checked once and delivered once. It is never cut into steps for its size or for time: every cut adds a review, a
merge check, an Approve and a delivery of waiting, so the fewest cuts is the fastest. Nor is it cut for an
order between its parts (the operator, 2026-10-22: "a milestone is a milestone, we shouldn't cut it"): which module
reaches the machines before which is the assigner's rules' (a build and a composition before the want, a provider
before its consumers, the canary before the rest; design 47), and that is what they are for. An order they cannot
keep is a fault of the build and delivery system, opened as an issue there, never a cut and never a step a session
takes by hand.
A milestone is one piece of functionality, possibly spanning several modules, repositories and dependencies such as
an SDK change (the operator, 2026-10-21). Its pull requests in every repository share the milestone's branch name,
so they are one delivery group (ADR 0482, which holds that a change across repositories is one group, one plan and
one Approve, and that its developer orders no release). Nothing of the milestone merges until every issue of it is
built, reviewed and checked; then the one Approve releases it all as one source revision, the assigner's rules
keep a provider before its consumers, and an SDK change is built into the modules that use it. A small fix found during the milestone rides in this
group, as playbook [08](08-small-fixes.md) says.
**One design is built at a time** (the operator, 2026-10-17). While the milestones of one design are being
built, no milestone of another design starts: its issues stay `open`, and nobody moves them to `diagnosing` or
`fixing`. The next design starts when the last milestone of the one being built is delivered. A
lead who finds another design's milestone already in `fixing` asks its owner before starting its own. A small
fix ([playbook 08](08-small-fixes.md)) and an issue that is in no design's milestones are not held by this rule.
**Scope is fixed at the prepare step.** An issue found during a feature never goes into the running milestone, unless it
blocks the running one: it is fixed in between or right after the delivery, as the next paragraph says, or goes to the
next milestone or the next feature.
**An issue opened along the way is fixed by the session that opened it** (the operator, 2026-10-21): it is never only
listed under "Opened along the way" and left. A small one (one repository, about an hour) is fixed in between, as a
small fix ([playbook 08](08-small-fixes.md)) while the milestone waits on a check, an Approve or a delivery; the
rest are fixed right after the milestone's delivery, before the next milestone starts, together on one branch where
they share a repository. Either way it stays out of the running milestone's branch and pull request, unless it blocks
the running milestone, so the scope above holds. Only an issue in another design's milestones (one design is built at
a time), or one that needs a decision or the operator first, waits, and the report says which and why. Each detailed report's line "Opened along the way" says for every
issue whether it is being fixed in between, after the delivery, or waits, and on what.
## Step 0 — Prepare (mesh-preparer, larger model; the lead runs the process)
**Agents work from hq's definitions, never from a prompt written by hand.** Every agent the lead starts is one of
`.claude/agents/`: `mesh-preparer` for this step, `mesh-developer` for step 1, `mesh-code-reviewer` for step 2,
`mesh-watcher` for every wait, and the four reviewers by architectural domain and `research-reader` of playbook 01.
The lead writes only the handover: what the agent works on (issue, the design and its milestone part at an hq commit,
branch, worktrees, commits) and where it reports; a handover carries no choice about what is built, and one that
does is the lead answering a design question outside its lead-answers file (step 0b). A subagent runs in the session that started it, from hq: its way of working comes from its definition and hq's playbooks; what it builds comes from the milestone part and the milestone's lead-answers file and nothing else; one given a coding task works in a worktree under hq's `.work/` and also reads the conventions of the repository it changes, and where those contradict hq, hq wins and the agent says so. How it works, what it reads first and what it judges come from its definition, and so does its model: a
`mesh-developer` runs on the smaller model, and the lead starts one on the larger model only for work whose parts meet
at an interface several of the milestone's subtasks build at once (the design names it whole; nothing is designed in
develop), written with its reason in the milestone file; a lesson about how an agent
works goes into its definition by an hq pull request (the operator, 2026-11-03: "please don't write prompts by hand,
only the handover prompt"). How it is checked: the lead's report names each agent by its definition; an agent started
from a prompt written by hand is a breach the lead names at the next report.
**The design is the only input; the implementation decides nothing** (the operator, 2026-11-10: implementation
follows the decided design and makes no decisions, least of all architectural ones). The milestone's part of its
design (playbook [02](02-graduation.md), *The shape of a design*) and the design's main file are what the preparer,
the developers and the code reviewer read whole, and build or judge against. Decision records, the mesh's principles
and the knowledge base were read when that design was written and reviewed by architectural domain; they are not read
again to judge the design while it is built, because a builder who re-judges it builds a second design. The
principles answer only what the design leaves open (step 0b), never a line it states. Where each
interaction travels (the seat, verb, event, provision, state on the bus, manifest field) is a design line; one the
design does not name is a design question, never the preparer's finding with its own alternative. The mesh paths
are held where they are decided: the reviewers by architectural domain judge the milestone part before it is built
(playbook [02](02-graduation.md), *Answering a design question*).
- **The prepare's only output** is one build map per repository (item 4), the list of design questions and the list
of places where a design line and the code disagree (item 10). It writes no findings of its own, no recommendations into the build map and no rulings, and no file of
the milestone holds a statement of how something should be.
- **Who answers a design question, and where design and code disagree** (the operator, 2026-11-11, about 21:48
CET). The lead tests each design question and each entry of `Design meets code` (item 10) against the principles
(`00-META/principles.md`) and answers it in one line in the milestone's lead-answers file, naming the principle that
settles it, without a design batch or a review round. Only a question no principle settles goes further: to the
operator when its answer changes what the operator sees or how they work, removes data or needs the operator's
terminal; otherwise to `hq-design-writer`, who answers it as a design line from the design and its records, with
its reason, read by the four reviewers by architectural domain in one round, and the lead tells the operator each
such answer in one line. When unsure whether a question changes what the operator sees or how they work, it goes to
the operator. The preparer, a developer and a reviewer answer none, nor does a lead of another session.
- **One milestone has one lead.** A session that held part of the work hands its branches and heads to the lead and
stops; between sessions travel heads, commits, design questions and the hq commits that answer them, never an
instruction on how to build.
How it is checked: every subtask in a build map and every commit of the milestone cites the design lines it builds
("design NN M §n"), and the review finds code that cites none (step 2, item 2a); the milestone's files hold no
rulings (`grep -n -i 'ruling' .work/<slug>/*.md` finds none); an answer of the lead's that names no principle, a
question answered other than as *Who answers a design question* says, or one sent on that no principle left open, is
a breach the lead names at the next report; the milestone file's `Design meets code` names, for each repository a design line lands in, the `origin/main`
commit the prepare read, and a developer's question that is a design line meeting code the prepare read is a miss
of the prepare the lead names at the next report.
1. **Name the feature once:** `feat/<slug>`, the same branch name in every repository it touches (but see the
exception for a new manifest word in phase 3: a release that must merge first has a name of its own). The
branch is never protected. **One milestone is one branch per repository** (the operator, 2026-10-17), with one
folder `.work/<slug>/`; never a second name for part of it (`-2`, `-step2`).
2. **Make the worktrees:** one per touched repository under `.work/<slug>/<repo>`, branched off `main`
(`git worktree add .work/<slug>/<repo> -b feat/<slug> origin/main`). The lab beds find the other
repositories by sibling path, so add the untouched siblings the lab reads as detached worktrees on
`main` (`git worktree add --detach .work/<slug>/mesh-tools main`), never symlinks. **A repository's own
clone stays on `main`** (the operator, 2026-10-17): no work is done in it and no branch is checked out
there, so a session that opens in it reads what holds now; fetch and fast-forward it before reading.
3. **Read the milestone part and the design's main file whole, then the code each design line lands in**, before any
code is written (the operator, 2026-11-11: the prepare reads the code as well as the design). The design is the
only thing the preparer reads to know what is to be built; the code, read at `origin/main` in each repository a
line lands in, says whether the line can be built as written. For each design line the preparer reads the files
and functions it changes, the contracts, types and packages it uses, and the rules the code holds there (a guard,
a check, a test that refuses), and asks three things: can the code take the form the line names; is every part the
line assumes built (a verb, a field, a package, an event, a module) there on main; does the line break a rule the
code holds. Each no goes onto the list `Design meets code` (item 10). Every question the code or the live mesh
raises that the milestone part does not answer goes onto the list of design questions (item 10). Neither is ever
answered by the preparer. A fixing agent that meets either stops that part, and its run is spent again: the
prepare is where both are found.
3a. **Read what exists today, and write it down before any code** (the operator, 2026-11-02: "if i ask to implement
feature A, you'd better first check what exists today with regards to feature A"). Research, decisions, the survey
and the review each check the layer before them; this is the step that checks the running code. Each repository's
build map (item 4) opens with a section `What exists today` that answers three questions, in writing:
1. **What exists today for this feature**, read from the code (file:line) and from the live mesh through the mesh
MCP server's tools (the seats, the modules on each machine, their state on the bus, their tools' answers), never
from memory and never from a record alone. Where the code or the mesh contradicts the milestone part, the answer
says so and the contradiction is a design question (item 10).
2. **Everything the change touches, replaces or removes, and what relies on each today.** For a part that is removed
or moved (a module, a seat, a job of a module, a file, a value's form, a label others read), every effect it has
is listed, found mechanically from its code and not recalled: each bus write (bucket key, stream subject, event),
each file it writes, each credential or grant it issues or rotates, each plan or record it makes, each process or
container it starts, each verb, tool or request it answers, and each timer it runs. Then, for each effect, every
reader that relies on it (a search across every repository and the live bus, file:line or address). The search is
written down as run (the pattern and where), so the review can run it again.
3. **For each item of the second answer, what happens to it after the change** (kept as it is, moved to a named seat,
module or verb, replaced by a named part, or dropped and why nothing needs it), **and the test that proves it**: an
acceptance criterion (item 5) at its level, or, for a dropped effect, the search showing no reader is left.
The fate is the milestone part's: the answer cites the design line that gives it, and an effect or a reader no
design line gives a fate is a design question. For every new exported type, field, constant, package or module,
the answer names the design line that places it (the milestone part's, or the design section *Where a seat's
code goes*): where new code goes is always the design's, or a lead's answer naming its principle (step 0b), never
a choice nobody wrote down.
**A seat's contract is a design line's form too.** For each seat contract the milestone adds or changes, the
answer compares what the contract on main says (its fields, subjects, callers and kinds) with the design lines
that name that seat, field by field; every difference is a design question (item 10), answered before develop
(2026-11-10: a seat contract and an event's subject that differed from the design surfaced only in develop).
Code starts only when the three answers are complete for every repository: no fixing agent starts on a build map
without them, and an effect found later is the prepare step missed, written into the answer and its issue before the
fix. In the days up to 2026-11-02 the controller was taken apart without this answer: jobs nobody had named (making
a provision's credentials for a new consumer, planning a module's next build) surfaced only after the delivery; a
module was moved without reading how its pieces were wired; a failure label was changed without reading what relied
on it; and each check found one more fault the preparation should have known.
4. **Write one build map per repository**, `.work/<slug>/<repo>.map.md`. It is what a fixing agent reads beside the
milestone part instead of rediscovering the code, and it is reused by every agent and every round. It says where,
never how: each entry is a design line's citation and a place in code, and a sentence in it that says how
something should be is a design question put in the wrong place.
- first, the section `What exists today` with item 3a's three answers;
- one row per design line the repository builds: the line ("design NN M §n"), the files and functions it
changes, the subtask that builds it (about 30 minutes, one change, its label), its acceptance criteria (item 5)
and the test that proves each;
- the order of the subtasks: **a subtask that uses what another adds** (a seat's contract, a type, a verb, an
event's form, a package) **starts from that subtask's commit, never beside it**, so the contracts and packages
come first and their users after; and **one writer per file**: each file the milestone changes has one subtask's
agent, named here;
- the patterns to copy (file:line), what not to touch, and what lands beside it in other repositories;
- the local facts: the worktree, the branch, the check commands, a temporary directory for tests outside
the home (`TMPDIR`), the unit tests to run (never a database server: tests that need one are integration tests,
which the pull request's one check runs), and **the one placement of the siblings** every agent of the
milestone uses (its `go.work` `use` lines or `replace` directives), as the running checker places them; no agent
writes a placement of its own.
When the reading is large, a read-only agent on the smaller model answers the preparer's exact questions with
file:line, and the preparer writes the map from its answers.
5. **Write the findings into the issues** (the operator, 2026-10-17: the better the content of the issues, the
better work the agents do, and the less review is needed). Before any agent starts, each issue carries, with
`issue-tracker.note`: every file and test that touches the change, found by search and not from memory
(file:line); **every other reader and writer of each value the change adds or changes** (a field, a key, a kind
of record), each with what it does with the new value, and a criterion for each that could treat it wrongly
(2026-10-19: the router's sync with the controller ended every condition the controller did not list, and the
survey, which followed only the new condition's own path, never named it); how the change is checked and delivered end to end (which test proves its done-when, which
modules its merge moves, read from the indexer's candidates of its group, and to which machines); and for a
group, its merge order. The build map
points to these notes; an issue reread by another session or a later agent then holds what was found.
When the reading is large, it starts with a read-only survey agent on the smaller model.
**Each issue carries its acceptance criteria, written on the larger model from the milestone part** (the operator,
2026-10-18: the larger model writes them, and they guide every test). Each criterion cites the design's
acceptance test or design line it comes from; a case the issue's done-when needs that no design line covers is a
design question, never a criterion of the writer's own. Each criterion is one sentence, given, when, then, about
what the module or the operator observes, never about how the code does it, and names the level of the test that
proves it: unit, integration (a bus, a store or a process started) or end to end (none exist yet, so such a
criterion is proven live after the delivery and said so). Together they cover the issue's done-when and the
cases its life passes through: on 2026-10-18 mesh-delivery's group life (a group of three, a member's own
check, a close in a group, a second pull request at the same commit, a stop and a resend) had no criterion,
and each case was found by a failure on the live mesh. Each criterion is numbered in its note and cited as
`<issue>/AC<n>` (`1118/AC2`). They are an `issue-tracker.note` headed `Acceptance criteria`, a revision a new note that replaces the older one, until the tracker holds them as a
field (issue 1118). A criterion the reviewer adds in step 2 is written onto the issue the same way.
**The survey sizes each issue, and an issue sized over an hour is split before any agent starts** (the operator,
2026-10-17), into issues of about 30 minutes each, one change each, in the order they land: the bound of a
fixing agent's issue is then a real bound. On 2026-10-17 one issue held four changes sized at four to six
hours; it ran past its 30-minute bound for over an hour, and the reports could only say "still on part D".
6. **List every part the change reaches, before any agent starts**, so each is an issue of the milestone and
nothing is found on the way. Read, for each repository of the milestone, what it takes from the others and how:
the SDK's users (they pin an SDK commit, and a pin to a commit no branch holds is a download that fails later,
issue 1148); every program that parses a manifest strictly (search `ParseManifest` across every repository, with
the SDK commit each pins), which must take an SDK that knows a new manifest word (2026-10-21: design 60's
catalog milestone found mesh-build-go and the delivery's indexer reading manifests with an SDK from before the
word); the SDK's list of a defined seat's verbs, which must name a verb a module adds (2026-10-21: node-files' two
new verbs were refused on the claim); the node-engine's decoder for a new key on the wire; the route by which a
repository's first module registers; and a part that needs something the bus or a manifest cannot yet give, which
needs its decision first. Each such part is an issue of the milestone and its pull request a member of the group;
the order in which they reach the machines is the assigner's rules' (the operator, 2026-10-22), never a cut.
Where those rules cannot keep an order (a node told of a key before it reads it, a module using a word before its
readers are delivered), that is an issue of the build and delivery system, opened with `issue-tracker.open` and
said to the operator.
7. **Write fixtures from the shape the other side writes, never from memory** (2026-10-18: a watchman's tests
mirrored a build key the controller never writes, and every test passed): copy a value from the writer's code or
from the live bus, and name where it came from.
8. **Answer three questions in the milestone file** (`.work/<slug>/milestone.md`; research 071, issue 1941), written by the
lead from this template before any agent starts. Each answer is a fact found, not a hope:
```
Lifetime of what the work creates (research 071, a):
- <bucket key or stream> | written by <module> | deleted by <module> on <event>, or time to live <duration>
(one line for every key-value bucket key and stream the work creates or starts writing; "none created" if none)
Trying the switch-over on one node first (b):
- <which node goes first, and what is read there before the rest>
- or: the operator chose no first trial on one node, on <date>; what that risks: <one sentence>
Integration level (c):
- <the one check that runs it: the group's pull requests, one check each, none before the review>
- what the check does not cover: <the parts of the group that meet only live>
```
Each line cites the design line that gives its deleter or its time to live. A key or stream with no one who deletes
it and no time to live, or with a lifetime no design line gives, is a design question, answered before work starts;
the lead writes no lifetime of its own.
9. **Move the issues to `fixing`**, `by` naming the feature's agent for that repository.
10. **List the design questions** in the milestone file, under `Design questions`: each with the design line it
concerns (or the section where a line is missing), what the line leaves to its builder, where the prepare met it
(file:line or the tool's answer), and the preparer's recommendation, said as a recommendation. A design that
contradicts a decision in force, a reader or an effect with no fate, a lifetime, a caller, a bound, a field's
form, a tool for a new state: each is a question.
Then, under `Design meets code`, every place item 3 found where a design line and the code disagree, each with
the design line, the code (file:line at the `origin/main` commit read), which of the three it is (a form the code
cannot take, a part the line assumes built that is not, a rule in code the line would break), and the preparer's
recommendation, said as a recommendation. The two lists are the prepare's last output and step 0b's input.
## Step 0b — Design complete
Develop starts only when the milestone's design questions and the entries of `Design meets code` are all answered,
each in an hq commit (the operator, 2026-11-10: a question the design does not answer stops that part, and its
answer is written down before the code; 2026-11-11: the lead answers it against the principles).
1. **The lead answers each question against the principles**, in one line in the milestone's lead-answers file
(beside the milestone part, cited as "design NN M A-n"), naming the principle that settles it (step 0, *Who answers
a design question*). One no principle settles the lead sends on: to the operator, one per ask, as playbook
[02](02-graduation.md), *Answering a design question*, says, each ask added to its wait list, when its answer
changes what the operator sees or how they work, removes data or needs the operator's terminal; every other one to
`hq-design-writer` in its handover. A question the writer finds is the operator's it hands back.
2. **An answer the lead does not give is written into the milestone part** by `hq-design-writer` on hq's branch of
the milestone, as a design line (the operator's citing the operator and the date, the writer's own giving its
reason) (or, outside every record's question, after its decision record), and the four reviewers by architectural
domain read the amended part in one round.
3. **The preparer adds the new lines to the build maps** (item 4) and the question's entry names the hq commit that
answers it.
4. **The design is complete** when every entry of both lists names its answering commit. Then step 1 starts, from the milestone
part at that commit.
**A question met later stops only its part.** A developer or the reviewer who meets a question the milestone part
does not answer stops the subtasks that need the answer, says the question to the lead with the design line and
file:line, and goes on with the subtasks that do not; the lead adds it to the list and answers it, or sends it on,
as item 1 says, and the stopped subtasks resume from the hq commit that answers it. Nobody builds around it, guesses it or builds both ways.
**A decision accepted while the milestone is built** that changes its part stops the subtasks of the lines it changes
until the part is amended (playbook [02](02-graduation.md)) and their build map rows are redone; code written before
the design was complete joins the milestone only where each of its commits builds a design line of the complete part,
and the review reads it as new code.
How it is checked: the milestone file's `Design questions` and `Design meets code` all name an answering hq commit
older than the first commit of step 1 (`git log` of each repository's branch against hq's); a commit with no design line, or one built on
an answer no hq commit holds, is a finding of the review (step 2, item 2a).
## Step 1 — Develop (one fixing agent per repository, smaller model)
- **One agent per repository, kept for the whole feature.** It reads its build map whole, and of the design the lines
its rows cite and the main-file sections those lines name (never the whole milestone part at once: on 2026-11-11
four developers ran out of context reading design 47's 580 KB before their second subtask), and builds the subtasks one after another in the build map's order, committing each
locally with a message naming the issue and, in its body, the design lines it builds ("Keep the assignments on
the bus (issue 652)", then "Builds: design 47 G §12, §13"). It builds what each line says, and nothing a line does
not say: no type, field, state, verb, event, bound, caller or tool of its own. Where it thinks a design line wrong
by the mesh's principles, it still builds it as written and says so in its report, for the lead to bring to the
operator; it never builds otherwise. It is not replaced per issue: the lead continues the same agent (by its id) with
the next instruction, so its context is paid for once.
- **Unit tests only, each well under a second** (how-we-build §5, ADR 0391). **The whole unit suite runs before
every commit** (the operator, 2026-10-17), not only the tests of what changed: it takes under a second, and a
change breaks tests in packages it never touched. Each issue's first test fails before its change, on an assertion about what the
code does, and passes after. **A test that fails only because it does not compile has not failed first**: where
the test calls what the change adds, the agent takes out the change's effect (the line that does it, not the new
function), sees the test fail, and puts it back (2026-10-19: a check request's new field was proven by a test of
its helper alone, and dropping the field from the request passed every test); `gofmt`, `go vet` and the whole unit suite stay green. **The tests are written from the issue's
acceptance criteria**: one test or more per criterion at the level it names, each test's comment citing
the criterion it proves by its label (`// 1118/AC2`), and no criterion left without its test; an integration criterion is a test
that compiles and is run by the pull request's one check. The integration tests (those that start a store, a bus
or a process) are compiled with `go vet -tags integration ./...` while developing and run by that check. **Once per head it
reports, not per commit, a developer also runs the integration tests of every package the change touches, and of
every package of the same module that imports one, against an embedded bus** (`go test -tags integration -count=1`
on those packages). Where the importers are many, it runs instead the tests of them that exercise the change
(`-run '<names>'`) and names that choice in its report. It is never a whole module's or level's run, so it stays
within the operator's rule of 2026-10-18 (step 3). On 2026-11-10 a kept call broke an integration test of a fix group whose
developers had run only the untagged suite, and the review's first round found it, not the developers. Before the
group's push the tests that exercise the change have run so at the reviewed heads (step 3), nothing else. **In mesh-sdk the whole
untagged `./...` runs at every commit, whatever package the change is in**: a test there holds its copy of the seat
list and fails on a change elsewhere. How it is checked: the developer's report names those packages and their
results, and the reviewer refuses a head reported without them.
- **Nothing is pushed and no pull request is opened in this step, and there is no try** (ADR 0548; the operator,
2026-10-26: "every release should only run 1 check or 1 try"). When every issue is committed, the lead brings each
feature branch up to the current trunk (fetch by name, then merge) and the review reads the local commits. Never call
`mesh-controller.try`, `mesh-delivery-checker.try` or `mesh-delivery-checker.checker_try`; one is run only when the operator asks for it. A reviewer
or a session that wants the code on the forge may push a branch that has no pull request: it runs nothing. Never land
on a red check: read the result, then land in a separate step.
- **The fixing agent's brief** (the lead gives it with the build map): name your issue in every step and
message ("issue 805: landing in mesh-catalog"); reach the mesh only through the mesh MCP server, never ssh;
never push, open, merge or close a pull request; never call a try; never write to a store's database by hand, a schema change
is a numbered migration and the consolidated schema; Go only unless the milestone part says otherwise; never
move another issue; **leave a module's whole integration level to the check** (no store or bus started by hand):
compile it with `go vet -tags integration ./...`, and once per head you report run the touched packages' and their importers' integration
tests against an embedded bus, or by name where the importers are many (above). **Judge a manifest and run the catalog's checks against what is live
now:** the seat list the seat `mesh-catalog`'s verb `seat-definitions` answers, read in the same turn and read again
when you report a head, with the
definitions the change's heads alter laid over it for the change's case (ADR 0636 §4), and the catalog at its trunk,
fetched fresh, beside it; never a captured copy, a test fixture or a list kept from an earlier run (2026-11-10: a
stale seat list made eight manifests refused locally that the running validator accepts, and stale copies hid two
failures). **Start a subtask only with room to finish it**: a subtask is sized so that its reading and its work
fit well inside a third of an agent's context; an agent with less than that left commits what is whole (tests
green) and stops between subtasks, never inside one (2026-11-10: developers that stopped at their bound inside a
subtask left half-built work for the next to read again). Its last report names its heads and the next subtask's
label; a fresh agent continues from the build map and the commits' design lines, and no file of the milestone
carries a handover of findings or choices. A single integration test may be run locally against an embedded bus when
it is the fastest way to find a cause, said in the review report and the pull request; before the group's push the
tests that exercise the change are run this way, by name (step 3). After a failed check it
usually pays to run that repository's whole integration level locally (`go test -tags integration -count=1 ./...` in each
module), by the lead or by the fixing agent on the lead's word, before the one more push: a verdict names only the first failed
test (issue 1921), and on 2026-10-23 R4g's faults surfaced one per run until a local run listed them all in a minute (a
guideline, the operator). Report back in under 150 words: commits, tests added and that they failed first, the
local results, anything you stopped on.
- **An agent that finds the code differs from its build map stops that subtask and reports** (file:line). A fact the
map got wrong (a file moved, a function named otherwise) the preparer corrects in the map, and the agent goes on;
anything that needs a choice is a design question (step 0b, *A question met later*), never settled by the lead.
- **Two repositories that depend on each other** keep their order in the build maps: the reader before the
writer, the contract before its users, the new manifest word before the catalog manifest that uses it. Two agents
never build against an interface neither has committed: the user's subtask starts from the commit that adds it.
- **Several agents in one repository** (only for a large repository with independent areas): each works on a
local branch of its own from the feature branch's head and lands by fast-forward under a lock
(`flock <feature worktree>.lock git -C <feature worktree> merge --ff-only <its branch>`), after its unit
tests pass; if another landed first, it merges again and repeats. In a shared clone, fetch the feature
branch by name before branching from it. Never resolve a conflict with a blind `git merge-file --union`.
## Step 2 — Review (one reviewer, larger model; at most 3 rounds, about 15 minutes)
1. **The reviewed tree is the tree that is pushed**: every feature branch was brought up to the current trunk
before the review (step 1). The check runs on the merge with the trunk as it is then, so a
trunk that moves later is met by the forge's merge check, not by another merge here. Every verdict names the
trunk it merged onto ("pass <head> on <trunk>"), and the lead reads that trunk against the repository's main
at once: a trunk behind main means the source revision (source.main) lags, and every check in that
repository is judged on it until it moves, so the operator's Approve will merge nothing. Say it then, not at the
merge (issue 1726: on 2026-10-24 the gate dropped two merges it heard before it held its seat, and a
reviewed, approved pull request in each of the two repositories was refused at its Approve).
2. **One reviewer reads every repository's local commits** together, against the milestone part, the design's
main file and the build maps. **It is one agent, kept for the whole release** like the fixing agents: the lead continues it by
its id for every later round, for the extra cycle after a failed check (step 3) and for its review record, so it
reads the milestone part, the issues, the build maps and the commits once (issue 1042). A fresh reviewer per
round or per mark pays for all of that again. Its report is per repository: each finding as file:line, the failure it causes, and the fix.
It says which round it is in ("round 1 of at most 3").
2a. **Every change is judged against its design line.** Each commit cites the design lines it builds; the reviewer
reads each line against the diff that cites it: the code does what the line says, all of it, and nothing it does
not say. Code no design line asks for (a new exported type, field, state, verb, event, bound, caller or tool, a
fate for what exists) is a finding: a choice the design does not make, taken out or held until the operator's
answer is in the design (step 0b). A design line in a build map with no commit, or a commit citing an answer no hq
commit holds, is a finding. The reviewer does not re-judge the design: a line it believes wrong by a decision or a
principle is a note to the lead for the operator, never a change asked of the code.
3. **The report goes to the same fixing agents** that wrote the code, continued by their ids, so they fix
with the context they already hold. Each answers the reviewer: what it changed, per finding, or why not.
4. **Every new integration test is read against the code it drives.** Fixing agents run only the touched packages' integration tests and their importers' (step 1), and no whole module's run precedes the review, so the reviewer judges each by reading too: a passing local run and the check that follows show whether it passed but not whether it proves what it says. The reviewer traces each step of each new integration test through the code (fixtures against the manifest rules, what the store keeps and reads back, who holds a seat), and says which steps it could not trace. On 2026-10-17 a new test failed on its first two runs, on a fixture and then on a fault of the change; reading it against the code after the first failure found another fault, which would have failed a run too. A review that finds a fault only by reading is the cheaper run. The reviewer also checks that each new integration test enters through the same path the live trigger takes, not through a state it writes by hand: on 2026-10-17 milestone 4's test saved its delivery plan directly, so it skipped the cut from a batch that every live plan takes, and it passed while the backup step never ran (issue 1086).
5. **The reviewer reads the answers and the new commits**, and approves or reports again (step 7 says what a round
may ask). After round 3 the lead stops and brings the operator what is left, with a recommendation.
6. **The reviewer reads every acceptance criterion against its test**: each criterion has a test at its level
that would fail without the change, and no test proves less than its criterion says. A criterion missing
for a case the issue's done-when needs is written onto the issue (step 0, item 5) and is a finding; a test
missing for a criterion is a finding.
**A rule keyed on a property is checked against everything else on the mesh that has it.** When a change
decides by a property the bus or the store gives (a stream's retention, a folder's name, an account's kind),
the reviewer lists what else already has that property, live, and asks what the rule does to it. On
2026-10-19 release 1 of feature mail-sender made a work-queue stream's dead letters drop-only by the bus's
work-queue retention; three review rounds passed it, and only its try showed that every seat's work stream has
that retention too, so dead asks across the mesh would no longer have been delivered again (issue 1178, fixed
before its pull request by a mark only a declared module work queue carries).
**A test fixture writes state in the form its real writer writes it** (for example a resolved config value with its
source, as the controller stores it); a fixture that agrees with the mistake proves the mistake. How it is checked:
the review asks it of every new fixture, and says which writer it compared with.
6a. **The reviewer reads the milestone file's three answers** (step 0, item 8) against the change: it lists every bucket
key and stream the diff creates or writes (search the diff for the bucket and stream names) and finds each in the
lifetime answer with a deleter and event, or a time to live; it reads the switch-over answer and checks it was done as
written or that the operator's choice is recorded; it reads the integration-level answer against the check the pull requests will ask. A missing answer, or a key or stream the diff creates that the answer omits, is a change asked.
6b. **The reviewer holds the change to each build map's `What exists today`** (step 0, item 3a). It refuses to
review a repository whose build map lacks the section or leaves one of its three answers open: that is the
prepare step undone, sent back to the lead, and not a round. For every part the diff removes, moves or changes the
form of, it runs the recorded search again on the reviewed tree and finds each effect and each reader in the second
answer; for each, it reads in the diff that the third answer's fate happened and that its test exists. An effect or a
reader the search finds and the answer omits, or a fate the diff does not carry out, makes the change wrong.
7. **A finding outside the issues' done-when and their acceptance criteria is never a change asked, in any round.** More hardening, a
further case, a nicer form: the reviewer opens it with `issue-tracker.open` and names the number in its
report, and the round does not wait for it. What a round asks is only what makes the change wrong against
its issues, their acceptance criteria and its decisions.
8. **A timer that writes state, or a rule fixed in code that overrides what a person sets, makes the change
wrong.** The mesh is NATS-native: a part says what happened as an event and acts on events; nothing polls
and rewrites state on an interval, and a policy the operator can change is a setting the module declares,
never a constant. The reviewer reads every new or changed interval, ticker, sleep loop and periodic
run-once in the change and asks of each: what event should drive it instead, and what setting turns it off.
One with no answer is a change asked. On 2026-10-23 the forge module's loop rewrote every repository's
branch protection every ten minutes from rules in its code and undid the operator's changes at the forge
(issue 1903).
9. **At the second instance of a fault kind in a review, the developer searches for every instance and names each in the
report.** On 2026-10-25 a "busy, return at once" guard that dropped a newer request was found in three places,
one review after another. The developer writes the kind in one line, searches the repository (`git grep`) for
its shape, fixes every hit in one change and lists each file and line in the report. How it is checked: a
report to the second round naming a kind and one place only, followed by a third round on the same kind, is
this rule skipped.
10. **The reviewer asks two questions of every change and every design, and answers both in its report** (the
operator, 2026-10-28: "design everything NATS-native"; "repositories are fully mesh agnostic"). The first:
*where does each piece of state live, and how does each seam (an integration, data, a part talking to
another) travel?* Anything that is not bus state, a stream or a seat's verb on the bus is a finding. The second:
*does a repository hold anything about this mesh's setup, such as node names, node-specific placement or
settings?* That is a finding: repositories are mesh-agnostic. On 2026-10-28 a placement design kept placement in
repository files with node names, because the accepted record it followed said so and nobody checked it against
these two principles. A finding in code the design does not place makes the change wrong (item 2a); where the
design line itself puts the state or the seam there, the finding is the design's: the reviewer names the line and
the record behind it, the lead brings it to the operator as a design question, and the code waits for the answer
in the design. How it is checked: the review report has a line for each question with its answer, and the lead reads both before the
push; a report without them is not an approval.
## Step 3 — Check (no review)
1. **Push the reviewed heads once, then open one pull request per repository, together** (ADR 0548; the operator,
2026-10-26: "every release should only run 1 check or 1 try"). **No pull request, draft or not, exists before the
review approves the heads**, and no fix round is pushed to an open pull request: every push to an open pull request
asks a new check, of every member for a group, and the mesh's build capacity is spent on it ("we don't have more
processing power"). The integration tests run once, in the checker's merge check on the merge with the trunk's head, at the unit
and the integration level, through the build module of the repository's language and by that language's convention
(ADR 0445, ADR 0529); the check waits on the language's check stream until a build node has a free slot
(ADR 0525 §1). **No try:** never call `mesh-controller.try`, `mesh-delivery-checker.try` or `mesh-delivery-checker.checker_try`, except when the
operator asks for one. While developing, no `go test -tags integration` run of a whole module or level, and no store or bus started
by hand on the machine (the operator, 2026-10-18).
**Before a group's single push, the integration tests that exercise the change have run locally against an
embedded bus**, at the reviewed heads: the touched packages' and their importers' tests that each developer ran for
the head it reported (step 1), or those picked by name (`go test -tags integration -count=1 -run '<names>'`) where
the importers are many; never a whole module's or level's integration run, and not only a compile with `go vet`; a
change in how a node composes or applies always has such a test (2026-10-28: a compiled-only group failed in the one
check on what a local run shows). How it is checked: the pull request's description names those tests and their
results.
**While a group is being checked, nothing else is merged or pushed into a repository that is one of its members:**
a moved main asks the group's check again. How it is checked: the lead's wait list names the group's members, and
`mesh-delivery.show` shows one check per head.
**A group is one check.** Before the push, every member pins the group's own package heads (mesh-sdk, and any other
package a member publishes) so it builds with `GOWORK=off`; the check itself builds against the group's heads whatever a
member's go.mod names (ADR 0573 §2, §4), so an older pin is not refused there, but the trunk builds after the merge read
the go.mod as written. Two members that import each other are pinned in order, each to the other's commit before its own
pin. Then all members are pushed and opened together, so the group's check runs once. A head the review replaces
counts for nothing against a running check; say so, and ask no other until the new head is reviewed.
**Before a session trusts an agent's "pushed", it reads the forge branch's head** (`git ls-remote origin refs/heads/<branch>`) and compares it with the commit reviewed; an agent may commit on a detached HEAD and report a push that never happened (2026-10-26: the first check of a reviewed fix failed "not our ref"). The pull request is opened only on that read head. Pull requests in two or
more repositories that share the branch name are one delivery group (ADR 0239 §2).
**A temporary mode that merges by hand** (the lead merges because the normal Approve and merge path is not
running): the pull request's one check still runs the integration level, and the lead names its verdict in the
pull request's description. A try with tests `.` is asked only when the operator asks for one, and then named there with its id and verdict (research 071).
Where a session pushes through the forge tool `gitea_commit` (one commit on the forge's current base), the
reviewer first confirms that commit's tree equals the reviewed one. **A large change is pushed by a pusher agent** on the smaller
model: `gitea_commit` patches of about 30 KB each, a file copied from another path sent as a copy (`copy_from`)
and not as its bytes, and the forge's tree compared with the local one after the last part (2026-10-20: R4c-2's
two repositories went up in parts this way, and the lead's own context stayed free for the review). **Each pull request's description carries
the review record** (ADR 0421 §5), one line the lead writes from the reviewer's approval:
`Reviewed-by: <who@node> at <full sha>` (the issue 1022 note gives its form). mesh-delivery reads it at every new
head and puts it in the Approve's ask; a missing line, or one naming another commit, is said first in the ask.
It is never a gate. **Beside it, the description names the session that pushed the head**, one line
`Pushed-by: <who@node>` (ADR 0505 §5): when the head cannot merge because its check failed after the Approve (a
conflict, a failed check, a rejected group), the cure is that session's new head, and mesh-delivery tells the
operator only after two hours with no new head, naming the branch's author and this session. The session that
pushed watches its own pull request (the instruction follow-what-you-start) and pushes the new head well inside
those two hours. A description without the line names the branch alone.
**The description names its issues as `issue <n>`, and only its own** (2026-10-21: okioki #9 listed its four
issues bare, `Issues: 1608, 1646, …`, and named a milestone-2 issue as `issue 1654` and a follow-up as
`issues 1665, 1666, 1667`, so mesh-delivery carried 1654 and 1665 as the pull request's issues and the Approve's
ask named them): mesh-delivery takes a pull request's issues from the words `issue <n>` and `issues <n>` in its
description (the plural yields its first number only), so write `issue 1608, issue 1646`, and name any other
issue in words, never by `issue <n>` or `issues <n>`.
**A catalog pull request that removes a module, or a subject a module names, is also judged by the
controller's unit tests against the catalog's branch**, because those tests read the catalog and no check
of the catalog runs them: on 2026-10-20 mesh-catalog #381 removed the old delivery module, and every
controller check failed afterwards on a test of the catalog's subjects until issue 1406 removed the name
mesh-issues still listened to. A controller's check does not find it, since a check reads the catalog's main
(also in a delivery group that holds the catalog's pull request); the lead runs mesh-controller's unit
suite with `MESH_CHECK_BESIDE` naming a directory that holds the catalog's branch, as mesh-controller's
`internal/beside` says.
**Before the push, every member's suites run as the running checker runs them**: each sibling repository placed
beside it by main's beside rules, the node-engine at the commit the machines run, and the running manifest validator
over every manifest the change touches, given the live seat list and the catalog's fresh trunk (step 1's brief). On 2026-11-02 release sdk1 failed four checks one fault at a time (test
globals left set, a sibling placed otherwise, the checker's manifest archive, a composition step the old checker could not
build), each of which a run as the checker places things would have shown before the first push. How it is
checked: the pull request's description names the placement, the node-engine commit and the manifest validator run used
locally; a check that fails on a placement the local run did not use is named by the lead at the next report.
2. **The checker's merge check runs the integration tests once, as the gate** (its one status, `mesh/check`).
**A merge with no verdict is unchecked, never passed.** Until the pipeline runner replaces the checker, the
checker drops a check still running when its pull request merges (met twice on 2026-11-10): the lead reads the
check's verdict (`mesh-delivery.show`) after every merge, and a merged change whose check has none is reported to
the operator as merged unchecked, with what its local runs covered, never as passed. How it is checked: a report
that says a merged change passed is read against its verdict in `mesh-delivery.show`. No second review: step 2
reviewed this tree.
3. **A check that fails** goes back to the same reviewer, continued by its id, with the failure, for **one more cycle** of step 2 with
the same fixing agents; then push **once** again (the one more push of ADR 0548). The check is **read, never re-asked to see if it passes**: a
check asked again without a new, reviewed head spends the build capacity for nothing. **The failure is read from the check's whole log**, never
reasoned from its summary: `mesh-delivery-checker.checker_pull` names every failure the verdict holds, one line each, and the full report
of the check. A check's summary picks only some failing lines;
on 2026-10-17 it showed a store test's `FAIL` without its cause, and a fix was first guessed from the code.
**A failure the check hides or loses** (a verdict naming only the first failed test, a log not kept) is a fault of the
checking tool: it is fixed there, the same turn (instruction fix-a-bug-met-twice), not asked around.
**A change to the Go build module's recipe is judged by the build module the nodes run**, not by the changed one, so a
test the change adds must pass under either version. **A change that needs the new recipe to judge it ships the recipe
first, as a small fix of its own**, and the rest waits for its delivery: on 2026-10-17 milestone 3 of design 47 moved its
integration tests behind a build tag in the same pull request as the script that ran that tag, and main's script would
have skipped every tagged test, its acceptance tests among them. Since R4g no repository holds such a script (ADR 0529):
which tests run at which level is the build tag's (ADR 0445 §2), and hq's checks are Go tests like any repository's
(ADR 0527). The prepare step looks for this: a change to what the checker's build module selects (its recipe, a build
tag convention) is cut ahead of the milestone.
**The same holds for every part that judges a change**: the checker, the indexer and its manifest validator, the grants part and
the build modules. A release that changes one of them is judged by the version that runs, so whatever the running
version cannot judge is delivered first as a change of its own, or left out and added back once the new part runs.
On 2026-11-02 release sdk1 delivered the build module's relative replaces first, and took the checker's new
composition call out of the release, adding it back in the next pull request once the new node-engines answered it. How it is checked: the prepare step's
milestone file lists every judging part the release changes and how each is delivered first or left out; the review
refuses a group that holds one without that line.
4. **The milestone's acceptance is proven by its check.** A milestone that adds or changes a module
carries an integration test that starts the module whole, its process against the real bus and store, and
shows the milestone's acceptance sentence; the forge's checks run it (ADR 0391 §1, §6). Unit tests alone are not
that proof; the mesh has no end-to-end tests yet, and the lab is not used (the operator, 2026-10-16).
**A new manifest word's test goes through the first composition that meets it, not only the verb that fills it.**
On 2026-10-19 release 1 of feature mail-sender tested a process's own bus account through `module issue`
alone; the first push after mesh-mail declared the process composed a random 40-character stand-in for the
account file before anyone issued it, and the process crash-looped until the account was issued and pushed by
hand (issue 1226).
5. **The operator's Approve is asked as soon as the checks pass** (ADR 0421). Nobody marks, labels, comments or
rechecks: mesh-delivery asks the Approve on Telegram, the channel that proves who answered today (ADR 0398 §3;
an Approve at the terminal is issue 953), once its one check (`mesh/check`) passed, for a delivery group once for all its
members, naming the review record. On the Approve it merges the approved heads, a group's in one pass
(ADR 0418). A new head ends the Approve and is asked again once its checks pass, which is why a head is pushed only after its review. A watcher follows the checks,
the Approve and the merge, and wakes the lead. Beyond that
Approve, the operator's word is waited for only when the milestone changes what the operator sees, removes
data, or needs a step only the operator's terminal can take; the lead says which before the milestone starts.
**A pull request that depends on an earlier one outside its delivery group is opened only once the earlier one is delivered**, its build
running on every machine it should reach, not merely merged. A note in the description is no safeguard: the
operator's Approve merges whatever is asked. On 2026-10-25 a second change merged before the first was delivered
and machines lost modules. How it is checked: `mesh-delivery.deliveries` shows the earlier change's source
revision `delivered` before the later pull request exists (`gitea.gitea_get_pull_request`, its creation time);
a later one older than that is this rule skipped. Members of one delivery group are the exception: they open together, with one check, one Approve and one merge in one pass (item 1).
**A reviewed follow-up to a change the operator has not yet approved is folded into that pull request** (its head
moved to include it): one Approve, one delivery. The old Approve ask closes itself on the new head and the new
head is asked once its checks pass. How it is checked: a follow-up that sits in a second pull request while the
first still waits shows in `gitea.gitea_list_pull_requests` as two open pull requests of one lead.
6. **A member pins mesh-sdk only at a commit that is a pull request's head**, merged or open (2026-10-28: the check
refused a pin to a merge commit on main as "on no pull request", though its tree equalled the head's). How it is
checked: the check's pin step; a refusal "on no pull request" is this rule skipped.
7. **Two groups that pin the same module's mesh-sdk conflict in `go.mod` and `go.sum`.** The group that merges
second merges main in and re-pins once, to a pull request head that holds both changes, after the first group
is merged and not before (a re-pin before makes the first group conflict). How it is checked: the check's merge
step; a group that conflicts after the first one merged is this rule skipped.
8. **A group that adds a seat, a verb or a manifest field in mesh-sdk and uses it in a module's manifest in the
same group cannot pass its check** until the running assigner pins a mesh-sdk that defines it, because the
check composes with the running assigner's mesh-sdk (issue 1585). The assigner's pin ships first, as its own
release. How it is checked: the check's composition step; a composition refusing the new word in such a group
is this rule skipped.
9. **A new head on an open pull request needs its `Reviewed-by` line at that head before the Approve is asked,
even for a pin-only commit.** How it is checked: the Approve's ask names the review record;
an ask whose line names another commit is this rule skipped.
**One exception: a catalog change that uses a new manifest word.** The catalog's merge check reads
manifests with the controller the mesh runs, so the controller's pull request is merged and delivered first;
then `mesh-delivery.recheck` the catalog's and merge it on the new verdict. Such work is two releases, the controller's first, and playbook 04 cuts its milestones that way.
**A new key the node-engine checks is such a word too** (issue 1051): the controller judges every machine with the
node-engine's own validator, vendored at the commit `go.mod`'s `replace` pins, so a key added to the node-engine is
refused by the gate until the controller's pin moves to the delivered node-engine (`go mod vendor`); the feature is
then three releases, the node-engine's, the controller's, the catalog's. **Every release that must merge before
the catalog's is on a branch name of its own** (`feat/<slug>-node-engine`, `feat/<slug>-controller`): on the
feature's name it joins the catalog's delivery group, and a group merges only whole, so neither merges.
The exception ends when milestone 3 of design 47 is delivered (issue 977, ADR 0402, ADR 0403): the group's composed
check, judged by the group's controller, is then each member's gate, and the feature is one group.
## Step 4 — Deliver
The merge moves the source revision; there is no delivery plan (design 47, ADR 0539). The indexer writes each
module's new fingerprint, the builder builds it once, the controller writes its compositions, credential and grant,
and the assigner writes each node's want when its seven rules hold: the module's canary first, its other nodes once
it runs healthy there. A merge into a branch other than `main` is not a delivery: no machine receives it.
**The view follows a delivery; nobody asks the controller.** The lead's watcher waits on the status view's events:
`moving` (a module's want on a node differs from its have), `settled` (the have reached the want, running and
healthy), `stuck` (held, a failed health check, or past the watchman's thirty minutes) and `delivered` (every want of
the source revision equals its fingerprint and every have its want). After each wake it reads the state again from
the view's wants page or its tools: `assigner_wants` and `assigner_want` (a want not yet at the newest fingerprint
names, in `newest` and `rule`, the rule that holds it back, and its words say why), and `node_haves` (the node
agent's haves: fingerprint, composition digest, phase and health). The delivery is done when the view says
`delivered` for its source revision; **"on the machines" from the delivery tools is not yet "delivered"**: the lead
also reads what the nodes run (the view's haves per node) and the indexer's record of the module (its newest
fingerprint) before saying a change is delivered. How it is checked: the report names each node's build.
Then the lead resolves the feature's issues with `fixed-by` naming its pull
requests, and removes what is left: no `feat/<slug>` branch and no `.work/<slug>` worktree survive.
**What a merge moves is read before the operator is told.** A change to mesh-sdk rebuilds every module that takes
the SDK, with their backups and their asks for a person (issue 721): on 2026-10-20 the lead said an SDK merge moved
nothing, and its delivery moved mesh-sdk with 41 dependents to all four machines. The lead reads the indexer's
candidates of the group (the view's `indexer_candidates`: each module whose fingerprint the change moves) and the
nodes that run them, and names what it moves before asking an Approve.
**A held move is the operator's answer, asked by the assigner.** A module of policy `record` whose move would
recreate a container or move data, a failed backup before an apply, and a data module whose new fingerprint failed
its health check on the canary each wait for the operator's answer to the assigner's ask; the view says them
`stuck`, and a condition names the node and the module. The lead reads the ask on the router
(`operator-channel.asks`) before telling the operator it waits, and adds it to the wait list. No session writes a
want to get past a hold.
**A new module's first assignment is its first real composition.** The composition check composes every machine as
it is assigned, so a module that no machine runs yet is composed by no check: on 2026-10-21 the build modules' first
assignment found two faults no merge check could see (issue 1537, a template the controller filled for a value the
forge serves only later; issue 1542, the node-engine refusing the module's own `.ssh`). So a new module is assigned
to one machine first, its have read after the node agent applies it (`node_haves`: phase and health) and its node's
answer read for a failed resource (`mesh-controller.node`), and taken back at once when that machine cannot compose
or apply, so the machine keeps applying everything else; the other machines follow once it runs there.
## Deliver the controller, the builder or a build module without the builder
The builder delivers its own module, the build modules and the controller from its keys, and nothing falls back to another builder
(ADR 0524 §7). When the builder or a build module cannot write references, or a controller cannot take its own fix (issue 1886: the
controller's plan could never finish, and no plan it made could deliver its own fix), the way is ADR 0526's, in this order, each
step recorded in the hand-act log with its reason:
1. **Revert, with no build.** Revert the change that broke the builder or the build module: the earlier source's fingerprint has a done key naming
references, so the revert's delivery builds nothing. Read first that the artifact store still holds the earlier artifact
(`mesh-controller.artifacts`): it keeps a recorded build while it is among its module's five newest or a definition names it, and the
controller keeps its composition while it is among the five newest too, so the assigner's want delivers it.
2. **A build by a session's call.** Call the build module's fetch and build tools on one named build node (for Go, `build_go_fetch` and then
`build_go_build` with `publish: true`); the build module pushes the artifact and answers its reference. `mesh-pack` in mesh-sdk gives a
hand build the build module's form; write the Go version of each hand build down, since another version gives another digest.
3. **Register by reference, at the controller's terminal only.** The operator names the module, its repository, its path and each artifact's
reference there; no verb reaches it. Say before you ask that this is a terminal step, and which notifications it raises; check that the
command exists on the node before you hand it over.
4. **A controller that cannot take its own fix** is put back by keys the operator writes at the terminal, with the operator's administrator
account (the operator's credential), never by a declaration sent by hand (ADR 0539 §10). To an earlier controller: the operator writes
`want.<control-node>.mesh-controller` naming a fingerprint whose composition is kept and that composition's digest; a controller
composes the one it replaced at its start, so that one is always kept. To a hand build never composed: register it as in step 3, then
`mesh-hand-compose` (in mesh-sdk, beside `mesh-pack`) composes the module for the control-node from the controller's kept inputs, signs it
with the operator's key, and with `-write` and the operator's credential writes the composition into `composed-<node>` and its digest
into `mesh-controller_composed`; the operator then writes the want naming that digest. Read the composition `mesh-hand-compose` prints
before `-write`. Each act goes into the hand-act log with its reason; say before you ask that these are terminal steps, and which
notifications they raise.
5. **Before a switch that moves the controller, the builder or a build module,** the lead keeps the running versions' artifacts outside the
artifact store, by digest on two nodes, with module, artifact, commit, Go version and the steps that put each back; the store's nightly
collection removes a blob the controller did not record.
Nothing here is a work-around for a delivery that can run normally: while the builder delivers, no hand act replaces it.
## Models
| Who | Model | Why |
|---|---|---|
| The lead (who works on what, asking the operator the design questions, following and reporting; it answers no design question) | larger | judgement of the process |
| The preparer (the build maps and the design questions, from the milestone part alone) | larger | reading the design and the code together |
| Read-only questions about the code for the build maps | smaller | reading, answered with file:line |
| Fixing agents (step 1, and the fixing in steps 2 and 3) | smaller | building to a written context |
| The reviewer (step 2, the extra cycle in step 3 and the review record; one agent, continued by its id) | larger | judgement, once per round |
| Decision records | larger | judgement |
Every agent the mesh runs draws on one weekly allowance shared by every session, and the larger model
spends it many times faster. Up to five agents on the smaller model at once, at most two subagents on the
larger one (the lead not counted).
## Following and reporting
Most lost time is waiting nobody saw. The lead therefore keeps a **wait list**: everything the feature waits
on, with when it started and its bound.
| Waiting on | Bound | Past the bound |
|---|---|---|
| a fixing agent's issue | 30 minutes | ask it where it stands; split or take over |
| the review | 15 minutes a round | ask the reviewer; stop at round 3 |
| a merge check | 15 minutes | read `mesh-delivery.show` (its state and verdict), then the check's log; the check stream's backlog and the age of its oldest ask are in the delivery view (ADR 0525 §9) |
| the Approve's ask | 5 minutes after the check (`mesh/check`) passes | read `mesh-delivery.show`: an ask not raised is a fault, said to the operator |
| a merge after the Approve | 5 minutes | read `mesh-delivery.show` for the delivery |
| a delivery | its class's budget (3 minutes for a leaf module, 10 for a core module), at most 30 minutes | read the view's wants page, or `assigner_wants` against `node_haves`: a want held back names its rule, a `stuck` module its words |
**Every wait on the list has a watcher** (the operator, 2026-10-17). A session runs only when a message reaches
it, so a check, a merge, a delivery, a record's review or the operator's Approve on a channel that lands
while the lead's turn has ended wakes nobody: on 2026-10-17 an approved group sat half merged for 14 minutes
unseen (issue 1032). For each wait the lead starts a watcher, an agent on the smaller model that changes nothing,
never the smallest (the operator, 2026-10-17).
It loops `mesh_wait` on the event families of what it watches (`mesh-delivery-gate.transition` and
`mesh-delivery-gate.group` for a merge, `mesh-delivery-view.moving`, `.settled`, `.stuck` and `.delivered` for its
delivery to the nodes, for example; the families a watcher may wait on are those the mesh granted
the tool runner, and a refusal names them) with a timeout under 60 seconds, since the call itself ends near
a minute. After every answer or timeout it reads the state from the verb that owns it (`mesh-delivery.show`,
the view's `assigner_wants` and `node_haves`, `knowledge-base.get`), because an event only wakes it (ADR 0367). It finishes, and so wakes
the lead, when the state changes or the wait passes its bound. The lead never sleeps or polls by hand to wait.
**A watcher watches one wait and ends with it.** It is never re-pointed at the next pull request or delivery: on
2026-10-19 one watcher sent on to three pull requests in turn missed that the third's checks had passed at 04:58,
and the lead told the operator for 15 minutes that they were still running. The next wait gets a fresh watcher,
and before a report the watcher reads the owning verb once more and says only what it says now.
**An ask is said to exist only after it is read on the router.** Before the lead tells the operator that an
Approve, a Retry or a Release waits for them, it reads `operator-channel.asks` and finds that ask open by its key;
on 2026-10-20 an ask was named to the operator that the router did not hold. A merge the gate passed but whose
ask is not on the router is the fault of the Approve's wait in the table above.
**The cadence is the instruction section "report-cadence"** (the operator, 2026-10-28; it replaces the full layout every
five minutes of "how-work-is-done"). Times are local and absolute, from the clock (`date`), never guessed; every number
has its unit and its bound or baseline; an issue is named by its number and a few words, never by its number alone.
- **Every five minutes** (ten until 2026-10-26, five since), every two minutes while a delivery moves (the view says
modules `moving`), and at once when something lands, stops or needs the operator, the lead sends the **short
report**: the tree exactly as `knowledge-base.progress` with `of: "design <nn>"` and `detail: minimal` answers it,
unedited, with the verb's read-at time, then at most three lines: what changed, what needs the operator, what is next.
Once the verb takes `since`, the short report asks `since: 5m`.
- **About every thirty minutes**, and whenever something stops, the lead sends the **detailed report**: the same verb
with `detail: detailed` (or `since: 60m`), then the full layout below.
- **Every report ends by scheduling the next** (a timer or a watcher set ahead), so that agents' incoming reports
never replace it.
- **An answer to the operator between reports is short and has no tree.**
**The tree is the verb's answer and is never drawn or corrected by hand.** `knowledge-base.progress` answers the
design's milestones, issues, pull requests and held groups in one call, each with when it last moved (issue 1947).
What it cannot read for certain from the design's milestone table it says in `warnings`; the lead fixes the table, it
does not correct the tree by hand.
**The full layout** (the detailed report) is the verb's detailed tree followed by these lines:
```
Opened along the way: <each issue opened during the feature, its number and a few words, and when it is fixed: in between, after the delivery, or waits on what> — or "none"
Past its bound: <the wait, how long, what is being done> — or "none"
Needs you: <one line per question, with my recommendation> — or "nothing"
Allowance: week <n> % (<+d> since the last report), session <n> %
Worth it: <what in the last stretch served the goal, and what did not>
Next: <the next actions up to the delivery, in order>
```
How it is checked: the operator sees a short report at least every five minutes and a detailed one at least every
thirty; a report's tree that differs from the verb's answer of the same minute is a tree assembled by hand, a report
without the verb's read-at time is the same, and a report that does not end by scheduling the next is a breach the
lead reports.
On a channel such as Telegram the same short report is sent, the tree as a code block.
## The context of the lead's own session
At the end of each step, and whenever the session's context grows large or spread over unrelated work, the
lead prepares a `/clear` as the mesh's instruction "prepare before clear" says: a save point with the
feature's step, its branches and heads, the build maps' paths, the design questions still open, the agents' ids,
the wait list and the next action; then the prompt the operator pastes. The milestone part, the build maps and the
commits' design lines make the feature resumable after a clear.
## The design's state is written back
Other sessions know what is built only from the design's frontmatter and the issue tracker; what the lead
knows and does not write back, nobody else knows. A design merged in one delivery with three of its tasks
left, its frontmatter still saying `designed`, read to another session as not built, and a second design
was started beside it (issue 1009, 2026-10-17). So the lead writes the design's state back at each of these
moments, the same hour, an hq change going through [playbook 08](08-small-fixes.md):
- **The first milestone starts:** the design's `status: in-progress` ([playbook 04](04-build-handoff.md) step 7),
if it is not already.
- **A milestone is delivered** (the view says `delivered` for its source revision): its issues are resolved (step 4), with `fixed-by` naming its pull
requests. The design's milestone entry is not changed: it names the milestone's issues, and whether they are
delivered, when and by what is read from the issue tracker when it is asked, never copied into the design
(issue 1038; AGENTS.md: cross-cutting views are generated when they are read).
- **The building pauses with work left** (another design takes its turn, a hand-over, the session's end): the
design stays `in-progress`, and each issue left gets a note with `issue-tracker.note` saying what it waits
for and what comes after it ("built after design N is delivered, before design M"). The first issue of
a design that waits its turn gets the same note.
- **The last milestone is delivered:** [playbook 02](02-graduation.md), "When something ships": the as-is is
written and the design says `implemented`.
## Issues that stop
An issue stays in `fixing` only while an agent works on it. A milestone that stops, for a wait past its bound, a
hand-over, or the session's end, moves each of its issues not delivered back to `open` with
`issue-tracker.move` and a note saying how far it got (its branch, its last commit, what is left). A list of
issues in `fixing` that nobody works on reads to the operator as stuck work.
## How it is checked
- A feature's issues show their commits on the feature branch (`git log --grep 'issue <n>'`), and no pull
request into a feature branch exists. A pull request per issue, or an agent waiting on a merge check in
step 1, is the failure this playbook prevents.
- A build map exists per touched repository under `.work/<slug>/` while the feature runs, and every row cites a
design line of the milestone part.
- Every commit of the milestone names in its body the design lines it builds (`git log --format=%B | grep 'Builds:'`),
and the milestone file's `Design questions` each name the hq commit that answers it, older than step 1's first
commit.
- The milestone's part is within 60 KB and the design's main file within 80 KB (`wc -c`); a milestone developed from
a larger part is playbook 04's step 4a skipped.
- Every build map opens with `What exists today` holding step 0 item 3a's three answers, each search written as run
(`grep -n -A3 'What exists today' .work/<slug>/*.map.md`), and its time (the file's commit or the lead's note) is
older than the repository's first commit of the feature; the review report says it ran the searches again (step 2,
item 6b). A fixing agent started on a file without the section, or an effect of a removed or moved part met only
after the delivery, is the prepare step skipped, named in the next detailed report and written into the playbook's
lessons here.
- No issue of a running milestone is sized over an hour in its prepare note; an issue whose fixing agent passes
twice its bound was not split.
- Every issue of a running milestone has a note from the prepare step naming its files and tests (file:line), how
it is checked and delivered, and for a group its merge order (`issue-tracker.get`); an issue moved to `fixing`
without one is a prepare step skipped.
- Every issue of a running milestone has a note headed `Acceptance criteria` before it moves to `fixing`
(`issue-tracker.get`), each criterion naming its test level, and every criterion's label is cited by a test in the
pushed tree (`git grep -n '<issue>/AC<n>'`); an issue without them is a prepare step skipped, and a
criterion no test names is a review that missed it (until issue 1118 makes the tracker refuse it).
- Every fixing agent's report gives the whole unit suite's result and time; a report naming only some packages'
tests is the whole-suite rule not kept.
- The lead's save point names each watcher with its model; a watcher on the smallest model is the failure of
"Following and reporting".
- A report or a save point that names a "phase" of a milestone is the old wording: a milestone has steps.
- Every repository's own clone says `main` (`git -C <clone> branch --show-current`); another branch there is
work done outside a worktree (issue 1010).
- After a feature's delivery, `git branch -r | grep feat/<slug>` and `git worktree list` return nothing for it.
- A design whose milestone issues are partly resolved says `in-progress`, and one whose issues are all
resolved and delivered says `implemented`: read its Milestones section against `issue-tracker.get` for each
issue. A design that says `designed` with a resolved milestone issue is a state not written back.
- A design's Milestones section names each milestone's issues and nothing of their state: a "delivered", a date
or a pull request in an entry is a copy of the tracker's state (issue 1038), read with
`grep -n 'delivered' <design>` over its Milestones section.
- Every open issue of a design that says `in-progress` and has no agent on it shows, in `issue-tracker.get`, a
note saying what it waits for; one without such a note is a pause not written back.
- The milestone issues in `fixing` (`issue-tracker.list`) belong to one design at most: milestone issues
of two designs in `fixing` at once is the failure of "one design is built at a time".
- More than one open pull request in a repository that share no feature name, or a milestone whose issues
stay in `fixing` for more than a working day, is the smell: stop and bring it to the operator.
- A review report that asks a change outside the issues' done-when and acceptance criteria, or a fourth round, is the failure of the
review rules; `issue-tracker.list` with `flag: abandoned` lists issues left in `fixing` with nobody on them.
- A pull request green for more than 5 minutes with no Approve asked is a fault of mesh-delivery
(`mesh-delivery.show`), said to the operator.
- Every review record of a release names one reviewer (`mesh-delivery.show`, the review record), and the lead's
save point names one reviewer id per release; a second reviewer within one release is a reviewer not kept
(issue 1042). A pull request whose ask says it has no review record at its head is a record not written.
- A running milestone's file holds the three answers of step 0 item 8 (`cat .work/<slug>/milestone.md`), and the
review report says it read them (step 2, item 6a): a bucket key or stream in the diff (`git diff main --
| grep -i 'bucket\|stream'`) that the lifetime answer omits is the failure of that item (research 071).
- A pull request merged by hand in a temporary mode names, in its description on the forge (`gitea.gitea_get_pull_request`), the
verdict of its one check; a try with tests `.` is named only where the operator asked for one.
- **One release, one check** (ADR 0548): `gitea.gitea_get_pull_request` shows each pull request created after its
review record's time, and `mesh-delivery.show` shows one check per head and, for a group, one head per member; a pull
request that existed before its review approved it, a second head with no failed check before it, or a check of a
head asked more than once, is this rule skipped. A call of `mesh-controller.try`, `mesh-delivery-checker.try` or `checker_try` that the operator
did not ask for shows in the checker's asks and is the same breach.
- A milestone that adds or changes a module whose pull request has no integration test that starts the module
whole is the failure of the check step's fourth item.
- A bed run from `.work/<slug>/mesh-lab` that fails naming a `.work/<slug>/<repo>/…` path it cannot find is a
missing sibling worktree, not a mesh fault.
When this playbook meets a problem, the lesson is added here, so the next feature avoids it.