papa-hq reads 01 research -> 03 decision -> 02 design. The order is a scar, not a choice: 02-DESIGN existed from its initial commit, and when adr/ was finally promoted on 2026-07-13 it took the next free number rather than its place in the sequence. By then design was too settled to renumber. hal-hq was three commits old, so it is not. adr/ becomes 02-DECISIONS and 02-DESIGN becomes 03-DESIGN, and following the folder numbers now walks the process in the order it happens: research produces a decision, the decision authorises a design. 00-GENESIS becomes 00-META, matching papa's rename from the same restructure. Every path reference rewritten across documents, frontmatter, playbooks and skills. All links resolve; all 58 frontmatter blocks parse and their path fields still point at files that exist.
68 lines
3.1 KiB
Markdown
68 lines
3.1 KiB
Markdown
---
|
|
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`.
|