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.
74 lines
3.3 KiB
Markdown
74 lines
3.3 KiB
Markdown
---
|
|
status: accepted
|
|
date: 2026-03-14
|
|
deciders: jochen
|
|
reconstructed: true
|
|
---
|
|
|
|
# 2. Everything is a module, and one manifest describes all of them
|
|
|
|
> Reconstructed after the fact from the evidence cited below.
|
|
|
|
## Context
|
|
|
|
The mesh carries several kinds of thing: containerised services with data and ports, pure
|
|
capability providers with no service at all, and bare markers whose only content is that a
|
|
node has them. Before this decision these were separate concepts with separate handling —
|
|
the earlier vocabulary was *capabilities*, and services were installed by a different path
|
|
than tools.
|
|
|
|
Every distinct kind of thing needs its own install path, its own change detection, its own
|
|
place in the delivery pipeline, and its own documentation. Three kinds means three of each,
|
|
and every new feature has to be built three times or, more commonly, once — leaving two kinds
|
|
quietly unsupported.
|
|
|
|
## Considered options
|
|
|
|
1. **Separate concepts per kind** — a service registry, a tool registry, a node feature flag
|
|
list. Rejected: it is what existed, and the cost was paid in every cross-cutting change.
|
|
2. **One manifest, kind inferred from directory contents.** Chosen.
|
|
3. **One manifest with an explicit `type:` field on every module.** Partly adopted — a service
|
|
still declares itself — but the general rule became inference, because a declared list and
|
|
the directory it describes drift, and the directory is the one that is true.
|
|
|
|
## Decision
|
|
|
|
Everything the mesh installs is a **module**: a directory with a manifest. The manifest
|
|
declares identity, environment variables, what the module provides, what it requires, and how
|
|
it is exposed. What kind of module it is follows from what the directory contains:
|
|
|
|
| Contains | Is |
|
|
|---|---|
|
|
| a compose definition | a service |
|
|
| a tools directory | a capability provider |
|
|
| a daemon or unit directory | a long-running process |
|
|
| a configs directory | a source of managed files |
|
|
| nothing but a manifest | a flag — presence is the whole content |
|
|
|
|
A module may be several of these at once. Each is a **feature**, and the delivery pipeline
|
|
addresses features, not modules.
|
|
|
|
The mesh's own components are modules on exactly these terms. They get no privileged install
|
|
path, no separate registry, and no exemption from the pipeline.
|
|
|
|
## Consequences
|
|
|
|
- One mechanism to learn, one to document, one to fix. A pipeline improvement reaches
|
|
everything the mesh carries.
|
|
- Dogfooding stops being a discipline and becomes structural: if the mesh's own components
|
|
need an exception, the machinery is unfinished, and that is visible immediately.
|
|
- Feature detection from directory contents means a directory rename silently changes what a
|
|
module *is*. This has bitten repeatedly — a hook named for a feature the module does not
|
|
have is skipped without complaint.
|
|
- The manifest becomes load-bearing and grows. It is now the largest single point of
|
|
coupling in the mesh.
|
|
|
|
## References
|
|
|
|
- `Rename capabilities → modules across the entire codebase`, 2026-03-14.
|
|
- `Merge fail2ban, ufw, firewall apps into modules`, 2026-03-15 — the first modules to arrive
|
|
by conversion rather than by creation.
|
|
- Knowledge base: `modules`, `modules/manifest-reference`, `conventions/modules`.
|
|
- The rename-breaks-detection shape: `troubleshooting/hooks-named-for-missing-feature`,
|
|
`troubleshooting/health-check-tools-index-false-positive`.
|