--- status: accepted date: 2026-04-06 deciders: jochen reconstructed: true --- # 5. Capabilities are provisioned on declaration, not configured by hand > Reconstructed after the fact from the evidence cited below. ## Context Most modules need something another module holds — a database, a cache, a bucket, a message vhost, an identity client. Wiring that by hand means creating the resource, creating a user, generating a credential, putting it in the consumer's configuration, and repeating all of it on every node the consumer runs on. Every step is a place to make a mistake that surfaces much later, and the credential ends up written somewhere it can be read. ## Considered options 1. **Manual setup, documented.** Rejected. Documentation of a manual procedure is a description of the mistakes people will make. 2. **A shared credential per resource type**, distributed to all consumers. Rejected: no isolation, and rotation becomes a mesh-wide outage. 3. **Declared requirements, satisfied by the provider module.** Chosen. ## Decision A module declares what it **provides** and what it **requires**. A requirement names the provider, the resource type, optionally a name and a target node, and a mapping from the resource's connection fields to the consumer's environment variables. The mesh satisfies it: a provisioner belonging to the provider creates the resource and its credential, records the grant, and writes the mapped values as database overrides. The synchroniser from [ADR 0004](0004-managed-files-are-generated-never-edited.md) then materialises them. Neither the credential nor the topology is ever written by hand. A requirement may name a provider on another node. The grant records consumer and provider nodes separately, so cross-node wiring is the same declaration. ## Consequences - **Provisioning becomes a core concern of the mesh, not plumbing.** A module asks for a capability; where it lives is the mesh's problem. This is the property [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) later builds the whole domain model around. - Credentials are never authored, so they are never authored badly, and they are never in the repository. - Each consumer gets its own credential, so revocation is per-consumer. - Rotation is where this bites. A shared secret rotated for a new consumer invalidates the peers holding the old one, and this has taken the mesh down. The declaration model makes granting easy and says nothing about fan-out. - A module with no requirements skips the stage entirely, which is correct and also means the absence of provisioning is indistinguishable from provisioning that did not run. ## References - `Remove shell/ helper library; split brain into independent workspaces`, 2026-04-06 — the provisioner daemon becomes its own component. - `Coordinator refactor: centralize pipeline orchestration`, 2026-04-04 — the provision-then- environment-then-start sequence becomes the coordinator's. - Knowledge base: `provisioning`, `provisioning/requires`. - The rotation failure: `troubleshooting/provision-rotation-invalidates-peers`, `troubleshooting/provision-adoption-rotates-live-credential`.