diff --git a/02-DECISIONS/0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md b/02-DECISIONS/0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md index 195c7c3a..63a6bcbf 100644 --- a/02-DECISIONS/0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md +++ b/02-DECISIONS/0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md @@ -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 diff --git a/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 b/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 index 2f326fd4..5ec2323c 100644 --- a/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 +++ b/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 @@ -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 "), 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 , 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 , 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 | diff --git a/03-DESIGN/00-as-is/13-the-console.md b/03-DESIGN/00-as-is/13-the-console.md index d68f484f..614d1b6e 100644 --- a/03-DESIGN/00-as-is/13-the-console.md +++ b/03-DESIGN/00-as-is/13-the-console.md @@ -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 diff --git a/03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md b/03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md index 790a1b09..e1ffb4e0 100644 --- a/03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md +++ b/03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md @@ -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 on ?", 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