Bind old runners through the bus, say when the same call asks anew, and leave release unmarked until the controller's warrant passes the mark (review)

This commit is contained in:
jochen
2026-10-10 22:00:27 +02:00
parent 9b0c6741e7
commit 1d6ee8885a
4 changed files with 46 additions and 27 deletions
@@ -281,7 +281,8 @@ met, and when. It carries no secret.
> **The mechanism changed — 2026-10-10, by [ADR 0286](0286-a-tool-or-verb-marked-in-its-manifest-runs-only-on-the-operators-approval-of-that-one-call-with-its-exact-arguments.md).** A tool or verb marked `needs-approval` in its manifest now runs
> only on a warrant for that one call, with its exact arguments, checked by the tool runner that serves it (or
> by the controller, for its own verbs). For a marked act the warrant is the only way; for the others this
> bullet stands. `mesh-delivery.release` is among the first marked.
> bullet stands. `mesh-delivery.release` is not marked first: issue 417 tracks how the controller's own warrant
> for it passes the mark.
### 7. Who the operator is on a channel: linking
@@ -128,8 +128,11 @@ never from the bundle**, so a bundle cannot drop it. A module with a mark is com
**A runner that does not honour the mark is not issued a marked tool.** A runner declares that it honours it
(`approval-mark/1`) when it joins; on a node whose runner does not, the controller withholds every marked tool
and verb, and the runner's status names them. A node is never left serving a marked tool unasked because its
runner is older than this record.
and verb, and the runner's status names them. **The bus enforces it, not the runner**: the controller leaves each
marked tool's and verb's subject out of the bus permissions it composes for that runner, so the bus refuses the
runner's subscription and a call there finds no responder. Where a runner's grant names a module's subjects as a
whole today, it names a marked tool's subject apart from the rest. A node is never left serving a marked tool
unasked because its runner is older than this record.
### 2. The act that is approved
@@ -150,7 +153,8 @@ On a call to a marked tool with no approval for its act, the runner:
goes to a phone; a marked tool takes its secrets another way), or whose arguments are more than 16 KiB;
2. publishes **one ask** under the module's name, unless an open ask for the same act exists, in which case it
asks nothing new;
3. waits up to 5 seconds for the router's word, as ADR 0274 §5 (its note of 2026-10-10) has it, and answers the call.
3. waits up to 5 seconds for the router's word (ADR 0274 §5's note of 2026-10-10 waits a few seconds; this record
fixes it at 5), and answers the call.
**The ask:**
@@ -189,8 +193,13 @@ When a call to a marked tool comes and its act has an ask that was chosen, the r
(`Option.Performs`): the same node, build and every argument;
4. requires the call to come **within 30 minutes of the choice**;
5. claims the ask as used in **the node's own file**, written whole and synced to the disk before it replaces
the old one, and kept for 48 hours. A warrant claimed before is refused, so a call runs once however often it
is made, and a warrant replayed into the bus runs nothing.
the old one, and kept for 48 hours, by one writer per node, so two calls at the same moment cannot both claim
it. A warrant claimed before is refused, so one approval runs one call however often it is made, and a
warrant replayed into the bus runs nothing.
The runner always judges **the newest ask it keeps for that act**. After "already run", "expired" or "approved
too long ago", the next identical call publishes a new ask, and the used claim stays: running the same act a
second time takes a second approval.
Then it runs the call, answers with the tool's own answer and a line naming the approval ("run on the operator's
approval via telegram at 19:21, ask <id>"), and asks the controller's `warranted` to record it in the hand-act
@@ -202,10 +211,10 @@ runs nothing: every check above is against the router's record and the call actu
### 5. What the caller is told
The call that does not run says so first, as an error, never as a result: "Not run: this needs the operator's
approval. Asked on telegram at 19:21 (ask <id>, fingerprint …); make the same call again once it is approved,
before 20:21." Then, for the same call made again: still waiting; declined (the same act is not asked again for
10 minutes, and the call says so); expired; approved too long ago (asked again); already run; or refused, with
the router's words. `operator-channel.asks` shows the same ask. No answer ever reads as done when nothing ran.
approval. Asked on telegram at 19:21 (ask <id>, fingerprint …); make the same call again within 30 minutes of
the approval; the ask expires at 20:21." Then, for the same call made again: still waiting; declined (the same
act is not asked again for 10 minutes, and the call says so); expired, approved too long ago, or already run
(each asks again, §4); or refused, with the router's words. `operator-channel.asks` shows the same ask. No answer ever reads as done when nothing ran.
### 6. Fail closed
@@ -227,14 +236,16 @@ The controller serves its own verbs and enforces the same mark on them, with the
- **`node-login-shell.execute`, on every node, in the seat's definition**, as ADR 0268 §4 decided, once the reads
of ADR 0268 §5 that have no tool yet (reading or searching a file, looking up an account) have one on every
node, tracked by issue 418. Until then the control-node keeps withholding it and the others serve it unmarked,
node, tracked by issue 418 (owner: mesh-tools, or the module that owns each area). Until then the control-node keeps withholding it and the others serve it unmarked,
as ADR 0268 has it. Whether the control-node then serves it again, under the mark, stays the operator's
setting.
- **`mesh-delivery.release`**, the glossary's "a person letting a held delivery go on". The controller's own
Release on a condition already goes through an ask, so the operator sees no new kind of question.
The rest of research 039's candidates, and the split of `rofi_run` and `node-terminal-emulator.open` into a
form that opens an entry or a window and a form that runs a command, which is marked, are tracked by issue 417.
`mesh-delivery.release`, the glossary's "a person letting a held delivery go on", is not marked first. The
controller's Release on a condition is already an ask, and the controller then calls `release` on its warrant;
marked as it stands, that call would ask the operator a second time for the same act. How a warrant the
controller holds passes the mark of a verb it calls, and then marking `release`, are tracked by issue 417
(owners: mesh-controller, mesh-tools). The rest of research 039's candidates, and the split of `rofi_run` and `node-terminal-emulator.open` into a
form that opens an entry or a window and a form that runs a command, which is marked, are tracked by issue 417
(owners: mesh-catalog for the modules, mesh-controller for the seat).
Each is a change to its module's manifest, reviewed like any other.
### 9. What this changes in the earlier records
@@ -270,9 +281,9 @@ Each is a change to its module's manifest, reviewed like any other.
| Rule | Checked by |
|---|---|
| A mark naming nothing served is refused; the mark reaches the runner from the membership | the controller's tests: a manifest marking an unknown tool is refused; a seat's mark reaches every holder's membership; the membership carries it whatever the bundle lists |
| A runner that does not honour the mark is not issued a marked tool | the controller's test: a membership for a runner without `approval-mark/1` leaves out the marked tool and names it |
| A runner that does not honour the mark cannot serve a marked tool | the controller's test: a membership for a runner without `approval-mark/1` leaves out the marked tool and names it; against a real bus, that runner's grant cannot subscribe the marked tool's subject, and a call there finds no responder |
| The first call asks once and runs nothing | the runner's test: a marked tool's bundle is not called; one ask is published under the module's name, passing `Check`, Approve and Decline both at approve, each binding the act's digest; the same call again asks nothing new; the answer is an error saying "Not run" |
| The same call runs once on Approve, and only that call | the runner's test against a real bus: after the router's record says Approve, the call runs once; again, it is refused as already run; with one argument changed, another build, another node, after 30 minutes, on Decline, at the level acknowledge, nobody choosing, another ask's warrant, or a record of the runner's pointing at another ask, nothing runs |
| The same call runs once on Approve, and only that call | the runner's test against a real bus: after the router's record says Approve, the call runs once; again, it is refused as already run and a new ask is published; two calls at once run once; with one argument changed, another build, another node, after 30 minutes, on Decline, at the level acknowledge, nobody choosing, another ask's warrant, or a record of the runner's pointing at another ask, nothing runs |
| A warrant replayed or a file lost runs nothing | the runner's test: a used claim kept across a restart; an unreadable file refuses every marked call |
| Fail closed | the runner's test: no holder of the operator channel, the router's refusal, a fourth ask, a secret in an argument and more than 16 KiB are each refused, nothing asked or run where so stated, each said |
| The digest is the same in both languages | the shared library's conformance vectors, run in Go and TypeScript |
+3 -2
View File
@@ -32,8 +32,9 @@ mesh records rather than rolls out — and 62 tools from the rest.
may call is every tool on the mesh; its account may publish nothing else and subscribes nothing.
No call is refused for want of a person's approval: a tool runner serves every call it is issued, whoever made
it, and cannot tell an agent from the operator (ADR 0259 §6, issue 340). Only the agent module's instruction
proposals and the controller's settings proposals wait for the operator's warrant, each in its own code.
it, and cannot tell an agent from the operator (ADR 0259 §6, issue 340). An act waits for the operator's warrant
only where its module asks first, in its own code: the agent module's instruction proposals, and the
controller's settings proposals and the actions it offers on a condition.
## The mesh's own verbs
@@ -450,7 +450,8 @@ said on the away channel, with its why.
*Added 2026-10-10, [ADR 0286](../../02-DECISIONS/0286-a-tool-or-verb-marked-in-its-manifest-runs-only-on-the-operators-approval-of-that-one-call-with-its-exact-arguments.md).*
A module's manifest marks a tool, or a seat verb it serves, as **`needs-approval`**; a seat's definition may mark
a verb for every holder. The controller issues the mark in the runner's membership, never from the bundle, and
withholds a marked tool from a runner that does not declare `approval-mark/1`.
withholds a marked tool from a runner that does not declare `approval-mark/1`, by leaving its subject out of that
runner's bus permissions.
```
agent ──call──► tool runner (serving node) ──ask, under the module's name──► router ──► Telegram
@@ -466,18 +467,23 @@ withholds a marked tool from a runner that does not declare `approval-mark/1`.
with the shared library's `ActDigest` (in Go and TypeScript, one set of vectors).
- **The first call asks and does nothing.** One ask per act (its `about` is the act's digest): "Run <tool> on
<node>?", the tool's first line, every argument whole where it may leave the mesh or in its shape with
‹path›, ‹address› or ‹withheld› and "Part shown", the fingerprint, and where the whole is read (the runner's
‹path›, ‹address› or ‹withheld› and "Part shown" (whole when at most 2000 bytes and 40 lines, else the
first 20 lines and 1200 bytes), the fingerprint, and where the whole is read (the runner's
`approvals` on that node). Approve and Decline, both at approve; expiry 60 minutes; never a default. The call
answers as an error: "Not run", with the ask's id and until when.
answers as an error: "Not run", with the ask's id, that the call runs within 30 minutes of the approval, and
when the ask expires.
- **The same call again** runs once on Approve, read from the router's record, within 30 minutes of the choice,
claimed in the node's own file (kept 48 hours); then `warranted` records the hand-act. Anything else is
claimed in the node's own file (kept 48 hours, one writer per node); the runner judges the newest ask it keeps
for the act, and after "already run", "expired" or "approved too long ago" the next identical call asks anew;
then `warranted` records the hand-act. Anything else is
refused and said: waiting, declined (not asked again for 10 minutes), expired, already run, or the router's
refusal.
- **Fail closed:** a secret's shape in an argument or more than 16 KiB of arguments, no operator channel, a
fourth open ask, an unpublished ask, an unreadable router record, node file or mark: nothing runs.
- **The controller** enforces the same mark on its own verbs, asking as `mesh-controller`.
- **Marked first:** `node-login-shell.execute` on every node once the reads it carried have tools (issue 418),
and `mesh-delivery.release`.
- **Marked first:** `node-login-shell.execute` on every node once the reads it carried have tools (issue 418).
`mesh-delivery.release` waits until a warrant the controller holds passes the mark of a verb it calls (issue
417), so a Release on a condition is not asked twice.
### The hand-act
@@ -597,7 +603,7 @@ Each phase ends at its own *done when*. Owning repositories from [`repos.md`](..
| **5a — Asks on the bus** (ADR 0259) | the kinded bench, caller-named verbs, `proof` subjects and the records users read (controller); a bundle's seat traffic, compare-and-set state and its own account (tool runner); the asker's and channel's types (shared library); the router's asks, tokens, identities, judging, warrants, expiry and linking with its hour (messenger); `telegram` and `desk-channel`; the controller asking for its conditions' actions and acting on warrants | mesh-controller, mesh-tools, mesh-sdk, mesh-catalog | a held delivery released from the phone; the hand-act reads "the operator, via telegram, user id verified"; a desk Silence goes through an ask |
| **5 — Authorise, with TOTP** | `authorises` in the verb table; the router's checks for the code; direct calls refused, break-glass; `retire approve` takes `expect`; the hand-act fields; the TOTP seed as the router's state, enrolled at a terminal with ten recovery codes; `factor recover`, `factor status`, the local-only break-glass enrolment; no P2 tier before recovery codes exist; optional key enrolment; the self-check probe for the away channel; agents' grants lose the authorising verbs | mesh-controller; mesh-catalog (agents' grants, the desk's code prompt) | one controller test per refusal passes; at the desk, approve needs a code; a recovery drill re-enrols with a recovery code, and is announced |
| **6 — Telegram live** | the `telegram` module (built in 5a) with replies and forced-reply codes, under its own account on the control node; the operator's two bots configured; the watcher assigned off the control node; the dead-man ping | mesh-catalog | the self-check says the away channel carries every tier; rehearsals: an approve and a destroy answered on the phone, with the hand-acts read |
| **7 — A call that needs approval** (ADR 0286) | `needs-approval` in the manifest and the seat set, issued in the membership, withheld from a runner without `approval-mark/1` (controller); the act's digest in TypeScript beside Go, with shared vectors (shared library); the check, the ask, the runner's `approvals`, the node's used file and `warranted` (tool runner); the controller's own verbs; `execute` and `mesh-delivery.release` marked (catalogue, the controller's seat set) | mesh-controller, mesh-sdk, mesh-tools, mesh-catalog | a marked call on a node is asked on the phone, does nothing, runs once when made again after Approve, is refused the third time, and `hand-acts` shows the warrant |
| **7 — A call that needs approval** (ADR 0286) | `needs-approval` in the manifest and the seat set, issued in the membership, withheld from a runner without `approval-mark/1` in its bus permissions (controller); the act's digest in TypeScript beside Go, with shared vectors (shared library); the check, the ask, the runner's `approvals`, the node's used file and `warranted` (tool runner); the controller's own verbs; `execute` marked (the controller's seat set) once issue 418's reads exist | mesh-controller, mesh-sdk, mesh-tools, mesh-catalog | a marked call on a node is asked on the phone, does nothing, runs once when made again after Approve, is refused the third time, and `hand-acts` shows the warrant |
**Switching phase 5a on: the operator's steps, in order** (amended 2026-10-09, ADR 0259). Each line is typed with
`nox` (`mesh-cli`) on the control-node, from the operator's own account, which is the controller's terminal