From 8f8f1b4337b2e677312a28e2da7e886a5ac64d32 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 02:44:15 +0200 Subject: [PATCH 01/23] Design 58: agent work as the mesh's own, graduated from research 053 with ADR 0383 to ADR 0390 Threads on the bus, a headless thread handler in a sandbox per session, a workspace toolkit with no general command runner, one identity seat, effects on every tool, signed bus logins and the switch to them; names the build's acceptance tests for the milestones. --- .../58-agent-work-as-the-meshs-own.md | 155 ++++++++++++++++++ 03-DESIGN/01-to-be/README.md | 1 + 2 files changed, 156 insertions(+) create mode 100644 03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md new file mode 100644 index 00000000..84af84f3 --- /dev/null +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -0,0 +1,155 @@ +--- +layer: to-be +status: designed +code: [] +updated: 2026-10-16 +decisions: + - "ADR 0383" + - "ADR 0384" + - "ADR 0385" + - "ADR 0386" + - "ADR 0387" + - "ADR 0388" + - "ADR 0389" + - "ADR 0390" +--- + +# 58 — Agent work as the mesh's own + +**An agent's work belongs to the mesh, not to one vendor's program or one machine. A thread is kept whole on the +bus by a thread seat; a thread handler on an always-on node runs the agent's harness headless for it, in a sandbox +of its own, with the thread's own branch on the forge as its workspace; the agent works through a workspace toolkit +and named tools, never a general command runner. Every person, agent and module is an identity held by one identity +seat, with a role made of grants; the bus checks each login by its signature, and the tool runner checks each call +against the role, tool by tool, by the effect every tool carries.** +(ADR 0383 to ADR 0390, from research 053.) + +**Acceptance.** The operator starts a thread from the terminal client, an agent on an always-on node works it in a +sandbox, asks a question the operator answers in place, and the thread moves to another node and carries on with +nothing lost; the agent's calls outside its role are refused, saying which grant is missing. + +## 1. The parts + +``` + any node always-on nodes the control-node + ───────── ─────────────── ──────────────── + front ends nox-thread-handler nox-threads (seat thread) + ├ terminal client (first) ├ takes a thread's lease ├ a restricted stream per thread + ├ web page (then) ├ runs the harness headless ├ the object store for large content + └ Telegram: questions, │ inside a microsandbox └ leases in the bus's key-value store + approvals ├ answers permission requests + │ │ through the mesh's asks identity seat + │ └ commits + pushes the workspace ├ persons, agents, modules, roles + │ branch every turn │ in the bus's key-value store + │ nox-workspace (node seat workspace) ├ signs logins (one key per role) + │ └ read, glob, search, edit, write, └ revokes over the bus, reads back + │ git, named tools; no command runner + │ claude-code + │ ├ mirrors a session into its thread + │ ├ rebuilds a session on pick-up + │ └ writes the login and licence token + │ into the sandbox + └──────────────── every call over the bus, carrying its thread and, + for a module acting for an agent, the agent's token +``` + +## 2. Threads (ADR 0383) + +A **thread** is one piece of agent work, kept as a stream on the bus in the mesh's own format. The stream is the +source of truth: the conversation, the agent's questions and their answers, tool calls and results, usage, and +every change of state. Large content goes to the object store and is named from the stream. The stream is +restricted (ADR 0376): only modules granted it read it. A thread is never deleted; the trail is kept for good. + +A thread is **open**, **assigned** (to a node and a harness), **released** or **stopped**. Its seat's verbs create, +assign, release, stop, move it, and take it over with a reason. The assignment is a **lease** in the bus's +key-value store, changed only by a compare-and-set on its revision. Its holder renews it every 20 s. A lease not +renewed for 60 s is said to the operator; nothing takes it over by itself. + +## 3. Running a thread (ADR 0384) + +The thread handler on an always-on node takes the lease and starts the harness (Claude Code today) headless, one +turn at a time. It answers the harness's permission requests through the mesh's asks, so a front end answers them in +place. At the end of every turn it commits and pushes the workspace, which is the thread's own branch on the forge; +a node that picks the thread up fetches it, so a move loses at most the turn in progress. Before a shutdown it +releases at a turn boundary; on a stop it ends the process group, since a tool's child process outlives the harness. + +The claude-code module mirrors the session's stream into the thread and, on pick-up, rebuilds a session from the +thread. Usage per thread comes from each run's result and rate-limit messages on the stream, not the transcript, and the +licence manager records it with the thread as its session. + +The front ends are clients of a thread doing the same work: the terminal client first, then the web page, and +Telegram for questions and approvals. Their first scope is the conversation as it streams, the agent's questions and +permission requests answered in place, sending a message and stopping a turn. The rest is tracked by issue 850. + +## 4. The workspace toolkit (ADR 0385) + +The node seat `workspace`, held by `nox-workspace` on every thread-handler node and served through the mesh's MCP +server, works in the thread's workspace only, by relative path: read, glob, regex search, edit, write, git, and named +tools such as running the repository's tests and its merge check. It is built early. There is no general command +runner in it, and no module offers one to an agent: a command an agent needs becomes a named tool in the module that +owns it. Claude Code's own built-in tools, its command tool included, are turned off once the toolkit is in. + +## 5. Identities and roles (ADR 0386) + +The identity seat, held once for the mesh, owns every **identity** (a person, an agent or a module) and every +**role**, in the bus's key-value store. An identity has a name, a kind, a role and whether it is switched on. They +change only through the seat's verbs, each recorded with who asked; anything may watch the store live. Only the +operator creates a person or an agent, or changes its role. A module's identity is asked for by the controller when +the module is assigned to a node, named by machine and module, with a role made from what its manifest declares it +calls. + +A role holds **grants**. A grant is an effect everywhere, an effect on one seat, or one named tool, and may be +limited to named machines. Two fences check them: the bus, coarsely, by seat and module, from the role's signing +key; and the tool runner, exactly, tool by tool, in the SDK. Every call carries its thread; a module acting for an +agent carries a token the identity seat signed for that agent, and the tool runner then checks the agent's role. A +refusal names the missing grant; every call is recorded with its identity and thread. + +## 6. Effects, asks and break-glass (ADR 0387) + +Every seat verb and module tool is one permission and carries one **effect**, set in its module's manifest: +**reads**, **acts** or **dangerous**. The catalogue's check refuses an unmarked tool, once every module already in +the catalogue is marked. A dangerous tool is granted only by name, and naming one in a role goes to the operator as +an ask first. Every other dangerous act is an ask (ADR 0259), bound to that act and carried out on the warrant. + +The **break-glass** agent holds every tool and never asks. It is sealed until the operator opens it, or a condition +the operator has named as opening it is raised (none is named at the start); it stays open until the operator closes +it, and every act it takes is said to the operator at once. A tool served without an effect, from a module built +before its mark, counts as dangerous. + +## 7. Signed logins on the bus (ADR 0388) + +The bus checks each login by its signature and reads no list. The root key is sealed in the vault and used only to +replace the identity seat's signing keys, on the operator's Approve. The seat signs with one scoped signing key per +role, so every login stays small and each identity gets its own inbox from the role's template. An agent's login +lives minutes, a module's and a node's hours; each is renewed by a reconnect forced before expiry, by the handler or +the node-engine. + +A switched-off identity is revoked over the bus. The seat reads back every update, sends updates at least a second +apart, and resends the current state to every server id it has not seen on the system account, which every joined +server carries. This changes ADR 0106's rule that the bus is configured only through its settings file. + +## 8. The switch (ADR 0389) + +A new bus with signed logins runs beside today's, joined as a leaf node carrying the system account. Identities move +one at a time, each checked before the next. Streams, key-value buckets and the object store move last, each by a +copy of its whole configuration: copy, wait for equal counts, stop its writers, then one update hands the addresses +over. Today's bus is switched off when nothing is left on it. + +## 9. Sandboxes (ADR 0390) + +Each session runs in a microsandbox of its own, its version pinned and declared in a module. The workspace is +mounted; the claude-code module writes in the agent's login and the licence token without its refresh part, and +replaces the token as the licence manager refreshes it. Connections are allowed only to the vendor's interface, by +address range, and to the bus. A node whose KVM modules are not loaded gets them from the sandbox module. + +## 10. The build's acceptance tests + +The build is not done until each of these has been shown, and the milestones of the work breakdown (playbook 04) +carry them: + +1. A licence token replaced under a running session keeps that session working. +2. The sandbox module loads KVM on the home server, and a sandbox runs there. +3. Every existing module's tools carry an effect, and the catalogue's check refuses an unmarked one. +4. The switch, run on the mesh's own modules in the lab from the bed test kept on the lab's branch + `research/053-signed-bus-logins`, loses nothing and leaves every identity on the new bus. +5. The acceptance sentence at the top, end to end. diff --git a/03-DESIGN/01-to-be/README.md b/03-DESIGN/01-to-be/README.md index 95b3e4da..d8fe9fc8 100644 --- a/03-DESIGN/01-to-be/README.md +++ b/03-DESIGN/01-to-be/README.md @@ -57,6 +57,7 @@ document is written and this one's status becomes `implemented`. | [`55-the-knowledge-base.md`](55-the-knowledge-base.md) | **Designed.** The mesh keeps its decision records and research efforts whole in one module, `mesh-knowledge`, on the control-node: number, status, topic, typed links both ways, each decision's clauses with their own status, and the reasoning, with every version; a record is proposed, checked at the write, reviewed by the knowledge base's own judgement and accepted there, with the operator's Approve when it needs it; agents ask what holds in one bounded call | ADR 0290 | | [`56-the-mail-client-set-up-by-the-mesh.md`](56-the-mail-client-set-up-by-the-mesh.md) | **Designed.** On every node with a display server, the `betterbird` module installs Betterbird from a pinned upstream release mirrored into the artifact store, ships the Owl add-on pinned and installed by Betterbird's enterprise policy, and declares the operator's mail accounts in a trusted setting without credentials; each account signs in once at a person's first use, and one the profile already holds is adopted by its address | ADR 0316, ADR 0317 | | [`57-building-config-and-provisioning.md`](57-building-config-and-provisioning.md) | **Designed.** The work of ADR 0348 and ADR 0349 as 37 packages, each an issue with its proof: foundations, template files, config in its own module, the provisioner and its client, secrets in the vault, bindings from providers, collections, a module's runtime readers, and removing the old forms; at most five worked at once | ADR 0348, ADR 0349 | +| [`58-agent-work-as-the-meshs-own.md`](58-agent-work-as-the-meshs-own.md) | **Designed.** Agent work as the mesh's own: a thread seat keeps every thread whole on the bus; a thread handler runs the harness headless in a sandbox per session, the workspace on the thread's own forge branch; a workspace toolkit and named tools, no general command runner; one identity seat for persons, agents and modules, roles of grants, every tool an effect, signed bus logins, and the switch to them one identity at a time | ADR 0383, ADR 0384, ADR 0385, ADR 0386, ADR 0387, ADR 0388, ADR 0389, ADR 0390 | ## Not yet written From cb4c18cedcf04a710c68114dcaa54482e8c9afcd Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 02:45:58 +0200 Subject: [PATCH 02/23] Design 58: the identity store is read by grant, and sessions never call through the tool runner's login (review round 1) --- 03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md index 84af84f3..cfae3781 100644 --- a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -93,7 +93,8 @@ owns it. Claude Code's own built-in tools, its command tool included, are turned The identity seat, held once for the mesh, owns every **identity** (a person, an agent or a module) and every **role**, in the bus's key-value store. An identity has a name, a kind, a role and whether it is switched on. They -change only through the seat's verbs, each recorded with who asked; anything may watch the store live. Only the +change only through the seat's verbs, each recorded with who asked; a module or front end whose role grants the +seat's reads may watch the store live, and it holds no secret. Only the operator creates a person or an agent, or changes its role. A module's identity is asked for by the controller when the module is assigned to a node, named by machine and module, with a role made from what its manifest declares it calls. @@ -102,7 +103,8 @@ A role holds **grants**. A grant is an effect everywhere, an effect on one seat, limited to named machines. Two fences check them: the bus, coarsely, by seat and module, from the role's signing key; and the tool runner, exactly, tool by tool, in the SDK. Every call carries its thread; a module acting for an agent carries a token the identity seat signed for that agent, and the tool runner then checks the agent's role. A -refusal names the missing grant; every call is recorded with its identity and thread. +refusal names the missing grant; every call is recorded with its identity and thread. A session on an operator's +machine calls as the operator's person identity or as an agent, never through the machine's tool-runner login. ## 6. Effects, asks and break-glass (ADR 0387) From 535fd8bb549844d04a876b8b0e2fc66a8bbe58ca Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 02:47:48 +0200 Subject: [PATCH 03/23] Glossary: the words of research 053's graduation, and harness and role as homonyms Playbook 02 adds a graduated effort's words; design 58 now says agent harness, never the bare word. --- 00-META/glossary.md | 53 +++++++++++++++---- .../58-agent-work-as-the-meshs-own.md | 12 ++--- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/00-META/glossary.md b/00-META/glossary.md index c64dad16..47773150 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -101,8 +101,8 @@ are a published vocabulary, fixed by the manifest's schema. **Decided by** ADR 0 (ADR 0188). - **tool** — one capability a module serves through the tool runner, addressed `.`. A seat's **verb** is the same thing carried by a seat rather than a module. -- **mesh-sdk** — the library a module's own code is written against, including the harness that serves a - tools bundle to the tool runner. The harness is part of it, not a library of its own. +- **mesh-sdk** — the library a module's own code is written against, including the SDK harness that serves a + tools bundle to the tool runner. The SDK harness is part of it, not a library of its own. *Not:* ~~tools-sdk~~ - **invokes** — the manifest word for the tools a module calls, `.` each or `*` for every one. A grant on the publish side and nothing else; a module that declares none calls nothing. @@ -270,8 +270,8 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 **Purpose.** To issue, hold, rotate and check the credentials and grants by which modules, nodes, agents and the operator act. **Recorded by** the controller's `identity` and `licences` databases and the vault. **Upstream of** Provisioning, Change and delivery, and Operator and conversation. -**Decided by** ADR 0085, 0113, 0183, 0225, 0234. -**Uses:** module, node, operator, consumer (Provisioning). +**Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388. +**Uses:** module, node, operator, consumer (Provisioning), agent (Operator and conversation), tool (Module). - **credential** — anything that proves an identity: a password, a key, a token. A **pair credential** is the two ends of one credential, the consumer's and the provider's. @@ -283,8 +283,24 @@ and the operator act. **Recorded by** the controller's `identity` and `licences` (ADR 0283). - **vault** — the module that owns every secret (`mesh-vault`, [24 — The secrets vault](../03-DESIGN/01-to-be/24-the-secrets-vault.md)). -- **grant** — what an identity may call or reach, bounded by the provisions it requires - (ADR 0225). +- **identity** — a person, an agent or a module as the mesh knows it: a name, a kind, a role, and whether it + is switched on. Every identity and role is held by the identity seat, in the bus's key-value store, and + changes only through its verbs (ADR 0386). +- **role** — what an identity may call, as a set of grants (ADR 0386). Not a seat: a bare *role* is a + homonym (see [Homonyms](#homonyms)). +- **grant** — one line of a role: an effect everywhere, an effect on one seat, or one named tool, and may be + limited to named machines; a dangerous tool is granted only by name (ADR 0386). A module's grants + come from what its manifest declares it calls, bounded by the provisions it requires (ADR 0225). +- **effect** — a tool's mark, set by its module in its manifest: **reads**, **acts** or **dangerous**; a + tool served without one counts as dangerous (ADR 0387). +- **break-glass agent** — the one agent that holds every tool and never asks: sealed until the operator, or + a condition the operator named, opens it, open until the operator closes it, and every act it takes told + at once (ADR 0387). +- **signed login** — a bus login signed by a key the bus trusts, carrying its expiry, which the bus checks by + its signature instead of reading a list (ADR 0388). The identity seat signs with one **signing key** per + role. +- **root key** — the key at the top of the signed logins, which vouches for the signing keys: sealed in the + vault and used only to replace them, on the operator's Approve (ADR 0388). - **bus account** and **membership** — a module's or a node's account on the bus, and the subjects it is issued. The bus server calls its accounts *users*; the mesh says bus account. - **rotate** — replacing a credential without a consumer holding one the provider does not know. @@ -503,7 +519,7 @@ it should not. **Recorded by** the controller. **Upstream of** Provisioning and trust. **Recorded by** the router (asks, warrants and the operator's identities). **Downstream of** Health and repair, Change and delivery, and Identity and access. An authorising answer acts in whichever domain asked, through that domain's own verb; the conversation owns the -asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272. +asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 0384, 0385, 0390. **Uses:** operator, person, proof (Identity and access), release (Change and delivery). - **mesh MCP server** — the endpoint on a node's loopback through which every agent and person on that @@ -559,8 +575,21 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272. instructions. - **reference** — an opaque token in a message's words standing for a detail the content rule keeps out of them (a path, an address); opened with `detail` only on a `private` channel or through the mesh MCP server. -- **agent** — a coding agent: the operator's, or one the mesh runs. Not the node-engine, and not the +- **agent** — a coding agent: the operator's, or one the mesh runs; to the mesh, an identity of kind agent + (ADR 0386). Not the node-engine, and not the build seat's holder, whose seat name `node-build-agent` is an identifier to rename. +- **thread** — one line of agent work, owned by the mesh: its turns, tool calls and results, its workspace + and usage, kept whole for good on the bus by the thread seat; it outlives any session, node or front end + (ADR 0383). +- **session** — one run of an agent harness on a thread. +- **agent harness** — the program that runs an agent's sessions, its context manager and loop: Claude Code + today (ADR 0384). Not the SDK harness (see [Homonyms](#homonyms)). +- **thread handler** — the node seat whose holder runs threads' sessions headless, on the always-on nodes + (ADR 0384). +- **workspace toolkit** — the tools a session works with on its thread's workspace, the same for every agent + harness: the node seat `workspace` (ADR 0385). +- **sandbox** — the small virtual machine one session runs in, with its thread's workspace mounted + (ADR 0390). - **instruction section** — one named section of the managed instruction file, which every agent session on the nodes it is for reads first, as the mesh's word: set at the controller's terminal in the agent module's settings, or **proposed** by an agent and made active on each node only by the operator's warrant, which that node @@ -624,7 +653,7 @@ Not a domain of the mesh but of the way it is built, listed because its words me `changed`, `superseded`): a later record may change one clause and leave the rest (ADR 0290). Not a *rule*, which is a line of `00-META/how-we-build.md`. -- **knowledge base** — the role that holds the decision records and research efforts whole (number, status, topic, +- **knowledge base** — what holds the decision records and research efforts whole (number, status, topic, typed links, clauses and reasoning, with every version), takes them as proposals, has them reviewed and accepted, and answers what holds: the seat `knowledge-base`, held by the module `mesh-knowledge` ([55 — The knowledge base](../03-DESIGN/01-to-be/55-the-knowledge-base.md)). Not **the record**, the literal reader @@ -634,7 +663,7 @@ Not a domain of the mesh but of the way it is built, listed because its words me holds it whole: its report, diagnosis and resolution included (ADR 0291); the folders in `04-ISSUES/` are imported there and removed. An **incident** is a past event that taught a rule. -- **issue tracker** — the role that holds the mesh's issues and hands out their numbers: the seat `issue-tracker`, +- **issue tracker** — what holds the mesh's issues and hands out their numbers: the seat `issue-tracker`, held by the module `mesh-issues` ([53 — The issue tracker](../03-DESIGN/01-to-be/53-the-issue-tracker.md)). Not hits's *item*; bare *ticket* is a homonym (see [Homonyms](#homonyms)). *Not:* ~~ticketing system~~ (hq), ~~ticket system~~ (hq) @@ -688,6 +717,10 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical. | tier | a level of the mesh | **layer** | Core | | | a step of a rollout | **tier** | Change and delivery | | | how much proof an ask needs | **assurance level** | Identity and access | +| harness | the part of `mesh-sdk` that serves a tools bundle | **SDK harness** | Module | +| | the program that runs an agent's sessions | **agent harness** | Operator and conversation | +| role | what a seat names, at a scope | **seat** | Module | +| | what an identity may call | **role** | Identity and access | | ask | a request for the operator's input | **ask** | Operator and conversation | | | an entry in the build queue | **build request** | Change and delivery | | store | the one database server | **store** | Core | diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md index cfae3781..a706879c 100644 --- a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -17,7 +17,7 @@ decisions: # 58 — Agent work as the mesh's own **An agent's work belongs to the mesh, not to one vendor's program or one machine. A thread is kept whole on the -bus by a thread seat; a thread handler on an always-on node runs the agent's harness headless for it, in a sandbox +bus by a thread seat; a thread handler on an always-on node runs the agent harness headless for it, in a sandbox of its own, with the thread's own branch on the forge as its workspace; the agent works through a workspace toolkit and named tools, never a general command runner. Every person, agent and module is an identity held by one identity seat, with a role made of grants; the bus checks each login by its signature, and the tool runner checks each call @@ -35,7 +35,7 @@ nothing lost; the agent's calls outside its role are refused, saying which grant ───────── ─────────────── ──────────────── front ends nox-thread-handler nox-threads (seat thread) ├ terminal client (first) ├ takes a thread's lease ├ a restricted stream per thread - ├ web page (then) ├ runs the harness headless ├ the object store for large content + ├ web page (then) ├ runs the agent harness headless ├ the object store for large content └ Telegram: questions, │ inside a microsandbox └ leases in the bus's key-value store approvals ├ answers permission requests │ │ through the mesh's asks identity seat @@ -60,18 +60,18 @@ source of truth: the conversation, the agent's questions and their answers, tool every change of state. Large content goes to the object store and is named from the stream. The stream is restricted (ADR 0376): only modules granted it read it. A thread is never deleted; the trail is kept for good. -A thread is **open**, **assigned** (to a node and a harness), **released** or **stopped**. Its seat's verbs create, +A thread is **open**, **assigned** (to a node and an agent harness), **released** or **stopped**. Its seat's verbs create, assign, release, stop, move it, and take it over with a reason. The assignment is a **lease** in the bus's key-value store, changed only by a compare-and-set on its revision. Its holder renews it every 20 s. A lease not renewed for 60 s is said to the operator; nothing takes it over by itself. ## 3. Running a thread (ADR 0384) -The thread handler on an always-on node takes the lease and starts the harness (Claude Code today) headless, one -turn at a time. It answers the harness's permission requests through the mesh's asks, so a front end answers them in +The thread handler on an always-on node takes the lease and starts the agent harness (Claude Code today) headless, one +turn at a time. It answers the agent harness's permission requests through the mesh's asks, so a front end answers them in place. At the end of every turn it commits and pushes the workspace, which is the thread's own branch on the forge; a node that picks the thread up fetches it, so a move loses at most the turn in progress. Before a shutdown it -releases at a turn boundary; on a stop it ends the process group, since a tool's child process outlives the harness. +releases at a turn boundary; on a stop it ends the process group, since a tool's child process outlives the agent harness. The claude-code module mirrors the session's stream into the thread and, on pick-up, rebuilds a session from the thread. Usage per thread comes from each run's result and rate-limit messages on the stream, not the transcript, and the From 9844020589df8c1bb76da1e6e6ee3d26218ae53c Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 02:49:22 +0200 Subject: [PATCH 04/23] =?UTF-8?q?Glossary:=20Uses=20lines,=20the=20thread'?= =?UTF-8?q?s=20two=20records,=20the=20grant=20from=20ADR=200386=20=C2=A74,?= =?UTF-8?q?=20the=20provisioner's=20harness,=20issue=20872=20for=20the=20s?= =?UTF-8?q?eat-sense=20role=20(review=20round=201)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 00-META/glossary.md | 13 +++++++------ 00-META/repos.md | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/00-META/glossary.md b/00-META/glossary.md index 47773150..a46638cf 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -271,7 +271,7 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02 and the operator act. **Recorded by** the controller's `identity` and `licences` databases and the vault. **Upstream of** Provisioning, Change and delivery, and Operator and conversation. **Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388. -**Uses:** module, node, operator, consumer (Provisioning), agent (Operator and conversation), tool (Module). +**Uses:** module, node, seat, tool (Module), operator, consumer and provision (Provisioning), agent and ask (Operator and conversation). - **credential** — anything that proves an identity: a password, a key, a token. A **pair credential** is the two ends of one credential, the consumer's and the provider's. @@ -289,8 +289,8 @@ and the operator act. **Recorded by** the controller's `identity` and `licences` - **role** — what an identity may call, as a set of grants (ADR 0386). Not a seat: a bare *role* is a homonym (see [Homonyms](#homonyms)). - **grant** — one line of a role: an effect everywhere, an effect on one seat, or one named tool, and may be - limited to named machines; a dangerous tool is granted only by name (ADR 0386). A module's grants - come from what its manifest declares it calls, bounded by the provisions it requires (ADR 0225). + limited to named machines; a dangerous tool is granted only by name (ADR 0386). A module's role + is made from what its manifest declares it calls (ADR 0386 §4). - **effect** — a tool's mark, set by its module in its manifest: **reads**, **acts** or **dangerous**; a tool served without one counts as dangerous (ADR 0387). - **break-glass agent** — the one agent that holds every tool and never asks: sealed until the operator, or @@ -520,7 +520,7 @@ trust. **Recorded by** the router (asks, warrants and the operator's identities) **Downstream of** Health and repair, Change and delivery, and Identity and access. An authorising answer acts in whichever domain asked, through that domain's own verb; the conversation owns the asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 0384, 0385, 0390. -**Uses:** operator, person, proof (Identity and access), release (Change and delivery). +**Uses:** operator, person, node, module, seat, tool (Module), proof and identity (Identity and access), release (Change and delivery). - **mesh MCP server** — the endpoint on a node's loopback through which every agent and person on that node reaches the mesh: the MCP server named `mesh`, with its five tools `mesh_overview`, @@ -580,7 +580,7 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03 build seat's holder, whose seat name `node-build-agent` is an identifier to rename. - **thread** — one line of agent work, owned by the mesh: its turns, tool calls and results, its workspace and usage, kept whole for good on the bus by the thread seat; it outlives any session, node or front end - (ADR 0383). + (ADR 0383, ADR 0384). - **session** — one run of an agent harness on a thread. - **agent harness** — the program that runs an agent's sessions, its context manager and loop: Claude Code today (ADR 0384). Not the SDK harness (see [Homonyms](#homonyms)). @@ -719,7 +719,8 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical. | | how much proof an ask needs | **assurance level** | Identity and access | | harness | the part of `mesh-sdk` that serves a tools bundle | **SDK harness** | Module | | | the program that runs an agent's sessions | **agent harness** | Operator and conversation | -| role | what a seat names, at a scope | **seat** | Module | +| | the TypeScript `provisioner` helper for database providers | **`provisioner`**, renamed by design 57 | Provisioning | +| role | what a seat names, at a scope | **seat**; the bare word in older designs is tracked by issue 872 | Module | | | what an identity may call | **role** | Identity and access | | ask | a request for the operator's input | **ask** | Operator and conversation | | | an entry in the build queue | **build request** | Change and delivery | diff --git a/00-META/repos.md b/00-META/repos.md index e503e45a..f3ee1201 100644 --- a/00-META/repos.md +++ b/00-META/repos.md @@ -34,7 +34,7 @@ one-for-one — `mesh-catalog`, `mesh-sdk` and `mesh-tools` exist where the tabl | `mesh-foundation` | 1 | the four pinned services, as declarations | | `mesh-controller` | 2 | **exists.** The controller and its contexts — one of seven built (ADR 0006) | | `mesh-surfaces` | 3 | tools, web, cli | -| `mesh-sdk` | — | the stable spine modules build against — the tool-serving harness, the messaging/event framework, the contracts and core primitives. Holds nothing per-module and nothing volatile (ADR 0039). | +| `mesh-sdk` | — | the stable spine modules build against — the tool-serving SDK harness, the messaging/event framework, the contracts and core primitives. Holds nothing per-module and nothing volatile (ADR 0039). | | `mesh-lab` | — | **exists.** The lab — scenario lifecycle, networking, placement. Ships to nobody; runs on a workstation. | Tier 4's shape is open, and deliberately so: see ADR 0019 and From 45e2d7e9722d7c967bff1e9eb710cbf851509200 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 03:03:21 +0200 Subject: [PATCH 05/23] Design 58: milestones for the operator to confirm, owners named, and the as-is of logins on the bus (playbook 04) --- 03-DESIGN/00-as-is/16-logins-on-the-bus.md | 41 +++++++++++++++++++ 03-DESIGN/00-as-is/README.md | 1 + .../58-agent-work-as-the-meshs-own.md | 26 +++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 03-DESIGN/00-as-is/16-logins-on-the-bus.md diff --git a/03-DESIGN/00-as-is/16-logins-on-the-bus.md b/03-DESIGN/00-as-is/16-logins-on-the-bus.md new file mode 100644 index 00000000..952d91db --- /dev/null +++ b/03-DESIGN/00-as-is/16-logins-on-the-bus.md @@ -0,0 +1,41 @@ +--- +layer: as-is +status: implemented +code: [mesh-controller, mesh-tools] +updated: 2026-10-16 +decisions: + - "ADR 0106" +--- + +# Logins on the bus, as they run + +**The bus reads one static list of logins from its settings file, in one account, written by the controller from +its own records. Every module has a login per assignment; a person's login may call only the tools it was given; +the sessions on the operator's machines call through their machine's tool-runner login, which may call every tool. +Nothing marks what a tool does.** Read from the controller's and the tool runner's code on main on 2026-10-15 +(research 053, question 8). Design 58 replaces it. + +## The list + +- **One list, one account.** The controller writes every login from its records into the bus's settings file; + the bus re-reads it without dropping connections (ADR 0106 §3). +- **A module's login per assignment**, named by machine and module, may publish and subscribe only what its + manifest declares it emits, consumes, serves and calls. +- **A person's login** may publish only to the tools it was given and listen only on its own inbox. +- **The caller is in the address.** A call's address carries the caller's name, so the runtime takes the caller + from the address, never from the message. For a seat every machine holds, the address also names the machine. + +## What it cannot do + +- **No expiry.** A login lives until its record is deleted and the list rewritten on the bus's node. +- **No per-agent login.** Agent sessions reach the bus through each machine's tool-runner login, which may call + every tool on the mesh; what one session did cannot be told from another's. +- **No effect.** No tool or seat verb declares whether it reads, acts or is dangerous; some module documents say + it in prose, and nothing reads that. +- **Asks and warrants exist** (ADR 0259): a module can have one act authorised by the operator, bound to that + act; nothing yet asks for a dangerous call by itself. + +## How it is checked + +By reading: the controller's code that renders the bus's settings and the tool runner's caller check, on main. +When design 58's switch is done, this document is replaced by the as-is of signed logins. diff --git a/03-DESIGN/00-as-is/README.md b/03-DESIGN/00-as-is/README.md index 75c8c544..fd64645d 100644 --- a/03-DESIGN/00-as-is/README.md +++ b/03-DESIGN/00-as-is/README.md @@ -24,6 +24,7 @@ Where the two disagree, the implementation wins and the disagreement is stated. | [`13-the-console.md`](13-the-console.md) | The mesh's tools on the machine a person sits at, served by a module the mesh assigned there | | [`14-a-modules-state.md`](14-a-modules-state.md) | A module's current state on the bus: what the controller creates, the runtime serves, and the first live use showed | | [`15-the-agent-and-its-licences.md`](15-the-agent-and-its-licences.md) | The operator's agent on every machine and the licence manager that keeps its licences | +| [`16-logins-on-the-bus.md`](16-logins-on-the-bus.md) | The bus's one list of logins, a login per module assignment, persons limited to their tools, sessions calling through the tool runner's login, and no effect on any tool | ## What these documents are not diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md index a706879c..ead12a78 100644 --- a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -1,7 +1,7 @@ --- layer: to-be status: designed -code: [] +code: [mesh-catalog, mesh-media-catalog, mesh-sdk, mesh-tools, mesh-controller, mesh-host, mesh-lab] updated: 2026-10-16 decisions: - "ADR 0383" @@ -155,3 +155,27 @@ carry them: 4. The switch, run on the mesh's own modules in the lab from the bed test kept on the lab's branch `research/053-signed-bus-logins`, loses nothing and leaves every identity on the new bus. 5. The acceptance sentence at the top, end to end. + +## 11. Milestones + +Each milestone is one feature step (playbook 07), usable as soon as its delivery plan is done, and starts when +the previous one's is. What it replaces is in the as-is documents +[15 — The agent and its licences](../00-as-is/15-the-agent-and-its-licences.md) and +[16 — Logins on the bus](../00-as-is/16-logins-on-the-bus.md). The issues are opened once the operator confirms +the milestones, and their numbers written here. + +| # | Outcome, in one sentence | Proves | Repositories and their parts | Depends on | +|---|---|---|---|---| +| 1 | Every tool on the mesh says whether it reads, acts or is dangerous, a tool's description shows it, and the catalogue refuses a module that leaves one unmarked | test 3 | mesh-sdk: the effect in a tool's declaration, an unmarked tool served as dangerous; mesh-controller: the manifest field; mesh-catalog and mesh-media-catalog: every module marked, the check | — | +| 2 | A session works on a repository's workspace through the mesh's tools alone: read, glob, search, edit, write, git, its tests and its merge check, with no command runner | — | mesh-catalog: the module `nox-workspace` on the node seat `workspace`, on the always-on nodes; mesh-controller: the seat | 1 | +| 3 | A thread created through the thread seat runs headless on an always-on node, its conversation readable through the seat, its usage counted per thread, and a move to another node loses at most the turn in progress | — | mesh-catalog: `nox-threads` (seat `thread`, restricted streams, leases), `nox-thread-handler` (seat `thread-handler`), claude-code (mirror and rebuild), claude-licence-manager (usage per thread) | 2 | +| 4 | The operator starts, follows, answers and stops a thread from a terminal client, and answers its questions on Telegram | — | mesh-catalog: the terminal client, a Go program of `nox-threads`; claude-code: questions and permission requests through the asks | 3 | +| 5 | Every session runs in a sandbox of its own that reaches only the vendor and the bus, and the home server runs one too | tests 1 and 2 | mesh-catalog: the sandbox module (microsandbox pinned, KVM loaded where off); `nox-thread-handler`: runs sessions in it; claude-code: writes the login and the licence token without its refresh part | 3 | +| 6 | Every person, agent and module is an identity with a role, and an agent's call outside its role is refused, saying which grant is missing | — | mesh-catalog: the identity seat's module; mesh-sdk: the tool runner's exact check, calls carrying thread and agent token; mesh-controller: an identity asked for each assignment; mesh-tools: sessions call as a person or an agent, never through the tool runner's login | 1 | +| 7 | A dangerous act not named in a role comes to the operator as an ask, and the sealed break-glass agent opens only on the operator's word or a named condition | test 5 | mesh-sdk: dangerous calls asked; identity module: dangerous tools granted by name on an ask, break-glass and its telling | 6, 5, 4 | +| 8 | The bus checks signed logins on a second bus beside today's, the identity seat signs and revokes them, and the switch, run in the lab on the mesh's own modules, loses nothing | test 4 | identity module: signing keys, renewal, revocation read back and resent to new servers; the node-engine (`mesh-host`): node and module logins renewed; mesh-controller: the second bus as a leaf with the system account; mesh-lab: the bed test from the branch `research/053-signed-bus-logins` | 6 | +| 9 | Every identity is on the new bus, its data moved by copy, and today's bus is switched off | — | mesh-controller and the identity module: one identity at a time, then streams, buckets and the object store; mesh-catalog: the old bus's module retired | 8 | +| 10 | The operator follows and answers threads from the web page as from the terminal client, logged in as a person identity | — | mesh-catalog: the web page, a client of the thread seat over the bus's WebSocket listener | 9, 4 | + +The front ends' later parts, the inference seat and the other agent harnesses are tracked by issue 850; the +seat-sense "role" in older designs by issue 872. From 43c3f2c0984852d779f9f7b6ed49758b1158fc5c Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 09:55:11 +0200 Subject: [PATCH 06/23] Design 58: the operator confirmed the milestones; issues 878 to 887, building after design 57's delivery (playbook 04) --- 03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md index ead12a78..f5e63aab 100644 --- a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -164,6 +164,13 @@ the previous one's is. What it replaces is in the as-is documents [16 — Logins on the bus](../00-as-is/16-logins-on-the-bus.md). The issues are opened once the operator confirms the milestones, and their numbers written here. +**Confirmed by the operator on 2026-10-16.** One issue per milestone: 1 is issue 878, 2 is 879, 3 is 880, 4 is +881, 5 is 882, 6 is 883, 7 is 884, 8 is 885, 9 is 886, 10 is 887. A milestone's issue is split into one issue per +repository part when its feature step starts (playbook 07): several of the parts are modules that do not exist yet, +and the issue tracker takes only registered owners. The building waits until the delivery under way of +[57 — Building config and provisioning](57-building-config-and-provisioning.md) is done; the status here stays +`designed` until milestone 1 starts. + | # | Outcome, in one sentence | Proves | Repositories and their parts | Depends on | |---|---|---|---|---| | 1 | Every tool on the mesh says whether it reads, acts or is dangerous, a tool's description shows it, and the catalogue refuses a module that leaves one unmarked | test 3 | mesh-sdk: the effect in a tool's declaration, an unmarked tool served as dangerous; mesh-controller: the manifest field; mesh-catalog and mesh-media-catalog: every module marked, the check | — | From ea359ea4e6eda4f1e73e50b93c7a88a22c565998 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 15 Oct 2026 23:33:20 +0200 Subject: [PATCH 07/23] Try a small fix's branch before its pull request, since local runs miss the check's toolchain (playbook 08) --- 00-META/process/08-small-fixes.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 83912b18..02efad3d 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -34,7 +34,11 @@ one delivery**. Everything before the push is local and fast. 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 its id, so the fix keeps its context. A playbook or design edit of a few lines may skip the reviewer: the operator's word on the pull request is its review. -5. **Push once and open the pull request.** The forge's merge checks run the integration tests. A failed check +5. **Push the branch, try it, then open the pull request.** `mesh-controller.try` with the repository and the + branch runs the merge check in the check's own toolchain before any status is set; open the pull request + only once it passes. A local run never stands in for it: the check's containers carry other tools than the + nodes (a test that called util-linux `flock -E` passed on a node and failed on BusyBox's in the check). The + forge's merge checks run the integration tests. A failed check goes back to the same agent with the failure, and the reviewer reads only the change it makes. 6. **Mark it ready** (`mesh/ready` and `ready at `) once the operator's word is given; mesh-delivery merges it when its checks pass. From c5fa1de26470acf10e521ae7b7314f54934313d5 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 10:11:26 +0200 Subject: [PATCH 08/23] Playbooks 07 and 08: review asks only what makes a change wrong, try before opening, mark ready on approval, prove a module whole first, hand back stopped issues From the delivery-time audit of 2026-10-16: seven review rounds on issue 704, a feature branch's first check failing on 29 problems, mesh-catalog #300 waiting 12 h unmarked, the mail modules failing live, 98 issues held in fixing. --- 00-META/process/07-feature-branches.md | 48 ++++++++++++++++++++++---- 00-META/process/08-small-fixes.md | 14 ++++++-- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 1b569c75..018c22d5 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -21,6 +21,16 @@ 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. - **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. +- **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 its own check finds in minutes. +- **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 @@ -107,19 +117,33 @@ never into the running one, unless it blocks the running one. 4. **The reviewer reads the answers and the new commits**, and approves or reports again. From round 2 it asks changes only for a finding that makes the feature wrong; smaller points become issues of their own. After round 3 the lead stops and brings the operator what is left, with a recommendation. +5. **A finding outside the issues' done-when 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 + its issues and its decisions. ## Phase 3 — Check (no review) -1. **Push every feature branch and open one pull request per repository, together.** Pull requests in two or +1. **Push every feature branch and try it before any pull request.** `mesh-controller.try` with the + repository and the branch runs the merge check in the check's own toolchain; a branch that fails goes back + to its fixing agent, and nothing is opened until every branch passes. A local run never stands in for it: + the check's containers carry other tools than the nodes. +2. **Open one pull request per repository, together.** Pull requests in two or more repositories that share the branch name are one delivery group (ADR 0239 §2). 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. -2. **The forge's merge checks run the integration tests once** (`mesh/merge-gate`, `mesh/repo-check`). No +3. **The forge's merge checks run the integration tests once** (`mesh/merge-gate`, `mesh/repo-check`). No second review: phase 2 reviewed this tree. -3. **A check that fails** goes back to the reviewer with the failure, for **one more cycle** of phase 2 with +4. **A check that fails** goes back to the reviewer with the failure, for **one more cycle** of phase 2 with the same fixing agents; then push once again. -4. **Mark each pull request ready** (`mesh/ready` and a comment `ready at `) once the operator's word - for the feature is given; mesh-delivery merges it when its checks pass (ADR 0364). +5. **Prove the step's acceptance before it is marked ready.** A step that adds or changes a module runs that + module whole (its process against a real bus and store) on the cheapest bed that can show the step's + acceptance sentence, as playbook [01](01-research.md) says for research; the lab when only machines can. + Unit tests alone are not that proof. +6. **The reviewer marks each pull request ready as soon as the acceptance is shown** (`mesh/ready` and a + comment `ready at `, 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 manifests with the controller the mesh runs, so the controller's pull request is merged and delivered first; @@ -127,7 +151,8 @@ then `mesh-delivery.recheck` the catalogue's and merge it on the new verdict. Pl ## Phase 4 — Deliver -The merge starts the delivery plan: build, publish, send. The lead follows it to done +The merge starts the delivery plan: build, publish, send. A merge into a branch other than `main` is not a +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` naming its pull requests, and removes what is left: no `feat/` branch and no `.work/` worktree survive. @@ -200,6 +225,13 @@ 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 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 - A feature's issues show their commits on the feature branch (`git log --grep 'issue '`), and no pull @@ -209,6 +241,10 @@ next action; then the prompt the operator pastes. The context files make the fea - After a feature's delivery, `git branch -r | grep feat/` and `git worktree list` return nothing for it. - More than one open pull request in a repository that share no feature name, or a feature step whose issues stay in `fixing` for more than a working day, is the smell: stop and bring it to the operator. +- A 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 bed run from `.work//mesh-lab` that fails naming a `.work///…` path it cannot find is a missing sibling worktree, not a mesh fault. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 02efad3d..22f83bc0 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -31,7 +31,8 @@ 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, `sh merge-check.sh`). 4. **One review of the local commit, before anything is pushed** (a reviewer that did not write it, larger - model; at most 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 + model; at most 3 rounds, as playbook 07; from round 2 only what is wrong; a finding outside the issue's + 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 operator's word on the pull request is its review. 5. **Push the branch, try it, then open the pull request.** `mesh-controller.try` with the repository and the @@ -40,17 +41,24 @@ one delivery**. Everything before the push is local and fast. nodes (a test that called util-linux `flock -E` passed on a node and failed on BusyBox's in the check). The forge's merge checks run the integration tests. A failed check goes back to the same agent with the failure, and the reviewer reads only the change it makes. -6. **Mark it ready** (`mesh/ready` and `ready at `) once the operator's word is given; mesh-delivery - merges it when its checks pass. +6. **The reviewer marks it ready at once** (`mesh/ready` and `ready at `, the head it approved); + mesh-delivery merges it when its checks pass. A fix to a module proves the issue's done-when with the + module running whole (its process against a real bus and store) before it is marked, not with unit tests + alone. 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 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 | Waiting on | Bound | Past the bound | |---|---|---| | building the fix | 1 hour | it is a feature: stop and plan it under playbook 07 | | the review | 15 minutes | ask the reviewer where it stands | +| the 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 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` | From 4e822c56a0f94d6846fdf47a5c74ca34e1513877 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 10:12:44 +0200 Subject: [PATCH 09/23] Playbooks 07 and 08: checks for every new rule, the ready mark's bound in both, the lead marks an unreviewed edit (review round 1) --- 00-META/process/07-feature-branches.md | 9 ++++++--- 00-META/process/08-small-fixes.md | 10 ++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 018c22d5..276091f4 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -114,9 +114,8 @@ never into the running one, unless it blocks the running one. It says which round it is in ("round 1 of at most 3"). 3. **The report goes to the same fixing agents** that wrote the code, continued by their ids, so they fix with the context they already hold. Each answers the reviewer: what it changed, per finding, or why not. -4. **The reviewer reads the answers and the new commits**, and approves or reports again. From round 2 it - asks changes only for a finding that makes the feature wrong; smaller points become issues of their own. - After round 3 the lead stops and brings the operator what is left, with a recommendation. +4. **The reviewer reads the answers and the new commits**, and approves or reports again (step 5 says what a round + may ask). After round 3 the lead stops and brings the operator what is left, with a recommendation. 5. **A finding outside the issues' done-when 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 @@ -181,6 +180,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 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 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` | @@ -245,6 +245,9 @@ issues in `fixing` that nobody works on reads to the operator as stuck work. 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 whose head has no passing `mesh-controller.try` before it was opened, or a step that adds or + changes a module marked ready with no run of the module whole (or lab run) named in the lead's report, is + the failure of phase 3's first and fifth steps. - A bed run from `.work//mesh-lab` that fails naming a `.work///…` path it cannot find is a missing sibling worktree, not a mesh fault. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 22f83bc0..40640e5a 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -34,14 +34,15 @@ one delivery**. Everything before the push is local and fast. model; at most 3 rounds, as playbook 07; from round 2 only what is wrong; a finding outside the issue's 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 - operator's word on the pull request is its review. + operator's word on the pull request is its review, and the lead marks it ready on that word. 5. **Push the branch, try it, then open the pull request.** `mesh-controller.try` with the repository and the branch runs the merge check in the check's own toolchain before any status is set; open the pull request only once it passes. A local run never stands in for it: the check's containers carry other tools than the nodes (a test that called util-linux `flock -E` passed on a node and failed on BusyBox's in the check). The forge's merge checks run the integration tests. A failed check goes back to the same agent with the failure, and the reviewer reads only the change it makes. -6. **The reviewer marks it ready at once** (`mesh/ready` and `ready at `, the head it approved); +6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the + operator's word) (`mesh/ready` and `ready at `, the head it approved); mesh-delivery merges it when its checks pass. A fix to a module proves the issue's done-when with the module running whole (its process against a real bus and store) before it is marked, not with unit tests alone. The operator's word is waited for only when the fix changes what the operator sees, removes data, @@ -75,3 +76,8 @@ 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 push. - Its issue moves to `resolved` within the hour its delivery plan ends. +- A pull request opened with no passing `mesh-controller.try` on its head, one reviewed and green but unmarked + for more than 15 minutes, a fix to a module marked ready with no run 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. From cb98a08384abc17f99b02039f73c71a641efe88b Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 10:13:38 +0200 Subject: [PATCH 10/23] Playbooks 07 and 08: prove a module whole on a throwaway bus and store, not in the lab while its runs are too slow (the operator, 2026-10-16) --- 00-META/process/07-feature-branches.md | 7 ++++--- 00-META/process/08-small-fixes.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 276091f4..5ee7eb9f 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -137,8 +137,9 @@ never into the running one, unless it blocks the running one. the same fixing agents; then push once again. 5. **Prove the step's acceptance before it is marked ready.** A step that adds or changes a module runs that module whole (its process against a real bus and store) on the cheapest bed that can show the step's - acceptance sentence, as playbook [01](01-research.md) says for research; the lab when only machines can. - Unit tests alone are not that proof. + acceptance sentence, as playbook [01](01-research.md) says for research: a test that starts the built module + against a throwaway bus and store. Unit tests alone are not that proof. The lab is not used for this while + its runs are too slow (the operator, 2026-10-16). 6. **The reviewer marks each pull request ready as soon as the acceptance is shown** (`mesh/ready` and a comment `ready at `, 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 @@ -246,7 +247,7 @@ issues in `fixing` that nobody works on reads to the operator as stuck work. - 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 whose head has no passing `mesh-controller.try` before it was opened, or a step that adds or - changes a module marked ready with no run of the module whole (or lab run) named in the lead's report, is + changes a module marked ready with no run of the module whole named in the lead's report, is the failure of phase 3's first and fifth steps. - A bed run from `.work//mesh-lab` that fails naming a `.work///…` path it cannot find is a missing sibling worktree, not a mesh fault. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 40640e5a..75f7bda9 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -44,7 +44,7 @@ one delivery**. Everything before the push is local and fast. 6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the operator's word) (`mesh/ready` and `ready at `, the head it approved); mesh-delivery merges it when its checks pass. A fix to a module proves the issue's done-when with the - module running whole (its process against a real bus and store) before it is marked, not with unit tests + module running whole (its process against a throwaway bus and store, never the lab for now) before it is marked, not with unit tests alone. 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 From f95043e3797e34a394a9d1172a617b0d80f63413 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 10:14:42 +0200 Subject: [PATCH 11/23] Playbooks 07 and 08: a module's acceptance is an integration test the forge runs, and try runs on the builder (ADR 0391) --- 00-META/process/07-feature-branches.md | 14 +++++++------- 00-META/process/08-small-fixes.md | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 5ee7eb9f..fb925e22 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -124,7 +124,8 @@ never into the running one, unless it blocks the running one. ## Phase 3 — Check (no review) 1. **Push every feature branch and try it before any pull request.** `mesh-controller.try` with the - repository and the branch runs the merge check in the check's own toolchain; a branch that fails goes back + repository and the branch runs the merge check on the builder, in the check's own toolchain, never + locally (ADR 0391 §4); a branch that fails goes back to its fixing agent, and nothing is opened until every branch passes. A local run never stands in for it: the check's containers carry other tools than the nodes. 2. **Open one pull request per repository, together.** Pull requests in two or @@ -135,11 +136,10 @@ never into the running one, unless it blocks the running one. second review: phase 2 reviewed this tree. 4. **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. -5. **Prove the step's acceptance before it is marked ready.** A step that adds or changes a module runs that - module whole (its process against a real bus and store) on the cheapest bed that can show the step's - acceptance sentence, as playbook [01](01-research.md) says for research: a test that starts the built module - against a throwaway bus and store. Unit tests alone are not that proof. The lab is not used for this while - its runs are too slow (the operator, 2026-10-16). +5. **The step's acceptance is proven before it is marked ready.** A step that adds or changes a module + carries an integration test that starts the module whole, its process against the real bus and store, and + shows the step's acceptance sentence; the forge's checks run it (ADR 0391 §1, §6). Unit tests alone are not + that proof, and no lab run is (ADR 0391 §5: end to end only on the operator's ask). 6. **The reviewer marks each pull request ready as soon as the acceptance is shown** (`mesh/ready` and a comment `ready at `, 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 @@ -247,7 +247,7 @@ issues in `fixing` that nobody works on reads to the operator as stuck work. - 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 whose head has no passing `mesh-controller.try` before it was opened, or a step that adds or - changes a module marked ready with no run of the module whole named in the lead's report, is + changes a module marked ready with no integration test that starts the module whole, is the failure of phase 3's first and fifth steps. - A bed run from `.work//mesh-lab` that fails naming a `.work///…` path it cannot find is a missing sibling worktree, not a mesh fault. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 75f7bda9..65670057 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -43,9 +43,9 @@ one delivery**. Everything before the push is local and fast. 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 operator's word) (`mesh/ready` and `ready at `, the head it approved); - mesh-delivery merges it when its checks pass. A fix to a module proves the issue's done-when with the - module running whole (its process against a throwaway bus and store, never the lab for now) before it is marked, not with unit tests - alone. The operator's word is waited for only when the fix changes what the operator sees, removes data, + 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, or a lab run, are not that proof. 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 the mesh (the symptom gone, measured), and resolve the issue with `located-in` and `fixed-by` the same hour. @@ -77,7 +77,7 @@ reading itself and uses one subagent only for the review. request with many heads is a fix reviewed after its push. - Its issue moves to `resolved` within the hour its delivery plan ends. - A pull request opened with no passing `mesh-controller.try` on its head, one reviewed and green but unmarked - for more than 15 minutes, a fix to a module marked ready with no run of the module whole, or a review report + 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. From 47f7321c05decb0d885a511b4de4ba7241e8fc37 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 10:15:31 +0200 Subject: [PATCH 12/23] Playbooks 07 and 08: integration tests only in the merge check, no try before it, no lab and no end-to-end tests yet (the operator, 2026-10-16) --- 00-META/process/07-feature-branches.md | 25 ++++++++++--------------- 00-META/process/08-small-fixes.md | 11 ++++------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index fb925e22..9780a22b 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -26,7 +26,7 @@ A small fix (one repository, one issue, about an hour of work) follows 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 its own check finds in minutes. + 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 @@ -123,24 +123,20 @@ never into the running one, unless it blocks the running one. ## Phase 3 — Check (no review) -1. **Push every feature branch and try it before any pull request.** `mesh-controller.try` with the - repository and the branch runs the merge check on the builder, in the check's own toolchain, never - locally (ADR 0391 §4); a branch that fails goes back - to its fixing agent, and nothing is opened until every branch passes. A local run never stands in for it: - the check's containers carry other tools than the nodes. -2. **Open one pull request per repository, together.** Pull requests in two or +1. **Push every feature branch and open one pull request per repository, together.** 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). 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. -3. **The forge's merge checks run the integration tests once** (`mesh/merge-gate`, `mesh/repo-check`). No +2. **The forge's merge checks run the integration tests once** (`mesh/merge-gate`, `mesh/repo-check`). No second review: phase 2 reviewed this tree. -4. **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. -5. **The step's acceptance is proven before it is marked ready.** A step that adds or changes a module +4. **The step's acceptance is proven before it is marked ready.** A step that adds or changes a module carries an integration test that starts the module whole, its process against the real bus and store, and shows the step's acceptance sentence; the forge's checks run it (ADR 0391 §1, §6). Unit tests alone are not - that proof, and no lab run is (ADR 0391 §5: end to end only on the operator's ask). -6. **The reviewer marks each pull request ready as soon as the acceptance is shown** (`mesh/ready` and a + 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 `, 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. @@ -246,9 +242,8 @@ issues in `fixing` that nobody works on reads to the operator as stuck work. 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 whose head has no passing `mesh-controller.try` before it was opened, or 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 first and fifth steps. +- 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//mesh-lab` that fails naming a `.work///…` path it cannot find is a missing sibling worktree, not a mesh fault. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 65670057..a4cd1678 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -35,17 +35,14 @@ one delivery**. Everything before the push is local and fast. 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 operator's word on the pull request is its review, and the lead marks it ready on that word. -5. **Push the branch, try it, then open the pull request.** `mesh-controller.try` with the repository and the - branch runs the merge check in the check's own toolchain before any status is set; open the pull request - only once it passes. A local run never stands in for it: the check's containers carry other tools than the - nodes (a test that called util-linux `flock -E` passed on a node and failed on BusyBox's in the check). The - forge's merge checks run the integration tests. A failed check +5. **Push once and open the pull request.** 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. 6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the operator's word) (`mesh/ready` and `ready at `, the head it approved); 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, or a lab run, are not that proof. The operator's word is waited for only when the fix changes what the operator sees, removes data, + (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 the mesh (the symptom gone, measured), and resolve the issue with `located-in` and `fixed-by` the same hour. @@ -76,7 +73,7 @@ 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 push. - Its issue moves to `resolved` within the hour its delivery plan ends. -- A pull request opened with no passing `mesh-controller.try` on its head, one reviewed and green but unmarked +- 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 From cf566498454b1a34a5b229bda586cdd49af1b645 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:00:46 +0200 Subject: [PATCH 13/23] Design 41: every file on a node is managed through node-files (WP9, ADR 0394, issue 900) --- ...-the-shell-and-the-accounts-environment.md | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index 2a5c8705..f5b9c46d 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -2,8 +2,9 @@ layer: to-be status: in-progress code: [mesh-host, mesh-controller, mesh-catalog] -updated: 2026-10-12 +updated: 2026-10-16 decisions: + - "ADR 0394" - "ADR 0310" - "ADR 0268" - "ADR 0252" @@ -90,6 +91,7 @@ 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 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 +WP9 every file on a node is managed (mesh-tools, mesh-controller) ADR 0394, issue 900 ``` WP1, WP2 and WP4 are independent, and are built in parallel on one feature branch per repository @@ -366,3 +368,32 @@ under the same issue. `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 server, and the agent's credentials file on the laptop is refused. + +## WP9 — Every file on a node is managed through `node-files` + +*`mesh-tools`, `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 the tool runner, with a verb for each file action: list, + stat, read, search, write, copy, move, delete, make a folder, change mode, change owner, and the trash's list and + restore. Each says what it replaces (ADR 0245): `ls`, `stat`, `cat`, `grep`, `cp`, `mv`, `rm`, `mkdir`, `chmod`, + `chown`, and `ssh cp` for a copy between nodes. +- **It may touch every file.** It runs with full rights and 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; this first version 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. +- **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 tool runner'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 shanks is listed, and a file copied from one node to another +arrives with its owner and modes. + From 330d3416185af878acda8d37e3c5c66459afd5e5 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:01:43 +0200 Subject: [PATCH 14/23] Design 41 WP9: node-files is held by a module of its own, mesh-files, beside mesh-reads --- .../41-the-shell-and-the-accounts-environment.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index f5b9c46d..9681c8a6 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -91,7 +91,7 @@ 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 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 -WP9 every file on a node is managed (mesh-tools, mesh-controller) ADR 0394, issue 900 +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 @@ -371,13 +371,14 @@ server, and the agent's credentials file on the laptop is refused. ## WP9 — Every file on a node is managed through `node-files` -*`mesh-tools`, `mesh-controller`. ADR 0394; tracked by issue 900.* +*`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 the tool runner, with a verb for each file action: list, +- **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, read, search, write, copy, move, delete, make a folder, change mode, change owner, and the trash's list and restore. Each says what it replaces (ADR 0245): `ls`, `stat`, `cat`, `grep`, `cp`, `mv`, `rm`, `mkdir`, `chmod`, `chown`, and `ssh cp` for a copy between nodes. @@ -392,7 +393,7 @@ project folders, downloads, logs, scratch. of a known credential file or a secret place (the mesh never prints a token); copying or moving one is allowed. -**Proof.** The tool runner's tests: each verb against a temporary tree keeps owner and modes, a new file takes its +**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 shanks is listed, and a file copied from one node to another arrives with its owner and modes. From 7ac5194bcbdc06c66c956b6d069afd7eee592ab8 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:06:32 +0200 Subject: [PATCH 15/23] Design 41 WP9: mesh-files runs as the operator account with sudo where needed, and replaces node-reads (ADR 0394) --- .../41-the-shell-and-the-accounts-environment.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index 9681c8a6..4c542a86 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -382,19 +382,22 @@ project folders, downloads, logs, scratch. stat, read, search, write, copy, move, delete, make a folder, change mode, change owner, and the trash's list and restore. Each says what it replaces (ADR 0245): `ls`, `stat`, `cat`, `grep`, `cp`, `mv`, `rm`, `mkdir`, `chmod`, `chown`, and `ssh cp` for a copy between nodes. -- **It may touch every file.** It runs with full rights and 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; this first version judges no permission. +- **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; `node-reads` and + `mesh-reads` are removed in the delivery that brings it. - **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 shanks is listed, and a file copied from one node to another +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. From 1f5a12e07e42fcf6ff474a82b61e538b83bee7a8 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:11:53 +0200 Subject: [PATCH 16/23] Design 41: WP8's node-reads is replaced by WP9's node-files (ADR 0394 supersedes ADR 0310) --- .../01-to-be/41-the-shell-and-the-accounts-environment.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index 4c542a86..aa92b0b8 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -343,6 +343,9 @@ 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.* +**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, and `node-reads` is removed in the delivery that brings it. + 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 every node. Two had none: reading or searching a file, and looking up an account or a group. From 26073f30b0dea3395d1287ad9adbd1b288ef6f52 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:14:01 +0200 Subject: [PATCH 17/23] =?UTF-8?q?Design=2041:=20node-reads=20goes=20in=20t?= =?UTF-8?q?he=20delivery=20after=20node-files=20is=20held=20on=20every=20n?= =?UTF-8?q?ode=20(ADR=200394=20=C2=A79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-to-be/41-the-shell-and-the-accounts-environment.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index aa92b0b8..5a2556ad 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -344,7 +344,8 @@ 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.* **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, and `node-reads` is removed in the delivery that brings it. +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 act and not for a read, and ADR 0286 §44 sets the approval mark on `execute` only once those reads have a tool on @@ -393,8 +394,9 @@ project folders, downloads, logs, scratch. 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; `node-reads` and - `mesh-reads` are removed in the delivery that brings it. +- **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. From 1efa37957db2c4d2b45c5d07ea947e75c279022f Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:28:32 +0200 Subject: [PATCH 18/23] Playbooks 07 and 08: is the coast clear? Hold a push while a release branch in flight shares its files; the glossary's release branch The operator, 2026-10-16: the file module waited for feature 57's release branch, which changes four of the same controller files. --- 00-META/glossary.md | 4 ++++ 00-META/process/07-feature-branches.md | 28 +++++++++++++++++++++++++- 00-META/process/08-small-fixes.md | 4 +++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/00-META/glossary.md b/00-META/glossary.md index c64dad16..3807c0b7 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -364,6 +364,9 @@ 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 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. +- **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 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 @@ -682,6 +685,7 @@ 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 | | | 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 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 | | | 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 | diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 9780a22b..1fe4c367 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -121,9 +121,32 @@ never into the running one, unless it blocks the running one. 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/`), or + a delivery plan of that release branch still running (`mesh-controller.plans`). +2. **Compare the files.** `git diff --name-only origin/main...origin/` 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) -1. **Push every feature branch and open one pull request per repository, together.** The integration tests +1. **Push every feature branch and open one pull request per repository, together, once the coast is clear** + (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). Where a session pushes through the forge tool `gitea_commit` (one commit on the forge's current base), the @@ -178,6 +201,7 @@ on, with when it started and its bound. | 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 | | 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 delivery plan | its class's budget (`mesh-delivery.times`), at most 30 minutes | read `mesh-controller.plans`, then `mesh-delivery.stalled` | @@ -242,6 +266,8 @@ issues in `fixing` that nobody works on reads to the operator as stuck work. 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//mesh-lab` that fails naming a `.work///…` path it cannot find is a diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index a4cd1678..c56ce817 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -35,7 +35,9 @@ one delivery**. Everything before the push is local and fast. 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 operator's word on the pull request is its review, and the lead marks it ready on that word. -5. **Push once and open the pull request.** The forge's merge check runs the integration tests, the only +5. **Push once and open the pull request, once the coast is clear** (playbook [07](07-feature-branches.md), *Is + 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. 6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the From 427fe4c9c58b22474a75a589bfb8e1a74588d343 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 12:38:59 +0200 Subject: [PATCH 19/23] Playbooks 01 and 02: place research in the domains before its direction, and carry its words into the glossary at graduation (ADR 0244) The operator, 2026-10-16: research defines the modules a feature lands in and the domain extensions and reductions that come with it. --- 00-META/process/01-research.md | 16 ++++++++++++---- 00-META/process/02-graduation.md | 7 ++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/00-META/process/01-research.md b/00-META/process/01-research.md index c1afd96f..ce31743e 100644 --- a/00-META/process/01-research.md +++ b/00-META/process/01-research.md @@ -63,13 +63,20 @@ An idea arrives in one of two forms, and the first step differs: the reviews. - **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 - put-off work: it is what the build proves, step 6); each figure is given as measured (a range, not a + put-off work: it is what the build proves, step 7); each figure is given as measured (a range, not a 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 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 in-process test does not, and its lab scenario is written as the build's acceptance test instead. -6. **Settle the direction with the operator.** When the questions are answered, write `05-direction.md`: +6. **Place it in the domains.** Before the direction, write `03-domains.md`: the domain or domains the idea + 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 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 @@ -84,7 +91,8 @@ 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 | | 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 | -| the direction (6) | 30 minutes | larger | +| placing it in the domains (6) | 15 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 as playbook 07 does: every ten minutes and at once when something is found, stops or needs the operator, @@ -124,7 +132,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 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 and 6 (options checked +after every acceptance and raise a condition when one fails. The habits of steps 2, 5, 6 and 7 (options checked 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 a record named but not linked, an untracked deferral and a figure not as measured. That this repository holds diff --git a/00-META/process/02-graduation.md b/00-META/process/02-graduation.md index ad224c30..e124f9d9 100644 --- a/00-META/process/02-graduation.md +++ b/00-META/process/02-graduation.md @@ -13,7 +13,7 @@ clauses in force for a topic or a record). ## Graduating research -The effort's `05-direction.md`, confirmed by the operator (playbook [01](01-research.md), step 6), is what +The effort's `05-direction.md`, confirmed by the operator (playbook [01](01-research.md), step 7), is what 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. @@ -48,6 +48,11 @@ 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 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): 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 From 300be928144ee5b24c1f9b58e6b250945d26b8b2 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 13:31:45 +0200 Subject: [PATCH 20/23] =?UTF-8?q?Design=2041=20WP9:=20readlink=20and=20the?= =?UTF-8?q?=20account=20and=20group=20lookup=20are=20node-files=20verbs=20?= =?UTF-8?q?too=20(ADR=200394=20=C2=A71;=20review)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-to-be/41-the-shell-and-the-accounts-environment.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md index 5a2556ad..c71ec4d8 100644 --- a/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md +++ b/03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md @@ -383,9 +383,10 @@ 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, read, search, write, copy, move, delete, make a folder, change mode, change owner, and the trash's list and - restore. Each says what it replaces (ADR 0245): `ls`, `stat`, `cat`, `grep`, `cp`, `mv`, `rm`, `mkdir`, `chmod`, - `chown`, and `ssh cp` for a copy between nodes. + 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 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 From 7b5f3582be903ef76c0a3a874866023d46791161 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 14:31:49 +0200 Subject: [PATCH 21/23] Playbooks 07 and 08: mark ready with mesh-delivery.mark-ready, label then comment in the order the forge counts (issue 913) --- 00-META/process/07-feature-branches.md | 5 +++-- 00-META/process/08-small-fixes.md | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/00-META/process/07-feature-branches.md b/00-META/process/07-feature-branches.md index 1fe4c367..663edd29 100644 --- a/00-META/process/07-feature-branches.md +++ b/00-META/process/07-feature-branches.md @@ -159,8 +159,9 @@ controller part touched four files feature 57's release branch also changed). carries an integration test that starts the module whole, its process against the real bus and store, and 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 `, the head it approved); mesh-delivery merges it when its checks pass +5. **The reviewer marks each pull request ready as soon as the acceptance is shown** with + `mesh-delivery.mark-ready` (the delivery of the head it approved, who reviewed it and why), which writes the + label `mesh/ready` and then `ready at `, the order the forge counts (issue 913); 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. diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index c56ce817..3ae0b95d 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -41,7 +41,8 @@ one delivery**. Everything before the push is local and fast. 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. 6. **The reviewer marks it ready at once** (for an edit that skipped the reviewer, the lead, on the - operator's word) (`mesh/ready` and `ready at `, the head it approved); + operator's word) with `mesh-delivery.mark-ready` (the delivery of the head it approved, who reviewed it and + why), which writes the label `mesh/ready` and then `ready at `, the order the forge counts (issue 913); 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, From 0eadc27fc722a349bf78c43f10f0b3463166a61e Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 17:46:23 +0200 Subject: [PATCH 22/23] Playbook 08: needing a decision keeps a fix small; a feature is several modules with research or a design before it (the operator, 2026-10-16) --- 00-META/process/08-small-fixes.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index 3ae0b95d..b8eec81d 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -2,7 +2,10 @@ **Trigger.** One issue in one repository, small enough to build in about an hour: a bug with a known cause, a missing check, a wording, a playbook or design edit. Anything larger, or anything that needs a change in a -second repository first, is a feature and follows [playbook 07](07-feature-branches.md). +second repository first, is a feature and follows [playbook 07](07-feature-branches.md). A feature is the +larger kind: it touches several modules and has a research effort or a design before it. **Needing a decision +does not make a fix a feature**: the decision is settled first (step 1) and the fix stays small (the operator, +2026-10-16). **Related issues in one fix.** A small fix may cover two or three related issues when they are in the same repository, mostly in the same module, and together still fit in about an hour: they touch the same files, or @@ -23,7 +26,8 @@ one delivery**. Everything before the push is local and fast. 1. **Read the issue and the code it names** (the session's own model, or one read-only agent on the smaller model answering exact questions with file:line). If a design question is open, it is settled before any code is written: on the issue, through the knowledge base, or by the operator. A fix that turns out to - need a decision or a second repository stops here and becomes a feature. + 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. 2. **Move the issue to `fixing`** with `by` as who@node. 3. **Build on a local branch** `fix/-`, in a worktree of its own branched from `main`. Write the test that fails today first; make the change; keep `gofmt`, `go vet` and the unit tests of what changed green From 152cc0c0e77ce8c950327205202cc8040a2671da Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Fri, 16 Oct 2026 17:06:25 +0000 Subject: [PATCH 23/23] Playbook 08: a second fault the delivery shows joins the issue only in the same files Taken from issue 937, where mesh-catalog #335 was taken into the issue and issue 943 was opened for a fault in other code. --- 00-META/process/08-small-fixes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/00-META/process/08-small-fixes.md b/00-META/process/08-small-fixes.md index b8eec81d..149a2612 100644 --- a/00-META/process/08-small-fixes.md +++ b/00-META/process/08-small-fixes.md @@ -57,6 +57,11 @@ one delivery**. Everything before the push 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. +**A second fault found by the delivery.** When a fix's delivery shows a second fault that keeps the issue's +done-when from holding, and that fault is in the same files, it is taken into the same issue as a second pull +request with a review round of its own. A fault in other code is opened as an issue of its own, and the first +issue waits for it (issue 937: mesh-catalog #335 was taken in; issue 943 was opened). + ## Bounds | Waiting on | Bound | Past the bound |