Files
hq/02-DECISIONS/0035-one-implementation-several-surfaces.md
jschoubben 0ef6d3f574 One implementation, several surfaces, and what that costs
The mesh is operated from a command line and must be operable from a
browser and from a model's tools, without becoming three systems. The
pattern is already in the code and was unnamed: `board` serves HTTP by
calling the same functions the CLI calls, holding nothing.

Takes the decision 0034 said had to be taken deliberately rather than
arrive with a feature: the HTTP surface is not read-only, so a browser
login now carries authority over the mesh.

Names the dependency by protocol — an OAuth2 identity provider — as the
mesh does for AMQP, S3 and OCI. Keycloak is what fills the role; what
the control plane knows is that it validates a token, and replacing the
provider is a migration rather than a redesign.

Says what this must not become, because it is the failure the project
was started over: a kernel every module imports, 155 files of code from
every context. Shared surfaces are not a shared library. Three adapters
calling the same functions is not the same as logic leaving the context
that owns it.

And records the loop it creates. The networked surfaces depend on a
module the control plane assigns, so when identity is down nobody can
authenticate — including whoever is trying to fix it. The way out is the
command line, which authenticates through nothing and is available to
the account that owns the machine. Hence the rule: no capability exists
only behind an authenticated surface, because that is a capability which
disappears exactly when identity does.
2026-08-31 21:17:17 +02:00

5.8 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
what runs on it accepted 2026-08-31 jochen false 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 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). 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).

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). 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). 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 — the local account owns the mesh, and the line this record deliberately crosses
  • ADR 0001 — the shared library this must not become
  • ADR 0008 — a context owns its store, which a surface does not change