Rewrite playbook 07 as five bounded phases with reused context, and add playbook 08 for small fixes
mesh/merge-gate head 464833d0ef3f merged into trunk 99a9da095010 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 464833d0ef3f merged into trunk 99a9da095010 — pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate head 464833d0ef3f merged into trunk 99a9da095010 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 464833d0ef3f merged into trunk 99a9da095010 — pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
A feature waited a day for its last issue, each small issue paid for its context again, and waits nobody saw cost the most time. The operator set the flow on 2026-10-15: prepared context per repository, one to two hours of local development on unit tests, one review of at most three rounds back to the same agents, one push for the integration checks, then the delivery plan; steps for a larger feature; a separate playbook for small fixes; models per step; a wait list with bounds; a prepared clear at each phase end.
This commit is contained in:
@@ -56,7 +56,8 @@ the expensive half.
|
||||
| [04](04-build-handoff.md) | Build handoff | A design is ready to be built |
|
||||
| [05](05-constitution-sync.md) | Constitution sync | `how-we-build.md` changed a rule the mesh enforces |
|
||||
| [06](06-writing-a-module.md) | Writing a module | Something that runs today must run on the mesh |
|
||||
| [07](07-feature-branches.md) | Feature branches across repos | Work that changes code, in one repo or several at once |
|
||||
| [07](07-feature-branches.md) | Features | Work that changes code across issues or repositories: prepared context, local development, one review, one check, one delivery |
|
||||
| [08](08-small-fixes.md) | Small fixes | One issue in one repository, about an hour of work: one review, one push, one delivery |
|
||||
|
||||
## The cycle is checked
|
||||
|
||||
|
||||
@@ -1,244 +1,175 @@
|
||||
# Playbook 07 — Feature branches across repos
|
||||
# Playbook 07 — Features
|
||||
|
||||
**Trigger.** Work that changes code — in one code repo or in several at once (`mesh-sdk`,
|
||||
`mesh-controller`, `mesh-catalog`, `mesh-host`, `mesh-lab`, and `hq` when a decision rides along).
|
||||
**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 —
|
||||
it is the guard against the failure it was written for.
|
||||
**Who runs it.** Anyone who writes code, engineers and agents alike. Agents follow it exactly.
|
||||
|
||||
## The failure it prevents
|
||||
## The failures it prevents
|
||||
|
||||
A feature was worked as a branch-and-MR per *unit of thought* — one per decision, one per
|
||||
stacked increment — and each MR was treated as finished when it was *opened*, not when it was
|
||||
*merged*. Across repos the same feature took a different branch name in each. The MRs piled up
|
||||
unmerged: one session left **sixteen** stacked intermediate MRs that had to be consolidated and
|
||||
closed by hand. An MR is a review checkpoint, not a scratchpad.
|
||||
- **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 plan
|
||||
or an agent waiting on something that had stopped, unseen.
|
||||
|
||||
It failed the other way too. A large feature was worked as one pull request per issue into protected
|
||||
integration branches, each waiting for the forge's merge check, again whenever another merge moved the
|
||||
branch, and for a review. Most of a day went to waiting on checks while the code itself was ready.
|
||||
## The shape
|
||||
|
||||
## The rule
|
||||
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:
|
||||
|
||||
One feature is **one branch name**, **one worktree per repo**, **one MR per repo**, opened
|
||||
**once, at the end**.
|
||||
| Phase | 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 | 1 to 2 hours |
|
||||
| 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 |
|
||||
|
||||
1. **Name the feature once.** `feat/<slug>`. The *same* branch name in every repo the feature
|
||||
touches — never a different name per repo, never a fresh branch per increment within the
|
||||
feature.
|
||||
A feature that cannot be developed in about two hours is split into **steps**. Each step runs all five
|
||||
phases on its own; the next step starts only when the previous step's delivery plan is done. A step is the
|
||||
unit that ships, so nothing finished waits for work that is not.
|
||||
|
||||
The feature branch is never protected and takes no pull request until step 4: a protected
|
||||
branch forces a merge check on every merge into it, which is the waiting this playbook avoids.
|
||||
**Scope is fixed at phase 0.** An issue found during a feature goes to the next step or the next feature,
|
||||
never into the running one, unless it blocks the running one.
|
||||
|
||||
2. **Isolate each repo.** One git worktree per touched repo under `.work/<slug>/<repo>`, branched
|
||||
off `main`:
|
||||
```
|
||||
git worktree add .work/<slug>/<repo> -b feat/<slug> origin/main
|
||||
```
|
||||
Parallel features never collide, and no shared checkout is edited.
|
||||
## Phase 0 — Prepare (the lead, larger model)
|
||||
|
||||
**Add the untouched siblings the lab reads.** The lab beds find the other repositories by
|
||||
sibling path from the lab checkout (`../mesh-tools/module.json`, `../mesh-sdk`, …), the way
|
||||
the main layout has them. A `.work/<slug>/` directory holding only the touched repos fails a
|
||||
bed at once with `no manifest for mesh-tools at …/.work/<slug>/mesh-tools/module.json`, after
|
||||
genesis has already passed. Give the directory those repos as **detached worktrees on `main`**
|
||||
— never symlinks:
|
||||
```
|
||||
git worktree add --detach .work/<slug>/mesh-tools main
|
||||
```
|
||||
3. **Commit as you go — locally.** Increments land on the one branch. Nothing is pushed and no
|
||||
MR is opened mid-feature.
|
||||
1. **Name the feature once:** `feat/<slug>`, the same branch name in every repository it touches. The
|
||||
branch is never protected.
|
||||
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.
|
||||
3. **Settle every open question** in the feature's issues before any agent starts: on the issue, through
|
||||
the knowledge base, or by asking the operator. A fixing agent that meets an undecided design question
|
||||
stops, and its run is spent again.
|
||||
4. **Write one context file per repository**, `.work/<slug>/<repo>.context.md`. It is what a fixing agent
|
||||
reads instead of rediscovering the code, and it is reused by every agent and every round:
|
||||
- the issues it builds, in order, each with: the files and functions it changes, the decisions it builds
|
||||
with (quoted, with where each was decided), the test to write first, done-when in one sentence;
|
||||
- the repository's map for this feature: the packages and files involved, with one line each on what they
|
||||
hold, and 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`), a throwaway database server if the store tests need one.
|
||||
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.
|
||||
|
||||
The unit of work is an **issue**. Each commit message names the issue it fixes, such as
|
||||
"Keep the assignments on the bus (issue 652)". No pull request, merge check, review or delivery
|
||||
per issue.
|
||||
## Phase 1 — Develop (one fixing agent per repository, smaller model)
|
||||
|
||||
4. **Finish, review, then publish.** When the whole feature is done — every repo, tests green —
|
||||
each repository's change gets one independent review **of the local commits, before anything
|
||||
is pushed**. A push starts the forge's checks (building the modules and running every test, up
|
||||
to a quarter of an hour), so a review finding fixed after a push costs another full run. The
|
||||
reviewer reads the feature worktree. Once the review approves, push every branch and open
|
||||
**one MR per touched repo**, together; the checks run once, on those MRs, and the feature is
|
||||
delivered as one delivery plan. MRs in two or more repositories that share the branch name are
|
||||
one delivery group (ADR 0239 §2); a feature in one repository is one delivery. A small change
|
||||
outside a feature (a playbook, a design) goes the same way: review the local commit, then push
|
||||
once.
|
||||
- **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.** 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.
|
||||
- **An agent that finds the code differs from its context file stops and reports** (file:line); the lead
|
||||
settles it, updates the context file, and continues the agent.
|
||||
- **Two repositories that depend on each other** keep their order in the context files: the reader before the
|
||||
writer, the controller's new manifest word before the catalogue manifest that uses 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`.
|
||||
|
||||
**One exception: a catalogue change that uses a new manifest word.** The catalogue's merge check
|
||||
reads manifests with the controller the mesh runs — the delivered one, not `main` and not the
|
||||
group's own branch — so such a feature is delivered in two steps, controller first: merge and
|
||||
deliver the controller's pull request, then ask `mesh-delivery.recheck` for the catalogue's, and
|
||||
merge it on the new verdict.
|
||||
## Phase 2 — Review (one reviewer, larger model; at most 3 rounds, about 15 minutes)
|
||||
|
||||
5. **Merge promptly, once approved.** Every merge into `main` is notified and approved
|
||||
(ADR 0023); once it is, merge —
|
||||
do not leave it sitting. The branch is deleted on merge.
|
||||
6. **Leave nothing behind.** After the MRs merge, no `feat/<slug>` branch and no `.work/<slug>`
|
||||
worktree survive.
|
||||
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. 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").
|
||||
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. **The reviewer reads the answers and the new commits**, and approves or reports again. From round 2 it
|
||||
asks changes only for a finding that makes the feature wrong; smaller points become issues of their own.
|
||||
After round 3 the lead stops and brings the operator what is left, with a recommendation.
|
||||
|
||||
## Working one feature with several agents
|
||||
## Phase 3 — Check (no review)
|
||||
|
||||
A large feature (a design's whole work) is fixed by several agents at once. The **lead** is the
|
||||
session that runs the feature: it holds the feature branch, sends an agent per issue, and pushes,
|
||||
reviews and delivers at the end. The agents never push.
|
||||
1. **Push every feature branch and open one pull request per repository, together.** Pull requests in two or
|
||||
more repositories that share the branch name are one delivery group (ADR 0239 §2).
|
||||
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 reviewer with the failure, for **one more cycle** of phase 2 with
|
||||
the same fixing agents; then push once again.
|
||||
4. **Mark each pull request ready** (`mesh/ready` and a comment `ready at <full sha>`) once the operator's word
|
||||
for the feature is given; mesh-delivery merges it when its checks pass (ADR 0364).
|
||||
|
||||
- **One feature worktree per repository, held by the lead.** Each agent works on a local branch of
|
||||
its own, in a worktree of its own, branched from the feature branch's current head.
|
||||
- **Land by fast-forward, under a lock.** An agent brings its branch up to the feature branch,
|
||||
runs the repository's tests and `merge-check.sh` in its own worktree, then fast-forwards the
|
||||
feature branch under a lock (`flock <feature worktree>.lock git -C <feature worktree> merge
|
||||
--ff-only <its branch>`). If another agent landed first, it merges again and repeats.
|
||||
- **The lead decides, a fixing agent builds.** Before an issue goes to an agent, the lead reads it and
|
||||
the code it touches, finds every open question and settles it: decided on the issue, through the
|
||||
knowledge base, or by the operator. An agent that meets an undecided design question stops, and its
|
||||
whole run is spent again when it restarts. The issue the agent gets then says, in its own text:
|
||||
- the repository and the files it changes: one repository and one change, sized so an agent finishes in
|
||||
five to ten minutes. The repository's own check is a floor under that: mesh-controller's, with its
|
||||
store, took 6 minutes 51 seconds on 2026-10-15 (the merge check of mesh-controller #342). A change that needs readers in one repository before a writer in another is two issues,
|
||||
the second depending on the first, not one agent through three repositories: each extra repository
|
||||
means merging the feature head and running every check again while other agents land;
|
||||
- the decisions it builds with, quoted, never "read notes 8 to 12";
|
||||
- the test to write first, which fails before the change;
|
||||
- its done-when, in one sentence;
|
||||
- what it must not touch, and what is landing beside it.
|
||||
An agent that finds the code differs from its issue stops and reports; it does not design around it.
|
||||
- **Spend the operator's allowance on judgement.** Every agent the mesh runs draws on one weekly
|
||||
allowance shared by every session, and the larger model (Opus) spends it many times faster than the
|
||||
smaller one (Sonnet). Fixing agents and read-only diagnosis agents run on Sonnet. The larger model is
|
||||
for the lead's own judgement, the independent review of each repository before the push, and
|
||||
decision records, and as few of its subagents as possible.
|
||||
- **Up to five Sonnet agents at once, at most two subagents on the larger model** (the lead not counted).
|
||||
What sets the limit is how many agents the lead can settle and follow, and their token cost, not the
|
||||
number of issues: an issue may take one agent or several, one after another. When one lands, the next ready
|
||||
issue starts at once; an issue is ready when every issue its `depends-on` links name has landed on the
|
||||
feature branch and the lead has settled its open questions. (Five agents on the larger model at once,
|
||||
with restarts, spent a week's allowance in a night.)
|
||||
- **An issue partly done goes back to `open`** with a note naming the commits that landed and what
|
||||
is left, linked `depends-on` to what it waits for. An issue is never left in `fixing` while
|
||||
nobody works on it. A finished issue's agent is gone, so the lead takes it over in `fixing` (its
|
||||
`by` names the lead) and keeps working it: for an agent that finished without committing, the lead
|
||||
commits, merges the feature head, runs the checks and lands it; for an agent that stopped on its
|
||||
stop rule, the lead settles the question first — then sends the issue again or lands it itself —
|
||||
or takes the question out of the feature as its own issue, saying on the issue which of the two it
|
||||
did. It is resolved, with `fixed-by` naming the feature's MRs, once the feature's delivery is done.
|
||||
- **Two issues in one file:** keep both sides' behaviour; where both added tests or list lines in
|
||||
one place, keep all of them. Never resolve code with a blind `git merge-file --union`: it can
|
||||
interleave two functions' braces. Build and test after every resolution.
|
||||
- **Fetch by name.** In a shared clone a plain `git fetch` may update only `main`. Fetch the
|
||||
feature branch with an explicit refspec before branching from it or comparing against it, or an
|
||||
agent merges a stale copy.
|
||||
- **Never land on a red check.** Run the checks, read the result, then land in a separate step; a
|
||||
command that checks and lands anyway is how a red branch lands. A manifest claiming a new seat or
|
||||
a new manifest word lands only after the controller change that understands it is delivered.
|
||||
- **Review the tree that is pushed.** Before the local review, bring each feature branch up to the
|
||||
current trunk (fetch by name, then merge or rebase), so the reviewed tree is the pushed tree.
|
||||
Where an agent session pushes through the forge tool `gitea_commit` (it puts one commit on a branch
|
||||
through the forge, as step 4's push), that commit is a new one on the forge's current base: the
|
||||
reviewer confirms the forge commit's tree equals the reviewed one before posting its verdict on the
|
||||
pull request.
|
||||
- **Three to five review rounds.** Tell every reviewer which round it is in ("round N of at most 5"): a
|
||||
reviewer that does not know keeps finding the next smaller thing. From round 3 it asks changes only for a
|
||||
finding that makes the change wrong, and lists smaller points as follow-ups that do not block. If it
|
||||
still asks changes at round 5, stop revising and bring the operator the findings with a recommendation:
|
||||
block, or follow as an issue of its own. The same holds for a decision record's review (issue 784).
|
||||
- **Report every ten minutes, and at once when something lands or needs the operator,** short, as a tree or a table: the issues done (of the total), each
|
||||
issue being fixed with its active time (minutes since its agent was sent, from a start time
|
||||
written down then, never guessed), the issues ready next, the ones waiting, and anything that
|
||||
needs the operator, and the allowance used (`anthropic-licence-manager.usage`: the week's and the
|
||||
session's share). Times are local and absolute.
|
||||
- **When this playbook meets a problem,** the lesson is added here, so the next feature avoids it.
|
||||
**One exception: a catalogue change that uses a new manifest word.** The catalogue'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 catalogue's and merge it on the new verdict. Plan such a feature as two steps.
|
||||
|
||||
## The ready note
|
||||
## Phase 4 — Deliver
|
||||
|
||||
The form of what "The lead decides, a fixing agent builds" (above) asks the issue to say: a note on the issue
|
||||
headed exactly "Ready to build". If any line cannot be filled in, the issue is not ready.
|
||||
The merge starts the delivery plan: build, publish, send. The lead follows it to done
|
||||
(`mesh-controller.plans` with `wait` and `until: done`), then 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.
|
||||
|
||||
```
|
||||
Ready to build (<lead>, <time>).
|
||||
Repository: <one repository; an issue that needs another is split, the second depending on the first>.
|
||||
Files: <path:function or path, each>.
|
||||
Decisions it builds with: <quoted, one line each, with where each was decided>.
|
||||
First test: <name and what it asserts; it fails today because …>.
|
||||
Done when: <one sentence>.
|
||||
Do not touch: <files, behaviour, other issues' areas>; landing beside it: <issues>.
|
||||
Stop if: <the assumption the note rests on>.
|
||||
```
|
||||
## Models
|
||||
|
||||
When the reading is large, a read-only agent on the smaller model reads the code and answers the lead's
|
||||
exact questions with file:line; the lead writes the note from its answers. The agent's prompt is then one
|
||||
paragraph: "Fix issue N of feature <name>. Follow playbook 07's agent brief; build exactly what the
|
||||
issue's ready note says." plus the feature's few local facts (below).
|
||||
| Who | Model | Why |
|
||||
|---|---|---|
|
||||
| The lead (phase 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, and the extra cycle in phase 3) | larger | judgement, once per round |
|
||||
| Decision records | larger | judgement |
|
||||
|
||||
## The brief a fixing agent follows
|
||||
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).
|
||||
|
||||
**Name your issue everywhere.** Begin every step, to-do item and message with the issue: "issue 805:
|
||||
landing in mesh-catalog", never "landing". The operator follows several agents at once.
|
||||
## Following and reporting
|
||||
|
||||
**Stop rule, the most important** ("The lead decides, a fixing agent builds", above): a decision the note
|
||||
does not give includes a new field, a new rule or a choice between two ways. Stop before writing code and
|
||||
report what and where (file:line). A stop costs minutes; building the wrong thing costs a review and a
|
||||
rebuild.
|
||||
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.
|
||||
|
||||
**Read the issue first,** its ready note first of all; read other notes, a design or a decision record only
|
||||
where the note points to them.
|
||||
| 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 the build queue (`mesh-controller.queue`) and the check's log |
|
||||
| a merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery |
|
||||
| a delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` |
|
||||
|
||||
**Hard rules.** Reach the mesh only through the mesh MCP server; never ssh, never run `nox`. Never push,
|
||||
never open, merge or close a pull request: the lead does. Never write to a store's database by hand; a schema change
|
||||
is a numbered migration and the consolidated schema. Go only, unless the note says otherwise. Never move another issue; never edit files
|
||||
the mesh manages on a machine. Use the glossary's words; the unit of work is an issue.
|
||||
**Every ten minutes, and at once when something lands, stops or needs the operator,** the lead reports in a
|
||||
short table: the phase and its time used against its bound, each issue with its state, every wait past its
|
||||
bound and what is being done about it, and the allowance used (`anthropic-licence-manager.usage`: the week's
|
||||
and the session's). Times are local and absolute.
|
||||
|
||||
**Steps.**
|
||||
1. Move the issue to `fixing` with `by` `<feature>-<issue>@<node>`. If it is refused, stop and report.
|
||||
2. Make your own worktree on a local branch `<feature>-<issue>` from the feature branch's head.
|
||||
3. Write the note's first test and see it fail. Make the change and see it pass; keep every other test
|
||||
passing.
|
||||
4. Commit: concise, imperative, about why, naming the issue.
|
||||
5. Merge the feature branch's head into yours. In a conflict keep both sides' behaviour and every test,
|
||||
then build again.
|
||||
6. Run the repository's checks in your worktree (`gofmt -l`, `go vet ./...`, `go test ./...`,
|
||||
`merge-check.sh`; where a test needs the store, a throwaway database server under the feature's
|
||||
scratchpad, stopped when done). Read the result. If anything is red, do not land.
|
||||
After every merge of the feature head, check again before landing.
|
||||
7. In a separate step, land by fast-forward under the feature worktree's lock. If it is not a
|
||||
fast-forward, go back to step 5.
|
||||
8. Note the issue: the commits and how its done-when is proven. Leave it in `fixing`.
|
||||
## The context of the lead's own session
|
||||
|
||||
**Fifteen minutes.** An agent still working after fifteen minutes tells the lead, in a few lines and
|
||||
without stopping, what has landed, what is left and whether part of it could be split off; the lead decides
|
||||
whether it goes on or is split.
|
||||
|
||||
**Report back,** in under 150 words: commits per repository, the tests added and that they failed first, the check
|
||||
results, and anything you stopped on or found that a later issue must know.
|
||||
|
||||
**The feature's local facts** (the lead gives them in the prompt or a short local file): the scratchpad and
|
||||
its worktrees, the feature branch's name, the lock files, and anything particular to the feature's
|
||||
repositories (a check that needs a gate built from another worktree, a test that is red at certain times).
|
||||
|
||||
**A shared machine's temporary directory can be filled by other sessions.** A test then fails with
|
||||
"disk quota exceeded", which is the machine, not the code: mesh-controller's `internal/builder` test
|
||||
`TestAGoProgramsBuildSourceIsItsImportClosure` fails when its temporary directory lies inside a git
|
||||
checkout such as the home. The local facts name a temporary directory for tests outside the home, and
|
||||
every check runs with `TMPDIR` set to it.
|
||||
|
||||
## What this is not
|
||||
|
||||
- **Not a licence to batch unbounded work.** A feature is a *bounded* unit; if it sprawls for
|
||||
days, end-of-feature bloat merely replaces per-increment bloat. Split it into features, each
|
||||
its own branch and MR.
|
||||
- **Not a second trunk.** Every repo branches off `main`. There is no longer an `initialization`
|
||||
trunk.
|
||||
At the end of each phase, 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
|
||||
next action; then the prompt the operator pastes. The context files make the feature resumable after a clear.
|
||||
|
||||
## How it is checked
|
||||
|
||||
The end state is visible, and its absence is the smell:
|
||||
- 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.
|
||||
- A context file exists per touched repository under `.work/<slug>/` while the feature runs.
|
||||
- After a feature's delivery, `git branch -r | grep feat/<slug>` and `git worktree list` return nothing for it.
|
||||
- More than one open pull request in a repository that share no feature name, or a feature step whose issues
|
||||
stay in `fixing` for more than a working day, is the smell: stop and bring it to the operator.
|
||||
- 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.
|
||||
|
||||
- After a feature merges, `git branch -r | grep feat/<slug>` and `git worktree list` return
|
||||
nothing for it. A surviving branch or worktree means step 6 was skipped.
|
||||
- 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.
|
||||
- A feature's issues show their commits on the feature branch (`git log --grep 'issue <n>'`), and no
|
||||
pull request into the feature branch exists. A pull request per issue, or an agent waiting on a
|
||||
merge check mid-feature, is the second failure above.
|
||||
- More than one open MR in a repo that share no feature name, or a stack of MRs none of which is
|
||||
merged, is the failure this playbook exists to prevent — stop and consolidate before opening
|
||||
more.
|
||||
When this playbook meets a problem, the lesson is added here, so the next feature avoids it.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Playbook 08 — Small fixes
|
||||
|
||||
**Trigger.** One issue in one repository, small enough to build in about an hour: a bug with a known cause,
|
||||
a missing check, a wording, a playbook or design edit. Anything larger, or anything that needs a change in a
|
||||
second repository first, is a feature and follows [playbook 07](07-feature-branches.md).
|
||||
|
||||
**Who runs it.** Anyone who writes code, engineers and agents alike.
|
||||
|
||||
## The aim
|
||||
|
||||
A small fix spends its time on the fix, and runs the long part once: **one review, one push, one check run,
|
||||
one delivery**. Everything before the push is local and fast.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Read the issue and the code it names** (the session's own model, or one read-only agent on the smaller
|
||||
model answering exact questions with file:line). If a design question is open, it is settled before any
|
||||
code is written: on the issue, through the knowledge base, or by the operator. A fix that turns out to
|
||||
need a decision or a second repository stops here and becomes a feature.
|
||||
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`. Write the
|
||||
test that fails today first; make the change; keep `gofmt`, `go vet` and the repository's unit tests green.
|
||||
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
|
||||
model; at most 2 rounds). The reviewer's findings go back to the same agent that wrote the fix, continued by
|
||||
its id, so the fix keeps its context. A playbook or design edit of a few lines may skip the reviewer: the
|
||||
operator's word on the pull request is its review.
|
||||
5. **Push once and open the pull request.** The forge's merge checks run the integration tests. A failed check
|
||||
goes back to the same agent with the failure, and the reviewer reads only the change it makes.
|
||||
6. **Mark it ready** (`mesh/ready` and `ready at <full sha>`) once the operator's word is given; mesh-delivery
|
||||
merges it when its checks pass.
|
||||
7. **Follow its delivery plan to done** (`mesh-controller.plans` with `wait` and `until: done`), prove the fix on
|
||||
the mesh (the symptom gone, measured), and resolve the issue with `located-in` and `fixed-by` the same hour.
|
||||
|
||||
## Bounds
|
||||
|
||||
| Waiting on | Bound | Past the bound |
|
||||
|---|---|---|
|
||||
| building the fix | 1 hour | it is a feature: stop and plan it under playbook 07 |
|
||||
| the review | 15 minutes | ask the reviewer where it stands |
|
||||
| the merge check | 15 minutes | read `mesh-controller.queue` and the check's log |
|
||||
| the merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery |
|
||||
| the delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` |
|
||||
|
||||
A wait past its bound is said to the operator at once, with what is being done about it.
|
||||
|
||||
## Models
|
||||
|
||||
The fixing agent runs on the smaller model; the reviewer on the larger. A session fixing alone does the
|
||||
reading itself and uses one subagent only for the review.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- A small fix has one pull request with one or few commits naming its issue, opened after its review: a pull
|
||||
request with many heads is a fix reviewed after its push.
|
||||
- Its issue moves to `resolved` within the hour its delivery plan ends.
|
||||
Reference in New Issue
Block a user