ADR 0095: the control plane is the way to ask a module; issue 049 resolved; design 19 amended
This commit is contained in:
@@ -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 <module> <tool> [json]` publishes the request on the tool exchange under
|
||||
`<module>.<tool>`, 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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 <module> <tool> [json]` publishes on `mesh.rpc` under `<module>.<tool>` 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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user