--- topic: what runs on it status: accepted date: 2026-08-31 deciders: jochen reconstructed: false extends: 02-DECISIONS/0034-the-local-account-owns-the-mesh.md --- # 35. One implementation, several surfaces, and what that costs ## Context The mesh is operated from a command line today. It needs to be operable from a browser and from a model's tools as well, and the three must not be three different systems. **The pattern is already in the code and unnamed.** `board` serves HTTP by calling the same functions the CLI calls; it holds nothing and decides nothing. What follows makes that the rule rather than a property of one command. **The board is a presentation layer over the control plane.** Not an application beside it holding a database credential — the thing that shows what the control plane knows, and asks it to do what a person asked for. ## Decision **The logic lives once, in the context that owns it. A surface is an adapter with no decisions in it.** | surface | for | |---|---| | **command line** | a person on a machine, and the recovery path below | | **HTTP** | the board, and anything else that speaks to the mesh over a network | | **model tools** | an agent asking the mesh to do something | **Every surface refuses identically, because the refusal is not in the surface.** An assignment that cannot be satisfied is refused by the same resolution whichever way it arrived. The moment a surface can accept something another would reject, the mesh has two answers to one question and people learn which to trust. **Reading and doing are both exposed.** The HTTP surface is not read-only: managing the mesh from a browser is the point. This takes the decision [ADR 0034](0034-the-local-account-owns-the-mesh.md) said had to be taken deliberately — **a browser login now carries authority over the mesh** — and takes it knowingly rather than letting it arrive with a feature. **The networked surfaces authenticate through an OAuth2 identity provider.** Named by protocol rather than by product, like every other dependency the mesh takes — AMQP for the bus, S3 for an object store, OCI for the registry ([ADR 0006](0006-the-substrate-and-the-control-plane.md)). What fills the role today is a module running Keycloak; what the control plane knows is that it validates a token against a provider speaking OAuth2, and replacing that provider is a migration rather than a redesign. **The command line does not authenticate at all**: it is already behind the machine's own login, which is what owns the mesh (ADR 0034). ## What this is not: a kernel every module imports **The shared library is the failure this project was started over**, and the difference has to be stated or it will be rebuilt. The old one is 155 files and 34,636 lines *containing code from every context* — work-domain logic sitting in the kernel every module imports, each piece landing there to avoid a cycle between two modules that both needed it. **Shared surfaces are not a shared library.** What is shared here is that three adapters call the same functions. Those functions stay in the context that owns them — provisioning's logic in provisioning, identity's in identity — and no module imports another's. A surface may call many contexts; a context still may not reach into another's store ([ADR 0008](0008-a-context-owns-its-store.md)). The test, when something is about to be put "somewhere shared": *does this belong to a context, or does it only belong to the surface?* If it belongs to a context it goes there, even if two surfaces want it. ## The loop this creates, and the way out **The control plane's networked surfaces will depend on a module the control plane assigns.** An identity provider is an ordinary module ([ADR 0031](0031-the-control-plane-authenticates-nobody.md)). When it is down, or being migrated, or misconfigured, the HTTP and tool surfaces cannot authenticate anybody — including the person trying to fix it. **The command line is the way out, and it is why local ownership matters more rather than less.** It authenticates through nothing, needs no network, and is available on the machine to the account that owns the mesh. **A mesh must always be operable by somebody standing at it.** So the rule: **no capability exists only behind an authenticated surface.** Anything the board can do, the command line can do. That is not a courtesy to CLI users; it is the recovery path, and a capability that exists only over HTTP is one that disappears exactly when identity does. ## Consequences **Identity is still not substrate**, and the test still answers no: the control plane runs, applies declarations and reaches nodes with no identity provider in existence ([ADR 0033](0033-the-substrate-is-a-store-and-a-broker.md)). What is unavailable without it is two surfaces, not the mesh. **Whoever the identity provider admits has authority over the mesh.** That is now a real perimeter with real consequences, where before it guarded a page that only read. Who may log in, and to which realm, becomes a decision about the mesh rather than about an application. **A surface must not grow an opinion.** The likely erosion is a validation added to the board because it was quicker there — and then the CLI accepts something the board rejects, or worse the reverse. Adapters hold no decisions. **Three surfaces over one implementation is a cost paid three times if it is not one implementation.** The reason to write this down now is that the second surface is the cheapest moment to get it right, and the third is where the drift usually starts. ## References - [ADR 0034](0034-the-local-account-owns-the-mesh.md) — the local account owns the mesh, and the line this record deliberately crosses - [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md) — the shared library this must not become - [ADR 0008](0008-a-context-owns-its-store.md) — a context owns its store, which a surface does not change