Research 039: a tool or verb that needs a person's approval, so an agent may ask but cannot act alone
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request

This commit is contained in:
jochen
2026-10-08 23:59:45 +02:00
parent e2de8811a3
commit c31a76cac5
@@ -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.