Files
hq/02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md
T
jschoubben 9ffb7eec55 ADR 0155: a definition names no installation, how that is checked, and the three ways out
Issues 122 and 134 resolved; design 27 in progress with its first cases; design 18 names the words.
2026-09-30 18:40:05 +02:00

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-purpose on an application's image is a debt visible in the definition until the application is built here. A reader of settings set output 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