The operator answered D-12, D-13 and D-19 at the terminal, and ruled on 2026-11-11 that a question touching nothing the operator sees, no permission and no data kept is answered as a design line by the design writer and read by the reviewers by architectural domain. The new part file G-10 carries those answers and the internal-form ones (§456 to §479), the earlier lines point to them, and playbooks 02, 07 and 08 and the glossary say who answers a design question now. The questions that touch who may call or what the operator sees are left for the operator. Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
187 lines
18 KiB
Markdown
187 lines
18 KiB
Markdown
# 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). A feature is the
|
|
larger kind: it touches several modules and has a research effort or a design before it. **Needing a decision
|
|
does not make a fix a feature**: the decision is settled first (step 1) and the fix stays small (the operator,
|
|
2026-10-16).
|
|
|
|
**Related issues in one fix.** A small fix may cover two or three related issues when they are in the same
|
|
repository, mostly in the same module, and together still fit in about an hour: they touch the same files, or
|
|
one would be wrong or unsafe without the other (switching a clipboard's history on before its history tool stops
|
|
handing out what was copied). Each issue is named in the commit and the pull request and moved to `fixing`,
|
|
and each is resolved on its own once the fix is delivered. More issues, a second repository, or more than an
|
|
hour is a feature.
|
|
|
|
**Who runs it.** Anyone who writes code, engineers and agents alike.
|
|
|
|
**A fix found during a milestone rides in that milestone's group** (the operator, 2026-10-21, after a day with ten
|
|
mesh-sdk merges, each rebuilding about forty dependent modules, and eight mesh-controller merges, each sending a
|
|
delivery to every node). Playbook [07](07-feature-branches.md) makes a milestone one piece of functionality
|
|
released once as one delivery group (ADR 0482). A small fix in a repository the running milestone touches, mesh-sdk
|
|
and mesh-controller above all, is built as below but on the milestone's branch, so its pull request joins the group
|
|
and merges with it. The exception is a fault that is broken for the operator now (something they see failing at
|
|
this moment): it goes alone as a small fix, and the lead's report says why.
|
|
|
|
## 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** (ADR 0548; the operator, 2026-10-26: "every release should only run 1 check or 1 try"; "we don't have more
|
|
processing power"). Everything before the push is local and fast, and no try is run.
|
|
|
|
## 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). **Read what exists in the fix's area today, briefly, before any
|
|
code** (playbook [07](07-feature-branches.md) step 0 item 3a, at a small fix's size): what the code and the live mesh
|
|
(through the mesh MCP server's tools) do there now, and for each value, label, file or job the fix changes or removes,
|
|
every reader that relies on it, found by a search across the repositories (written down as run) and not from memory,
|
|
with what happens to each after the fix. It is a few lines in the issue's note, under `What exists today`, and the
|
|
review runs the search again; a reader it finds that the note omits makes the fix wrong. **A fix builds what a
|
|
design says, and decides nothing** (the operator, 2026-11-10; playbook [07](07-feature-branches.md), step 0): its
|
|
input is the issue and the design that covers the area (the design whose `code:` names the repository, or the
|
|
issue's design link), read in the parts the fix touches and in the design section that places code, *Where a
|
|
seat's code goes*. The note names, for everything the fix adds or changes (an exported type, field, constant,
|
|
package or module, a state, a verb, an event, a bound, a caller), the design line that gives it. A fix that only
|
|
makes the code do what its issue and its design already say needs nothing more. Anything no design line gives is
|
|
a **design question**: the session asks the operator, one question with its recommendation, and the answer is
|
|
written into the design (playbook [02](02-graduation.md), *Answering a design question*) before any code builds
|
|
it; neither the session nor the lead answers it. A question of internal form only (playbook
|
|
[07](07-feature-branches.md), step 0, *Who answers a design question*) is answered instead by `hq-design-writer`
|
|
as a design line, read by the four reviewers by architectural domain in one round, and told to the operator in
|
|
one line. A handover to the developer quotes the design lines and never
|
|
decides a placement itself (2026-11-04: a class placed in mesh-sdk by a lead's handover, against that section,
|
|
passed review and its check). A fix that turns out to need a second repository, or more than about an hour,
|
|
stops here and becomes a feature; one that needs a design question answered stays a small fix. **The session's own model (the larger) then writes the issue's acceptance
|
|
criteria** as playbook [07](07-feature-branches.md) step 0 item 5 says: each one sentence, given, when, then,
|
|
naming the level of the test that proves it and the design line or issue done-when it comes from, as an
|
|
`issue-tracker.note` headed `Acceptance criteria`. A
|
|
playbook or design edit has none: its check is `go test ./...` at hq's root, which runs the four checks (ADR 0527).
|
|
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), step 0, item 2). Write the
|
|
test that fails today first, on an assertion about what the code does: a test that fails only because it
|
|
does not compile has not failed first (playbook [07](07-feature-branches.md) step 1); 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).
|
|
Check that it compiles with `go vet`, never `go build` in a module's folder: with one main package it writes the
|
|
program beside `go.mod`, and `git add -A` takes it (issue 1577: two 5-10 MB programs committed on 2026-10-21,
|
|
caught only by the review); read `git show --stat` before pushing.
|
|
The tests are written from the acceptance criteria, at least one per criterion at its level, each citing the
|
|
criterion it proves by its label (`<issue>/AC<n>`, playbook 07 step 0 item 5). Commit, naming the issue. For a playbook or design edit, run the repository's own checks (in hq,
|
|
`go test ./...` at the root). The integration tests are compiled whole (`go vet -tags integration ./...`), and once
|
|
per head reported those of the packages the fix touches and of their importers in the module run against an
|
|
embedded bus, or the tests of them that exercise the fix by name where the importers are many, named in the report;
|
|
never a whole module's or level's run (playbook 07 step 1). Nothing is pushed, no pull request is opened and no try (`mesh-controller.try`, `mesh-delivery-checker.try`, `mesh-delivery-checker.checker_try`) is called, unless the operator asks for
|
|
one. A single integration test may be run locally against an embedded bus when it is the fastest way to find a cause;
|
|
before the push, the integration tests that exercise the change have run that way at the reviewed head
|
|
(playbook 07 step 3), and the pull request names them and their results. A test fixture writes state in the form its real
|
|
writer writes it; the review asks it.
|
|
4. **One review of the local commit** (a reviewer that did not write it, larger
|
|
model; at most 3 rounds, as playbook 07; from round 2 only what is wrong; it judges each change against the design line its note names, as playbook 07 step 2 item 2a, and code no
|
|
design line gives is a finding; it reads each acceptance criterion
|
|
against its test, as playbook 07 step 2 item 6; it runs the `What exists today` search again, as playbook 07 step 2 item 6b; a finding outside the issue's done-when and its acceptance
|
|
criteria is opened as an issue of its own, never asked as a change; it judges the integration tests by reading them against the code, as playbook 07 step 2 item 4 says; it answers playbook 07 step 2 item 10's two questions, on state and seams and on mesh-agnostic repositories, in its report). 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 Approve of its merge is its review, and the review record says so.
|
|
5. **Push the reviewed head once and open the pull request, only after the review approves.** The trunk is what runs and nothing holds merged work back
|
|
(ADR 0401), so a fix waits for no other change's delivery. No pull request, draft or not, exists before the review
|
|
approves the head, and no fix round is pushed to an open pull request: every push to an open pull request asks a new
|
|
check. The checker's merge check runs the unit and the integration level once, as the gate (playbook [07](07-feature-branches.md) step 3); the pushed head is read from the forge first, as playbook 07 step 3 item 1 says. A merge whose check has no verdict
|
|
(the checker drops a check still running at the merge) is reported to the operator as merged unchecked, never as
|
|
passed (playbook 07 step 3 item 2).
|
|
A failed check is read from its whole log (never re-asked to see if it passes), then the repository's whole integration level
|
|
is run locally (`go test -tags integration -count=1 ./...` in each module) so every failure shows at once, where a verdict
|
|
names only the first (issue 1921); the failures go back to the same agent, fixed in one change, the reviewer reads only the change
|
|
it makes, and the head is pushed once more.
|
|
**A temporary mode that merges by hand** (the lead merges because the normal Approve and merge path is not
|
|
running): the one check still runs, 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 (research 071; playbook
|
|
[07](07-feature-branches.md) step 3).
|
|
6. **The pull request's description carries the review record** (`Reviewed-by: <who@node> at <full sha>`,
|
|
playbook [07](07-feature-branches.md) step 3) and the session that pushed it (`Pushed-by: <who@node>`, ADR 0505 §5), and mesh-delivery asks the operator's Approve as soon as its
|
|
checks pass and merges the approved head (ADR 0421); nobody marks, labels, comments or rechecks. A fix to a module that changes how it runs carries an
|
|
integration test starting the module whole against the real bus and store, run by the checker's one merge check
|
|
(ADR 0391 §1, §6); unit tests alone are not that proof, and the lab is not used. The operator's word is waited for only when the fix changes what the operator sees, removes data,
|
|
or needs the operator's terminal.
|
|
**A fix that depends on another pull request outside its delivery group opens only once that one is delivered**, not merely merged (members of one group open together, as playbook 07 step 3 item 1 says) (a note
|
|
in the description does not hold it back: the Approve merges whatever is asked; 2026-10-25, machines lost modules
|
|
when a second change merged first). **A reviewed follow-up to a fix still waiting for the Approve is folded into
|
|
that pull request** (head moved): one Approve, one delivery. Both are checked as playbook
|
|
[07](07-feature-branches.md) step 3 says.
|
|
**At the second instance of a fault kind found in a review, the developer searches for every instance** and names
|
|
each in the report (playbook [07](07-feature-branches.md) step 2, item 9).
|
|
7. **Follow its delivery to done**: a watcher waits on the status view's events (`mesh-delivery-view.moving`,
|
|
`.settled`, `.stuck` and `.delivered`) and reads the view's `assigner_wants` and `node_haves` after each wake, as
|
|
playbook [07](07-feature-branches.md) step 4 says; the delivery is done when the view says `delivered` for its
|
|
source revision, and the haves per node and the indexer's record of the module name the build (playbook 07 step 4;
|
|
"on the machines" alone is not "delivered"). Then prove the fix on the mesh (the symptom gone, measured), and resolve the issue with
|
|
`located-in` and `fixed-by` the same hour.
|
|
|
|
A fix that stops before its delivery moves its issue back to `open` with a note saying how far it got
|
|
(branch, last commit, what is left), as playbook [07](07-feature-branches.md) says.
|
|
|
|
**An issue opened along the way is fixed too** (the operator, 2026-10-21). A fix's review, check or delivery that
|
|
opens an issue (a remark outside the done-when, a fault met live) leaves it to the same session to fix: right after
|
|
this fix's delivery, as a small fix of its own, or folded into the next one in the same repository. It waits only
|
|
when another running milestone owns it, or it needs a decision or the operator first; the report then says on what.
|
|
|
|
**A second fault found by the delivery.** When a fix's delivery shows a second fault that keeps the issue's
|
|
done-when from holding, and that fault is in the same files, it is taken into the same issue as a second pull
|
|
request with a review round of its own. A fault in other code is opened as an issue of its own, and the first
|
|
issue waits for it (issue 937: mesh-catalog #335 was taken in; issue 943 was opened).
|
|
|
|
**A fix that moves a file to a new filler compares the values first.** When a fix makes a module's file filled a
|
|
new way for the first time (the provisioner client in place of the controller, a provider's entry in place of a
|
|
composed value), the fix lists every value the old way put into that file on each machine it reaches and shows,
|
|
in its review, that the new way gives the same values, or says which differ and why. A difference nobody looked
|
|
at is an outage: on 2026-10-16 the forge and the identity provider on the control node were down for 17 minutes
|
|
because postgres's consumers were served the port inside its container instead of the port it is published on
|
|
(issue 957). The comparison is read from the machines (the file as it is today) before the merge, not from the
|
|
code.
|
|
|
|
## 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 | 30 minutes (it waits behind the asks before it for a build node's free slot, ADR 0525) | read `mesh-delivery.show`, the check's log and the check stream's backlog in the delivery view |
|
|
| 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 |
|
|
| the merge after the Approve | 5 minutes | read `mesh-delivery.show` for the delivery |
|
|
| the 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 |
|
|
|
|
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 pull request was opened.
|
|
- A pull request merged by hand in a temporary mode names the verdict of its one check in its description
|
|
on the forge (`gitea.gitea_get_pull_request`); one without is the step skipped.
|
|
- One fix, one check (ADR 0548): a pull request that existed before its review approved the head, or a head whose check was
|
|
asked more than once with no new reviewed head, is steps 4 and 5 skipped; so is a `mesh-controller.try` or `mesh-delivery-checker.try` the operator did not ask for.
|
|
- Its issue moves to `resolved` within the hour the view says its source revision `delivered`.
|
|
- A pull request with no review record at its head (the Approve's ask says so first), a fix to a module's
|
|
running pushed with no integration test of the module whole, or a review report
|
|
asking a change outside the issue's done-when and acceptance criteria, is the failure of steps 4 to 6.
|
|
- A fixed code issue's note names the design line for each thing the fix adds, and its commit names the same lines
|
|
(`Builds:`); a fix adding what no design line gives, with no answered design question behind it, is step 1 skipped.
|
|
- A fixed code issue shows a note with `What exists today` (`issue-tracker.get`) older than its first commit, its
|
|
search written as run; one without is step 1 skipped, and a reader of a changed value met only after the delivery
|
|
is that note left short.
|
|
- A fixed code issue shows a note headed `Acceptance criteria` (`issue-tracker.get`) older than its first
|
|
commit, and each criterion's label is cited by a test in the pushed tree
|
|
(`git grep -n '<issue>/AC<n>'`); one without is step 1 skipped.
|
|
- An issue in `fixing` with nobody on it shows in `issue-tracker.list` with `flag: abandoned`; a stopped fix
|
|
moves it back to `open` with its note.
|
|
- A fix found during a milestone is named in the lead's report with the group it rides in, or with the reason it
|
|
went alone. `mesh-delivery.deliveries` shows the milestone's members in one group, merged as one source revision
|
|
per milestone; a merge of mesh-sdk or mesh-controller outside the group, with no reported reason, is this rule skipped.
|
|
- The repository's own clone says `main` (`git -C <clone> branch --show-current`); another branch there is a
|
|
fix built outside a worktree (issue 1010).
|