From 464833d0ef3f8a9cd9a8ad07c983187557194f18 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 15 Oct 2026 19:26:02 +0200 Subject: [PATCH] Rewrite playbook 07 as five bounded phases with reused context, and add playbook 08 for small fixes 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. --- 00-META/process/00-overview.md | 3 +- 00-META/process/07-feature-branches.md | 353 ++++++++++--------------- 00-META/process/08-small-fixes.md | 57 ++++ 3 files changed, 201 insertions(+), 212 deletions(-) create mode 100644 00-META/process/08-small-fixes.md diff --git a/00-META/process/00-overview.md b/00-META/process/00-overview.md index c0a4f145..379725e2 100644 --- a/00-META/process/00-overview.md +++ b/00-META/process/00-overview.md @@ -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 diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 68c29501..beb75993 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -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/`. 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//`, branched - off `main`: - ``` - git worktree add .work// -b feat/ 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//` directory holding only the touched repos fails a - bed at once with `no manifest for mesh-tools at …/.work//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//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/`, the same branch name in every repository it touches. The + branch is never protected. +2. **Make the worktrees:** one per touched repository under `.work//`, branched off `main` + (`git worktree add .work// -b feat/ 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//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//.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 .lock git -C merge --ff-only `), 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/` branch and no `.work/` - 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 `) 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 .lock git -C merge - --ff-only `). 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/` branch and no `.work/` worktree +survive. -``` -Ready to build (,