Answer round 1 of the domain review of the approval mark and marked waits

The bus withholds a marked subject from a runner that does not honour the
mark again, as ADR 0286 has it; marks follow G's catalog half; a recording,
a stuck gate, an absent router and a start before the marks are read each
have a stated answer, so nothing runs unasked and nothing fails silently.

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 02:46:01 +01:00
parent ca1fbf7867
commit a6c9b96be3
5 changed files with 252 additions and 162 deletions
+2 -2
View File
@@ -1120,8 +1120,8 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03
(ADR 0286). It covers a module's events and streams too (the operator, 2026-11-11; design 34 every-event §32): a
module may mark one of its events, a restricted stream is marked whole, and a `mesh_wait` on a marked event runs
only on the operator's warrant for that one wait, with the exact names it waits on and its bound, which the tool
runner asks and checks before it subscribes. The tool runner reads every mark from the manifests and the seat list
on the bus (design 46 7-approval-mark §5).
runner asks and checks before it subscribes. The tool runner reads every mark from the catalog half on the bus
(design 46 7-approval-mark §5).
- **operator message / input** — what arrives on `intake`, once the router has checked the sender
against its own list of the operator's identities: a **trusted** one is an operator message,
addressed to an agent by `@name` or thread or else to the **responder** (`@mesh`, the router's own
+63 -37
View File
@@ -121,8 +121,11 @@ that holds its mark reach the machines together.
## The tool runner (module `node-tools`)
11. **Its manifest loses `waits`.** `node-tools/module.json` drops the key `waits` and its five entries; nothing else
in it changes, its `version` stays `2` (ADR 0670 §2).
11. **Its manifest's changes, every one.** `node-tools/module.json` drops the key `waits` and its five entries (ADR
0670 §2); gains `operator-channel` in `uses`, for the asks of marked waits (§35; design 46 7-approval-mark §7); gains
in `requires` the state `approvals` of design 46 7-approval-mark §13; and gains the stream `node-tools-findings` and
the `consumes` of `mesh-conditions.findings-asked` that design 47 G §387 writes. Its `version` stays `2`, a label
no reader judges. Nothing else in it changes.
12. **The publication time is kept.** `bus.Heard` gains `Published`, read from the event's header `x-time`, which
mesh-sdk's emit sets (`go/process/emit.go`) and the status view's own emit too; `HearFirst` reads it from the
message's headers, and leaves it empty for an event that carries none.
@@ -135,11 +138,12 @@ that holds its mark reach the machines together.
named by `buscompose.EventName` of the subject it arrived on. The timeout, the filter and the timed-out answer are
unchanged (ADR 0367 §1). The refusal of names outside a list, and its words naming the manifest, go (ADR 0670 §2).
14. **A misspelt name is refused, not waited on for ever.** Before it subscribes, `waitAnswer` refuses a name whose
emitter is neither a seat of the seat list the tool runner reads through the seat `mesh-catalog` nor a module of
the indexer's manifests it holds as a first view (`mesh-delivery-indexer.views.manifests`), naming both sources.
emitter is neither a seat nor a module of the catalog half the tool runner holds from G (its first view by
`mesh-catalog.revision`, followed on `catalog-revision`; design 47 G §196), naming that source and its revision.
A name whose emitter is known but whose event no seat definition and no manifest's `emits` declares is waited on,
and its timed-out answer says that no declaration names that event. While either source is not yet read (the
first views' state, `mesh_first_views`), names are not checked, and the answer says `unchecked` with why.
and its timed-out answer says that no declaration names that event. While the catalog half is not yet read (the
first views' state, `mesh_first_views`), names are not checked, and the answer says `unchecked` with why; a
marked wait is then held as §34 says.
15. **The answer names the heard event.** A heard event is answered as today, `heard` with `subject`, `body` and
`at`, where `subject` is now the heard event's whole name (`mesh-delivery-view.delivered`,
`operator-channel.decided.claude-code`), with two new fields: `from`, `seat` or `module`, the namespace it
@@ -176,8 +180,9 @@ that holds its mark reach the machines together.
a name with `*`, with `>`, of one token, 17 names, an emitter no source knows (§14), and a bus-refused subscription
answered after the timeout with §16's words; `TestMeshWaitWithNoFamiliesIssuedWaitsOnNothing` is deleted. In
`bus/wait_test.go`, `TestTheBusRefusesAWaitOutsideTheGrant` stays as §16's refusal test, with a timeout of a
fraction of a second, its comment citing ADR 0670 §1. No test function is added: the module stays within its
budget.
fraction of a second, its comment citing ADR 0670 §1. The manifest test also holds each change of §11: no `waits`,
`operator-channel` in `uses`, the state `approvals` in `requires` with its options, and the finding stream. No test
function is added: the module stays within its budget.
## The claude-code module's Stop hook
@@ -190,8 +195,9 @@ that holds its mark reach the machines together.
21. **The prepare lists every event.** The milestone file's prepare (playbook 07, step 0) gains a section *Events and
their fields*: every event each module's manifest `emits` and each seat's definition declares, read from the
indexer's modules (`mesh-delivery-view.indexer_modules`) and the seat definitions (`mesh-catalog.seat-definitions`),
each a holder's event with its subject form; and every event mesh-sdk publishes on a module's behalf (the
manifests and the seat definitions at the group's heads, not only from what the live bus holds, so the events G
and design 46's milestone 7 add are listed (the finding streams of design 47 G §383 among them), each a holder's
event with its subject form; and every event mesh-sdk publishes on a module's behalf (the
announcement's `states` on `mesh.mod.<module>.event.states`, found by the callers of its subject builders); each
with the fields of its body as the emitting code builds it, by file and line (ADR 0670 §4).
22. **The code review confirms none carries a secret, before the grant is delivered.** The milestone's code review
@@ -242,8 +248,10 @@ that holds its mark reach the machines together.
## Delivery
28. **One delivery group, no order named between its members.** The members are pushed and checked as one group. No
order is named between them, and no transitional field is kept (the operator, 2026-11-03: a change is designed as
28. **In G's delivery group, no order named beyond the module graph's.** The members are pushed and checked in design
47 milestone G's group, with design 46's milestone 7, whose edges (design 46 7-approval-mark §23) order the gate
before the seat definition that marks `execute`; this milestone adds no order of its own between its members, and no
transitional field is kept (the operator, 2026-11-03: a change is designed as
it should be, its delivery is the delivery system's): a part built with the new mesh-sdk reads a stored manifest of
the tool runner that still carries `waits` without it (ADR 0578 §3), and a node-engine is given a want only for a
manifest whose words it reads (ADR 0614 §4).
@@ -253,7 +261,7 @@ that holds its mark reach the machines together.
that it was issued no event families. Both are loud. A watcher reads its owner after every answer (ADR 0367 §4) and
ends at a call failed twice (its definition), so neither becomes a loop; a laptop asleep through the window gets
its new tool runner when it wakes, and its watchers read their owners meanwhile in the same way.
30. **Going back is going forward.** A fault met after the delivery is fixed by a new change delivered the same way.
30. **Going back is going forward** (design 46 7-approval-mark §24 for the gate's part). A fault met after the delivery is fixed by a new change delivered the same way.
Reverting the group instead reverts every member, the indexer first, since the manifest validator delivered here
sets aside the old tool runner's manifest carrying `waits` (§10); until the revert reaches a node, `mesh_wait`
there answers as §29 says.
@@ -288,22 +296,30 @@ approves, for a marked event or a restricted stream.
`events` carry, naming the event, as ADR 0286 §4 refuses a mark on a tool the module does not serve (design 46
7-approval-mark §4's table gains the row). A module that marks only events needs neither `operator-channel` in
`uses` nor `approval-mark/1`: the tool runner asks for the wait, not the module.
33. **The tool runner reads the marks from the manifests on the bus.** The tool runner derives each module's marked
subjects from the indexer's manifests it already holds as a first view (`mesh-delivery-indexer.views.manifests`,
§14): for a marked event `<event>` of module `<module>`, `mesh.mod.<module>.event.<event>` and
`mesh.stream.<module>.event.<event>`, each event pattern as the bus spells it (`WirePattern`); for a stream with a
`grant`, every subject of `ModuleStream.Subjects()`. It derives them again on every change of that view, and no
module's name is written in its code; it is design 46 7-approval-mark §5's derivation, extended to events. *Why:*
33. **The tool runner reads the marks from the catalog half on the bus.** The tool runner derives each module's marked
subjects from the catalog half it holds (§14; the catalog graph entry carries `needs-approval` and each stream's
`grant`, design 46 7-approval-mark §5): for a marked event `<event>` of module `<module>`,
`mesh.mod.<module>.event.<event>` and `mesh.stream.<module>.event.<event>`, each event pattern as the bus spells it
(`WirePattern`); for a stream with a `grant`, every subject of `ModuleStream.Subjects()`; and each of these also
followed by `.>`, since an event may name its node or asker after its name (design 47 G §383) and
`ModuleStream.Subjects()` answers only the patterns the stream stores. It derives them again on every revision it
hears, and no module's name is written in its code; it is design 46 7-approval-mark §5's derivation, extended to
events, following the running version as that line says. A mark added while a wait waits applies from the next
call, which that call's answer says. *Why:*
ADR 0286 §5 had the mark issued in a membership; no controller issues one now, a membership names no event (ADR
0670 §2), and the judged manifest on the bus keeps the mark out of any bundle as §5 required (the operator,
2026-11-11: the mark read from the manifests on the bus); §14 already reads this view.
2026-11-11: the mark read from the manifests on the bus); from G the catalog half is where the tool runner reads
which modules exist (design 47 G §196).
34. **Which wait is marked.** A wait is marked when any subject it subscribes (§13, §26, after `from`) overlaps a
marked subject of §33, that is, some subject matches both, a wildcard on either side. mesh-sdk's `events.go` (§1)
gains `Overlaps(a, b)` for it. While the manifests view is not yet read (`mesh_first_views`), a wait with any
subject outside `mesh.seat.` is marked and its refusal says the marks are not yet read, since a mark that cannot
be read runs nothing (ADR 0286 §40; design 46 7-approval-mark §19); a wait `from: seat` is never marked.
gains `Overlaps(a, b)` for it. Before the catalog half is read (`mesh_first_views`), a wait with any subject
outside `mesh.seat.` waits, within its own timeout, for the first view and is then judged; nothing is asked while
the marks are unread, and a wait still unjudged when its timeout ends is refused then, saying the marks are not
yet read, since a mark that cannot be read runs nothing (ADR 0286 §40; design 46 7-approval-mark §19). A wait
`from: seat` is never marked.
35. **A marked wait runs only on the operator's warrant for that one wait.** The call is an act as design 46
7-approval-mark §8 makes one: the address `mesh_wait`, the node, the module `node-tools`, its build, and every
7-approval-mark §8 makes one: the address `mesh_wait`, the node, the module `node-tools` and the tool `mesh_wait`,
its build (the digest of the tool runner's own artifact), and every
argument given (`subjects`, `from`, `filter`, `timeout`), so the warrant binds the exact names, the filter and the
bound. The tool runner refuses, asks, judges and claims it as that part's §9, §10, §11 and §13 to §17 do for a
marked tool, asking on the seat `operator-channel` under its own module's name, `node-tools`, whose manifest gains
@@ -317,18 +333,24 @@ approves, for a marked event or a restricted stream.
shown with the exact names it waits on and its bound.
36. **A refused marked wait is said, and never a hot loop.** A marked wait with no warrant the tool runner accepts
subscribes to nothing. Its first call publishes the ask at once; every such call answers, as an error, design 46
7-approval-mark §12's or §17's words with "this wait" for "the call", only after its timeout or its caller's going, as §16
answers a refused subscription. *Why:* ADR 0286 §14 answers within 5 seconds, which a watcher's loop would turn
into a call every few seconds for the ask's hour; a call made again after the operator's Approve, within 30
minutes of it, runs. An unmarked wait is heard as §13 to §16 say, with no ask.
37. **The tests hold it.** §19's table of refusals in `console/wait_test.go` gains rows, no test function: a wait on a
fixture module's marked event, and one on a fixture stream with a `grant`, each with no warrant, subscribes
nothing, asks once and answers ADR 0286 §37's words after its timeout; the same wait with a warrant bound to its
exact names, filter and timeout subscribes and answers the event published after it, so the restricted stream's
event is heard only after the warrant; with a warrant for other names, another filter or another timeout it is
refused; the same names `from: seat` ask nothing; and before the manifests view is read, a module's name is
refused as §34 says. They run on the tool runner's test bus (`meshtest`), the warrant written there as the
router's record. `Overlaps` gains rows in §1's table (`mesh.stream.mail.event.mail.>` overlaps
7-approval-mark §12's or §17's words with "this wait" for "the call", when its timeout ends or its caller goes, as
§16 answers a refused subscription, or as soon as the router's record of its ask says it was chosen: the wait hears
the warrant event `operator-channel.decided.node-tools` for its ask's id and then reads the record, an event only
waking it, and answers at once, so the same call made again runs within the warrant's 30 minutes. *Why:* ADR 0286
§14 answers within 5 seconds, which a watcher's loop would turn into a call every few seconds for the ask's hour;
ending at the choice keeps a long wait from spending the warrant's window. An unmarked wait is heard as §13 to §16
say, with no ask.
37. **The tests hold it.** Unit, as the budget counts them (`meshtest` runs its bus in the test's process): §19's table
of refusals in `console/wait_test.go` gains rows, no test function: a wait on a fixture module's marked event, and
one on a fixture stream with a `grant`, each with no warrant, subscribes nothing, asks once and answers design 46
7-approval-mark §12's words after its timeout; a wait with the most timeout a wait takes (ten minutes, ADR 0367
§1), its ask chosen at its second minute, answers at the choice, and the same call made then runs; the same wait
with a warrant bound to its exact names, filter and timeout subscribes and answers the event published after it,
so the restricted stream's event is heard only after the warrant; with a warrant for other names, another filter
or another timeout it is refused; the same names `from: seat` ask nothing; a wait named `<module>.<event>.<node>`
under a marked `<module>.<event>` is marked; and before the catalog half is read, a marked wait asks nothing, is
judged when the first view comes within its timeout, and is refused at its timeout when it does not. The warrant is
written on the test bus as the router's record. `Overlaps` gains rows in §1's table (`mesh.stream.mail.event.mail.>` overlaps
`mesh.stream.mail.event.mail.*.message`; `mesh.mod.mail.event.x` does not overlap `mesh.stream.mail.event.x`), and
§32's refusal a row in the indexer's `judge/rules_test.go`.
@@ -353,4 +375,8 @@ approves, for a marked event or a restricted stream.
`mesh-delivery-checker.verdict` wakes on the checker's next verdict (§25, §26; ADR 0671 §1).
- **The grant does not follow a restricted stream's grant value** (integration on a real bus): §27's cases pass
(ADR 0671 §2).
- **A marked wait runs only on the operator's warrant** (unit, and on the test bus): §37's rows pass.
- **A marked wait runs only on the operator's warrant** (unit): §37's rows pass.
- **A wait on mail, as the operator sees it** (live, read by tool call and on the phone): a session's `mesh_wait` on
`mesh-mail.mail`, the mail module's restricted stream, asks "Wait on mesh-mail.mail on <node>?" on the phone with
its bound, and hears nothing before; it ends refused when its timeout ends or as soon as the operator chooses; the
same call made after the Approve hears the next mail, and the next call asks again (§32 to §36).
+2 -2
View File
@@ -143,7 +143,7 @@ reads the state once from the verb that owns it: an event only wakes it (ADR 036
flowchart LR
E[a seat's, a module's or a module stream's event<br/>mesh.seat.&lt;seat&gt;.event.… / mesh.mod.&lt;module&gt;.event.… / mesh.stream.&lt;module&gt;.event.…] -->|heard for the call| TR[the tool runner's account]
G[seat mesh-grants] -->|grants the three event subjects| TR
M[the indexer's manifests] -->|the marked events and restricted streams| TR
M[the catalog half, seat mesh-catalog] -->|the marked events and restricted streams| TR
TR -->|a marked wait only on the operator's warrant| OC[seat operator-channel]
TR -->|mesh_wait answers it by name| S[a session]
S -->|then reads the state| O[the verb that owns it]
@@ -169,7 +169,7 @@ needs no `consumes` and no entry in that value, and keeps no consumer of it.
**A marked event is heard only on the operator's warrant** (the operator, 2026-11-11). The approval mark (ADR 0286) covers a module's events and streams as well as its tools and
verbs: a module may mark one of its events in `needs-approval`, and a restricted stream is marked whole. The tool
runner reads the marks from the indexer's manifests on the bus, and a `mesh_wait` on a marked event, or on any subject
runner reads the marks from the catalog half on the bus (seat `mesh-catalog`), and a `mesh_wait` on a marked event, or on any subject
of a marked stream, runs only on the operator's warrant for that one wait, asked on the seat `operator-channel` with
the exact names it waits on and its bound, and checked before the tool runner subscribes; without one it is refused
and says so. The bus grants the subjects, and the tool runner's own gate holds the mark, as the operator chose; the
@@ -8,12 +8,14 @@ decisions:
- "ADR 0286"
- "ADR 0259"
- "ADR 0627"
- "ADR 0656"
- "ADR 0666"
- "ADR 0668"
- "ADR 0595"
- "ADR 0597"
- "ADR 0310"
- "ADR 0268"
- "ADR 0564"
---
# Design 46, milestone 7 — a call that needs the operator's approval
@@ -21,78 +23,100 @@ decisions:
**What it builds.** A tool or a seat verb marked in its manifest or its seat's definition runs only on the operator's
approval of that one call, with its exact arguments (ADR 0286). The first call asks the operator on the seat
`operator-channel` and runs nothing; the same call made again within 30 minutes of the operator's Approve runs once.
The tool runner (module `node-tools`) asks, judges and claims; the mark is read from the manifests and the seat list on
the bus. The shape is in the design's main file,
The tool runner (module `node-tools`) asks, judges and claims; it reads the marks from the catalog half on the bus; and
on a machine whose tool runner does not honour the mark the grants part withholds every marked subject. The shape is in
the design's main file,
[§10, *A call that needs the operator's approval*](../46-the-conversation-with-the-operator.md#a-call-that-needs-the-operators-approval);
this part holds every line the milestone builds, cited as "design 46 7-approval-mark §n".
**When.** It is built and delivered in design 47's milestone G, in one delivery group with G and with design 34's
milestone every-event, whose marked waits (design 34 every-event §32 to §37) use this gate (the operator, 2026-11-11:
"Build the gate in G").
**When.** It is built and delivered in design 47's milestone G, in G's delivery group, with design 34's milestone
every-event, whose marked waits (design 34 every-event §32 to §37) use this gate (the operator, 2026-11-11: "Build the
gate in G").
**Where.** mesh-sdk (the manifest field, the seat definition's field, the seat list), mesh-contracts (the login shell's
seat definition), mesh-delivery (the manifest validator in the indexer), mesh-tools (the tool runner's gate, its state,
its tool) and mesh-catalog (the zsh module, which holds the login shell). Nothing is built in a controller: no
controller issues memberships today, bus permissions are the grants part's (seat `mesh-grants`), the hand-act log is
the seat `mesh-hand-acts`, and the asker's logic is operator-channel's client in mesh-contracts (ADR 0627 §1).
**Where.** mesh-sdk (the manifest field, the seat definition's field, the per-machine state's keys), mesh-contracts
(the login shell's seat definition), mesh-delivery (the indexer's manifest validator and catalog graph entry, the grants
part's deny), mesh-tools (the tool runner's gate, its state, its tools) and the mesh MCP server's `mesh_describe` in
it. Nothing is built in a controller: no controller issues memberships today, bus permissions are the grants part's
(seat `mesh-grants`), the hand-act log is the seat `mesh-hand-acts`, and the asker's logic is operator-channel's client
in mesh-contracts (ADR 0627 §1).
**What changes from ADR 0286 as written.** Each line below says in its *Why* where something built since ADR 0286
(2026-10-10) changes how a clause is met: the mark is read from the bus and not from a membership (§5), a module is held
off a runner that does not honour it by the capability hold and not by its bus permissions (§6), the digest is Go alone
(§8), the claim is kept in the runner's bus state and not a file (§13), `warranted` is a kept call and not a retry on
a timer (§16), and a fourth open ask is offered as G makes it (§17). The controller's own verbs (ADR 0286 §43) are
not built: no controller serves verbs.
**What changes from ADR 0286 as written.** Each line says in its *Why* where something built since ADR 0286
(2026-10-10) changes how a clause is met: the mark is read from the catalog half and not from a membership (§5), the
digest is Go alone (§8), the claim is kept in the runner's bus state and not a file (§13), `warranted` is a kept call
and not a retry on a timer (§16), and a fourth open ask is offered as G makes it (§17). The controller's own verbs (ADR
0286 §43) are not built: no controller serves verbs.
**The bound of the gate.** The gate holds for every call that reaches the tool runner's handler. It does not hold for
a process that reads the tool runner's bus credential (the file `broker` in its state directory, `own-secrets`) and
speaks to the bus itself: its account may subscribe a marked subject on a machine whose runner honours the mark. Who
may read that file is therefore the bound of the operator's choice; the prepare reads its mode on every machine with
`<node>/node-reads.stat` and writes it in the milestone file, and a mode readable beyond the operator's account is a
design question for the operator before develop. The same limit as design 47 G §385 (one tool-runner account per
machine).
## The mark
1. **A module marks its tools and verbs in `needs-approval`.** mesh-sdk's `catalogue.Manifest` gains `NeedsApproval`,
the manifest key `needs-approval`: a list of strings, each a tool the module serves (`<tool>`) or a seat verb it
serves (`<seat>.<verb>`), and, under design 34 every-event §32, one of its events. Absent is no mark. *Why:* ADR
0286 §1, §49 (each marking is a manifest change, reviewed like any other). *How it is checked:* a row in the
decoder's table test in `go/catalogue` decodes the key, and the manifest reads baseline gains `word:needs-approval`.
0286 §1, §49 (each marking is a manifest change, reviewed like any other). *How it is checked:* unit, a row in the
decoder's table test in `go/catalogue`; the manifest reads baseline gains `word:needs-approval`.
2. **A seat's definition marks a verb for every holder.** mesh-sdk's `seatdef` reads a verb's `needs-approval`, a
boolean, in a seat definition (`seats/<seat>/seat.json` in mesh-contracts), and the seat list it reads into
(`seatlist`, read with `mesh-catalog.seat-definitions`) carries it on the verb. *Why:* ADR 0286 §2; the seat list
is where the tool runner already reads the seats it holds verbs of. *How it is checked:* a fixture row in
`seatdef`'s table test, and one in `seatlist`'s.
boolean, in a seat definition (`seats/<seat>/seat.json` in mesh-contracts); the seat definitions the catalog half
carries (design 47 G §194) carry it on the verb. *Why:* ADR 0286 §2. *How it is checked:* unit, a fixture row in
`seatdef`'s table test.
3. **Marks add up.** A verb is marked when its seat's definition or its holder's `needs-approval` marks it; a holder
cannot unmark what its seat marks. *Why:* ADR 0286 §3. *How it is checked:* a row of §5's table: a seat-marked verb
with no entry in the holder's manifest is marked.
cannot unmark what its seat marks. *Why:* ADR 0286 §3. *How it is checked:* unit, a row of §5's table.
4. **The manifest validator refuses a mark it cannot honour.** The indexer's manifest validator (`judge/rules.go`)
refuses, as the checker runs it, and sets aside to wait, as the indexer runs it, a manifest that: marks a tool its
`tools` does not list, or a verb its `claims` do not serve (ADR 0286 §4); marks a tool or a verb, or holds a seat
verb its seat marks, without `operator-channel` in `uses` (§7) or without `approval-mark/1` in `capabilities` (§6); or
marks a tool or a verb and declares a resource of type `process`, whose tools its own program answers and no tool runner
gates. Each refusal names the entry and the rule. *Why:* a mark nothing enforces would be a call that runs unasked
while saying it is guarded; ADR 0286 §43 had the controller enforce its own verbs, and no other own-process server
has a gate, so such a mark is refused rather than ignored (the design's choice under ADR 0286 §4, §40). *How it is
checked:* one row per refusal in `judge/rules_test.go`, and a row that accepts the zsh module's manifest of §21.
verb its seat marks, without `operator-channel` in `uses` (§7); marks a tool or a verb and declares a resource of
type `process`, whose tools its own program answers and no tool runner gates; or names in `needs-approval` one name
that is both one of its tools and one of its events. Each refusal names the entry and the rule. *Why:* a mark
nothing enforces would be a call that runs unasked while saying it is guarded; ADR 0286 §43 had the controller
enforce its own verbs, and no other own-process server has a gate, so such a mark is refused rather than ignored;
and an entry that names two things is read one way by one reader and another way by the next (the design's choices
under ADR 0286 §4, §40). *How it is checked:* unit, one row per refusal in `judge/rules_test.go`, and a row that
accepts the zsh module's manifest of §21.
## Where the tool runner reads it
## Where the marks are read, and where they are withheld
5. **From the manifests and the seat list on the bus, never from a bundle.** The tool runner derives, for each module
it serves, the set of its marked tools and verbs from the indexer's manifests it consumes as a first view
(`mesh-delivery-indexer.views.manifests`) and from the seat list it reads (`seatlist`), again on every change of
either, in a package of its own, `node-tools/internal/approval`. No module's name is written in its code. *Why:*
ADR 0286 §5 had the controller issue the mark in a membership so that a bundle could not drop it; no controller
issues memberships now, and the judged manifest on the bus is the same guarantee: the bundle never carries the mark.
*How it is checked:* a table test in `approval` derives the marks from fixture manifests and a fixture seat list,
§3's row among them.
6. **A marked module runs only where the runner honours the mark.** The tool runner states `approval-mark/1` among
its call capabilities (`runtime.CallCapabilities`), which its announcement carries and its node's node-engine takes
into the node's record; a module whose manifest asks for `approval-mark/1` in `capabilities` (§4) is held off a
machine whose runner does not state it, as every capability is (ADR 0595 §9, ADR 0597). *Why:* ADR 0286 §7 and §8
withheld each marked tool from a runner that did not honour the mark, by leaving its subject out of that runner's
bus permissions; the capability hold, built since, keeps the module from running there at all, and the grants part
grants a module's tools as `mesh.mod.<module>.tool.>` whole, so no subject is left out (ADR 0286 §9 has nothing to
name apart). *How it is checked:* the existing capability test of `CallCapabilities` gains the entry; and in §22's
whole test a marked fixture module is not loaded by a runner built without the capability.
5. **From the catalog half on the bus, never from a bundle.** The indexer's catalog graph entry of a module (design 47
G §174) gains its `needs-approval` and, for each stream it declares, whether the stream carries a `grant`; the seat
definitions of the catalog half carry the verb marks (§2). The tool runner, which from G takes its first view of the
catalog half by `mesh-catalog.revision` and follows `catalog-revision` (design 47 G §196), derives from it, for each
module it serves, its marked tools and verbs, in a package of its own, `node-tools/internal/approval`, again on
every revision it hears. No module's name is written in its code. The marks follow the running version: the runner
applies the marks of the module's version it serves, and, while the newest revision's entry for that module
differs, the union of both, so a mark is never lost before or after the module moves. A mark added while a call
waits applies from the next call, which the answer of §12 says. *Why:* ADR 0286 §5 had the controller issue the mark
in a membership so that a bundle could not drop it; no controller issues memberships now, and the judged catalog
half is the same guarantee: the bundle never carries the mark (ADR 0656 §6, one source for which modules exist).
The union keeps ADR 0286 §3's "marks add up" across a version change. *How it is checked:* unit, a table test in
`approval` derives the marks from fixture catalog halves, §3's row, a version change and the union among them.
6. **A machine whose tool runner does not honour the mark serves no marked tool or verb.** The tool runner states
`approval-mark/1` among its call capabilities (`runtime.CallCapabilities`), which its announcement carries and its
node's node-engine takes into the node's record; the assignment half carries it among the capability readings
(design 47 G §194). The grants part, composing a runtime's account, reads that runtime's node's readings: where the
tool runner does not state `approval-mark/1`, it composes a subscribe deny of every marked subject of every module
the runtime carries (`mesh.mod.<module>.tool.<tool>`, the same followed by `.*`, and for a marked verb
`mesh.seat.<seat>.tool.<verb>`, the same followed by `.<node>`), which the bus's deny outranks its allow of
`mesh.mod.<module>.tool.>` for. `Permissions` gains `SubscribeDeny`, written into the user list as the server's
subscribe deny, as `PublishDeny` is for publishing. The withheld tools and verbs are named in the grants part's read
of that account (`mesh-grants.grants_user_list`, a field `withheld` with each subject and "its tool runner does not
state approval-mark/1"), and in the node-engine's `composition` of the module. *Why:* ADR 0286 §7, §8, §9: the bus
enforces the mark; the runner's status of ADR 0286 §7 is read from the grants part's account read, since a runner
that does not honour the mark is a version that cannot say so. *How it is checked:* unit, the grants part's
composition table: with readings lacking the capability the deny of each marked subject is composed and named in
`withheld`, with it no deny; integration, the grants part's real-bus test: an account composed with the deny is
refused delivery of a call on a marked subject while it holds `mesh.mod.<module>.tool.>`.
7. **The asker's grants are a user's of `operator-channel`.** Because the manifest says `operator-channel` in `uses`
(§4), the grants part composes, on the account of the runtime carrying the module, the publish of
`mesh.seat.operator-channel.accept.ask.<module>` and `.cancel.<module>`, the hearing of its warrants on
`mesh.seat.operator-channel.event.decided.<module>` and the read of the router's record under `<module>.` in the
seat's state `asks`, as for every user (ADR 0259 §3). Nothing new is composed for the mark. *Why:* ADR 0286 §6.
*How it is checked:* a row in the grants part's composition table test for a fixture module with a mark.
seat's state `asks`, as for every user (ADR 0259 §3). The runner passes the client its own publish and read on that
runtime's account (`Client.Publish`, `Client.Record`), never the bundle's. *Why:* ADR 0286 §6. *How it is checked:*
unit, a row in the grants part's composition table for a fixture module with a mark.
## The act, and the first call
@@ -102,12 +126,12 @@ not built: no controller serves verbs.
argument given, a string as itself and any other value as its JSON in RFC 8785's canonical form; an argument left
out is not in the act. Its digest is `operatorchannelclient.ActDigest`. *Why:* ADR 0286 §10, §11; the digest is in
mesh-contracts since ADR 0627 §1. The TypeScript twin ADR 0286 named is not built: the tool runner is Go, and no
TypeScript asker computes an act. *How it is checked:* table rows in `approval` for the act's fields, an omitted
TypeScript asker computes an act. *How it is checked:* unit, rows in `approval` for the act's fields, an omitted
argument, a number, an object and a changed build each giving another digest.
9. **A call refused without asking.** On a call with no approval for its act, the runner refuses at once, asking
nothing, a call whose arguments hold anything `outward.CheckSecret` refuses (mesh-sdk), or whose arguments are more
than 16 KiB. *Why:* ADR 0286 §12; mesh-sdk's `outward` is the content rule ADR 0310 §4 moved there. *How it is
checked:* two rows of §22's refusal table.
checked:* unit, two rows of §22's table.
10. **One ask, under the module's name.** Otherwise the runner asks through an `operatorchannelclient.Client` whose
`Module` is the marked module and whose `State` is the runner's state of §13, unless an ask for the same act is
open there (§13's `act.` key), in which case it asks nothing new. The ask: `about` the act's digest; `who`
@@ -117,103 +141,138 @@ not built: no controller serves verbs.
whole; the explanation: the first line of the tool's own description, the node, that it was called through the
mesh's tools, which cannot tell who called, every argument one per line as "name: value", and the act's
fingerprint, its digest's first 24 hexadecimal digits in groups of four. *Why:* ADR 0286 §13, §15, §16, §20 to
§23; the client checks the ask (`Check`) before it publishes. *How it is checked:* a test in `approval` holds the
published ask's fields against a fixture call, and a second identical call publishes nothing.
§23; the client checks the ask (`Check`) before it publishes. *How it is checked:* unit, a row in `approval` holds
the published ask's fields against a fixture call, and a second identical call publishes nothing.
11. **An argument is shown whole only where it may leave the mesh.** Each argument is shown whole where
`outward.Check` passes it, else in its shape with ‹path›, ‹address› or ‹withheld› in place of what it refuses; the
arguments are shown whole when they are at most 2000 bytes and 40 lines, otherwise their first 20 lines and 1200
bytes, marked "NOT SHOWN IN FULL", and the explanation then says that the whole is read with `mesh_approvals`
(§18) on that node, whose fingerprint must be the one on the phone. *Why:* ADR 0286 §17 to §19. *How it is
checked:* rows of §10's test with a path, an address and a long argument.
12. **The first call answers "Not run".** The runner waits up to 5 seconds for the router's word on the ask (its
record, §14) and answers the call as an error, never as a result: "Not run: this needs the operator's approval.
Asked on <channel> at <time> (ask <id>, fingerprint …); make the same call again within 30 minutes of the
approval; the ask expires at <time>." *Why:* ADR 0286 §14, §37. A held call that runs on the Approve and returns
its outcome to the caller, which the operator asked for on 2026-10-16 (issue 417), is not this record's shape; it
is a question open with the operator. *How it is checked:* a row of §22's table holds the words.
checked:* unit, rows of §10's test with a path, an address and a long argument.
12. **The first call answers "Not run", or that the router has not taken it.** The runner waits up to 5 seconds for
the router's record of the ask (§14) and answers the call as an error, never as a result. With the record: "Not
run: this needs the operator's approval. Asked on <channel> at <time> (ask <id>, fingerprint …); make the same call
again within 30 minutes of the approval; the ask expires at <time>." With no record within the 5 seconds: "Not
run, asked; not yet taken by the router (ask <id>, fingerprint …); make the same call again later." The ask stays
in the seat's stream of accepts, a work queue the router takes it from when it runs, and the `act.` key stays, so
the next call reads the router's record of the same ask and asks nothing new. A mark added since the caller last
called is named in the answer ("marked since <revision>"). *Why:* ADR 0286 §14, §37. The caller calls again: the
held call the operator asked for on 2026-10-16 (issue 417), which runs on the Approve and returns its outcome, is
with the operator; this line is written for "call again" until the operator answers. *How it is checked:* unit,
rows of §22's table hold both answers; a row with no router holds that a second call asks nothing new.
## The runner's record, and the same call again
13. **The runner keeps its asks and claims in a state of its own, per machine.** The tool runner's manifest asks in
`requires` for a state `approvals`, template `state`, `per-machine`, `ttl-seconds` 172,800 (48 hours). Its keys:
`ask.<id>`, the asked call as the client keeps it (the ask, the act, the whole arguments, when asked, whether
acted on), and `act.<digest>`, the id of the newest ask for that act. The runner on each machine is the one writer
of its machine's bucket; a key is deleted by its time to live, never by hand. *Why:* ADR 0286 §24, §30 kept the
waiting call in the runner's record and claimed a warrant in the node's own file, kept 48 hours, by one writer per
node; the client built since keeps asks and marks a warrant acted on by compare-and-set in a module's bus state
(ADR 0259 §10, ADR 0627 §1), which is one writer per machine as a per-machine state (ADR 0595), so the file is not
built. *How it is checked:* the manifest test of `node-tools` holds the entry; §22's whole test reads the keys.
14. **The same call again is judged on the router's record.** When a call of a marked tool comes and `act.<digest>`
`requires` for a state `approvals`, template `state`, `per-machine`, `ttl-seconds` 172,800 (48 hours), cap 64 MiB.
Its keys: `<node>.ask.<id>`, the asked call as the client keeps it (the ask, the act, the whole arguments, when
asked, whether acted on, and `recorded` once `warranted` answered, §16), and `<node>.act.<digest>`, the id of the
newest ask for that act. The runner on each machine is the one writer of its machine's keys; a key is deleted by
its time to live, never by hand. A per-machine state reaches today only the key named for its machine; mesh-sdk's
per-machine form and the grants part's `stateAccess` gain the keys below it, `<node>.>`, for every per-machine
state: one more subject per per-machine state on each account, and every module's per-machine keys keep their
form. A write the bus refuses (the cap reached, or any other) fails closed under §19 and is said in the answer.
*Why:* ADR 0286 §24, §30 kept the waiting call in the runner's record and claimed a warrant in the node's own file,
kept 48 hours, by one writer per node; the client built since keeps asks and marks a warrant acted on by
compare-and-set in a module's bus state (ADR 0259 §10, ADR 0627 §1), and a per-machine state (ADR 0595) is one
writer per machine, so the file is not built. The cap and the key form are the design's choices. *How it is
checked:* unit, the manifest test of `node-tools` holds the entry; the grants part's composition table holds the
`<node>.>` reach and no other node's; integration, §22's whole test reads the keys.
14. **The same call again is judged on the router's record.** When a call of a marked tool comes and `<node>.act.`
names an ask, the runner reads the router's own record of that ask under the module's name (`Client.Where`, the
seat state `asks`, key `<module>.<id>`), never a record of its own or the caller's; it composes the ask again from
the act and holds the warrant to it with `operatorchannelclient.For` (the same asker and ask, the ask's digest, a
person's choice, an option offered, at its level, before it expired); it requires the option to be `approve` and
the act to be the one it bound (`operatorchannelclient.Performs`: the same node, build and every argument); and it
requires the call within 30 minutes of the choice. It judges the newest ask it keeps for the act. *Why:* ADR 0286
§26 to §29, §32. *How it is checked:* rows of §22's table: approved, approved for other arguments, approved 31
minutes ago, declined, expired, another asker's warrant.
15. **One approval runs one call.** Before it runs, the runner marks `ask.<id>` acted on by compare-and-set
§26 to §29, §32. *How it is checked:* unit, rows of §22's table: approved, approved for other arguments, approved
31 minutes ago, declined, expired, another asker's warrant.
15. **One approval runs one call.** Before it runs, the runner marks `<node>.ask.<id>` acted on by compare-and-set
(`Client.Take`); a warrant marked before is refused, so one approval runs one call however often the call is made,
and a warrant replayed onto the bus runs nothing. After "already run", "expired" or "approved too long ago" the next
identical call asks anew, and the used mark stays. *Why:* ADR 0286 §30, §31, §33, §36. *How it is checked:* a row
of §22's table makes the approved call twice and runs it once; two calls at the same moment run it once.
16. **The call runs, and its warrant is recorded.** Once the checks pass, the runner runs the call and answers with
the tool's own answer and a line naming the approval ("run on the operator's approval via <channel> at <time>, ask
<id>"). It then calls `mesh-hand-acts.warranted` with `asker` (the module) and `ask` (the id) as a kept call (ADR
0668 §1, §2: the verb takes it once per ask), so a transport fault calls it again until it is answered, and one
unanswered after five minutes is the runner's `call-unanswered` finding. *Why:* ADR 0286 §34, §35; the hand-act log
is the seat `mesh-hand-acts`, whose `warranted` reads the router's own record, and its "again every ten minutes for
a week" is ADR 0668's kept call now. *How it is checked:* §22's whole test reads the hand-act recorded once.
identical call asks anew, and the used mark stays. *Why:* ADR 0286 §30, §31, §33, §36. *How it is checked:* unit, a
row of §22's table makes the approved call twice and runs it once; two calls at the same moment run it once.
16. **The call runs, and its warrant is recorded, across a restart too.** Once the checks pass, the runner runs the
call and answers with the tool's own answer and a line naming the approval ("run on the operator's approval via
<channel> at <time>, ask <id>"). It then calls `mesh-hand-acts.warranted` with `asker` (the module) and `ask` (the
id) as a kept call (ADR 0668 §1, §2: the verb takes it once per ask), and on its answer writes `recorded` on
`<node>.ask.<id>`. At each start the runner calls `warranted` again for every acted, unrecorded ask its keys hold,
within their 48 hours, each named in its `findings-stated`'s `pending` until it is made (design 47 G §384). One
unanswered after five minutes is the runner's finding `<node>.<ask id>.call-unanswered` in its state `findings`,
said on its stream `node-tools-findings` (design 47 G §383, §387), which the condition keeper hears; it clears when
`warranted` answers. *Why:* ADR 0286 §34, §35; the hand-act log is the seat `mesh-hand-acts`, whose `warranted`
reads the router's own record, and its "again every ten minutes for a week" is ADR 0668's kept call now, kept
across a restart by the `recorded` mark (ADR 0668 §3, ADR 0564). *How it is checked:* integration, §22's whole test
reads the hand-act recorded once, also when the runner is restarted after the run and before `warranted` answers.
17. **What a later call is told.** For the same call made again before it can run, the caller is told, as an error:
still waiting; declined (the same act is not asked again for 10 minutes, and the answer says so); expired,
approved too long ago or already run (each asks again, §15); or refused, with the router's words. An ask the router
holds back as the asker's fourth open one is still waiting, and `operator-channel.asks` lists it (ADR 0666 §12, as
G builds it). *Why:* ADR 0286 §38, §39; ADR 0286 §40's refusal of a fourth open ask was the router's before G, which
now offers a fourth and holds the oldest back. *How it is checked:* rows of §22's table.
18. **The tool `mesh_approvals` reads what was asked.** The mesh MCP server on each machine gains the tool
`mesh_approvals`: the calls asked on that machine in the last day, newest first, each with its state and
fingerprint, read from §13's state; given an ask's id, its whole arguments and the act's digest. It writes nothing.
*Why:* ADR 0286 §25 (the runner's `approvals`), named as the mesh MCP server's own tools are. *How it is checked:*
a row in the mesh MCP server's tool table test, and §22's whole test reads an asked call with it.
approved too long ago or already run (each asks again, §15); not yet taken by the router (§12); or refused, with the
router's words. An ask the router holds back as the asker's fourth open one is still waiting, and
`operator-channel.asks` lists it (ADR 0666 §12, as G builds it). *Why:* ADR 0286 §38, §39; ADR 0286 §40's refusal
of a fourth open ask was the router's before G, which now offers a fourth and holds the oldest back. *How it is
checked:* unit, rows of §22's table.
18. **The tools read and steer what was asked.** The mesh MCP server on each machine gains the tool `mesh_approvals`:
with no argument, the calls asked on that machine in the last day, newest first, each with its state and
fingerprint, read from §13's state, and the marks it applies, each module's marked tools and verbs with their
source (its manifest or its seat's definition) and the catalog revision read; given an ask's id, its whole
arguments and the act's digest; given `cancel` and an ask's id, it takes that open ask back (`Client.Cancel`),
recorded first in the hand-act log through `mesh-hand-acts.hand-act` with who and why, and refused when the record
cannot be written. `mesh_describe` answers, for a marked tool or verb, `needs-approval` with its source. *Why:*
ADR 0286 §25 (the runner's `approvals`), named as the mesh MCP server's own tools are; a tool reads everything a
module holds and does by hand what it does by itself (the operator's instruction of 2026-10-25). *How it is
checked:* unit, rows in the mesh MCP server's tool table test: the list, the marks with their sources, an ask read
whole, a cancel recorded and one refused without a record, and `mesh_describe` of a marked tool.
## Failing closed
19. **Nothing runs when a part of the check is missing.** A call of a marked tool is refused, runs nothing and says
why when: no module holds `operator-channel` (the seat list says no holder); the router refuses the ask; the ask
cannot be published; the router's record cannot be read; §13's state cannot be read or written, in which case no
marked call runs on that machine until it can; or the marks cannot be read (the manifests view or the seat list not
yet read, `mesh_first_views`). Each refusal is written in the runner's log with the ask's id and fingerprint, never
the arguments. *Why:* ADR 0286 §40, §42. *How it is checked:* one row of §22's table per case.
19. **Nothing runs when a part of the check is missing, and a stuck gate is said.** A call of a marked tool is
refused, runs nothing and says why when: no module holds `operator-channel` (read from the assigner's first view
`mesh-delivery-assigner.views.seat-holders`, which the tool runner consumes; the seat list names no holders); the
router refuses the ask; the ask cannot be published; the router's record cannot be read; §13's state cannot be read
or written, in which case no marked call runs on that machine until it can; or the marks are not yet read. Before
the first view of the catalog half is read, a call waits for it within its 5 seconds and is then judged, asking
nothing while the marks are unread; still unread, it is refused, naming `mesh_first_views`. When §13's state has
been unreadable or unwritable for five minutes, the runner raises its finding `<node>.approvals.approvals-unreadable`
(said on `node-tools-findings` as §16's), and clears it at the next read and write that succeed. Each refusal is
written in the runner's log with the ask's id and fingerprint, never the arguments. *Why:* ADR 0286 §40, §42; a
gate that refuses every call for a reason nobody hears is a silent fault, and the finding and its five minutes are
the design's choice. *How it is checked:* unit, one row of §22's table per case, the holder read from a fixture
`views.seat-holders` with none and with one, and the finding raised after five minutes and cleared.
20. **The terminal is not exempt.** A marked tool called through `mesh-cli` or any caller asks as every call does: the
runner cannot tell who called. *Why:* ADR 0286 §41. *How it is checked:* the gate sits on the call's handler,
before the bundle, whatever the caller; the code review reads that no path to a bundle passes around it.
runner cannot tell who called. *Why:* ADR 0286 §41. *How it is checked:* the code review reads that the gate sits
on the call's handler, before the bundle, and that no path to a bundle passes around it.
## Marked first
21. **`node-login-shell.execute` is marked in its seat's definition.** mesh-contracts' `seats/node-login-shell/seat.json`
marks the verb `execute` with `needs-approval`; the zsh module's manifest (mesh-catalog `modules/zsh`), which holds
the seat, gains `operator-channel` in `uses` and `approval-mark/1` in `capabilities`. The control-node keeps
withholding `execute`, and whether it serves it again under the mark stays the operator's setting. *Why:* ADR 0286
§44, §45: the reads it carried have their tools on every node (the seat `node-reads`, ADR 0310; issue 418 resolved
2026-10-12, answering on every node since 2026-10-16). No other tool or verb is marked in this milestone. *How it
is checked:* live, as the acceptance says.
the seat, gains `operator-channel` in `uses`. The control-node keeps withholding `execute`, and whether it serves
it again under the mark stays the operator's setting. *Why:* ADR 0286 §44, §45: the reads it carried have their
tools on every node (the seat `node-reads`, ADR 0310; issue 418 resolved 2026-10-12, answering on every node since
2026-10-16). No other tool or verb is marked in this milestone. *How it is checked:* live, as the acceptance says.
## Tests and delivery
## Tests, delivery and going back
22. **The tests.** The tool runner's tests in `node-tools/internal/approval` are one table-driven test of the refusals
and answers (§9, §12, §14, §15, §17, §19) and one of the marks (§5), on the tool runner's test bus (`meshtest`),
the router's record and the warrant written there as the router writes them; and one whole test that starts the
runner against the real bus and store with a fixture marked module, makes a call, writes the operator's Approve as
the router's record, makes the call again, and reads the run, the hand-act and `mesh_approvals`. *Why:* the
operator's test budget (one whole test over many small ones). *How it is checked:* the check counts the module's
tests against its budget.
23. **One delivery group with milestone G and every-event.** The members are pushed and checked as one group with
design 47's milestone G and design 34's milestone every-event. The orders between them are the module graph's: the
indexer's manifest validator that reads `needs-approval` before any manifest or seat definition carrying it (a
reader edge), and the tool runner stating `approval-mark/1` before the zsh module's version asking for it is placed
(the capability hold, §6). *Why:* the operator, 2026-11-11, "Build the gate in G"; the operator, 2026-11-03, a
change is designed as it should be and its delivery is the delivery system's. *How it is checked:* the delivery
plan names both edges.
22. **The tests.** The tool runner's tests in `node-tools/internal/approval` are one table-driven unit test of the
refusals and answers (§9, §12, §14, §15, §17, §19) and one of the marks (§5), on the tool runner's test bus
(`meshtest`), the router's record and the warrant written there as the router writes them; and one integration
test that starts the runner against the real bus, with no store, with a fixture marked module: a call, the
operator's Approve written as the router's record, the call again, the run, the hand-act, `mesh_approvals`, and a
restart between the run and `warranted`'s answer. *Why:* the operator's test budget (one whole test over many small
ones). *How it is checked:* the check counts the module's tests against its budget.
23. **In G's delivery group, ordered by the module graph.** The members are pushed and checked in design 47 milestone
G's group, with design 34's milestone every-event. The orders are the module graph's: the indexer's manifest
validator and catalog graph entry that read `needs-approval` before any manifest or seat definition carrying it (a
reader edge, design 47 G §89); and the grants part that composes the deny of §6 before the seat definition marking
`execute` (an edge of the seat definition's readers), so no machine serves `execute` unasked between the two.
*Why:* the operator, 2026-11-11, "Build the gate in G"; the operator, 2026-11-03, a change is designed as it should
be and its delivery is the delivery system's. *How it is checked:* the delivery plan names both edges.
24. **Going back is going forward.** A fault met after the delivery is fixed by a new change delivered the same way.
Reverting instead reverts G's whole group in the reverse of §23's order: the seat definition's mark first, then the
grants part, then the validator. The `approvals` state is then declared by no running module: it is an orphan
`orphans` lists, its keys aging out within 48 hours, dropped through ADR 0595's `drop` on the operator's word.
*Why:* design 47 G's revert rule; ADR 0595 §4, §5. *How it is checked:* the delivery plan of a revert names the
order.
## Acceptance
@@ -221,6 +280,10 @@ not built: no controller serves verbs.
`node-login-shell.execute` on a node other than the control-node answers "Not run", the ask is on
`operator-channel.asks`, and after the operator's Approve the same call runs once, a third identical call is refused
as already run, and `mesh-hand-acts.hand-acts` names the warranted act (§10, §12, §14 to §16, §21).
- **No machine serves `execute` unasked** (live, read by tool call): before this acceptance passes, on every node
`execute` is either asked as above or absent, read with each node's `node-engine.composition` and
`mesh-grants.grants_user_list`'s `withheld` (§6).
- **A marked wait as the operator sees it** (live): design 34 every-event's acceptance of a wait on a mail event.
- **The mark cannot be lost on the way** (unit): §5's and §8's tables pass; a bundle carries no mark.
- **It fails closed** (unit): §19's rows pass.
- **The validator refuses a mark nothing enforces** (unit): §4's rows pass.
@@ -569,8 +569,9 @@ said on the away channel, with its why.
*Added 2026-10-10, ADR 0286; amended 2026-11-11 to the mesh as built and as design 47's milestone G leaves it.*
A module's manifest marks a tool, or a seat verb it serves, in **`needs-approval`**; a seat's definition may mark
a verb for every holder. The tool runner reads the marks from the manifests and the seat list on the bus, never from
the bundle, and a marked module runs only on a machine whose tool runner states that it honours the mark.
a verb for every holder. The tool runner reads the marks from the catalog half on the bus (seat `mesh-catalog`), never from
the bundle, and on a machine whose tool runner does not state that it honours the mark the grants part withholds every
marked subject from its account.
```
agent ──call──► tool runner (serving node) ──ask, under the module's name──► seat operator-channel ──► Telegram