--- topic: what runs on it status: accepted date: 2026-09-20 deciders: jochen reconstructed: false extends: 02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md --- # 84. Which provider serves a consumer, when the mesh runs more than one ## Context [ADR 0027](0027-a-provision-names-what-the-consumer-is-coupled-to.md) settled what a provision is *named* for — the thing the consumer's code is coupled to, so `postgres-database` and `mssql-database` are different provisions and a wrong match is refused at resolution. It said one thing more, in passing, and left it: *"Two providers of `postgres-database` — a container on this node and a managed instance elsewhere — are interchangeable and should both match."* Naming was decided; **which of several providers serves a given consumer was not.** The mesh assumes there is only one to choose. Provisions are mesh-scoped: the adopted store is a single `mesh-store` a consumer on any node reaches, and `scope: "mesh"` is written into the provision definitions. **That assumption is false on day one, and was always meant to be.** Node-specific services delivered to the mesh is the plan, not an edge case: - Both control-capable nodes already run their **own** general-purpose relational store (the same engine, one instance each), serving that node's own applications. - Each runs its **own** SQL server, its **own** cache, its **own** object store. One node alone runs six separate relational-store instances, each raised by the module that needed it. - The one provision that is currently single — the identity provider, one instance on one node — already authenticates applications whose home is a **different** node. So several providers of one provision name genuinely coexist, and they are **not** interchangeable the way 0027's aside supposed. They differ by node, by the data they hold, and by locality. A consumer bound to the wrong one reads the wrong database, or takes a cross-node hop it did not need, or cannot be moved without silently rebinding. The model has no field in which to say which one. This is 0027's own fault — *a match that resolves and is wrong* — one level up: 0027 refused the wrong **dialect**; nothing refuses, or even asks about, the wrong **instance**. ## Considered Options 1. **Keep `scope: "mesh"` — one provider per provision, mesh-wide.** Rejected: it is false on day one, and making it true would force every node's applications onto one node's server — the exact opposite of node-specific services delivered to the mesh, and a single point of failure the topology was built to avoid. 2. **Resolve to any provider of the name (0027's "both match").** Rejected: when providers hold different data and live on different nodes they are not interchangeable, and picking one arbitrarily is a wrong-instance match — the confidently-wrong answer 0027 exists to prevent, restated at the level of the instance rather than the dialect. 3. **Always require the consumer to name the provider explicitly.** Rejected: needless ceremony in the common case, where the consumer wants the provider on its own node; and a field every manifest must carry is a field an author forgets, which then matches everything again — the failure 0027 warned about for qualifiers. 4. **A provision is node-scoped; the consumer selects the provider, defaulting to co-location.** Adopted. ## Decision **A provision is served by a provider identified by its node, and the consumer selects which one.** A provider is a (node, module) pair, not a mesh-wide singleton. A consumer's binding resolves to a specific provider, and the selection is part of the assignment ([ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md)), not the manifest. **The default is co-location.** A consumer that names no provider is served by the provider of that provision on **its own node**. This is the common case and needs nothing said. A mesh with one provider of a kind is just the case where co-location and "the only one" coincide — expressed as *there happens to be one*, not as a scope. **A consumer coupled to a provider's data names it.** Where two consumers must share one database, or a consumer must reach a provider on another node, the assignment names that provider — because that coupling is exactly what may not be guessed, and naming it is what makes a later move safe. **A module need not consume a provider at all.** It may carry its **own** instance inside its own composition — on its own module network, publishing no host port, **not** declared as a provision — when a genuine engine fork or a pinned server version makes the shared provider unusable. Such an instance is invisible to resolution and can be bound by nothing else. The rule is *share by default; embed only when a fork or a version forces it* — most of the per-module stores that exist today are vanilla engines on stale pins that a consolidation onto the node's provider would absorb. ## Consequences The mesh can carry its real topology **deliberately** rather than by the accident of which provider happened to be the single one. A consumer's data-coupling becomes a stated fact, which is what lets a provider be moved without a consumer silently following the wrong one — provided a provider keeps its identity across a relocation, which is a follow-up this record opens rather than closes. Rotation ([13](../03-DESIGN/01-to-be/13-credentials-and-their-rotation.md)) addresses a specific provider's holders, not "the provision's". What got harder: an assignment now may carry a provider selection, and a wrong one is a new way to misconfigure. It is mitigated the way 0027 mitigated its own: the co-location default removes the choice in the common case, and genuine ambiguity — several providers, none named, none co-located — is refused with the candidates named, never resolved by picking. ## References - [ADR 0027](0027-a-provision-names-what-the-consumer-is-coupled-to.md) — the naming this extends; its "both match" aside is the gap closed here. - [ADR 0031](0031-the-control-plane-authenticates-nobody.md) — identity is exactly such a provider, and already serves consumers on another node. - [ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md) — where the selection lives. - [ADR 0078](0078-the-store-and-broker-are-modules.md) — the adopted store, whose mesh-wide binding is the single-provider assumption this record replaces. - [issue 067](../04-ISSUES/067-a-provision-cannot-name-which-provider-serves-it/00-report.md) — the gap, and the day-one evidence. - [`03-DESIGN/01-to-be/23-choosing-a-provider.md`](../03-DESIGN/01-to-be/23-choosing-a-provider.md) — the design.