--- topic: what runs on it status: accepted date: 2026-09-30 deciders: jochen reconstructed: false extends: 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](0112-a-module-definition-names-no-node-mesh-or-path.md) 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](../04-ISSUES/134-a-definition-may-still-name-the-mesh/00-report.md)). 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](../04-ISSUES/122-a-module-cannot-ask-for-its-own-public-name/00-report.md)). Two of the answers were built before this record: a module is told the name its route composes (`${bound::name}`, controller PR 149, 2026-09-30), and a source may be a path on the git seat ([ADR 0111](0111-a-build-source-is-on-the-git-seat-or-external.md)). 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:}` 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:}`**, 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 ` 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": "/"}` 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](0038-the-mesh-assigns-the-port.md) was for ports. Host paths ([issue 119](../04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md)) are the next step of the same group, and the registry's name ([issue 123](../04-ISSUES/123-the-image-registry-is-named-after-a-role/00-report.md)) 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](0112-a-module-definition-names-no-node-mesh-or-path.md) — extended: the check it promised, and the operator provider's first form - [ADR 0111](0111-a-build-source-is-on-the-git-seat-or-external.md) — a source on the seat; now a context too - [issue 122](../04-ISSUES/122-a-module-cannot-ask-for-its-own-public-name/00-report.md), [issue 134](../04-ISSUES/134-a-definition-may-still-name-the-mesh/00-report.md) — what this closes - [27 — A module requires, the mesh resolves](../03-DESIGN/01-to-be/27-a-module-requires-the-mesh-resolves.md) — 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