diff --git a/01-RESEARCH/039-a-tool-that-needs-a-persons-approval/00-overview.md b/01-RESEARCH/039-a-tool-that-needs-a-persons-approval/00-overview.md new file mode 100644 index 00000000..f8b4a4ba --- /dev/null +++ b/01-RESEARCH/039-a-tool-that-needs-a-persons-approval/00-overview.md @@ -0,0 +1,90 @@ +--- +status: active +initiated: 2026-10-08 +touches: [] +became: [] +--- + +# 039 — A tool or verb that needs a person's approval + +A note to design from later, not a design. + +## What is investigated + +Whether a module's tool or a seat's verb can declare, in its manifest, that **calling it needs a +person's approval**, and the mesh then refuses the call without one. + +The operator's idea, 2026-10-08: *"I think we need to be able to mark tools as 'requires human +approval'."* + +The shape, as first seen: + +- **The declaration is the tool's own.** The manifest marks a tool or verb as needing approval, beside + the rest of what it declares about itself. +- **The mesh enforces it, not the MCP client.** The tool runner, or the controller for a seat verb, + refuses the call unless it carries a **warrant**: the router's record that a person chose one option + of one ask, from the flow ADR 0259 sets out (hq pull request 211, not yet merged). An agent may ask; + it cannot act alone. A client-side prompt is no boundary, because any tool runner may call any tool + on any node (ADR 0175). +- **The ask carries** what is to be done, why, the exact arguments, and who asks. Its options are + Approve and Decline, Approve at the `approve` **assurance level**. On a warrant for Approve the call + goes ahead **once, with those arguments, before the warrant's expiry**; anything else is refused. +- **Where it is answered** until a channel that declares a verified sender (Telegram) is live: at the + operator's desk, or at the controller's terminal. Open: the desk answers only `acknowledge` options + ([ADR 0258](../../02-DECISIONS/0258-a-desk-click-performs-only-an-acknowledgement-and-an-answer-is-a-one-time-ticket.md)), + so the desk alone cannot approve. + +## Why now + +On 2026-10-08 the only thing between an agent and acts like a snapshot of the media library, a +whole-mesh push or the bus's upgrade was the agent asking in chat before it called the tool. Nothing in +the mesh would have refused the call. The same day, several holes were found in exactly this layer: +an agent on the control-node could become root without a person, and through the login shell's tool an +agent on any node could run a command there as an account that can (ADR 0259 §8 as revised, and +ADR 0266, hq pull request 225, not yet merged). Once agents run without root, **the tools are the +boundary**, and a tool that can do lasting harm needs a person behind each call. + +## Candidates seen on 2026-10-08 + +| Tool or verb | Why a person | +|---|---| +| the new zfs module's `zfs_snapshot` | a snapshot of the media library holds its space; on a scratch dataset it does not matter | +| `mesh-controller.push` | sends builds to nodes outside a walk | +| the bus's upgrade, `mesh-controller.bus upgrade` | already a step a person starts ([ADR 0236](../../02-DECISIONS/0236-a-build-is-judged-on-its-first-machine-and-put-back-by-something-other-than-itself-and-so-it-rolls-out-unattended.md) rule 6); today "a person" is whoever calls it | +| `mesh-delivery.release` | the glossary defines it as a person's word, and nothing checks that a person said it | +| the controller's `plans` go and stop | starts or halts a walk | +| a secret's `rotate` | can cut off every consumer of a credential | +| the places and accesses settings | being made terminal-only; approval is the other way | +| the media library's share and mounts (`nfs-server`, `mounts`) assignment | the library is the operator's sacred data | + +## What it bears on + +- **ADR 0259** (pull request 211): asks, the router, warrants and assurance levels. This effort adds a + new kind of asker: the tool runner or the controller asking on behalf of a call. Who the asker is + matters, because a warrant is issued to one asker alone. +- **ADR 0266** (pull request 225): agents without root. It makes the tool layer the boundary this + effort guards. +- **The `record` upgrade policy** (ADR 0236): "a person's push" is today only a convention. +- **The held delivery's release**: the same. +- **Issue 336** (pull request 228, a hold nobody is told about): an approval waiting with nobody told is + the same fault, so a waiting approval must be said, as a condition or on a channel. +- **The hand-act log** (ADR 0234 §8): a call made on a warrant is recorded with the warrant. + +## Open questions + +1. **Per tool or per argument.** A snapshot of the library needs a person; one of a scratch dataset + does not. Is the mark on the tool, on an argument's value, or decided by the tool from its arguments? +2. **Who may approve.** Only the operator role exists today. Is that enough for every tool? +3. **Replay and expiry.** One warrant, one call: how is "these exact arguments" bound to the warrant, + and how long does a warrant stay good? +4. **A call waiting for approval.** How is it shown: a condition, the asks list, the call's own answer? +5. **The MCP client while it waits.** Does the call block until answered, or return "asked, waiting" + with a handle the agent calls again? +6. **The answer before a verified channel exists.** The desk is `acknowledge` only; is the controller's + terminal the place, and how does it prove a person there? +7. **Audit.** Is a warranted call a hand-act, and where is a declined or expired one recorded? + +## How it will be checked + +Nothing measured yet. The first evidence to gather: how many tools and verbs in the catalogue act on +data or on other nodes, and of those, how many are guarded by anything but the caller's restraint.