102 lines
5.9 KiB
Markdown
102 lines
5.9 KiB
Markdown
---
|
|
topic: what runs on it
|
|
status: accepted
|
|
date: 2026-09-03
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 0009-modules-and-the-graph.md
|
|
---
|
|
|
|
# 40. What a module is
|
|
|
|
_Reconciliation note (2026-09-05): supersedes the earlier "grouped by domain" decision, which the consolidation folded into how-we-build.md; no standalone record remains to point at._
|
|
|
|
## Context
|
|
|
|
[ADR 0009](0009-modules-and-the-graph.md) settled that everything is a module, but never said what a
|
|
module *is* beyond "a directory the mesh processes." That gap let the catalogue's breadth read as a
|
|
smell: a module can carry a container, a built image, tools, a provisioner, migrations, health,
|
|
config, seat claims, requires and provides — so much that the unit seemed ill-defined.
|
|
The earlier "grouped by domain" decision (folded in consolidation; see the reconciliation note
|
|
above) tried to organise modules by domain, which is the wrong axis. This record states what a module is, drawn from the cases that
|
|
stress-tested it: the shell, i3-vs-sway, umami, and "database."
|
|
|
|
## Decision
|
|
|
|
**A module is one self-contained piece of software the mesh installs and manages** — everything
|
|
needed to make that one thing real and integrable: what runs, the seats it claims, what it provides
|
|
to other modules, what it requires from them, and what operates it.
|
|
|
|
The **software is the module's identity.** Capabilities, seats and provisioned resources are the
|
|
**relationships *between* modules**, not what a module is — and that is what binds a module into one
|
|
thing. umami is bound by *being umami*: its container runs umami, its provisioner creates umami sites,
|
|
its tools query umami, its `requires` gets umami a database. Every feature serves the one software.
|
|
|
|
### The three relationships
|
|
|
|
1. **Shared seat** — several modules fulfil a capability and coexist; one may be default. bash, zsh
|
|
and fish all join `shell`.
|
|
2. **Exclusive seat** — modules contend for a single slot; one holds it. i3 (needs x11) and sway
|
|
(needs wayland) contend for `display-session`.
|
|
3. **Provide / require** — a provider ships the **provisioner** that creates instances of the
|
|
resource it offers and returns sealed credentials; a consumer requires it and the mesh wires the
|
|
credential in. Symmetric: umami requires a database *and* provides analytics.
|
|
|
|
### Interfaces are mesh-owned; providers adapt to them
|
|
|
|
The mesh **defines the interface** for a capability — the provider-neutral contract of what a
|
|
consumer receives and how it integrates. Both sides conform: a provider's provisioner **adapts** its
|
|
software's real API to the mesh contract; a consumer depends on the **interface**, never on a
|
|
provider. Swap one provider for another and the consumer does not change.
|
|
|
|
### The naming rule — draw the interface at the consumer's real coupling
|
|
|
|
Name a `provides`/`requires` at the **widest boundary across which the consumer genuinely does not
|
|
care which implementation serves it**:
|
|
|
|
- Where the consumer's coupling is thin — an analytics embed snippet and dashboard, opaque to it —
|
|
the mesh defines a neutral interface (`analytics`) and providers (umami, amumi) adapt. Swappable
|
|
across vendors.
|
|
- Where the consumer **speaks a protocol** — a database's wire protocol and query dialect — the
|
|
interface *is* the protocol: `postgres-database`, `mssql-database`, `mongodb-database`. Swappable
|
|
only among protocol-compatible implementations, **never across**, because the application cannot
|
|
cross it either. "database" is not a capability; the protocol is.
|
|
- **Never false genericity.** A name must not promise a swap the contract cannot deliver
|
|
([research 005](../01-RESEARCH/005-domain-grouping/analysis.md)).
|
|
|
|
This is [ADR 0027](0027-a-provision-names-what-the-consumer-is-coupled-to.md)'s rule made general — "names the protocol, not
|
|
the product; a database names the engine because the app targets it" — with the reason stated: the
|
|
contract sits where the coupling is.
|
|
|
|
### What is not a module
|
|
|
|
- A **library** (built against, never deployed — [ADR 0039](0039-what-the-sdk-holds-and-refuses.md)).
|
|
- A **control-plane context** (the mesh itself — [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md)).
|
|
|
|
A **swappable machine mechanism** (a firewall — ufw, nftables) *is* a module implementing a
|
|
capability. The host hardcodes no firewall, supervisor, package manager or runtime; it owns only the
|
|
generic apply primitives and platform detection, so it runs where none of those exist — an Android
|
|
phone has no ufw, systemd, pacman or Docker.
|
|
|
|
## Consequences
|
|
|
|
- **Supersedes the earlier "grouped by domain" decision** (folded in consolidation; see the
|
|
reconciliation note above). Modules are
|
|
organised by their relationships (seats, provisions), not grouped into domain folders.
|
|
- **Refines [ADR 0009](0009-modules-and-the-graph.md).** Everything the mesh runs and integrates is
|
|
a module — but a module is defined by the *software it delivers*, not by being a bucket of features.
|
|
- The target is a **self-fulfilling mesh**: declared wants bound to swappable modules, provisioners
|
|
wiring credentials, nothing hardcoded. The control plane's whole job is the binding.
|
|
- Converting a module from the old system includes pulling its per-module code out of the shared SDK
|
|
([ADR 0039](0039-what-the-sdk-holds-and-refuses.md)) and shipping its provisioner as an adapter to a
|
|
mesh interface — a de-coupling, not just a move.
|
|
|
|
## References
|
|
|
|
- [ADR 0009](0009-modules-and-the-graph.md) — everything is a module; this says what one is.
|
|
- [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md) — contexts are the mesh, not modules.
|
|
- The earlier "grouped by domain" decision — superseded (folded in consolidation; see the note above).
|
|
- [ADR 0027](0027-a-provision-names-what-the-consumer-is-coupled-to.md) — protocol-not-product, generalised here.
|
|
- [ADR 0039](0039-what-the-sdk-holds-and-refuses.md) — per-module code lives in the module.
|
|
- [research 011](../01-RESEARCH/011-the-module-graph/00-overview.md) — the graph of these relationships.
|