Playbook 07: a milestone has steps, runs the whole unit suite, writes its findings into its issues and watches on the smaller model; design 47 names milestone 2b and takes 895 into milestone 3 (issue 1053)
mesh/merge-gate head 2001d6e06334 merged into trunk e44ec3f61235 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 2001d6e06334 merged into trunk e44ec3f61235 — pass: its merge-check.sh passed
mesh/delivery delivered

This commit is contained in:
2026-10-17 20:19:16 +02:00
parent 90c6793096
commit 2001d6e063
3 changed files with 56 additions and 38 deletions
+47 -29
View File
@@ -35,12 +35,13 @@ A small fix (one repository, one issue, about an hour of work) follows
## The shape
One feature is **one branch name**, **one worktree per repository**, **one pull request per repository**,
opened **once**, after the review. It runs in five phases, and its time is bounded:
opened **once**, after the review. It runs in five steps, 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:
| Phase | What happens | Bound |
| Step | What happens | Bound |
|---|---|---|
| 0. Prepare | the lead settles the open questions and writes one context file per repository | 15 minutes |
| 1. Develop | one fixing agent per repository builds every issue locally, unit tests only | the milestone's issues, 30 minutes each |
| 1. Develop | one fixing agent per repository builds every issue locally, the whole unit suite before every commit | the milestone's issues, 30 minutes each |
| 2. Review | one reviewer reads all of it; reports go both ways; at most 3 rounds | 15 minutes |
| 3. Check | push; the forge's merge checks run the integration tests; no further review | one check run |
| 4. Deliver | merge; the delivery plan builds, publishes and sends the whole feature | its delivery plan |
@@ -57,10 +58,10 @@ built, no milestone of another design starts: its issues stay `open`, and nobody
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 phase 0.** An issue found during a feature goes to the next milestone or the next feature,
**Scope is fixed at the prepare step.** An issue found during a feature goes to the next milestone or the next feature,
never into the running one, unless it blocks the running one.
## Phase 0 — Prepare (the lead, larger model)
## Step 0 — Prepare (the lead, larger model)
1. **Name the feature once:** `feat/<slug>`, the same branch name in every repository it touches. The
branch is never protected. **One milestone is one branch per repository** (the operator, 2026-10-17), with one
@@ -86,19 +87,27 @@ never into the running one, unless it blocks the running one.
integration tests, which the forge's checks run).
When the reading is large, a read-only agent on the smaller model answers the lead's exact questions with
file:line, and the lead writes the file from its answers.
5. **Move the issues to `fixing`**, `by` naming the feature's agent for that repository.
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); how the change is checked and delivered end to end (which test proves its done-when, which
modules its delivery plan moves, to which machines); and for a group, its merge order. The context file
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.
6. **Move the issues to `fixing`**, `by` naming the feature's agent for that repository.
## Phase 1 — Develop (one fixing agent per repository, smaller model)
## Step 1 — Develop (one fixing agent per repository, smaller model)
- **One agent per repository, kept for the whole feature.** It reads its context file once and builds the
issues one after another, committing each locally with a message naming the issue ("Keep the assignments
on the bus (issue 652)"). 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, of what changed, each well under a second** (how-we-build §5, ADR 0391). Each issue's
first test fails before its change and passes after; `gofmt`, `go vet`
and the repository's unit tests stay green. The integration tests (`merge-check.sh` with the store and the
bus) wait for phase 3.
- **Nothing is pushed** and no pull request is opened in this phase. Never land on a red check: run the
- **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 and passes
after; `gofmt`, `go vet` and the whole unit suite stay green. The integration tests (`merge-check.sh` with the store and the
bus) wait for the check step.
- **Nothing is pushed** and no pull request is opened in this step. Never land on a red check: run the
checks, read the result, then land in a separate step.
- **The fixing agent's brief** (the lead gives it with the context file): 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;
@@ -116,13 +125,13 @@ never into the running one, unless it blocks the running one.
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`.
## Phase 2 — Review (one reviewer, larger model; at most 3 rounds, about 15 minutes)
## Step 2 — Review (one reviewer, larger model; at most 3 rounds, about 15 minutes)
1. **Bring every feature branch up to the current trunk** (fetch by name, then merge), so the reviewed tree is
the tree that is pushed.
2. **One reviewer reads every repository's local commits** together, against the context files and the
decisions. **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 (phase 3) and for the ready mark, so it
its id for every later round, for the extra cycle after a failed check (step 3) and for the ready mark, so it
reads the decisions, the issues, the context files 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").
@@ -135,7 +144,7 @@ never into the running one, unless it blocks the running one.
report, and the round does not wait for it. What a round asks is only what makes the change wrong against
its issues and its decisions.
## Phase 3 — Check (no review)
## Step 3 — Check (no review)
1. **Push every feature branch and open one pull request per repository, together.**
The integration tests
@@ -144,8 +153,8 @@ never into the running one, unless it blocks the running one.
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.
2. **The forge's merge checks run the integration tests once** (`mesh/merge-gate`, `mesh/repo-check`). No
second review: phase 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 phase 2 with
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 failure is read from the check's whole log**, never
reasoned from its summary: `mesh-delivery.show` names the check's build id, and `mesh-controller.builds` with
`log` set to that id prints everything the builder said. A check's summary picks only some failing lines;
@@ -172,7 +181,7 @@ then `mesh-delivery.recheck` the catalogue's and merge it on the new verdict. Su
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.
## Phase 4 — Deliver
## Step 4 — Deliver
The merge starts the delivery plan: build, publish, send. A merge into a branch other than `main` is not a
delivery: no machine receives it (issue 889 while it still starts one). The lead follows it to done
@@ -184,10 +193,10 @@ survive.
| Who | Model | Why |
|---|---|---|
| The lead (phase 0 decisions, the context files, following and reporting) | larger | judgement |
| The lead (step 0 decisions, the context files, following and reporting) | larger | judgement |
| Read-only questions about the code for the context files | smaller | reading, answered with file:line |
| Fixing agents (phase 1, and the fixing in phases 2 and 3) | smaller | building to a written context |
| The reviewer (phase 2, the extra cycle in phase 3 and the ready mark; one agent, continued by its id) | larger | judgement, once per round |
| 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 ready mark; 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
@@ -211,7 +220,8 @@ on, with when it started and its bound.
**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 plan, 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 smallest model that changes nothing.
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.transition` and
`mesh-delivery.group` for a delivery, for example) 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`,
@@ -228,7 +238,7 @@ overview): every milestone of the design with its state, and under the running m
their issues, each issue under the one it waits for, marked ✓ landed or delivered, ▶ fixing, ⏸ waiting, ✗ stopped:
```
Feature <slug> · milestone <n> of <m> · phase <name>, <minutes used> of <bound> min
Feature <slug> · milestone <n> of <m> · step <name>, <minutes used> of <bound> min
Issues: <landed> of <total> landed · <fixing> fixing · <waiting> waiting
Design <nn> · <its title>
@@ -253,7 +263,7 @@ Next: <the next actions up to the delivery, in order>
**The short layout** (on a channel such as Telegram, or when nothing changed but time):
```
<slug> milestone <n>/<m> · <phase> <used>/<bound> min · <landed>/<total> landed · past bound: <none | what> · needs you: <nothing | what> · week <n> %
<slug> milestone <n>/<m> · <step> <used>/<bound> min · <landed>/<total> landed · past bound: <none | what> · needs you: <nothing | what> · week <n> %
```
A report says what changed since the last one first. In the session every report is the full layout, the whole
@@ -262,9 +272,9 @@ asking. The short layout is for a channel.
## The context of the lead's own session
At the end of each phase, and whenever the session's context grows large or spread over unrelated work, the
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 phase, its branches and heads, the context files' paths, the agents' ids, the wait list and the
feature's step, its branches and heads, the context files' paths, the agents' ids, the wait list and the
next action; then the prompt the operator pastes. The context files make the feature resumable after a clear.
## The design's state is written back
@@ -277,7 +287,7 @@ moments, the same hour, an hq change going through [playbook 08](08-small-fixes.
- **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's delivery plan is done:** its issues are resolved (phase 4), with `fixed-by` naming its pull
- **A milestone's delivery plan is done:** 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).
@@ -299,8 +309,16 @@ issues in `fixing` that nobody works on reads to the operator as stuck work.
- 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
phase 1, is the failure this playbook prevents.
step 1, is the failure this playbook prevents.
- A context file exists per touched repository under `.work/<slug>/` while the feature runs.
- 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 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.
@@ -323,7 +341,7 @@ issues in `fixing` that nobody works on reads to the operator as stuck work.
- Every ready mark of a release names one reviewer (`mesh-delivery.show`, `ready.by`), 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 milestone that adds or changes a module marked ready with no integration test that starts the module whole is
the failure of phase 3's fourth step.
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.
+3 -3
View File
@@ -30,9 +30,9 @@ one delivery**. Everything before the push is local and fast.
decision stays a small fix.
2. **Move the issue to `fixing`** with `by` as who@node.
3. **Build on a local branch** `fix/<issue>-<slug>`, in a worktree of its own branched from `main`, never in
the repository's own clone, which stays on `main` (playbook [07](07-feature-branches.md), phase 0 step 2). Write the
test that fails today first; make the change; keep `gofmt`, `go vet` and the unit tests of what changed green
(each well under a second; never a merge check or a database locally: how-we-build §5, ADR 0391).
the repository's own clone, which stays on `main` (playbook [07](07-feature-branches.md), step 0, item 2). Write the
test that fails today first; make the change; keep `gofmt`, `go vet` and the repository's whole unit suite green
before every commit (each test well under a second; never a merge check or a database locally: how-we-build §5, ADR 0391).
Commit, naming the issue. For a playbook or design edit, run the repository's own checks (in hq,
`sh merge-check.sh`).
4. **One review of the local commit, before anything is pushed** (a reviewer that did not write it, larger