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.
94 lines
4.8 KiB
Markdown
94 lines
4.8 KiB
Markdown
---
|
|
status: proposed
|
|
date: 2026-08-23
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 0015-mesh-brokers-nodes-host-agents-think.md
|
|
---
|
|
|
|
# 17. Modules outside the platform core are grouped by domain, not by single function
|
|
|
|
## Context
|
|
|
|
[ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) recomposes the platform's own modules
|
|
into bounded contexts named after their aggregates, and sends the rest out of the monorepo on
|
|
the grounds that they run *on* the mesh rather than being *of* it.
|
|
|
|
That leaves the larger half unaddressed. Around three quarters of the catalogue are modules
|
|
that are neither part of the mesh's domain nor standalone applications: a firewall, a VPN, an
|
|
SSH daemon and a resolver; a file manager, a media player and a system monitor; a set of
|
|
media-library services. Today each is its own module, because one module is the unit of *one
|
|
piece of software*, and no other grouping exists.
|
|
|
|
The result is that the catalogue's shape records what was installed, not what anything is for.
|
|
Four modules that together constitute "how a node is reachable" have no relationship the mesh
|
|
can see: they cannot be assigned, versioned, reasoned about or replaced as one thing, and a
|
|
change to how the mesh handles connectivity has to be made four times.
|
|
|
|
This is the same failure ADR 0015 names for the core — *boundaries drawn by deployment accident
|
|
rather than by domain* — appearing outside it.
|
|
|
|
## Considered options
|
|
|
|
1. **Leave them as they are.** Rejected. The core gets domain boundaries and everything else
|
|
keeps accident boundaries, so the catalogue becomes harder to read after the refactor than
|
|
before it.
|
|
2. **One module per piece of software, with a tag or category field.** Rejected. A label is not
|
|
a boundary: it does not change what can be assigned, versioned or replaced as a unit, and it
|
|
drifts from the thing it labels.
|
|
3. **Group them into domain modules, each owning the software that serves one purpose.**
|
|
Proposed here.
|
|
4. **Extend ADR 0015's contexts to cover everything.** Rejected. Those contexts are named for
|
|
the mesh's own aggregates; a media library is not an aggregate of the mesh, and forcing it
|
|
into that model repeats the metaphor-naming mistake ADR 0015 exists to correct.
|
|
|
|
## Decision
|
|
|
|
*Proposed — the principle is settled; the domain list is not. See "Open" below.*
|
|
|
|
Modules that are not part of the platform core are grouped into **domain modules**. A domain
|
|
is named for the concern it serves, and owns the software that serves it. The unit stops being
|
|
one piece of software and becomes one purpose.
|
|
|
|
This extends ADR 0015 rather than replacing it. The eight bounded contexts for the mesh's own
|
|
domain stand unchanged. This decision covers what ADR 0015 leaves outside them.
|
|
|
|
Naming follows the same rule as the core: **name the domain for what it does, not for what it
|
|
is made of**. Connectivity, not a VPN implementation.
|
|
|
|
## Consequences
|
|
|
|
- A domain becomes assignable, versionable and replaceable as one thing. Changing how nodes
|
|
reach each other is a change to one module.
|
|
- The catalogue's shape starts describing purpose. A reader can tell what a mesh is *for* from
|
|
its module list.
|
|
- Swapping an implementation stops being a module replacement, with the data-volume and
|
|
provisioning consequences that carries, and becomes a change inside a domain.
|
|
- The count drops sharply, which is a symptom of the improvement rather than the point of it.
|
|
- **Grouping conceals.** A domain module hides which implementation is in use, and every
|
|
operational question — which port, which unit, which credential — gains an indirection.
|
|
- The migration is not free and has no obvious increments: a domain is only useful once
|
|
everything belonging to it has moved.
|
|
- Some modules genuinely serve one purpose and are already correctly sized. Grouping for its
|
|
own sake would be the same error in the other direction.
|
|
|
|
## Open
|
|
|
|
**The domain list is not settled and this record does not invent one.** What is decided is the
|
|
principle; what is not decided is the set. Candidate groupings are visible in the catalogue —
|
|
connectivity and reachability, node presentation and desktop, media libraries, observation and
|
|
metrics, storage and data services — but naming them here would be reconstructing a decision
|
|
that has not been taken.
|
|
|
|
Settling the list is a research effort, not an act of this record. Until it concludes, this
|
|
ADR stays `proposed`.
|
|
|
|
## References
|
|
|
|
- [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) — the core decomposition this
|
|
extends, and its rule about naming a context after its aggregate.
|
|
- [ADR 0010](0010-applications-live-in-their-own-repository.md) — standalone applications are
|
|
already out of scope here; they are not domains and do not group.
|
|
- [`03-DESIGN/00-as-is/10-module-catalogue.md`](../03-DESIGN/00-as-is/10-module-catalogue.md)
|
|
— the catalogue's current shape, which is the evidence for the problem.
|