Merge remote-tracking branch 'origin/main' into feat/1126-nodes-compose
mesh/delivery merged: source.main moved to novox/hq@132aae843383
mesh/delivery-group group feat/1126-nodes-compose merged: every member is merged
mesh/check pass 28d84f31bfcb on 132aae843383 | unit 39 run, 0 kept, 1 skipped | integration 39 run, 0 kept, 1 skipped | composition passed in 2ms
mesh/delivery merged: source.main moved to novox/hq@132aae843383
mesh/delivery-group group feat/1126-nodes-compose merged: every member is merged
mesh/check pass 28d84f31bfcb on 132aae843383 | unit 39 run, 0 kept, 1 skipped | integration 39 run, 0 kept, 1 skipped | composition passed in 2ms
This commit is contained in:
@@ -60,7 +60,7 @@ A drawn overview of them, the cycle, a feature's steps, the review loop and an i
|
||||
| [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) | 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 try, one review, one delivery |
|
||||
| [08](08-small-fixes.md) | Small fixes | One issue in one repository, about an hour of work: one review, one check, one delivery |
|
||||
| [09](09-cleanup.md) | Cleanup | Merged branches, stale pull requests, finished worktrees and folders: read first, delete only what the operator approves, report the rest |
|
||||
| [10](10-visual-design.md) | Visual design | A page the operator will use is about to be designed or rebuilt: mockups with fixed data, the operator picks, the pick is the reference |
|
||||
|
||||
|
||||
@@ -35,25 +35,30 @@ A small fix (one repository, one issue, about an hour of work) follows
|
||||
proved nothing, and dropping the field it was for passed every test. A reader of the changed record that the
|
||||
survey never listed ended a module's conditions at each sync. The reviewer judged the bus tests by reasoning, and
|
||||
wrongly, because they ran only after the review.
|
||||
- **A check asked again and again.** Build capacity is the mesh's scarcest resource ("we don't have more
|
||||
processing power", the operator, 2026-10-26), and a release that ran a try before its review, a try after it
|
||||
and a check per fix round on an open pull request spent it several times over: every push to an open pull
|
||||
request asks a new check, of every member for a group. A release runs one check ("every release should only
|
||||
run 1 check or 1 try", the operator, 2026-10-26; ADR 0548).
|
||||
- **A module proven only after it reached the machines.** The mail modules were delivered with unit tests
|
||||
only, then failed live three times (issues 859, 865, 868) and took five more hours of fixes.
|
||||
|
||||
## The shape
|
||||
|
||||
One feature is **one branch name**, **one worktree per repository**, **one pull request per repository**,
|
||||
opened **once**, after the review. It runs in five steps, and its time is bounded. A milestone has no phases
|
||||
opened **once**, after the review, and **one check** (ADR 0548). 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:
|
||||
|
||||
| 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, the whole unit suite before every commit; then each branch is pushed and tried | the milestone's issues, 30 minutes each, and one try |
|
||||
| 2. Review | one reviewer reads all of it with the tries' results; reports go both ways; at most 3 rounds | 15 minutes |
|
||||
| 3. Check | push the reviewed heads; a head the review changed is tried again; then the pull requests are opened and the forge's merge checks run the integration tests again; no further review | at most one more try and one check run |
|
||||
| 1. Develop | one fixing agent per repository builds every issue locally, the whole unit suite before every commit, the integration tests compiled; nothing is pushed | the milestone's issues, 30 minutes each |
|
||||
| 2. Review | one reviewer reads all of it, the local commits, judging the integration tests by reading them against the code; reports go both ways; at most 3 rounds | 15 minutes |
|
||||
| 3. Check | push the reviewed heads once and open the pull requests together; the checker's one check runs the integration tests; no further review unless the check fails | one check run |
|
||||
| 4. Deliver | merge; the source revision moves, each module is built once and wanted on its nodes, its canary first | until the view says the source revision `delivered` |
|
||||
|
||||
**One milestone is one release** (the operator, 2026-10-17). A milestone is developed whole, tried before its review, reviewed once,
|
||||
opened once and delivered once. It is never cut into steps for its size or for time: every cut adds a review, a
|
||||
**One milestone is one release** (the operator, 2026-10-17). A milestone is developed whole, reviewed once,
|
||||
pushed once, checked once and delivered once. It is never cut into steps for its size or for time: every cut adds a review, a
|
||||
merge check, an Approve and a delivery of waiting, so the fewest cuts is the fastest. Nor is it cut for an
|
||||
order between its parts (the operator, 2026-10-22: "a milestone is a milestone, we shouldn't cut it"): which module
|
||||
reaches the machines before which is the assigner's rules' (a build and a composition before the want, a provider
|
||||
@@ -100,7 +105,10 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
clone stays on `main`** (the operator, 2026-10-17): no work is done in it and no branch is checked out
|
||||
there, so a session that opens in it reads what holds now; fetch and fast-forward it before reading.
|
||||
3. **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
|
||||
the knowledge base, or by asking the operator. **Read what is decided before designing** (`knowledge-base.ask`):
|
||||
a question about delivery, checks or builds is most likely answered in design 47 and its decisions already (the operator,
|
||||
2026-10-26: "that is simply our delivery plan and milestones, we've already researched it"); propose new research
|
||||
only for what no record decides. 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:
|
||||
@@ -112,7 +120,7 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
- 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`), and the unit tests to run (never a database server: tests that need one are
|
||||
integration tests, which the try (`mesh-controller.try`) and the checker's merge check run).
|
||||
integration tests, which the pull request's one check runs).
|
||||
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. **Write the findings into the issues** (the operator, 2026-10-17: the better the content of the issues, the
|
||||
@@ -165,13 +173,12 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
(one line for every key-value bucket key and stream the work creates or starts writing; "none created" if none)
|
||||
Trying the switch-over on one node first (b):
|
||||
- <which node goes first, and what is read there before the rest>
|
||||
- or: the operator chose no try on one node first, on <date>; what that risks: <one sentence>
|
||||
Integration level before the pull requests (c):
|
||||
- <the tries that run it, per repository; a group try if issue 1921 has delivered one>
|
||||
- what no try covers: <the parts of the group that meet only in the merge check>
|
||||
- or: the operator chose no first trial on one node, on <date>; what that risks: <one sentence>
|
||||
Integration level (c):
|
||||
- <the one check that runs it: the group's pull requests, one check each, none before the review>
|
||||
- what the check does not cover: <the parts of the group that meet only live>
|
||||
```
|
||||
A key or stream with no one who deletes it and no time to live is a leak and is settled before work starts. Until
|
||||
issue 1921 gives a group try, answer (c) with the single-repository tries and say so.
|
||||
A key or stream with no one who deletes it and no time to live is a leak and is settled before work starts.
|
||||
9. **Move the issues to `fixing`**, `by` naming the feature's agent for that repository.
|
||||
|
||||
## Step 1 — Develop (one fixing agent per repository, smaller model)
|
||||
@@ -189,27 +196,27 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
its helper alone, and dropping the field from the request passed every test); `gofmt`, `go vet` and the whole unit suite stay green. **The tests are written from the issue's
|
||||
acceptance criteria**: one test or more per criterion at the level it names, each test's comment citing
|
||||
the criterion it proves by its label (`// 1118/AC2`), and no criterion left without its test; an integration criterion is a test
|
||||
that compiles and waits for the try at this step's end. The integration tests (those that start a store, a bus
|
||||
or a process) are run first by that try, and again by the checker's merge check.
|
||||
- **No pull request is opened in this step. When every issue is committed, the lead brings each feature branch up
|
||||
to the current trunk (fetch by name, then merge), pushes it and tries it** (`mesh-controller.try`, as step 3 item 1 says), so the review reads the integration tests' real
|
||||
results and judges none by reasoning (2026-10-19: a reviewer reasoned that a warning goes out at once, the
|
||||
router holds it 30 s, and the try after the review found it). A failed try goes back to the same fixing agent
|
||||
with its whole log, read as step 3 item 3 says, before the review starts. Never land on a red check: run the
|
||||
checks, read the result, then land in a separate step.
|
||||
that compiles and is run by the pull request's one check. The integration tests (those that start a store, a bus
|
||||
or a process) are compiled with `go vet -tags integration ./...` while developing and run by that check, nowhere
|
||||
else.
|
||||
- **Nothing is pushed and no pull request is opened in this step, and there is no try** (ADR 0548; the operator,
|
||||
2026-10-26: "every release should only run 1 check or 1 try"). When every issue is committed, the lead brings each
|
||||
feature branch up to the current trunk (fetch by name, then merge) and the review reads the local commits. Never call
|
||||
`mesh-controller.try` or `mesh-delivery-checker.checker_try`; one is run only when the operator asks for it. A reviewer
|
||||
or a session that wants the code on the forge may push a branch that has no pull request: it runs nothing. Never land
|
||||
on a red check: read the result, then land in a separate step.
|
||||
- **The fixing agent's brief** (the lead gives it with the 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;
|
||||
never push, open, merge or close a pull request; never write to a store's database by hand, a schema change
|
||||
never push, open, merge or close a pull request; never call a try; never write to a store's database by hand, a schema change
|
||||
is a numbered migration and the consolidated schema; Go only unless the context file says otherwise; never
|
||||
move another issue; **leave the integration tests to the try while developing** (no `go test -tags integration`,
|
||||
no store or bus started by hand): compile them with `go vet -tags integration ./...` and leave the running to
|
||||
the lead's try at the end of this step, where `mesh-controller.try` runs them on the pushed branch. On 2026-10-17 three fixing agents ran them anyway, one for minutes on end, because the
|
||||
brief only said they wait for the check (the operator). After a failed try or check it
|
||||
move another issue; **leave the integration tests to the check** (no store or bus started by hand): compile them
|
||||
with `go vet -tags integration ./...`. A single integration test may be run locally against an embedded bus when
|
||||
it is the fastest way to find a cause, said in the review report and the pull request. After a failed check it
|
||||
usually pays to run that repository's whole integration level locally (`go test -tags integration -count=1 ./...` in each
|
||||
module), by the lead or by the fixing agent on the lead's word, before another try: a verdict names only the first failed
|
||||
test (issue 1921), and on 2026-10-23 R4g's faults surfaced one per try until a local run listed them all in a minute (a
|
||||
module), by the lead or by the fixing agent on the lead's word, before the one more push: a verdict names only the first failed
|
||||
test (issue 1921), and on 2026-10-23 R4g's faults surfaced one per run until a local run listed them all in a minute (a
|
||||
guideline, the operator). Report back in under 150 words: commits, tests added and that they failed first, the
|
||||
check results, anything you stopped on.
|
||||
local results, anything you stopped on.
|
||||
- **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
|
||||
@@ -222,11 +229,11 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
|
||||
## Step 2 — Review (one reviewer, larger model; at most 3 rounds, about 15 minutes)
|
||||
|
||||
1. **The reviewed tree is the tree that was tried**: every feature branch was brought up to the current trunk
|
||||
before its push and try (step 1). A try and a merge check each run on the merge with the trunk as it is then, so a
|
||||
1. **The reviewed tree is the tree that is pushed**: every feature branch was brought up to the current trunk
|
||||
before the review (step 1). The check runs on the merge with the trunk as it is then, so a
|
||||
trunk that moves later is met by the forge's merge check, not by another merge here. Every verdict names the
|
||||
trunk it merged onto ("pass <head> on <trunk>"), and the lead reads that trunk against the repository's main
|
||||
at once: a trunk behind main means the source revision (source.main) lags, and every check and try in that
|
||||
at once: a trunk behind main means the source revision (source.main) lags, and every check in that
|
||||
repository is judged on it until it moves, so the operator's Approve will merge nothing. Say it then, not at the
|
||||
merge (issue 1726: on 2026-10-24 the gate dropped two merges it heard before it held its seat, and a
|
||||
reviewed, approved pull request in each of the two repositories was refused at its Approve).
|
||||
@@ -238,7 +245,7 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
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. **Every new integration test is read against the code it drives and against its try.** Fixing agents only compile it, and its one run before the review is the try (step 1), which shows whether it passed but not whether it proves what it says. The reviewer traces each step of each new integration test through the code (fixtures against the manifest rules, what the store keeps and reads back, who holds a seat), and says which steps it could not trace. On 2026-10-17 a new test failed on its first two runs, on a fixture and then on a fault of the change; reading it against the code after the first failure found another fault, which would have failed a run too. The reviewer also checks that each new integration test enters through the same path the live trigger takes, not through a state it writes by hand: on 2026-10-17 milestone 4's test saved its delivery plan directly, so it skipped the cut from a batch that every live plan takes, and it passed while the backup step never ran (issue 1086).
|
||||
4. **Every new integration test is read against the code it drives.** Fixing agents only compile it, and no run precedes the review (step 1), so the reviewer judges it by reading; the check that follows shows whether it passed but not whether it proves what it says. The reviewer traces each step of each new integration test through the code (fixtures against the manifest rules, what the store keeps and reads back, who holds a seat), and says which steps it could not trace. On 2026-10-17 a new test failed on its first two runs, on a fixture and then on a fault of the change; reading it against the code after the first failure found another fault, which would have failed a run too. A review that finds a fault only by reading is the cheaper run. The reviewer also checks that each new integration test enters through the same path the live trigger takes, not through a state it writes by hand: on 2026-10-17 milestone 4's test saved its delivery plan directly, so it skipped the cut from a batch that every live plan takes, and it passed while the backup step never ran (issue 1086).
|
||||
5. **The reviewer reads the answers and the new commits**, and approves or reports again (step 7 says what a round
|
||||
may ask). After round 3 the lead stops and brings the operator what is left, with a recommendation.
|
||||
6. **The reviewer reads every acceptance criterion against its test**: each criterion has a test at its level
|
||||
@@ -255,8 +262,7 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
6a. **The reviewer reads the milestone file's three answers** (step 0, item 8) against the change: it lists every bucket
|
||||
key and stream the diff creates or writes (search the diff for the bucket and stream names) and finds each in the
|
||||
lifetime answer with a deleter and event, or a time to live; it reads the switch-over answer and checks it was done as
|
||||
written or that the operator's choice is recorded; it reads the integration-level answer against the tries named
|
||||
in the pull request. A missing answer, or a key or stream the diff creates that the answer omits, is a change asked.
|
||||
written or that the operator's choice is recorded; it reads the integration-level answer against the check the pull requests will ask. A missing answer, or a key or stream the diff creates that the answer omits, is a change asked.
|
||||
7. **A finding outside the issues' done-when and their acceptance criteria is never a change asked, in any round.** More hardening, a
|
||||
further case, a nicer form: the reviewer opens it with `issue-tracker.open` and names the number in its
|
||||
report, and the round does not wait for it. What a round asks is only what makes the change wrong against
|
||||
@@ -278,23 +284,24 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
|
||||
## Step 3 — Check (no review)
|
||||
|
||||
1. **Push the reviewed heads, try again a head the review changed, then open one pull request per repository,
|
||||
together.** **The integration tests run before the pull requests are opened**, first before the review (step 1)
|
||||
and again for a head the review changed since its try: `mesh-controller.try` with the
|
||||
repository and the pushed branch is a check ask of the checker (ADR 0501 §5): the checker runs the repository's tests on the
|
||||
merge with the trunk's head, at the unit and the integration level, through the build module of the repository's language and by
|
||||
that language's convention, as the merge check does, and answers with an id to read back. The try is an ask on the language's check
|
||||
stream (ADR 0525 §1), so it waits behind the asks before it until a build node has a free slot; no script of the repository decides
|
||||
it (ADR 0445, ADR 0529). A try that fails goes to step 3 item 3 as a failed check does; the pull requests are opened only
|
||||
when every head's last try passed (the operator, 2026-10-18: three pushes in a row failed their first merge check on
|
||||
faults a try finds in minutes). While developing, no `go test -tags integration` or store or bus started
|
||||
by hand on the machine (the operator, 2026-10-18); after a failed try, a local run of the whole level is the guideline
|
||||
in step 1's brief. **Before a session trusts an agent's "pushed", it reads the forge branch's head** (`git ls-remote origin refs/heads/<branch>`) and compares it with the commit reviewed; an agent may commit on a detached HEAD and report a push that never happened (2026-10-26: the first try of a reviewed fix failed "not our ref"). The try and the pull request are started only on that read head. Pull requests in two or
|
||||
1. **Push the reviewed heads once, then open one pull request per repository, together** (ADR 0548; the operator,
|
||||
2026-10-26: "every release should only run 1 check or 1 try"). **No pull request, draft or not, exists before the
|
||||
review approves the heads**, and no fix round is pushed to an open pull request: every push to an open pull request
|
||||
asks a new check, of every member for a group, and the mesh's build capacity is spent on it ("we don't have more
|
||||
processing power"). The integration tests run once, in the checker's merge check on the merge with the trunk's head, at the unit
|
||||
and the integration level, through the build module of the repository's language and by that language's convention
|
||||
(ADR 0445, ADR 0529); the check waits on the language's check stream until a build node has a free slot
|
||||
(ADR 0525 §1). **No try:** never call `mesh-controller.try` or `mesh-delivery-checker.checker_try`, except when the
|
||||
operator asks for one. While developing, no `go test -tags integration` run of a whole level, and no store or bus started
|
||||
by hand on the machine (the operator, 2026-10-18).
|
||||
**A group is one check.** Before the push, every member pins the group's own mesh-sdk head exactly (the checker refuses an
|
||||
older commit of the same branch), then all members are pushed and opened together, so the group's check runs once. A head the review replaces
|
||||
counts for nothing against a running check; say so, and ask no other until the new head is reviewed.
|
||||
**Before a session trusts an agent's "pushed", it reads the forge branch's head** (`git ls-remote origin refs/heads/<branch>`) and compares it with the commit reviewed; an agent may commit on a detached HEAD and report a push that never happened (2026-10-26: the first check of a reviewed fix failed "not our ref"). The pull request is opened only on that read head. Pull requests in two or
|
||||
more repositories that share the branch name are one delivery group (ADR 0239 §2).
|
||||
**A temporary mode that merges by hand** (the lead merges because the normal Approve and merge path is not
|
||||
running): before it asks the merge, the lead runs the full integration level with nothing kept, a try with tests
|
||||
`.` for each repository of the group, and names those tries (ids and verdicts) in the pull request's description.
|
||||
A merge asked without them is a step skipped (research 071).
|
||||
running): the pull request's one check still runs the integration level, and the lead names its verdict in the
|
||||
pull request's description. A try with tests `.` is asked only when the operator asks for one, and then named there with its id and verdict (research 071).
|
||||
Where a session pushes through the forge tool `gitea_commit` (one commit on the forge's current base), the
|
||||
reviewer first confirms that commit's tree equals the reviewed one. **A large change is pushed by a pusher agent** on the smaller
|
||||
model: `gitea_commit` patches of about 30 KB each, a file copied from another path sent as a copy (`copy_from`)
|
||||
@@ -319,17 +326,20 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
controller's unit tests against the catalogue's branch**, because those tests read the catalogue and no check
|
||||
of the catalogue runs them: on 2026-10-20 mesh-catalog #381 removed the old delivery module, and every
|
||||
controller check failed afterwards on a test of the catalogue's subjects until issue 1406 removed the name
|
||||
mesh-issues still listened to. A controller try does not find it, since a check reads the catalogue's main
|
||||
mesh-issues still listened to. A controller's check does not find it, since a check reads the catalogue's main
|
||||
(also in a delivery group that holds the catalogue's pull request); the lead runs mesh-controller's unit
|
||||
suite with `MESH_CHECK_BESIDE` naming a directory that holds the catalogue's branch, as mesh-controller's
|
||||
`internal/beside` says.
|
||||
2. **The checker's merge check runs the integration tests again, as the gate** (its one status, `mesh/check`). No
|
||||
2. **The checker's merge check runs the integration tests once, as the gate** (its one status, `mesh/check`). No
|
||||
second review: step 2 reviewed this tree.
|
||||
3. **A check that fails** goes back to the same reviewer, continued by its id, with the failure, for **one more cycle** of step 2 with
|
||||
the same fixing agents; then push once again. **The failure is read from the check's whole log**, never
|
||||
the same fixing agents; then push **once** again (the one more push of ADR 0548). The check is **read, never re-asked to see if it passes**: a
|
||||
check asked again without a new, reviewed head spends the build capacity for nothing. **The failure is read from the check's whole log**, never
|
||||
reasoned from its summary: `mesh-delivery.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;
|
||||
on 2026-10-17 it showed a store test's `FAIL` without its cause, and a fix was first guessed from the code.
|
||||
**A failure the check hides or loses** (a verdict naming only the first failed test, a log not kept) is a fault of the
|
||||
checking tool: it is fixed there, the same turn (instruction fix-a-bug-met-twice), not asked around.
|
||||
**A change to the Go build module's recipe is judged by the build module the nodes run**, not by the changed one, so a
|
||||
test the change adds must pass under either version. **A change that needs the new recipe to judge it ships the recipe
|
||||
first, as a small fix of its own**, and the rest waits for its delivery: on 2026-10-17 milestone 3 of design 47 moved its
|
||||
@@ -349,9 +359,9 @@ issue whether it is being fixed in between, after the delivery, or waits, and on
|
||||
hand (issue 1226).
|
||||
5. **The operator's Approve is asked as soon as the checks pass** (ADR 0421). Nobody marks, labels, comments or
|
||||
rechecks: mesh-delivery asks the Approve on Telegram, the channel that proves who answered today (ADR 0398 §3;
|
||||
an Approve at the terminal is issue 953), once both checks passed, for a delivery group once for all its
|
||||
an Approve at the terminal is issue 953), once its one check (`mesh/check`) passed, for a delivery group once for all its
|
||||
members, naming the review record. On the Approve it merges the approved heads, a group's in one pass
|
||||
(ADR 0418). A new head ends the Approve and is asked again once its checks pass. A watcher follows the checks,
|
||||
(ADR 0418). A new head ends the Approve and is asked again once its checks pass, which is why a head is pushed only after its review. A watcher follows the checks,
|
||||
the Approve and the merge, and wakes the lead. Beyond that
|
||||
Approve, the operator's word is waited for only when the milestone changes what the operator sees, removes
|
||||
data, or needs a step only the operator's terminal can take; the lead says which before the milestone starts.
|
||||
@@ -472,7 +482,7 @@ on, with when it started and its bound.
|
||||
| a fixing agent's issue | 30 minutes | ask it where it stands; split or take over |
|
||||
| the review | 15 minutes a round | ask the reviewer; stop at round 3 |
|
||||
| a merge check | 15 minutes | read `mesh-delivery.show` (its state and verdict), then the check's log; the check stream's backlog and the age of its oldest ask are in the delivery view (ADR 0525 §9) |
|
||||
| the Approve's ask | 5 minutes after both checks pass | read `mesh-delivery.show`: an ask not raised is a fault, said to the operator |
|
||||
| the Approve's ask | 5 minutes after the check (`mesh/check`) passes | read `mesh-delivery.show`: an ask not raised is a fault, said to the operator |
|
||||
| a merge after the Approve | 5 minutes | read `mesh-delivery.show` for the delivery |
|
||||
| a delivery | its class's budget (3 minutes for a leaf module, 10 for a core module), at most 30 minutes | read the view's wants page, or `assigner_wants` against `node_haves`: a want held back names its rule, a `stuck` module its words |
|
||||
|
||||
@@ -626,8 +636,13 @@ issues in `fixing` that nobody works on reads to the operator as stuck work.
|
||||
- A running milestone's file holds the three answers of step 0 item 8 (`cat .work/<slug>/milestone.md`), and the
|
||||
review report says it read them (step 2, item 6a): a bucket key or stream in the diff (`git diff main --
|
||||
| grep -i 'bucket\|stream'`) that the lifetime answer omits is the failure of that item (research 071).
|
||||
- A pull request merged by hand in a temporary mode names, in its description on the forge (`gitea.gitea_get_pull_request`), a try with
|
||||
tests `.` for each repository of the group; one without is the step 3 rule skipped.
|
||||
- A pull request merged by hand in a temporary mode names, in its description on the forge (`gitea.gitea_get_pull_request`), the
|
||||
verdict of its one check; a try with tests `.` is named only where the operator asked for one.
|
||||
- **One release, one check** (ADR 0548): `gitea.gitea_get_pull_request` shows each pull request created after its
|
||||
review record's time, and `mesh-delivery.show` shows one check per head and, for a group, one head per member; a pull
|
||||
request that existed before its review approved it, a second head with no failed check before it, or a check of a
|
||||
head asked more than once, is this rule skipped. A call of `mesh-controller.try` or `checker_try` that the operator
|
||||
did not ask for shows in the checker's asks and is the same breach.
|
||||
- A milestone that adds or changes a module whose pull request has no integration test that starts the module
|
||||
whole is the failure of the check step's fourth item.
|
||||
- A bed run from `.work/<slug>/mesh-lab` that fails naming a `.work/<slug>/<repo>/…` path it cannot find is a
|
||||
|
||||
@@ -26,14 +26,15 @@ 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 try before the review, one review, one check run,
|
||||
one delivery**. Everything before the try is local and fast.
|
||||
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). 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
|
||||
code is written: on the issue, through the knowledge base (`knowledge-base.ask` first: what is decided is read before anything is designed), or by the operator. 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
|
||||
decision 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,
|
||||
@@ -50,30 +51,30 @@ one delivery**. Everything before the try is local and fast.
|
||||
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). Then push the branch and run `mesh-controller.try` on it, so the review reads the
|
||||
integration tests' real results; a failed try goes back to the same agent before the review.
|
||||
4. **One review of the commit and its try** (a reviewer that did not write it, larger
|
||||
`go test ./...` at the root). The integration tests are compiled (`go vet -tags integration ./...`) and not run:
|
||||
nothing is pushed, no pull request is opened and no try (`mesh-controller.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.
|
||||
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 reads each acceptance criterion
|
||||
against its test, as playbook 07 step 2 item 6; 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). The reviewer's findings go back to the same agent that wrote the fix, continued by
|
||||
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). 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, try it again if the review changed it, and open the pull request.** The trunk is what runs and nothing holds merged work back
|
||||
(ADR 0401), so a fix waits for no other change's delivery. `mesh-controller.try` on the pushed branch runs
|
||||
the integration tests, and the pull request is opened only when the head's last try passed (the pushed head is read from the forge first, as playbook [07](07-feature-branches.md) step 3 item 1 says); the checker's merge check runs
|
||||
them again as the gate (playbook [07](07-feature-branches.md) step 3). A failed try or check is best run locally
|
||||
first: the repository's whole integration level (`go test -tags integration -count=1 ./...` in each module) shows every
|
||||
failure at once, where a verdict names only the first (issue 1921) and a try per fault costs a round each (a guideline,
|
||||
the operator, 2026-10-23). The failures go back to the same agent, fixed in one change where they can be, and the
|
||||
reviewer reads only the change it makes, before the next try.
|
||||
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 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): before it asks the merge, the lead runs the full integration level with nothing kept, `mesh-controller.try`
|
||||
with tests `.`, and names that try (id and verdict) in the pull request's description (research 071; playbook
|
||||
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 `mesh-controller.try` and the checker's merge check
|
||||
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
|
||||
@@ -92,7 +93,7 @@ one delivery**. Everything before the try is local and fast.
|
||||
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, try or delivery that
|
||||
**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.
|
||||
@@ -116,10 +117,9 @@ code.
|
||||
| Waiting on | Bound | Past the bound |
|
||||
|---|---|---|
|
||||
| building the fix | 1 hour | it is a feature: stop and plan it under playbook 07 |
|
||||
| the try | 30 minutes | a try is a check ask on the language's check stream and waits behind the asks before it for a build node's free slot (ADR 0525); past the bound, read the stream's backlog and the age of its oldest ask in the delivery view |
|
||||
| the review | 15 minutes | ask the reviewer where it stands |
|
||||
| the merge check | 15 minutes | 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 both checks pass | read `mesh-delivery.show`: an ask not raised is a fault, said to the operator |
|
||||
| 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 |
|
||||
|
||||
@@ -134,8 +134,10 @@ reading itself and uses one subagent only for the review.
|
||||
|
||||
- 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 a try with tests `.` at its head in its description
|
||||
- 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` 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
|
||||
|
||||
@@ -75,7 +75,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<main>
|
||||
<button class="chip theme" id="theme" type="button">Theme</button>
|
||||
<h1>Novox Playbooks</h1>
|
||||
<p class="sub">How work is done on the mesh, from an idea or a symptom to a delivered change. Drawn from hq's <code>00-META/process/</code> at main <code>f269e83</code>, 2026-10-19, including playbook change hq #433 (try before the review).</p>
|
||||
<p class="sub">How work is done on the mesh, from an idea or a symptom to a delivered change. Drawn from hq's <code>00-META/process/</code> at main <code>f269e83</code>, 2026-10-19, amended 2026-10-26 for ADR 0548 (one release, one check: no try).</p>
|
||||
|
||||
<nav>
|
||||
<a href="#cycle">The cycle</a>
|
||||
@@ -189,7 +189,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
|
||||
<!-- ============ FEATURE SWIMLANE ============ -->
|
||||
<h2 id="feature">A feature, step by step (playbook 07)</h2>
|
||||
<p class="lead">One milestone is one release: one branch name in every repository it touches, one worktree per repository, one fixing agent per repository kept for the whole milestone, one reviewer, and one pull request per repository, opened once. Since hq #433 the branches are <b>tried before the review</b>, so the reviewer reads real integration results.</p>
|
||||
<p class="lead">One milestone is one release: one branch name in every repository it touches, one worktree per repository, one fixing agent per repository kept for the whole milestone, one reviewer, and one pull request per repository, opened once. Nothing is pushed or tried before the review (ADR 0548): the branches are pushed <b>once, after the review approves</b>, and the one check runs the integration tests.</p>
|
||||
<div class="box scroll">
|
||||
<svg viewBox="0 0 1080 430" role="img" aria-label="Playbook 07 in lanes: lead, fixing agents, reviewer, the mesh, the operator">
|
||||
<defs>
|
||||
@@ -199,12 +199,12 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<g class="mute">
|
||||
<text x="190" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">0 · Prepare</text>
|
||||
<text x="190" y="34" text-anchor="middle" class="mute">15 min</text>
|
||||
<text x="410" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">1 · Develop + try</text>
|
||||
<text x="410" y="34" text-anchor="middle" class="mute">30 min per issue · one try</text>
|
||||
<text x="410" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">1 · Develop</text>
|
||||
<text x="410" y="34" text-anchor="middle" class="mute">30 min per issue · local only</text>
|
||||
<text x="630" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">2 · Review</text>
|
||||
<text x="630" y="34" text-anchor="middle" class="mute">≤ 3 rounds · 15 min</text>
|
||||
<text x="830" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">3 · Check</text>
|
||||
<text x="830" y="34" text-anchor="middle" class="mute">≤ 1 more try · 1 check</text>
|
||||
<text x="830" y="34" text-anchor="middle" class="mute">push once · 1 check</text>
|
||||
<text x="1000" y="20" text-anchor="middle" class="t" style="fill:var(--mute)">4 · Deliver</text>
|
||||
<text x="1000" y="34" text-anchor="middle" class="mute">until delivered</text>
|
||||
</g>
|
||||
@@ -216,7 +216,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<text x="10" y="86" class="t">Lead</text><text x="10" y="102" class="mute">larger model</text>
|
||||
<text x="10" y="158" class="t">Fixing agents</text><text x="10" y="174" class="mute">smaller model</text>
|
||||
<text x="10" y="230" class="t">Reviewer</text><text x="10" y="246" class="mute">larger model</text>
|
||||
<text x="10" y="302" class="t">The mesh</text><text x="10" y="318" class="mute">try, checks, wants</text>
|
||||
<text x="10" y="302" class="t">The mesh</text><text x="10" y="318" class="mute">the one check, wants</text>
|
||||
<text x="10" y="374" class="t">Operator</text><text x="10" y="390" class="mute">Telegram</text>
|
||||
</g>
|
||||
<!-- lead -->
|
||||
@@ -224,11 +224,11 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<text x="190" y="78" text-anchor="middle" class="t">Survey · criteria</text>
|
||||
<text x="190" y="96" text-anchor="middle" class="mute">context file per repo</text>
|
||||
<rect x="340" y="56" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--dec)" stroke-width="2"/>
|
||||
<text x="410" y="78" text-anchor="middle" class="t">Up to trunk · push</text>
|
||||
<text x="410" y="96" text-anchor="middle" class="mute">each branch</text>
|
||||
<text x="410" y="78" text-anchor="middle" class="t">Up to trunk</text>
|
||||
<text x="410" y="96" text-anchor="middle" class="mute">each branch, local</text>
|
||||
<rect x="760" y="56" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--dec)" stroke-width="2"/>
|
||||
<text x="830" y="78" text-anchor="middle" class="t">Push reviewed heads</text>
|
||||
<text x="830" y="96" text-anchor="middle" class="mute">open the PRs together</text>
|
||||
<text x="830" y="96" text-anchor="middle" class="mute">once, PRs together</text>
|
||||
<rect x="930" y="56" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--dec)" stroke-width="2"/>
|
||||
<text x="1000" y="78" text-anchor="middle" class="t">Follow to done</text>
|
||||
<text x="1000" y="96" text-anchor="middle" class="mute">resolve the issues</text>
|
||||
@@ -242,14 +242,14 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<!-- reviewer -->
|
||||
<rect x="560" y="200" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--idea)" stroke-width="2"/>
|
||||
<text x="630" y="222" text-anchor="middle" class="t">Read all repos</text>
|
||||
<text x="630" y="240" text-anchor="middle" class="mute">+ tries · every criterion</text>
|
||||
<text x="630" y="240" text-anchor="middle" class="mute">reads tests · every criterion</text>
|
||||
<!-- mesh -->
|
||||
<rect x="340" y="272" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--mesh)" stroke-width="2"/>
|
||||
<text x="410" y="294" text-anchor="middle" class="t">try</text>
|
||||
<text x="410" y="312" text-anchor="middle" class="mute">integration tests run</text>
|
||||
<text x="410" y="294" text-anchor="middle" class="t">no try</text>
|
||||
<text x="410" y="312" text-anchor="middle" class="mute">nothing pushed yet</text>
|
||||
<rect x="760" y="272" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--mesh)" stroke-width="2"/>
|
||||
<text x="830" y="294" text-anchor="middle" class="t">Forge checks</text>
|
||||
<text x="830" y="312" text-anchor="middle" class="mute">gate · repo · group</text>
|
||||
<text x="830" y="312" text-anchor="middle" class="mute">one check · mesh/check</text>
|
||||
<rect x="930" y="272" width="140" height="52" rx="8" fill="var(--card)" stroke="var(--mesh)" stroke-width="2"/>
|
||||
<text x="1000" y="294" text-anchor="middle" class="t">Merge · wants</text>
|
||||
<text x="1000" y="312" text-anchor="middle" class="mute">backups first, canary first</text>
|
||||
@@ -260,10 +260,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<!-- edges -->
|
||||
<path class="edge" d="M190,108 C190,140 260,154 298,154" marker-end="url(#ar2)"/>
|
||||
<path class="edge" d="M410,128 V110" marker-end="url(#ar2)"/>
|
||||
<path class="edge" d="M480,90 C545,110 545,250 462,270" marker-end="url(#ar2)"/>
|
||||
<path class="edge" d="M480,298 C530,298 540,226 558,226" marker-end="url(#ar2)"/>
|
||||
<text x="490" y="262" class="mute">results</text>
|
||||
<path class="edge" d="M630,200 V182" marker-end="url(#ar2)"/>
|
||||
<path class="edge" d="M630,200 V182" marker-end="url(#ar2)"/>
|
||||
<path class="edge dash" d="M610,182 V198" marker-end="url(#ar2)"/>
|
||||
<text x="514" y="196" class="mute">round n+1</text>
|
||||
<path class="edge" d="M700,226 C740,226 740,82 758,82" marker-end="url(#ar2)"/>
|
||||
@@ -302,7 +299,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
|
||||
<!-- ============ TESTS ============ -->
|
||||
<h2 id="tests">When tests run</h2>
|
||||
<p class="lead">Two levels. Unit tests run all the time on the machine; integration tests (a bus, a store or a process started) never run there: <code>mesh-controller.try</code> runs them on the pushed branch (a check ask on the language's stream), and the checker's merge check runs them again as the gate.</p>
|
||||
<p class="lead">Two levels. Unit tests run all the time on the machine; integration tests (a bus, a store or a process started) are compiled there and never run: the checker's one merge check, asked by the one push after the review, runs them as the gate. There is no try (ADR 0548).</p>
|
||||
<div class="box scroll">
|
||||
<svg viewBox="0 0 1080 170" role="img" aria-label="Test levels over a feature's timeline">
|
||||
<defs><marker id="ar3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0L10,5L0,10z" fill="var(--mute)"/></marker></defs>
|
||||
@@ -318,8 +315,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<g>
|
||||
<rect x="120" y="96" width="340" height="16" rx="8" fill="var(--mute)" opacity=".18"/>
|
||||
<text x="290" y="108" text-anchor="middle" class="mute">compiled only: go vet -tags integration</text>
|
||||
<rect x="470" y="90" width="110" height="28" rx="6" fill="var(--mesh)"/><text x="525" y="109" text-anchor="middle" style="fill:var(--bg)" class="t">try</text>
|
||||
<rect x="770" y="90" width="120" height="28" rx="6" fill="none" stroke="var(--mesh)" stroke-width="2" stroke-dasharray="5 4"/><text x="830" y="109" text-anchor="middle" class="mute">try again if changed</text>
|
||||
<rect x="770" y="90" width="120" height="28" rx="6" fill="none" stroke="var(--mesh)" stroke-width="2" stroke-dasharray="5 4"/><text x="830" y="109" text-anchor="middle" class="mute">push once</text>
|
||||
<rect x="920" y="90" width="120" height="28" rx="6" fill="var(--mesh)"/><text x="980" y="109" text-anchor="middle" style="fill:var(--bg)" class="t">merge check</text>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -332,7 +328,7 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<svg viewBox="0 0 520 300" role="img" aria-label="The review loop: at most three rounds">
|
||||
<defs><marker id="ar4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0L10,5L0,10z" fill="var(--mute)"/></marker></defs>
|
||||
<rect x="20" y="20" width="150" height="54" rx="8" fill="var(--card)" stroke="var(--idea)" stroke-width="2"/>
|
||||
<text x="95" y="44" text-anchor="middle" class="t">Round n of ≤ 3</text><text x="95" y="62" text-anchor="middle" class="mute">code + tries + criteria</text>
|
||||
<text x="95" y="44" text-anchor="middle" class="t">Round n of ≤ 3</text><text x="95" y="62" text-anchor="middle" class="mute">code + criteria</text>
|
||||
<polygon points="300,20 380,47 300,74 220,47" fill="var(--card)" stroke="var(--mute)"/>
|
||||
<text x="300" y="51" text-anchor="middle" class="t">Wrong?</text>
|
||||
<rect x="400" y="20" width="110" height="54" rx="8" fill="var(--okbg)" stroke="var(--ok)" stroke-width="2"/>
|
||||
@@ -357,10 +353,10 @@ code{font:12.5px ui-monospace,monospace;background:var(--soft);padding:1px 5px;b
|
||||
<h3 style="margin-top:12px">What every round reads</h3>
|
||||
<ul style="margin:6px 0;padding-left:20px;font-size:14px">
|
||||
<li>Every criterion against its test: a test at its level that would fail without the change.</li>
|
||||
<li>Every new integration test traced through the code, and its try's result.</li>
|
||||
<li>Every new integration test traced through the code by reading it: no run exists before the check.</li>
|
||||
<li>That each integration test enters by the path the live trigger takes.</li>
|
||||
</ul>
|
||||
<div class="note" style="margin-top:10px">Why reviews took more than one round (R3b, 2026-10-19): a test that "failed" only by not compiling, a reader of the changed record the survey missed, and bus tests judged by reasoning before they ran. hq #433 changes all three.</div>
|
||||
<div class="note" style="margin-top:10px">Why reviews took more than one round (R3b, 2026-10-19): a test that "failed" only by not compiling, a reader of the changed record the survey missed, and bus tests judged by reasoning before they ran. ADR 0548 and playbook 07 step 2 item 4 change the last: bus tests are judged by reading them against the code, and the one check runs them after the review.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -465,17 +461,17 @@ const P = [
|
||||
{n:"07",name:"Features",kind:"build",c:"--build",
|
||||
trig:"Work that changes code across issues or repositories, too large for a small fix.",
|
||||
who:"A lead (larger model), one fixing agent per repository (smaller), one reviewer (larger).",
|
||||
steps:["Prepare: name the branch, make the worktrees, settle every question.","Write one context file per repository.","Write the findings and acceptance criteria into each issue.","Survey every other reader and writer of each changed value. (new)","Answer three questions in the milestone file: who deletes each new key and stream, how the switch-over is tried on one node first, how the integration level runs before the pull requests. The review checks them. (new)","List every part the change reaches; copy fixtures from the real writer.","Develop: one agent per repository, one commit per issue.","A test fails first on behaviour, not on compiling. (new)","Bring each branch up to the trunk, push, and try it. (new)","Review all of it with the tries' results; at most 3 rounds.","Push the reviewed heads and read each forge head against the reviewed commit; try again only what changed.","A merge by hand in a temporary mode first runs a try with tests \".\" and names it in the pull request. (new)","Open one pull request per repository, together, with Reviewed-by and Pushed-by.","The operator's Approve on Telegram; the group merges in one pass.","Follow the delivery in the status view (moving, settled, stuck, delivered) to done; resolve the issues; clean up. (new)","When the builder cannot deliver its own fix: revert, a build by a session's call, a registration at the terminal, copies kept outside the store; a broken controller is put back by a want the operator writes, a hand build by mesh-hand-compose and a want. (new)"],
|
||||
steps:["Prepare: name the branch, make the worktrees, settle every question.","Write one context file per repository.","Write the findings and acceptance criteria into each issue.","Survey every other reader and writer of each changed value. (new)","Answer three questions in the milestone file: who deletes each new key and stream, how the switch-over is tried on one node first, what the one check does not cover. The review checks them. (new)","List every part the change reaches; copy fixtures from the real writer.","Develop: one agent per repository, one commit per issue.","A test fails first on behaviour, not on compiling. (new)","Bring each branch up to the trunk; nothing is pushed, no try runs. (new)","Review all of it, reading the integration tests against the code; at most 3 rounds.","A group pins the group's own mesh-sdk head in every member. (new)","Push the reviewed heads once and read each forge head against the reviewed commit; no draft pull request, no fix round on an open one. (new)","Open one pull request per repository, together, with Reviewed-by and Pushed-by; the one check runs. A failed check is read, fixed, reviewed, pushed once more. (new)","The operator's Approve on Telegram; the group merges in one pass.","Follow the delivery in the status view (moving, settled, stuck, delivered) to done; resolve the issues; clean up. (new)","When the builder cannot deliver its own fix: revert, a build by a session's call, a registration at the terminal, copies kept outside the store; a broken controller is put back by a want the operator writes, a hand build by mesh-hand-compose and a want. (new)"],
|
||||
prod:"One pull request per repository, one source revision delivered, resolved issues, no branch or worktree left.",
|
||||
next:"02 (when it ships)",bounds:"Prepare 15 min · 30 min per issue · review 15 min, ≤ 3 rounds · one try and one check",
|
||||
next:"02 (when it ships)",bounds:"Prepare 15 min · 30 min per issue · review 15 min, ≤ 3 rounds · one check, pushed once",
|
||||
prev:["Pull requests as scratchpads","Context bought again and again","Review rounds spent on what a run would show"],
|
||||
check:"The checker's one status, mesh/check; the review record; the tracker's move."},
|
||||
{n:"08",name:"Small fixes",kind:"build",c:"--build",
|
||||
trig:"One issue in one repository, about an hour of work.",
|
||||
who:"The session, with one reviewer on the larger model.",
|
||||
steps:["Read the issue and the code; settle any open question.","Write the acceptance criteria.","Move the issue to fixing.","Build on fix/<issue>-<slug> in its own worktree.","A test that fails today first, on behaviour. (new)","Push and try before the review. (new)","One review of the commit and its try.","Push the reviewed head; open the pull request.","The operator's Approve; the merge; the delivery, followed in the status view. (new)","Prove the fix live and resolve the same hour.","During a milestone: ride in its delivery group, unless broken for the operator now. (new)"],
|
||||
steps:["Read the issue and the code; settle any open question.","Write the acceptance criteria.","Move the issue to fixing.","Build on fix/<issue>-<slug> in its own worktree.","A test that fails today first, on behaviour. (new)","Nothing is pushed and no try runs before the review. (new)","One review of the local commit.","Push the reviewed head once; only then open the pull request. (new)","The operator's Approve; the merge; the delivery, followed in the status view. (new)","Prove the fix live and resolve the same hour.","During a milestone: ride in its delivery group, unless broken for the operator now. (new)"],
|
||||
prod:"One pull request, one delivery, a resolved issue.",
|
||||
next:"—",bounds:"About an hour · one try before the review, one review, one check",
|
||||
next:"—",bounds:"About an hour · one review, one push, one check",
|
||||
prev:["A fix reviewed after its pull request opened","A long part run twice","A fix waiting on someone else's delivery","Ten SDK merges and eight controller merges in a day, one per fix"],
|
||||
check:"The checker's status; the review record; the tracker's move; one delivery group and one source revision per milestone."},
|
||||
{n:"09",name:"Cleanup",kind:"side",c:"--side",
|
||||
|
||||
@@ -1161,7 +1161,7 @@ release reports the controller's code lines against research 063's baseline (acc
|
||||
| 3 fix | A group approved together merges in one pass and goes out in one delivery plan, also when its members' tests read each other's repositories | 1 | mesh-catalog (mesh-delivery, gitea) | 1082, 1049, 1047, 1083, 1079 (1084 closed as its duplicate) |
|
||||
| 5 | One read of a module on a node names the commit, build and rollout that put it there | 10, 12 | mesh-controller, mesh-catalog (mesh-config, nats) | 981 |
|
||||
| 5b | Decided: building and delivering leave the controller for parts that watch and write keys in the repository `mesh-delivery`, landing in six releases (ADR 0429); the forge module makes that repository from its config, protected before any team reaches it (ADR 0428) | — (ADR 0429 names them: 13 to 20) | hq, mesh-catalog (gitea) | 1117, 1124, 1128 |
|
||||
| 6 | Folded into release 4 by ADR 0429 §10 (the fetch over SSH in R4c, the cut-over in R4e): installed toolchains, builders fetching over SSH with their own key, and an SDK change shipping with its users are built in the builder's new home, so the builder is changed once | (2: proved by R4e; 4: in part by R4e, wholly by R4g) | — | 979; the builder's own forge key moved to release 4 (R4c) |
|
||||
| 6 | Folded into release 4 by ADR 0429 §10 (the fetch over SSH in R4c, the cut-over in R4e): installed toolchains, builders fetching over SSH with their own key, and an SDK change shipping with its users are built in the builder's new home, so the builder is changed once | (2: proved by R4e; 4: in part by R4e, wholly by R4g) | — | its issue is R4g's (the installed toolchains); the builder's own forge key moved to release 4 (R4c) |
|
||||
| R1a | The node-engine, the controller and the parts can read one layout of the have, presence, pulse and stuck keys: mesh-sdk ships it before its users | — (13, 14 need it) | mesh-sdk | 1131 (key layouts) |
|
||||
| R1b | Every node writes what it runs of each module, on its own keys and nobody else's, and the bus says to one part when a connection opens and closes | 13 in part | the node-engine (`mesh-host`), mesh-controller | 1132 (have keys), 1142 (the node-engine's check, its tests half), 1136 (the have bucket and its grants), 1145 (a module and a build per resource), 1146 (a new repository's first module registered at its merge's Approve), 1147 (the bus's connect events for the watchman), 1160 (a plan passes a machine silent at a middle tier), 1162 (the have bucket takes a node's facts) |
|
||||
| R1c | The operator sees every module on every node, with its build, phase and health, in `mesh-delivery-cli` (aliased `nox-delivery`) and its web view | 13 | mesh-delivery (view) | 1134 (the view), 1137 (the alias, in the view's manifest) |
|
||||
@@ -1171,20 +1171,26 @@ release reports the controller's code lines against research 063's baseline (acc
|
||||
| R2d | The node-engine sends no alive message | 14 | the node-engine (`mesh-host`) | 1158 (the node-engine's alive side deleted) |
|
||||
| R3a | The gate, the bridge, the indexer and the teller can read one layout of the source revision, candidates, modules, merges, asks, answers, owed acts, forge messages and conditions, and one function computes the source fingerprint: mesh-sdk ships them before their users (ADR 0437) | — (15 needs it) | mesh-sdk | 1200 (source revision, candidates, modules, forge messages), 1201 (merges, asks, owed acts, answers), 1202 (a condition on its one subject), 1203 (the source fingerprint, proven against three fingerprints the live builder recorded); ahead of it in mesh-controller, so those could be read: 1204 and 1208 (`builds` says each build's source fingerprint) |
|
||||
| R3b | The controller finds the delivery seat's holder by its claim and records each build's fingerprint inputs; the router takes conditions on their one subject; the operator sees no change (ADR 0437) | — | mesh-controller, mesh-catalog (messenger) | 1210 (the controller's own path and the composition check's rule by the seat's claim), 1211 (a merge's announcement heard from the seat's holder), 1212 (the pull requests' keys read from the holder's bucket), 1213 (a merge's warrant read under the asker the announcement names: the teller, or mesh-delivery until R3d), 1214 (the builder computes the source fingerprint with mesh-sdk's function), 1215 (a build record carries its fingerprint's inputs), 1216 (a module may say a condition only under its own name, proven on the controller's grant); in the messenger: 1217 (the router takes a condition on its one subject), 1218 (the same over the bus); one delivery group. Its prepare step found that the controller hears no `transition` or `group` event, and that the router cannot refuse a condition under another module's name, the grant does: both go into R3c's insight on ADR 0437 with R3c's fingerprint issue |
|
||||
| R3c | The forge bridge, the indexer and the teller run beside today's mesh-delivery and write their keys; the view shows modules against the controller's source fingerprints; nothing is merged by them yet (ADR 0437) | 15 in part | mesh-delivery (forge bridge, indexer, teller, view), mesh-catalog (the forge module) | 1235 (the forge bridge writes pull messages on FORGE), 1236 (its merged message, with the trees of the merge commit), 1237 (its messages for the pull requests open at its start and each reconnect), 1238 (the indexer writes the candidate groups), 1239 (the indexer writes the modules' fingerprints at a trunk merge, and 1209: none for an image that compiles a Go program from a context), 1240 (the teller runs and carries nothing yet), 1241 (the view shows the candidate groups and each module's fingerprint against the controller's); in the forge module: 1234 (a merge commit's trees in one call, and the head branch in the open pull requests); one delivery group, mesh-catalog first. Its prepare step found three orders: the forge had no tool for a commit's trees, so the forge module joins the milestone as a member of its group; and mesh-sdk shipped two layouts before it, the controller's build record (1223) and a build's directory and a pull request's module directories (1233). It also found that the bridge's FORGE is a stream the others hear by `consumes`, not a bucket they `read`; that the broker test of the three credentials goes into R3d with the gate's (1243); and that the parts hand-write their bus connection until mesh-sdk gives one (1242): facts for ADR 0437's next insight, with R3d's |
|
||||
| R3c | The forge bridge, the indexer and the teller run beside today's mesh-delivery and write their keys; the view shows modules against the controller's source fingerprints; nothing is merged by them yet (ADR 0437) | 15 in part | mesh-delivery (forge bridge, indexer, teller, view), mesh-catalog (the forge module) | 1235 (the forge bridge writes pull messages on FORGE), 1236 (its merged message, with the trees of the merge commit), 1237 (its messages for the pull requests open at its start and each reconnect), 1238 (the indexer writes the candidate groups), 1239 (the indexer writes the modules' fingerprints at a trunk merge, and 1209: none for an image that compiles a Go program from a context), 1240 (the teller runs and carries nothing yet), 1241 (the view shows the candidate groups and each module's fingerprint against the controller's); in the forge module: 1234 (a merge commit's trees in one call, and the head branch in the open pull requests); one delivery group, mesh-catalog first. Its prepare step found three orders: the forge had no tool for a commit's trees, so the forge module joins the milestone as a member of its group; and mesh-sdk shipped two layouts before it, the controller's build record (1223) and a build's directory and a pull request's module directories (1233). It also found that the bridge's FORGE is a stream the others hear by `consumes`, not a bucket they `read`; that the broker test of the three credentials goes into R3d with the gate's (its issue is R3d's); and that the parts hand-write their bus connection until mesh-sdk gives one (1242): facts for ADR 0437's next insight, with R3d's |
|
||||
| R3d | The gate's keys can carry what the forge needs and the controller answers a what-if as data, so the gate has what it reads before it runs; a failed delivery plan asks the operator Retry on the phone, and a seat whose holder is assigned nowhere passes to its only claimant; the operator sees only the Retry notice (ADR 0450, ADR 0449) | — | mesh-sdk, mesh-controller | in mesh-sdk: 1321 (a merge key carries the Approve's heads), 1322 (an owed act carries a status's target, a commit without a pull request, two comments), 1323 (a name a key cannot hold is escaped); in mesh-controller: 1324 (what-if as data), 1325 (the build seat reads the gate's pull keys), 1326 (the gate's buckets writable by its runner only), 1243 (the three parts' credentials); and, delivered first as feature no-terminal (ADR 0449): 1317 (the seat passes to its only claimant), 1314 (a failed delivery plan raises a condition), 1315 (Retry offered and performed), 1316 (a refused answer is told). Its prepare step found four things the gate reads that ship before it, which cut the former R3d in two (ADR 0450), and two steps on the path that needed the operator's terminal (ADR 0449) |
|
||||
| R3e | A group reaches the mesh as one source revision written by the gate; the merge's Approve is asked by the teller and answered on the phone until issue 953; the view shows the open asks; today's module mesh-delivery is carried over into the gate when it first holds the seat and ends; no step needs the operator's terminal (ADR 0437, ADR 0450) | 15 | mesh-delivery (gate's parts: forge bridge, teller, indexer, view), mesh-catalog (the gate, mesh-delivery removed, mesh-issues), mesh-tools (the tool runner's waits) | opened when it is prepared, from R3d's survey; the controller's deletions it makes possible go to release 4 (1318) |
|
||||
| R4a | The shared layouts of release 4 are on mesh-sdk's main before their users pin them: the catalogue, the validator and the composition over a plain input, the fingerprint's new form, and the key layouts of the builder, the checker, the kept verdicts, the manifests and the candidates; the node-engine reports the user namespaces capability (ADR 0453 clauses 1, 2, 3) | — (2 needs it) | mesh-sdk, the node-engine (`mesh-host`) | in mesh-sdk: 1353 to 1364, 1298 (the composition over a plain input); in the node-engine: 1308 (the user namespaces capability) |
|
||||
| R3e | A group reaches the mesh as one source revision written by the gate; the merge's Approve is asked by the teller and answered on the phone until issue 953; the view shows the open asks; today's module mesh-delivery is carried over into the gate when it first holds the seat and ends; no step needs the operator's terminal (ADR 0437, ADR 0450) | 15 | mesh-delivery (gate's parts: forge bridge, teller, indexer, view), mesh-catalog (the gate, mesh-delivery removed, mesh-issues), mesh-tools (the tool runner's waits) | opened when it is prepared, from R3d's survey; the controller's deletions it makes possible go to release 4 (their issue is R4g's) |
|
||||
| R4a | The shared layouts of release 4 are on mesh-sdk's main before their users pin them: the catalogue, the validator and the composition over a plain input, the fingerprint's new form, and the key layouts of the builder, the checker, the kept verdicts, the manifests and the candidates; the node-engine reports the user namespaces capability (ADR 0453 clauses 1, 2, 3) | — (2 needs it) | mesh-sdk, the node-engine (`mesh-host`) | in mesh-sdk: 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1298 (the composition over a plain input); in the node-engine: 1308 (the user namespaces capability) |
|
||||
| R4b | mesh-controller and the node-engine use the catalogue, the validator and the composition from mesh-sdk and delete their copies; the controller composes every node both ways on the live facts and the two agree before this is delivered; it writes the grants and credential bindings the assigner reads; its unit level meets its bound (ADR 0453 clauses 1, 3) | — | mesh-controller, the node-engine (`mesh-host`) | 1375 (to be split when it is prepared), 1337 (the unit level's bound) |
|
||||
| R4c | The new parts run dark beside today's: the indexer writes the manifests by digest and the fingerprints in the new form beside today's (its own, first delivery), then the build modules (the Go build module, the Node and TypeScript build module: toolchain, sandbox, fetch, digest, test, build), the builder, the checker writing `mesh/check` as a status the forge does not require, and the assigner's composition check writing into the checker's report; the build seat's accounts are decided by a record before the build modules' pull requests are opened (ADR 0453 clauses 4, 6, 7, 8, 11, 12, 16; ADR 0465 §4); the builder is ADR 0478's. It is delivered in ADR 0465 §5's order: mesh-sdk's layouts; the forge bridge and the indexer with the controller's facts in format 2; the build modules; the builder; the checker; the bus user list's composer moved into mesh-sdk; the assigner's composition check; the fetch and run steps. The build modules each run as an account of their own with a forge key known read-only on one forge user (ADR 0466); each builds with the node's installed toolchain at the agreed version and does not refuse on a node with another (ADR 0477, issue 1572), answers a long step with its id and finishes it on a key, is called on a named machine, and runs on the four nodes that run the build agent today (ADR 0469) | 22, 23 (measured on the dark run, proved in R4f) | mesh-delivery (indexer, builder, checker, assigner's composition check), mesh-catalog (build modules, ssh-client, gitea), mesh-controller (the build agent's whole-check tests, the script's steps as tests), mesh-sdk | 971 (its record first), 1297 (the assigner's composition check), 1309 (the fetch and run steps), 1287, 1288, 1289, 1290, 1291, 1292 (the checker; the build modules run the tests), 1251; the steps of 1293 and 1294 that are no test become tests in R4c to R4e; the rest opened when it is prepared |
|
||||
| R4c | The new parts run dark beside today's: the indexer writes the manifests by digest and the fingerprints in the new form beside today's (its own, first delivery), then the build modules (the Go build module, the Node and TypeScript build module: toolchain, sandbox, fetch, digest, test, build), the builder, the checker writing `mesh/check` as a status the forge does not require, and the assigner's composition check writing into the checker's report; the build seat's accounts are decided by a record before the build modules' pull requests are opened (ADR 0453 clauses 4, 6, 7, 8, 11, 12, 16; ADR 0465 §4); the builder is ADR 0478's. It is delivered in ADR 0465 §5's order: mesh-sdk's layouts; the forge bridge and the indexer with the controller's facts in format 2; the build modules; the builder; the checker; the bus user list's composer moved into mesh-sdk; the assigner's composition check; the fetch and run steps. The build modules each run as an account of their own with a forge key known read-only on one forge user (ADR 0466); each builds with the node's installed toolchain at the agreed version and does not refuse on a node with another (ADR 0477, issue 1572), answers a long step with its id and finishes it on a key, is called on a named machine, and runs on the four nodes that run the build agent today (ADR 0469) | 22, 23 (measured on the dark run, proved in R4f) | mesh-delivery (indexer, builder, checker, assigner's composition check), mesh-catalog (build modules, ssh-client, gitea), mesh-controller (the build agent's whole-check tests, the script's steps as tests), mesh-sdk | 971 (its record first), the assigner's composition check (its issue is R4g's), 1309 (the fetch and run steps), 1287, 1288, 1289, 1290, 1291, 1292 (the checker; the build modules run the tests), 1251; the steps of 1293, and of R4g's issue on the old checks, that are no test become tests in R4c to R4e; the rest opened when it is prepared |
|
||||
| R4d | Four modules stop being built from a Dockerfile: route-proxy, nats, n8n and mail's autoconfiguration module (automx, replaced by a Go program), each rework its own release step, nats in a delivery of its own; free between R4a and R4e and never in the same delivery as another release (ADR 0452, ADR 0453 clauses 13, 14, 16) | — | mesh-catalog, mesh-controller (route-proxy), the node-engine (`mesh-host`: n8n's supplementary group) | the four image reworks, opened when it is prepared |
|
||||
| R4e | The controller asks no build: a build is keyed by its fingerprint, the new form becomes the only one as one group, and a merge builds nothing its check built; builders fetch over SSH, so an SDK change ships with its users; the vendored copies leave mesh-controller and mesh-sdk; delivered only once the builder's artifact digests equal build-agent's (ADR 0453 clauses 2, 4, 5, 6) | 16, 2, 4 in part | mesh-controller (builds are no longer asked), mesh-delivery (builder), mesh-sdk | 979 (the installed toolchains; closed with the toolchain images in R4g), 1304, the controller asking no build (opened when it is prepared) |
|
||||
| R4f | A pull request carries one required status that says what it proved and how long each part took; the controller's composition check and its replays are deleted with the two old statuses; the controller's deletions R3e makes possible go; each level's times are measured, and a bound fails a repository from the first check that meets it (ADR 0447, ADR 0450 §8, ADR 0453 clauses 4, 9, 10) | 21, 22, 23, 24 (the status; the scripts' absence is proved in R4g) | mesh-delivery (checker, assigner), mesh-controller (composition check, replays, `delivery-plan`, `forget-checks`, the asker `mesh-delivery` deleted), mesh-catalog (gitea) | 1299 (the composition check deleted; closes issue 709, the replays' socket), 1300, 1301, 1302 (one status), 1305 (ADR 0482 §8), 1318 |
|
||||
| R4e | The controller asks no build: a build is keyed by its fingerprint, the new form becomes the only one as one group, and a merge builds nothing its check built; builders fetch over SSH, so an SDK change ships with its users; the vendored copies leave mesh-controller and mesh-sdk; delivered only once the builder's artifact digests equal build-agent's (ADR 0453 clauses 2, 4, 5, 6) | 16, 2, 4 in part | mesh-controller (builds are no longer asked), mesh-delivery (builder), mesh-sdk | the installed toolchains (their issue is R4g's), 1304, the controller asking no build (opened when it is prepared) |
|
||||
| R4f | A pull request carries one required status that says what it proved and how long each part took; the controller's composition check and its replays are deleted with the two old statuses; the controller's deletions R3e makes possible go; each level's times are measured, and a bound fails a repository from the first check that meets it (ADR 0447, ADR 0450 §8, ADR 0453 clauses 4, 9, 10) | 21, 22, 23, 24 (the status; the scripts' absence is proved in R4g) | mesh-delivery (checker, assigner), mesh-controller (composition check, replays, `delivery-plan`, `forget-checks`, the asker `mesh-delivery` deleted), mesh-catalog (gitea) | 1300, 1301, 1302 (one status); the composition check deleted (closing issue 709, the replays' socket), ADR 0482 §8 and the controller's deletions are R4g's issues |
|
||||
| R4g | The last milestone of release 4 and release 5 as one, with one switch-over and no rehearsal (ADR 0524 §1): builds and checks are asks on streams that each build node pulls when it has a free slot, deliveries first, with nothing holding checks and no controller queue (ADR 0525); the assigner is made with its composition check, writes each node's wants compared with what the controller sends and every difference, and the view answers the asks that need no proof of who answered (ADR 0528, ADR 0437 §10); no module's fingerprint takes the builder (ADR 0530); the scripts of the repositories a module is built from, build-agent with its socket and Dockerfile code, the toolchain images and the controller's build code go, and the builder delivers its own module, the build modules and the controller from its keys (ADR 0453 clauses 5, 8, 10; ADR 0524 §5, §7); the ways to deliver without the builder are recorded (ADR 0526); hq's four checks are Go tests (ADR 0527); each repository's script goes (ADR 0529); the word for the composition check's predecessor is struck. Its pull requests are opened only after five readings, the revert path read, not shown on a test merge (ADR 0524 §3) | 4 (from R4g mesh-build-image, rootless, is the only part that builds an image: ADR 0487 §7), 17, 24 (no `merge-check.sh` in a repository a module is built from) | mesh-sdk, mesh-controller (build-agent removed), mesh-delivery, mesh-catalog, mesh-tools, mesh-tools-go, the node-engine (`mesh-host`), mesh-media-catalog, okioki, hq | 1887 (the flow), 1297 (the assigner), 1295 (`merge-check.sh` goes), 979 (closed with the toolchain images), 1296 and 1303 (hq's check, the old word struck), 1299, 1305, 1294, 1318 (the controller's deletions) |
|
||||
| R6 | Each node applies from its wants the compositions its own node agent composes (ADR 0547 §2; as released it applied the controller's signed ones), a new version reaches the module's canary first and the rest once it is healthy there, a move a person must allow is asked before its want, the view says what is moving, settled, stuck and delivered, and the plans are deleted from the code; switched over by release 5's last plan (ADR 0539) | 18, 19, 20 | mesh-sdk, the node-engine (`mesh-host`: the node agent), mesh-controller (plans deleted; as released also compositions and credentials, which ADR 0547 moves to the node agents, the grants part and the vault), mesh-delivery (assigner, watchman, view), mesh-catalog (the gate, the messenger, the issue tracker, the backup holder), hq | 1942 (the planner puts the node-engine and the controller in one tier for the switch; delivered first), the bus's user list granting what release 6 uses (delivered first, under L1's issue), 1943 (mesh-sdk: the composition's layout and signature, the want's digest, `mesh-hand-compose`, the verb tables without the plan verbs), 1944 (the node agent), 1946 (the gate keeps the merge's states; the messenger and the issue tracker hear the view), 1906 (the assigner's seventh rule and its asks, the watchman's pulses for wants, the view's wants and events), 1130 (hq) |
|
||||
| L1 | The controller leaves build and delivery, first milestone: the bus node follows the user list alone, the grants part composes in shadow and the vault holds the bus accounts' hashes, so the operator's take-over can make the grants part's list the one loaded (ADR 0547 §8, §11; ADR 0550 §4) | — | mesh-controller, mesh-delivery, mesh-catalog (the vault, the grants part), the node-engine (`mesh-host`), mesh-sdk | 1945 |
|
||||
| L2 | Nodes compose: each node agent composes its own modules, and no node applies a composition made elsewhere but the bus's user list (ADR 0547 §11) | — | the node-engine (`mesh-host`), mesh-sdk, mesh-controller | 1126 |
|
||||
| L3 | Nothing is left with the controller: the vault mints bus accounts and signs, the grants part writes grants, the try is the checker's own verb, placement is read from the catalogue alone, and the lease passes to a holder that is no controller (ADR 0547 §11, ADR 0549 §5, §6, ADR 0550 §2); the rest of the controller's code lines is the issue of L2 | — | mesh-controller, mesh-catalog (the vault, the grants part), mesh-delivery | 774 |
|
||||
| M1 | A milestone is a record of the issue tracker: each row of a design's milestone table is a milestone record its issues are linked to by `issue-tracker.link`, an issue to at most one, and pull requests and commits to issues the same way; the knowledge base's `progress` reads the milestones from the tracker, not from this table (ADR 0493 §1 to §4) | — (ADR 0493 §13 in part) | hq, mesh-catalog (mesh-issues, mesh-knowledge) | 1781 |
|
||||
|
||||
An issue is in one row only (ADR 0493 §2): where a row named an issue another row names too, the last row keeps it and the
|
||||
earlier row says so in words (the operator, 2026-10-26). Milestone M1 makes each row a record of the issue tracker
|
||||
(issue 1781): once its seed has run, the tracker is the only list of a milestone's issues, `issue-tracker.milestones`
|
||||
reads them, and this table keeps its rows without the Issues column (the operator, 2026-10-26).
|
||||
|
||||
Milestones L1 to L3 are the three of "The controller leaves build and delivery" above (ADR 0547 §11), given rows on
|
||||
2026-10-26 so that a reader of this table, the knowledge base's `progress` among them (issue 1947), sees the work that
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
layer: to-be
|
||||
status: in-progress
|
||||
code: [mesh-catalog modules/mesh-issues, mesh-catalog modules/claude-code, mesh-catalog modules/messenger, mesh-sdk]
|
||||
updated: 2026-10-11
|
||||
updated: 2026-10-26
|
||||
decisions:
|
||||
- "ADR 0275"
|
||||
- "ADR 0278"
|
||||
@@ -13,6 +13,7 @@ decisions:
|
||||
- "ADR 0291"
|
||||
- "ADR 0294"
|
||||
- "ADR 0300"
|
||||
- "ADR 0493"
|
||||
---
|
||||
|
||||
# 53 — The issue tracker
|
||||
@@ -81,7 +82,10 @@ agent finds them with `mesh_search` ("open an issue") and calls them as `issue-t
|
||||
| `set` | a number and any of `severity`, `needs`, `suggested-owner` | changes them as a person decides (§ 10) |
|
||||
| `tracking` | optionally condition keys | for every condition key an issue links, the issues that link it and where each stands: status, needs, worker, fix (§ 12) |
|
||||
| `groom` | optionally `confirm` and a pass's id | the duplicate check over the backlog (§ 9): without `confirm`, starts a dry run in the background and answers its id; with the id alone, its progress and findings; with `confirm` and the id, applies exactly that pass's findings, each checked again |
|
||||
| `import` (slice 3) | optionally `dry-run`, a commit | reads every issue folder of hq through the records module and writes each as an issue at its own number; creates what is absent, fills a status the tracker holds empty, never overwrites, never advances the counter; run again, changes nothing and says so |
|
||||
| `import` (slice 3) | optionally `dry-run`, a commit, and `milestones` with a design's number | reads every issue folder of hq through the records module and writes each as an issue at its own number; creates what is absent, fills a status the tracker holds empty, never overwrites, never advances the counter; run again, changes nothing and says so. With `milestones`, it seeds that design's milestone records from its table instead (§ 13) |
|
||||
| `milestones` | optionally a design, a status, or one milestone as design/id | the milestone records, each with its issues and their count by status; one milestone with its issues' rows and its history (§ 13) |
|
||||
| `milestone-set` | a design, an id, an outcome, optionally an order, or `announce` | makes a milestone record, or changes its outcome or order; with `announce`, says the record again as its event (§ 13) |
|
||||
| `milestone-move` | a milestone as design/id, a status and a reason | opens or closes a milestone; closing is refused while an issue linked to it is neither resolved nor wontfix (§ 13) |
|
||||
|
||||
Each verb's description says in plain words what it does and what it refuses, without the mesh's internal names, so
|
||||
an agent picks the right one from `mesh_search` alone. A refusal says what was wrong and what would be accepted.
|
||||
@@ -100,8 +104,8 @@ the issue's worker, who works on it, as the worker states it
|
||||
- `located-in`: entries of the registered list of owners (repositories and modules), never free text;
|
||||
- `fixed-by` (pull requests or commits), `amended-design`, `replay` or `replay-none`, and a reason for `wontfix`;
|
||||
- `notes`: appended, each with who wrote it, when, and the text;
|
||||
- `links`, typed: to another issue (`duplicates`, `relates-to`), a pull request, a decision record, a design, a
|
||||
condition key (the issue **tracks** that condition, § 12) or a delivery;
|
||||
- `links`, typed: to another issue (`duplicates`, `relates-to`), a pull request, a commit, a decision record, a design,
|
||||
a condition key (the issue **tracks** that condition, § 12), a delivery, or the one milestone it belongs to (§ 13);
|
||||
- `documents`: the report, and a diagnosis and a resolution when written, each with its author and date, revised in
|
||||
place with its history kept (ADR 0291);
|
||||
- `record`: the path of the issue's folder in hq, while one exists; none is opened any more, and the folders are
|
||||
@@ -203,6 +207,7 @@ worker; one that stops moves the issue on, or is stale a day later.
|
||||
| The triage fills only what is empty, links no cycle, and an issue is ready only when its dependencies' fixes are delivered | the rows of ADR 0279's "How it is checked" |
|
||||
| The duplicate check acts only on a clear duplicate, never on an older or a resolved issue, once per issue, loudly when it cannot judge | the rows of ADR 0278's "How it is checked" |
|
||||
| An issue's documents are kept whole, with author, date and history, and the import of hq's folders loses nothing (ADR 0291) | the module's tests of `documents` and of the import, one case per document kind; the comparison of every issue with its folder before the folders are removed, written on issue 427. Tracked by issue 427 |
|
||||
| An issue belongs to at most one milestone, linked only by the verb, and only to an open one (ADR 0493 §2 to §4) | the module's table test of the `milestone` and `commit` link kinds, one case per refusal; the test that the triage and the duplicate check never add a `milestone`, `pull-request` or `commit` link; one integration test that starts the module whole on a real bus and makes, links and refuses |
|
||||
| Live | on the mesh, an agent calls `issue-tracker.open` and gets the next number; two sessions on two nodes open at the same moment and get two different numbers; `list` shows both |
|
||||
|
||||
## 8. The slices after the first
|
||||
@@ -312,6 +317,32 @@ with no pull request open is **abandoned**.
|
||||
**tracking line** in every condition's message; the words and the verdict it changes are its own (to-be 45 § 5).
|
||||
The controller learns nothing of issues.
|
||||
|
||||
## 13. Milestones
|
||||
|
||||
**A milestone is a record of the tracker, made from its design's table** (ADR 0493 §1). The state `milestones`, which the
|
||||
manifest declares beside `issues`, keeps one value per milestone, keyed by its design's number and its id: the id as the
|
||||
design's table writes it, the outcome, its order in the table, its status (`open` or `closed`, with a reason), who made
|
||||
and who last moved it and when, and the hq commit and path it was seeded from. It is written by compare-and-set at the
|
||||
revision read, and its history is the key's kept values with the events `milestone-set` and `milestone-moved`.
|
||||
|
||||
**An issue's milestone is the issue's own link, not a list on the milestone.** The link kind `milestone` (its target
|
||||
design/id, such as 47/R6) is written in the issue's log like any link, so the rule that an issue belongs to at most one
|
||||
milestone (ADR 0493 §2) is checked inside that issue's one write, refused naming the milestone it is in; a link to a
|
||||
milestone that does not exist or is closed is refused (§3: a fix found on the way joins the open milestone). A milestone's
|
||||
issues are read from the issues in memory. Pull requests and commits are linked to the issue they fix the same way, with
|
||||
the kinds `pull-request` and `commit` (§4); nothing reads them from a description, and the triage never adds one.
|
||||
|
||||
**The seed** is `import` with `milestones` and a design's number: it reads the table through the records module, makes
|
||||
each record that is absent in the table's order, links each issue it names that has no milestone, refuses (and names)
|
||||
an issue another milestone holds or two rows name, closes a milestone whose issues are all done (wontfix, or resolved
|
||||
with every live fix delivered, or resolved with no live fix) when it refused none of its row's issues, and run again
|
||||
changes nothing. Once a design is seeded, the tracker is the only list of its milestones'
|
||||
issues: the design's table keeps its rows without an Issues column, and the knowledge base's `progress` reads
|
||||
`milestones` (issue 1781).
|
||||
|
||||
Readiness, the one ask per milestone and its release are the delivery seat's (ADR 0493 §7 to §11, issue 1783); the
|
||||
tracker gives them the records and links they read.
|
||||
|
||||
## What it leaves out
|
||||
|
||||
Priorities beyond severity, notifications beyond the `ready` and `ready-to-verify` events and the stuck-fix warning, full-text or semantic search, the forge's own issue lists, and an index of any kind:
|
||||
|
||||
Reference in New Issue
Block a user