Compare commits

..
Author SHA1 Message Date
mesh-tools 4ebbefa3fc Merge main into feature 57's release branch, so it merges cleanly into main: playbooks 07 and 08 take main's #374 (feature 57)
mesh/merge-gate head 4ebbefa3fcad merged into trunk 110bb7d1d7e1 — pass: [release feat/57-config-and-provisioning, judged by its controller 6a6628a76961] t…
mesh/repo-check head 4ebbefa3fcad merged into trunk 110bb7d1d7e1 — pass: [release feat/57-config-and-provisioning, judged by its controller 6a6628a76961] i…
mesh/delivery stopped: the pull request closed unmerged
2026-10-16 08:22:43 +00:00
mesh-tools 110bb7d1d7 Merge pull request 'Feature 57 (config and provisioning): designs, playbooks and glossary words into the release branch' (#373) from 57-config-and-provisioning into feat/57-config-and-provisioning
mesh/merge-gate head 110bb7d1d7e1 merged into trunk c22b58143b74 — fail: head 110bb7d1d7e1 does not merge cleanly into trunk c22b58143b74: in conflict 00-M…
mesh/repo-check head 110bb7d1d7e1 merged into trunk c22b58143b74 — fail: head 110bb7d1d7e1 does not merge cleanly into trunk c22b58143b74: in conflict 00-M…
mesh/delivery-group group feat/57-config-and-provisioning rejected: a member's own check failed
mesh/delivery stopped: the pull request closed unmerged
2026-10-16 07:35:26 +00:00
mesh-tools 6be8f6eada Feature 57 (config and provisioning): the record of its designs, playbooks and glossary words, synced with main
mesh/merge-gate head 6be8f6eada67 merged into trunk b7e22be7f55f — pass: [release feat/57-config-and-provisioning, judged by its controller cf897e89fe31] t…
mesh/repo-check head 6be8f6eada67 merged into trunk b7e22be7f55f — pass: [release feat/57-config-and-provisioning, judged by its controller cf897e89fe31] i…
mesh/delivery delivered
2026-10-16 07:22:11 +00:00
mesh-admin b7e22be7f5 Merge pull request '57/F4: The glossary gains the words of config and provisioning (issue 653)' (#351) from pkg/57-f4-glossary-config-words into feat/57-config-and-provisioning 2026-10-13 23:56:11 +00:00
mesh-adminandClaude Opus 5.5 21508a7348 Answer review 237 of hq#351 (issue 653)
mesh/merge-gate head 21508a73483a merged into trunk fc9edd5c75b3 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 21508a73483a merged into trunk fc9edd5c75b3 — pass: its merge-check.sh passed
mesh/delivery delivered
The controller holds no config value (ADR 0348 section 9), so the record
mirror and the assignment no longer say it does. Name issue 683 for the
Not: line, quote the old word, add the alias identifiers, define trusted,
and add the homonym rows for managed and trusted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:53:25 +00:00
mesh-adminandClaude Opus 5.5 1f6d1b3005 Give the glossary the words of config and provisioning (issue 653)
mesh/merge-gate head 1f6d1b30053b merged into trunk fc9edd5c75b3 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 1f6d1b30053b merged into trunk fc9edd5c75b3 — pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
ADR 0348 makes config a domain of its own and ADR 0349 makes every value a
module needs a provision placed by mesh-provisioner, but the glossary had no
word for a config value, a predefined key, the provisioner client, a
collection or who owns a placed file. Add them in their domains, move
preference under Config, and use config value where the glossary itself said
setting. "setting" is not put on a Not: line: 67 documents in force still use
it in running prose, so retiring it now would fail words.py on all of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:45:31 +00:00
mesh-admin fc9edd5c75 Open the integration branch of release 57 (config and provisioning)
So the packages of design 57 meet here, reviewed one by one, and reach main as one delivery group.
2026-10-13 23:39:25 +00:00
6 changed files with 18 additions and 154 deletions
-4
View File
@@ -434,9 +434,6 @@ planner, the rollout). **Downstream of** Module, Core, Health and repair and Dat
- **delivery group** — two or more deliveries sharing a pull request head branch name across the mesh's - **delivery group** — two or more deliveries sharing a pull request head branch name across the mesh's
repositories, delivered as one unit in an order declared (`after:`) or inferred by the planner. One repositories, delivered as one unit in an order declared (`after:`) or inferred by the planner. One
level: a group holds deliveries, never groups. Its state is derived from its members, never set. level: a group holds deliveries, never groups. Its state is derived from its members, never set.
- **release branch** — a branch other than `main`, shared by name across repositories, that collects a feature's
merged work and is brought into `main` as one delivery (design 57's `feat/57-config-and-provisioning`). While it
is in flight, a change that touches its files waits for it (playbook 07, *Is the coast clear?*).
- **delivery plan** — what a delivery does to the mesh: its **build plan** (the modules it moves and - **delivery plan** — what a delivery does to the mesh: its **build plan** (the modules it moves and
their dependents, in tiers), its **deploy plan** (per node, what it receives and what waits for a their dependents, in tiers), its **deploy plan** (per node, what it receives and what waits for a
person) and its verdict (the composed nodes, the replays). Computed by the controller's planner from a person) and its verdict (the composed nodes, the replays). Computed by the controller's planner from a
@@ -755,7 +752,6 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| release | a person letting a held delivery go on | **release** | Change and delivery | | release | a person letting a held delivery go on | **release** | Change and delivery |
| | taking a consumer off a licence | **unbind** (verb `release`, to rename) | Identity and access | | | taking a consumer off a licence | **unbind** (verb `release`, to rename) | Identity and access |
| | a copy of a work an engine can fetch | **media release** | Media | | | a copy of a work an engine can fetch | **media release** | Media |
| | a branch brought into `main` as one delivery | **release branch** | Change and delivery |
| gate | the judgement on a delivery's first node | **first-node gate** | Change and delivery | | gate | the judgement on a delivery's first node | **first-node gate** | Change and delivery |
| | the pull request status | **merge gate** | Change and delivery | | | the pull request status | **merge gate** | Change and delivery |
| | a failed step stopping its module's later steps (ADR 0136) | *a failed step holds its module* | Placement | | | a failed step stopping its module's later steps (ADR 0136) | *a failed step holds its module* | Placement |
+4 -12
View File
@@ -63,20 +63,13 @@ An idea arrives in one of two forms, and the first step differs:
the reviews. the reviews.
- **Pre-check before proposing**, against what the review sends back most: every record, issue or design - **Pre-check before proposing**, against what the review sends back most: every record, issue or design
the text names is in `links`; work put off names the issue that tracks it (an acceptance test is not the text names is in `links`; work put off names the issue that tracks it (an acceptance test is not
put-off work: it is what the build proves, step 7); each figure is given as measured (a range, not a put-off work: it is what the build proves, step 6); each figure is given as measured (a range, not a
rounded claim); no word on a glossary *Not:* line. rounded claim); no word on a glossary *Not:* line.
- **Try at the cheapest level that answers the question.** A program's own behaviour (a library, a - **Try at the cheapest level that answers the question.** A program's own behaviour (a library, a
server, a protocol) is tried in process, on the machine's loopback, in minutes. Lab runs (about 12 to server, a protocol) is tried in process, on the machine's loopback, in minutes. Lab runs (about 12 to
16 minutes fresh) are for the mesh's own code; before that code exists, a lab run tests nothing an 16 minutes fresh) are for the mesh's own code; before that code exists, a lab run tests nothing an
in-process test does not, and its lab scenario is written as the build's acceptance test instead. in-process test does not, and its lab scenario is written as the build's acceptance test instead.
6. **Place it in the domains.** Before the direction, write `03-domains.md`: the domain or domains the idea 6. **Settle the direction with the operator.** When the questions are answered, write `05-direction.md`:
belongs to (the glossary's sections, ADR 0244); the modules and seats it lands in, each new, changed or
retired; what it does to each domain's words, each word added (with its domain and a one-line meaning),
changed or retired, and none on a *Not:* line or already meaning something else (the glossary's homonyms);
and whether a domain grows or shrinks, a concept moving between domains included. The direction names its
decisions in those words. Asked when the idea is set up, too: an option that lands a concept in the wrong
domain is offered with that cost named, like one that breaks a rule.
7. **Settle the direction with the operator.** When the questions are answered, write `05-direction.md`:
the proposed decisions in a few lines each, the options rejected and why, and the build's acceptance the proposed decisions in a few lines each, the options rejected and why, and the build's acceptance
tests: what the build must prove before it is done, carried by its milestones (playbook tests: what the build must prove before it is done, carried by its milestones (playbook
[04](04-build-handoff.md)). Nothing else is left open: each question closes by a test, by a decision the [04](04-build-handoff.md)). Nothing else is left open: each question closes by a test, by a decision the
@@ -91,8 +84,7 @@ An idea arrives in one of two forms, and the first step differs:
| reading and the setup questions (1, 2) | 30 minutes | the session's own, larger | | reading and the setup questions (1, 2) | 30 minutes | the session's own, larger |
| proposing (3, 4) | 15 minutes | larger | | proposing (3, 4) | 15 minutes | larger |
| each experiment or reading task (5) | 30 minutes | smaller, one agent at a time unless the operator allows more | | each experiment or reading task (5) | 30 minutes | smaller, one agent at a time unless the operator allows more |
| placing it in the domains (6) | 15 minutes | larger | | the direction (6) | 30 minutes | larger |
| the direction (7) | 30 minutes | larger |
A step past its bound is said to the operator at once, with what is being done about it. The lead reports A step past its bound is said to the operator at once, with what is being done about it. The lead reports
as playbook 07 does: every ten minutes and at once when something is found, stops or needs the operator, as playbook 07 does: every ten minutes and at once when something is found, stops or needs the operator,
@@ -132,7 +124,7 @@ and why, is the more expensive half to rediscover.
The rules on an effort are the knowledge base's: `propose` refuses one that breaks a rule that judges one The rules on an effort are the knowledge base's: `propose` refuses one that breaks a rule that judges one
record (the module's table test holds one case per rule), and the rules that judge the whole record set run record (the module's table test holds one case per rule), and the rules that judge the whole record set run
after every acceptance and raise a condition when one fails. The habits of steps 2, 5, 6 and 7 (options checked after every acceptance and raise a condition when one fails. The habits of steps 2, 5 and 6 (options checked
against the rules, one version per settled set, the cheapest level, nothing left open) are the lead's, read by against the rules, one version per settled set, the cheapest level, nothing left open) are the lead's, read by
the reviewer; of the pre-check, `propose` refuses a link to nothing and a retired word, and the review returns the reviewer; of the pre-check, `propose` refuses a link to nothing and a retired word, and the review returns
a record named but not linked, an untracked deferral and a figure not as measured. That this repository holds a record named but not linked, an untracked deferral and a figure not as measured. That this repository holds
+1 -6
View File
@@ -13,7 +13,7 @@ clauses in force for a topic or a record).
## Graduating research ## Graduating research
The effort's `05-direction.md`, confirmed by the operator (playbook [01](01-research.md), step 7), is what The effort's `05-direction.md`, confirmed by the operator (playbook [01](01-research.md), step 6), is what
graduates. The lead writes the records and the design on the larger model; it is one sitting, bounded at graduates. The lead writes the records and the design on the larger model; it is one sitting, bounded at
about an hour, and said to the operator if it runs past. about an hour, and said to the operator if it runs past.
@@ -48,11 +48,6 @@ about an hour, and said to the operator if it runs past.
The design lists the direction's acceptance tests: what the build proves before it is done. The design lists the direction's acceptance tests: what the build proves before it is done.
The words of the effort's `03-domains.md` go into the glossary in the same change, each in its domain: a
word added gets its entry, a word whose meaning changed gets its entry rewritten, and a retired word moves to
its replacement's *Not:* line. A word that already means something else in another domain is named as a
homonym with the qualified form each domain uses.
4. **Hand it to the work breakdown.** The design goes on through playbook [04](04-build-handoff.md): 4. **Hand it to the work breakdown.** The design goes on through playbook [04](04-build-handoff.md):
milestones, issues, and each milestone built as one feature step (playbook [07](07-feature-branches.md)). milestones, issues, and each milestone built as one feature step (playbook [07](07-feature-branches.md)).
5. **Close the effort.** `knowledge-base.propose` the effort again, whole, with `status: graduated` and a 5. **Close the effort.** `knowledge-base.propose` the effort again, whole, with `status: graduated` and a
+7 -68
View File
@@ -21,16 +21,6 @@ A small fix (one repository, one issue, about an hour of work) follows
undelivered for a day: an issue done at 21:09 was still not on the machines at 15:00 the next day. undelivered for a day: an issue done at 21:09 was still not on the machines at 15:00 the next day.
- **Work that waits and nobody notices.** Most lost time was not work at all, but a check, a delivery plan - **Work that waits and nobody notices.** Most lost time was not work at all, but a check, a delivery plan
or an agent waiting on something that had stopped, unseen. or an agent waiting on something that had stopped, unseen.
- **Review that keeps hardening.** One fix went through seven review rounds in five and a half hours, each
asking for more hardening than its issue asked (issue 704, 2026-10-14). A round is for what makes the
change wrong; everything else is an issue of its own.
- **The first check after the whole branch is written.** A feature's catalogue branch, pushed once after
hours of local work, met its first check on 2026-10-16 and failed on 29 problems, TypeScript errors among
them, that a unit suite run continuously while working finds at once.
- **A green pull request nobody marks.** An approved, green pull request that was not marked ready waited
12 h 17 min for someone to merge it (mesh-catalog #300, 2026-10-14).
- **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 ## The shape
@@ -114,40 +104,13 @@ never into the running one, unless it blocks the running one.
It says which round it is in ("round 1 of at most 3"). 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 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. with the context they already hold. Each answers the reviewer: what it changed, per finding, or why not.
4. **The reviewer reads the answers and the new commits**, and approves or reports again (step 5 says what a round 4. **The reviewer reads the answers and the new commits**, and approves or reports again. From round 2 it
may ask). After round 3 the lead stops and brings the operator what is left, with a recommendation. asks changes only for a finding that makes the feature wrong; smaller points become issues of their own.
5. **A finding outside the issues' done-when is never a change asked, in any round.** More hardening, a After round 3 the lead stops and brings the operator what is left, with a recommendation.
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
its issues and its decisions.
## Is the coast clear?
Before the push of phase 3 (and of a small fix, playbook [08](08-small-fixes.md) step 5), the lead checks, for every
repository the change touches, whether a **release branch** is in flight there: a branch other than `main` that
collects a feature's merged work to bring it into `main` as one delivery.
1. **Look for one.** A pull request into `main` whose head is a release branch (`gitea.gitea_open_pulls`), a
release branch holding merged work that `main` does not have yet (`git log origin/main..origin/<branch>`), or
a delivery plan of that release branch still running (`mesh-controller.plans`).
2. **Compare the files.** `git diff --name-only origin/main...origin/<release branch>` against the files the
change touches.
3. **Overlap: hold.** If the release branch touches a file the change touches, nothing is pushed into that repository
until the release branch's delivery plan is done. Then the feature branch is brought up to the new `main`, the unit
tests run again, and the push follows. The hold is on the wait list (its bound: the release branch's delivery plan),
and is said to the operator with what the change waits for.
4. **No overlap: go on.** A release branch in another repository, or one that shares no file with the change, does not
hold it; its merge joins the merge window as any other (ADR 0276).
Merging beside a release branch still in flight would make its lead resolve someone else's conflicts in the
middle of it, and could send part of the change with its delivery (2026-10-16: the file module's
controller part touched four files feature 57's release branch also changed).
## Phase 3 — Check (no review) ## Phase 3 — Check (no review)
1. **Push every feature branch and open one pull request per repository, together, once the coast is clear** 1. **Push every feature branch and open one pull request per repository, together.** Pull requests in two or
(above). The integration tests
run only in the merge check (the operator, 2026-10-16), never before. Pull requests in two or
more repositories that share the branch name are one delivery group (ADR 0239 §2). more repositories that share the branch name are one delivery group (ADR 0239 §2).
Where a session pushes through the forge tool `gitea_commit` (one commit on the forge's current base), the 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. reviewer first confirms that commit's tree equals the reviewed one.
@@ -155,14 +118,8 @@ controller part touched four files feature 57's release branch also changed).
second review: phase 2 reviewed this tree. second review: phase 2 reviewed this tree.
3. **A check that fails** goes back to the reviewer with the failure, for **one more cycle** of phase 2 with 3. **A check that fails** goes back to the reviewer with the failure, for **one more cycle** of phase 2 with
the same fixing agents; then push once again. the same fixing agents; then push once again.
4. **The step's acceptance is proven before it is marked ready.** A step that adds or changes a module 4. **Mark each pull request ready** (`mesh/ready` and a comment `ready at <full sha>`) once the operator's word
carries an integration test that starts the module whole, its process against the real bus and store, and for the feature is given; mesh-delivery merges it when its checks pass (ADR 0364).
shows the step's acceptance sentence; the forge's checks run it (ADR 0391 §1, §6). Unit tests alone are not
that proof; the mesh has no end-to-end tests yet, and the lab is not used (the operator, 2026-10-16).
5. **The reviewer marks each pull request ready as soon as the acceptance is shown** (`mesh/ready` and a
comment `ready at <full sha>`, the head it approved); mesh-delivery merges it when its checks pass
(ADR 0364). The operator's word is waited for only when the step changes what the operator sees, removes
data, or needs a step only the operator's terminal can take; the lead says which before the step starts.
**One exception: a catalogue change that uses a new manifest word.** The catalogue's merge check reads **One exception: a catalogue change that uses a new manifest word.** The catalogue's merge check reads
manifests with the controller the mesh runs, so the controller's pull request is merged and delivered first; manifests with the controller the mesh runs, so the controller's pull request is merged and delivered first;
@@ -170,8 +127,7 @@ then `mesh-delivery.recheck` the catalogue's and merge it on the new verdict. Pl
## Phase 4 — Deliver ## Phase 4 — Deliver
The merge starts the delivery plan: build, publish, send. A merge into a branch other than `main` is not a The merge starts the delivery plan: build, publish, send. The lead follows it to done
delivery: no machine receives it (issue 889 while it still starts one). The lead follows it to done
(`mesh-controller.plans` with `wait` and `until: done`), then resolves the feature's issues with `fixed-by` (`mesh-controller.plans` with `wait` and `until: done`), then resolves the feature's issues with `fixed-by`
naming its pull requests, and removes what is left: no `feat/<slug>` branch and no `.work/<slug>` worktree naming its pull requests, and removes what is left: no `feat/<slug>` branch and no `.work/<slug>` worktree
survive. survive.
@@ -200,8 +156,6 @@ on, with when it started and its bound.
| a fixing agent's issue | 30 minutes | ask it where it stands; split or take over | | 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 | | the review | 15 minutes a round | ask the reviewer; stop at round 3 |
| a merge check | 15 minutes | read the build queue (`mesh-controller.queue`) and the check's log | | a merge check | 15 minutes | read the build queue (`mesh-controller.queue`) and the check's log |
| the ready mark | 15 minutes after the acceptance is shown | the reviewer marks it, or the lead does |
| a release branch in flight that shares files | its delivery plan done | report it every ten minutes; bring the branch up to `main` after |
| a merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery | | a merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery |
| a delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` | | a delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` |
@@ -246,13 +200,6 @@ lead prepares a `/clear` as the mesh's instruction "prepare before clear" says:
feature's phase, its branches and heads, the context files' paths, the agents' ids, the wait list and the feature's phase, its branches and heads, the context files' paths, the agents' ids, the wait list and the
next action; then the prompt the operator pastes. The context files make the feature resumable after a clear. next action; then the prompt the operator pastes. The context files make the feature resumable after a clear.
## Issues that stop
An issue stays in `fixing` only while an agent works on it. A step that stops, for a wait past its bound, a
hand-over, or the session's end, moves each of its issues not delivered back to `open` with
`issue-tracker.move` and a note saying how far it got (its branch, its last commit, what is left). A list of
issues in `fixing` that nobody works on reads to the operator as stuck work.
## How it is checked ## How it is checked
- A feature's issues show their commits on the feature branch (`git log --grep 'issue <n>'`), and no pull - A feature's issues show their commits on the feature branch (`git log --grep 'issue <n>'`), and no pull
@@ -262,14 +209,6 @@ issues in `fixing` that nobody works on reads to the operator as stuck work.
- After a feature's delivery, `git branch -r | grep feat/<slug>` and `git worktree list` return nothing for it. - After a feature's delivery, `git branch -r | grep feat/<slug>` and `git worktree list` return nothing for it.
- More than one open pull request in a repository that share no feature name, or a feature step whose issues - More than one open pull request in a repository that share no feature name, or a feature step whose issues
stay in `fixing` for more than a working day, is the smell: stop and bring it to the operator. stay in `fixing` for more than a working day, is the smell: stop and bring it to the operator.
- A review report that asks a change outside the issues' done-when, or a fourth round, is the failure of the
review rules; `issue-tracker.list` with `flag: abandoned` lists issues left in `fixing` with nobody on them.
- A pull request reviewed and green but not marked ready for more than 15 minutes is a lead that did not
mark it.
- A pull request opened into a repository whose release branch was in flight and shared a file with it is the failure of
*Is the coast clear?*; the lead's report names the check it made before the push.
- A step that adds or changes a module marked ready with no integration test that starts the module whole is
the failure of phase 3's fourth step.
- A bed run from `.work/<slug>/mesh-lab` that fails naming a `.work/<slug>/<repo>/…` path it cannot find is a - A bed run from `.work/<slug>/mesh-lab` that fails naming a `.work/<slug>/<repo>/…` path it cannot find is a
missing sibling worktree, not a mesh fault. missing sibling worktree, not a mesh fault.
+5 -22
View File
@@ -31,34 +31,22 @@ one delivery**. Everything before the push is local and fast.
Commit, naming the issue. For a playbook or design edit, run the repository's own checks (in hq, Commit, naming the issue. For a playbook or design edit, run the repository's own checks (in hq,
`sh merge-check.sh`). `sh merge-check.sh`).
4. **One review of the local commit, before anything is pushed** (a reviewer that did not write it, larger 4. **One review of the local commit, before anything is pushed** (a reviewer that did not write it, larger
model; at most 3 rounds, as playbook 07; from round 2 only what is wrong; a finding outside the issue's model; at most 3 rounds, as playbook 07; from round 2 only what is wrong). The reviewer's findings go back to the same agent that wrote the fix, continued by
done-when 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
its id, so the fix keeps its context. A playbook or design edit of a few lines may skip the reviewer: the its id, so the fix keeps its context. A playbook or design edit of a few lines may skip the reviewer: the
operator's word on the pull request is its review, and the lead marks it ready on that word. operator's word on the pull request is its review.
5. **Push once and open the pull request, once the coast is clear** (playbook [07](07-feature-branches.md), *Is 5. **Push once and open the pull request.** The forge's merge checks run the integration tests. A failed check
the coast clear?*: no release branch in flight in the repository that shares a file with the fix). The forge's merge
check runs the integration tests, the only
place they run (the operator, 2026-10-16). A failed check
goes back to the same agent with the failure, and the reviewer reads only the change it makes. goes back to the same agent with the failure, and the reviewer reads only the change it makes.
6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the 6. **Mark it ready** (`mesh/ready` and `ready at <full sha>`) once the operator's word is given; mesh-delivery
operator's word) (`mesh/ready` and `ready at <full sha>`, the head it approved); merges it when its checks pass.
mesh-delivery merges it when its checks pass. A fix to a module that changes how it runs carries an
integration test starting the module whole against the real bus and store, run by the forge's checks
(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.
7. **Follow its delivery plan to done** (`mesh-controller.plans` with `wait` and `until: done`), prove the fix on 7. **Follow its delivery plan to done** (`mesh-controller.plans` with `wait` and `until: done`), prove the fix on
the mesh (the symptom gone, measured), and resolve the issue with `located-in` and `fixed-by` the same hour. the mesh (the symptom gone, measured), and resolve the issue with `located-in` and `fixed-by` the same hour.
A fix that stops before its delivery moves its issue back to `open` with a note saying how far it got
(branch, last commit, what is left), as playbook [07](07-feature-branches.md) says.
## Bounds ## Bounds
| Waiting on | Bound | Past the bound | | Waiting on | Bound | Past the bound |
|---|---|---| |---|---|---|
| building the fix | 1 hour | it is a feature: stop and plan it under playbook 07 | | building the fix | 1 hour | it is a feature: stop and plan it under playbook 07 |
| the review | 15 minutes | ask the reviewer where it stands | | the review | 15 minutes | ask the reviewer where it stands |
| the ready mark | 15 minutes after the review approved | the reviewer marks it, or the lead does |
| the merge check | 15 minutes | read `mesh-controller.queue` and the check's log | | the merge check | 15 minutes | read `mesh-controller.queue` and the check's log |
| the merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery | | the merge after ready | 5 minutes after the checks pass | read `mesh-delivery.show` for the delivery |
| the delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` | | the delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` |
@@ -75,8 +63,3 @@ 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 - A small fix has one pull request with one or few commits naming its issue, opened after its review: a pull
request with many heads is a fix reviewed after its push. request with many heads is a fix reviewed after its push.
- Its issue moves to `resolved` within the hour its delivery plan ends. - Its issue moves to `resolved` within the hour its delivery plan ends.
- A pull request reviewed and green but unmarked
for more than 15 minutes, a fix to a module's running marked ready with no integration test of the module whole, or a review report
asking a change outside the issue's done-when, is the failure of steps 4 to 6.
- An issue in `fixing` with nobody on it shows in `issue-tracker.list` with `flag: abandoned`; a stopped fix
moves it back to `open` with its note.
@@ -2,9 +2,8 @@
layer: to-be layer: to-be
status: in-progress status: in-progress
code: [mesh-host, mesh-controller, mesh-catalog] code: [mesh-host, mesh-controller, mesh-catalog]
updated: 2026-10-16 updated: 2026-10-12
decisions: decisions:
- "ADR 0394"
- "ADR 0310" - "ADR 0310"
- "ADR 0268" - "ADR 0268"
- "ADR 0252" - "ADR 0252"
@@ -91,7 +90,6 @@ WP5 assign and prove (operator-gated) needs WP
WP6 a module puts the account in a group (mesh-host, mesh-controller, mesh-catalog) issue 247 WP6 a module puts the account in a group (mesh-host, mesh-controller, mesh-catalog) issue 247
WP7 the control-node withholds execute (mesh-controller, mesh-catalog) ADR 0268 WP7 the control-node withholds execute (mesh-controller, mesh-catalog) ADR 0268
WP8 a node's files and accounts are read (mesh-sdk, mesh-catalog, mesh-controller) ADR 0310, issue 418 WP8 a node's files and accounts are read (mesh-sdk, mesh-catalog, mesh-controller) ADR 0310, issue 418
WP9 every file on a node is managed (mesh-catalog, mesh-controller) ADR 0394, issue 900
``` ```
WP1, WP2 and WP4 are independent, and are built in parallel on one feature branch per repository WP1, WP2 and WP4 are independent, and are built in parallel on one feature branch per repository
@@ -343,10 +341,6 @@ out, the control-node's value is set to `withhold` and zsh is pushed to it. Then
*`mesh-sdk`, `mesh-catalog`, `mesh-controller`. ADR 0310, extending ADR 0268; tracked by issue 418.* *`mesh-sdk`, `mesh-catalog`, `mesh-controller`. ADR 0310, extending ADR 0268; tracked by issue 418.*
**Replaced by WP9.** ADR 0394 supersedes ADR 0310: `node-files` takes over every read below, with the same
bounds, content rule and refusal of secret places; once `node-files` is held on every node, the next delivery
removes `node-reads` and `mesh-reads`.
ADR 0268 §5 has narrow read tools take the common reads over from `execute`, so that an approval is asked for an ADR 0268 §5 has narrow read tools take the common reads over from `execute`, so that an approval is asked for an
act and not for a read, and ADR 0286 §44 sets the approval mark on `execute` only once those reads have a tool on act and not for a read, and ADR 0286 §44 sets the approval mark on `execute` only once those reads have a tool on
every node. Two had none: reading or searching a file, and looking up an account or a group. every node. Two had none: reading or searching a file, and looking up an account or a group.
@@ -372,38 +366,3 @@ under the same issue.
`mesh-sdk` test of the content rule and one in each of its users; `mesh_search` for `cat`, `grep` and `mesh-sdk` test of the content rule and one in each of its users; `mesh_search` for `cat`, `grep` and
`getent passwd` finding the verbs. Live, the kernel's RAID status file is read through the seat on the home `getent passwd` finding the verbs. Live, the kernel's RAID status file is read through the seat on the home
server, and the agent's credentials file on the laptop is refused. server, and the agent's credentials file on the laptop is refused.
## WP9 — Every file on a node is managed through `node-files`
*`mesh-catalog`, `mesh-controller`. ADR 0394; tracked by issue 900.*
`node-reads` only reads, and as an account that cannot open a person's home, so nothing in the mesh could copy,
move, write or delete a file, and a cleanup needed a shell on the machine. Most files belong to no module: homes,
project folders, downloads, logs, scratch.
- **A node seat, `node-files`, on every node**, held by a module of its own, `mesh-files`, beside `mesh-reads`
in the catalogue; the controller holds the seat's definition beside the other node seats. It has a verb for each file action: list,
stat, readlink, read, search, write, copy, move, delete, make a folder, change mode, change owner, account and group
lookup, and the trash's list and restore. Each says what it replaces (ADR 0245): `ls`, `stat`, `readlink`, `cat`,
`grep`, `cp`, `mv`, `rm`, `mkdir`, `chmod`, `chown`, `getent passwd`, `getent group`, `id`, and `ssh <node> cp` for a
copy between nodes.
- **It may touch every file.** It declares no account of its own: the tool runner starts it as the node's
operator account, which has sudo without a password, and it uses `sudo -n` only where that account's own rights
do not reach. It keeps each file's owner and modes as well as it can: a copy or a move keeps them, a new file
takes its folder's owner. Which files to touch is the caller's responsibility; it judges no permission.
- **Nothing is lost at once.** A file deleted or overwritten goes to the node's trash with who asked and why, is
restorable for 7 days, and is emptied after.
- **A path a module owns is refused**, naming the module and its tool, unless the call says `override` with a
reason; an override is recorded and said to the operator.
- **It replaces `node-reads`.** Its reads keep WP8's bounds, content rule and kernel reads. Every node is
assigned `mesh-reads`, so `node-reads` and `mesh-reads` are removed by the next delivery, once `mesh-files`
holds `node-files` on every node.
- **No Approve is asked**; every act is recorded with its caller. Read and search never return the content
of a known credential file or a secret place (the mesh never prints a token); copying or moving one is
allowed.
**Proof.** The module's tests: each verb against a temporary tree keeps owner and modes, a new file takes its
folder's owner, a delete is restorable from the trash and gone after 7 days, an owned path is refused and an
override recorded, a credential file's content is never returned. Live: the operator's `~/.claude` on a workstation is listed, a file in `/etc` is read through sudo, and a file copied from one node to another
arrives with its owner and modes.