From 39a01b7f7e2334baacc36b5d622f2aa73b8f331a Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 21 Sep 2026 20:38:23 +0200 Subject: [PATCH] ADR 0095: the control plane is the way to ask a module; issue 049 resolved; design 19 amended --- ...ontrol-plane-is-the-way-to-ask-a-module.md | 60 +++++++++++++++++++ 02-DECISIONS/README.md | 1 + 03-DESIGN/01-to-be/19-the-module-protocol.md | 19 +++--- .../00-report.md | 8 +-- .../01-diagnosis.md | 5 +- 5 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md diff --git a/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md b/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md new file mode 100644 index 0000000..df3d292 --- /dev/null +++ b/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md @@ -0,0 +1,60 @@ +--- +topic: the tiers +status: accepted +date: 2026-09-21 +deciders: jochen +reconstructed: false +extends: 02-DECISIONS/0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md +--- + +# 95. The control plane is the way to ask a module + +## Context + +A module serves tools over the broker under an account scoped to what it emits, consumes and +serves ([ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md)). A +tool call is a request and a reply: the caller creates a reply queue and publishes to the serving +module's request key, and no module's scope grants either — nor should it, since a module that +only publishes events has no business declaring queues. So a module could serve tools and nothing +in the mesh could call them +([issue 049](../04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md)): +not an operator at a terminal, not an agent acting for one. + +## Considered Options + +1. **Calling is a grant**: a module declares it may be asked, and a consumer is issued an + account that may create a reply queue and publish to that module's request key. Deferred: a + module-to-module call is the only caller that resembles what the mesh mints today, and none + asks for one yet. +2. **The control plane is the way in.** Adopted. It holds a connection that may already, so a + person or an agent asks through it, and every question passes one process — which is where + an audit of who asked what belongs. + +## Decision + +`mesh-controller ask [json]` publishes the request on the tool exchange under +`.`, with a private reply queue bound under its own name, waits for the answer +whose correlation matches, and prints it as the module gave it. A tool that answered with an +error has answered: the answer is printed and the exit status says so. A module that never +answers is said to have not answered, with where to look. + +A module declares nothing about being asked: serving a tool is being askable through the control +plane. A module-to-module call, if one is wanted, is a grant like any other and a later decision. + +## Consequences + +Anything with the control plane in reach can ask any module anything it serves. What got +harder: nothing outside the control plane can, and the control plane's connection is one more +thing on the path of every question — a cost accepted for the audit it buys. + +## How it is checked + +A tools-only bed asks a served tool through the control plane and asserts an answer arrived — +an error, since the lab has no upstream and no token, which is an answer where a timeout would +not be. + +## References + +- [issue 049](../04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md) +- [ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md) +- [`03-DESIGN/01-to-be/19-the-module-protocol.md`](../03-DESIGN/01-to-be/19-the-module-protocol.md) diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 0cbf5d5..71b8182 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -114,6 +114,7 @@ python3 00-META/checks/index.py fail if stale - **0079** — [The foundation seats are named after their servers](0079-the-foundation-seats-are-named-after-their-servers.md) - **0092** — [An operator delivers a pair credential, and the mesh never replaces it](0092-an-operator-delivers-a-pair-credential.md) - **0094** — [A module may hold several secrets from one provider, each a pair of its own](0094-a-module-may-hold-several-secrets-from-one-provider.md) +- **0095** — [The control plane is the way to ask a module](0095-the-control-plane-is-the-way-to-ask-a-module.md) ### What runs on them, and how it gets there diff --git a/03-DESIGN/01-to-be/19-the-module-protocol.md b/03-DESIGN/01-to-be/19-the-module-protocol.md index 633d451..8f0775b 100644 --- a/03-DESIGN/01-to-be/19-the-module-protocol.md +++ b/03-DESIGN/01-to-be/19-the-module-protocol.md @@ -5,8 +5,9 @@ code: - mesh-sdk src - mesh-tools src/broker-amqp.ts - mesh-controller internal/link -updated: 2026-09-15 +updated: 2026-09-21 decisions: + - 02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md - 02-DECISIONS/0074-the-wire-is-specified-not-the-types.md - 02-DECISIONS/0039-what-the-sdk-holds-and-refuses.md - 02-DECISIONS/0043-a-module-broker-account-is-scoped-by-emits-and-consumes.md @@ -137,13 +138,15 @@ A module's tools are its operator-facing surface. into any queue on the broker. - A caller needs a **reply queue**, and that is what a module's scoped account may not declare ([issue 049](../../04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md)). - So a module may serve tools and may not call them, and nothing today issues an account to anything - that wants to ask. - -### Not yet true - -The caller's half has no account. Until that is settled, the only thing that can ask a module a -question is the foundation's bootstrap admin, which is not a protocol so much as a way in. + So a module may serve tools and may not call them. +- **The control plane is the way to ask** + ([ADR 0095](../../02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md)): + `ask [json]` publishes on `mesh.rpc` under `.` with a private reply + queue bound under its own name, and prints the answer as the module gave it. A module declares + nothing about being asked — serving a tool is being askable through the control plane. A + module-to-module call, if one is wanted, is a grant like any other and a later decision. + *How it is checked:* a tools-only bed asks a served tool through the control plane and asserts + an answer arrived, where a timeout would read differently. --- diff --git a/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md b/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md index aa0a36d..a7fc02f 100644 --- a/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md +++ b/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/00-report.md @@ -1,9 +1,9 @@ --- -status: located +status: resolved opened: 2026-09-14 -located-in: [mesh-controller cmd/mesh-controller, mesh-tools (the request contract)] -fixed-by: -amended-design: +located-in: [mesh-controller cmd/mesh-controller (ask), mesh-controller internal/link] +fixed-by: ADR 0095; mesh-controller multiple-fixes (ask: the control plane publishes the request with a private reply queue and prints the answer); proven by the confluence bed +amended-design: 03-DESIGN/01-to-be/19-the-module-protocol.md --- # 049 — A module can serve tools, and nothing is allowed to call them diff --git a/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/01-diagnosis.md b/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/01-diagnosis.md index ab791e9..6e06eb4 100644 --- a/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/01-diagnosis.md +++ b/04-ISSUES/049-a-module-can-serve-tools-and-nothing-can-call-them/01-diagnosis.md @@ -14,5 +14,6 @@ like any other, and a later decision. **Located in:** the controller (a command speaking the tool request/reply over its own connection) -and the tool runtime's request contract. Not fixed here: it is a new command against a protocol -the runtime owns, and needs a lab run against a tools-only bed to be proven. +and the tool runtime's request contract. Fixed as +[ADR 0095](../../02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md): `ask`, +proven by the confluence bed asking a served tool and getting its answer.