Issues 122 and 134 resolved; design 27 in progress with its first cases; design 18 names the words.
8.8 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| what runs on it | accepted | 2026-09-30 | jochen | false | 02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md |
155. A definition names no installation: how that is checked, and the three ways a value that did gets out
Context
ADR 0112 decided that a module definition names no node, no mesh and no host path, and said how the name half is checked: a catalogue test finds no domain name in any definition value. No such test existed (issue 134). Written and run over the 77 definitions on 2026-09-30, the check it describes finds 42 values, in 15 definitions, and they are of four kinds that want four different answers:
| kind | count | example |
|---|---|---|
| a service told its own public name as a literal | 5 | an identity provider's KC_HOSTNAME, an object store's console redirect, an automation tool's webhook URL |
| an operator's value written into the definition | 10 | a mail server's domain, site name, website, and the address it trusts a real-IP header from |
| this mesh's forge, by URL, as a recipe's build context | 2 | the builder and the proxy, which package the controller's source |
| an application built outside the mesh, pulled from this mesh's registry | 7 | four sites and tools whose repositories are the operator's own |
| the world's servers, named by upstream defaults | 10 | a Matrix homeserver's trusted key server, Element's integration manager |
| a module named after the domain it serves | 8 | one site module, with its paths and network named after it |
Not one was careless. Each was the value the software needs, and until today there was nowhere else
to put it (issue 122).
Two of the answers were built before this record: a module is told the name its route composes
(${bound:<route>:name}, controller PR 149, 2026-09-30), and a source may be a path on the git seat
(ADR 0111). What was missing: an operator's
value in a file the software reads, the same for a build context, a way to say a name is meant, and
the check.
Considered Options
1. A string search for the installation's own names. Rejected. The controller is as mesh-agnostic as the definitions; it does not know which names are "this mesh's", and a check that had to be told would be configured per installation and pass everywhere else. What it can know is the shape: a name under a public top-level domain, a public address.
2. Report every such shape. Rejected. Eight of the 42 were why strings — prose the mesh never
reads, explaining what a port is for — and a check that reports those beside KC_HOSTNAME teaches
people to ignore the report. And a Matrix homeserver must name the federation's public key server;
a check with no way to say so would be a check people argue with rather than obey.
3. Judge what the mesh acts on; let a definition say which names it means, one by one, with a reason; exempt the world's services that a definition may name as a policy default. Chosen.
For an operator's value, one option was to wait for design 27's requirement form in full. Rejected
for the reason 0112 gave against a slow operator provider: if asking a person for a value takes more
than a setting, module authors route around it and the literals come back. ${setting:<key>} is the
operator provider in its first form, on the settings a module already has.
Decision
The check. Every string value of a definition that the mesh acts on is judged for a hostname under
a public top-level domain and for a public address. Not judged: why and description, which are
prose. Allowed where they can only mean the world: the public registries an image may be pulled
from, the public resolvers a machine may forward to, and the public certificate authorities' ACME
directories. The container runtime's alias for its own host is the runtime's. A module's own name is a
value too. The check runs in module check and as a catalogue-wide test; it does not yet refuse at
registration, because the list it prints is the list that shrinks, and a registration that refused a
manifest whose only remedy is a merge elsewhere would refuse the mesh's own catalogue on the day the
check landed. It moves to registration when the list has been empty for a release.
A name a definition means is declared with its reason. names-on-purpose on a resource maps each
such name to why: the federation's public key server, the world's; built outside the mesh, from the
application's own repository, until that repository is a build source on the git seat. A name the map
does not cover is still reported. The host never sees the word.
An operator's value reaches a file as ${setting:<key>}, filled from the module's settings
layers — the mesh's, then the node's — the same layers a mergeable file and a contribution take, so
settings set <module> stays the one place a person's values go. Refused, naming the key and the
command, when nothing set it: a default for a mail domain would be the literal this removes, and a
blank written silently would be a service that comes up wrong somewhere that names nothing.
A build context may live on the git seat. context: {"seat": "git", "repository": "<owner>/<name>"}
is composed by the mesh that builds it: the request carries each seat's clone base, and a builder told
no base for a seat a context names refuses the build by the seat's name rather than guessing a forge.
A module is named for what it is. The site module named after its domain is website.
Consequences
- The catalogue names no installation, and a test says so. The forty-two became zero the same day, by the four answers above; seven of them are declared on purpose and stay visible as the list to shrink — four applications the mesh does not build yet.
- An operator's values are the assignment's. The mail module takes its domain, its site name, its website and the address it trusts a real-IP header from as settings; a mesh that installs it without them is refused at composition, by name, which is the right moment. The module's own README says which.
- What got harder: a manifest reviewer has one more word to read, and
names-on-purposeon an application's image is a debt visible in the definition until the application is built here. A reader ofsettings setoutput sees more keys than files, because a key a file asks for is a destination too. - Not decided here: ADR 0112's requirement form (design 27) still replaces
${setting:…}and the other placeholders when it lands; this is its first case, the way ADR 0038 was for ports. Host paths (issue 119) are the next step of the same group, and the registry's name (issue 123) the one after.
How this is checked
| Rule | Checked by |
|---|---|
| A value naming an installation is reported at its path, in the definition's words | a catalogue unit test over a definition with a hostname in an env value and a public address in a file |
| Prose, the world's registries in an image, public resolvers, ACME directories and the runtime's own alias are not reported | the same tests |
| A name declared on purpose is not reported; a name beside it that is not declared is | a test with a homeserver's config |
| An image from an installation's registry needs a reason | a test without and with the word |
| A module named after a domain is reported | a test |
| No definition in the catalogue names an installation | TestNoCatalogueManifestNamesAnInstallation over the checkout, and module check modules/ |
${setting:key} fills from the layers, node over mesh; refused by name when unset; not stray when set |
three tests |
| A context on a seat is cloned from the base the mesh sent; a seat with no base is refused by name | the builder's test |
References
- ADR 0112 — extended: the check it promised, and the operator provider's first form
- ADR 0111 — a source on the seat; now a context too
- issue 122, issue 134 — what this closes
- 27 — A module requires, the mesh resolves — where this sits in the larger design
- mesh-controller PR 169, mesh-catalog PR 188 — the check, the words, and the catalogue that passes it