Brings the independent ADR branches (0044-0052) onto one branch so hq lands as a single MR, and ratifies the five that were still proposed — 0017, and 0049-0052, which are implemented and green in the lab. With 0053/0054 already accepted here, the whole ADR chain 0044-0054 is accepted on this branch. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
5.1 KiB
status, date, deciders, reconstructed, extends
| status | date | deciders | reconstructed | extends |
|---|---|---|---|---|
| accepted | 2026-09-04 | jochen | false | 0005-capabilities-are-provisioned-on-declaration.md |
51. A module's configuration is its assignment's, not its manifest's
Context
A module is assigned to a node — assign <node> <module>, always to a machine; there is no
assignment to the mesh. "Mesh" is a scope, not a place: a provides or a claim scoped mesh
reaches the whole mesh, but the module still runs on a node. So the two kinds of thing a module can
carry are the manifest (what the module is) and, separately, what it should do here — which
differs by deployment and by node.
The mesh already has the second: settings. settings set <module> [--node <node>] — with a node
it is that machine's, without it the whole mesh's — layered over what the module declares and applied
at resolution, changeable without editing the module and without a rebuild. That is the surface a
meshboard would edit.
But settings today reach only a module's config-file content (a mergeable file the module owns).
Configuration that is not a file has been landing in the manifest instead, statically — a registrar's
zone and domain, the address public names point at, and, most sharply, listens.from. That last one
is the tell: whether a port is open to the private overlay or to the public internet is a
per-node deployment choice — the same database internal on one machine and public on another — and
a value fixed in the manifest is one value for every machine, so it cannot be. Static configuration in
the manifest is configuration in the wrong place: it cannot vary per node, and it cannot change
without a new module version.
Decision
The manifest is identity and defaults; the assignment's settings are the configuration
A module's manifest declares what it is — what it provides, requires and claims, the shape of its resources — and, for anything configurable, a default. The values that make a running instance this instance are settings, carried by the assignment: per-node, or mesh-wide when no node is named, applied over the defaults at resolution. Change one and the next reconcile carries it; nothing is edited on a machine and nothing is rebuilt.
Settings drive the configurable fields the manifest marks, not only file content
Settings extend beyond a config file's content to the manifest fields a module declares settable — foremost:
listens.from: a module declares its safe default (from: mesh), and a per-node setting raises or lowers it. postgres declareslistens: [{ port: 5432, from: mesh }]; on the machine that should expose it, a setting makes that portfrom: anywhere. Same module, different exposure, and the firewall (ADR 0050) is computed from the effective value, so the packet filter follows the setting.- A provider's own configuration: a registrar's zone, domain and the ingress its names point at (ADR 0049) are mesh-wide settings, not manifest constants — one mesh's Cloudflare zone is not another's, and the module description is the same for both.
Unset is the default, and an unknown setting is refused
A field with no setting keeps the manifest's default, so a module runs correctly configured by nobody.
A setting that matches no settable field — like a config value that reaches no file today — is named,
not silently dropped, so a misspelled setting is found rather than believed (the discipline of
UnusedSettings, and of ADR 0048:
a declaration is enforced or it is a comment).
Consequences
- The postgres case works: one module,
from: meshby default,from: anywherewhere a setting says so — internal on ace, public on novox, changeable live. - Provider modules stop carrying a mesh's specifics:
cloudflare-dnsdescribes a Cloudflare registrar, and which zone and ingress is a setting, so the same module serves every mesh. - Configuration becomes a thing a meshboard manages — set per node or mesh-wide, applied on the next reconcile — rather than a manifest edit and a rebuild (ADR 0004: the way you change a managed thing is not by editing it).
- What a manifest may not do is grow a value that differs per machine; if it differs per machine it is a setting, and the manifest holds only the default.
References
- ADR 0005 — what is provisioned on declaration; its per-instance values are the assignment's.
- ADR 0004 — a managed thing is changed through the mesh, not by editing it; settings are that, for configuration.
- ADR 0050 — the firewall follows the
effective
listens.from, so makingfroma setting makes exposure a setting. - ADR 0049 — the provider whose zone and ingress are settings, not manifest constants.