Not every host path names this machine. A system file the mesh owns is at that path on every machine of the kind — the path is the fact. The operator's shared data is already answered as an access. A path inside a container is the software's contract. What is left, and what a node's default layout would replace, is 514: a module's own data, and what the mesh writes for that module. Documents the reservation model as the records already have it — a root per node, one directory per assignment, a placement for adopted data — and the three things nothing states: where the root comes from, what sits beneath it, and the order the 514 are retired in. Stops there deliberately. Changing where a definition looks without moving the data does not fail: the mesh creates the directory, the container starts, the service comes up empty. Retiring these is a data migration with a verification step, module by module, and belongs with whoever can see the machine.
7.1 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design | ||||
|---|---|---|---|---|---|---|---|---|
| located | 2026-09-26 |
|
122 — A module cannot ask for its own public name, so three manifests wrote this mesh's names into the catalogue
What was observed
Reviewing the open module changes on 2026-09-26, three of them independently put a name belonging to one particular mesh into a module definition, each for a different piece of software and each as the only way to make the software work:
- The identity provider's manifest gains
KC_HOSTNAME: https://<label>.<public-domain>as a literal, because the software generates absolute URLs and, behind a proxy, cannot derive them. - The object store's manifest gains
MINIO_BROWSER_REDIRECT_URL: https://<label>.<public-domain>as a literal, for the same reason — its console redirects to an absolute URL. - The file-sync module's S3 bucket is renamed from
nextcloudto a name carrying this mesh's own name, so the module matches a bucket that already exists here.
No reviewer introduced these carelessly: each is the value the software needs, and there is nowhere else to put it.
And they are not the first. Asked whether merging them would set a precedent, the catalogue answered no: five modules already on the main branch carry one. The clearest is the workflow automation module, whose environment file states its host, its protocol and a full absolute webhook URL as literals; two more — the proxy and the builder — carry a complete clone URL for a repository on this mesh's own forge, scheme, host and port included.
Counted properly, 2026-09-26. The five were what a first look found. A sweep of all 71 definitions, for values that could only be true of one installation:
| What is named | Occurrences | Modules |
|---|---|---|
| A public domain, or a name under one | 49 | 26 |
| The node's own name | 58 | 19 |
| A routable IP address | 12 | 1 |
| A host path for a module's own files — the node's to decide | 514 | 70 |
| An email address | 0 | 0 |
The path row is issue 119,
counted again — and counted differently, which is the correction worth keeping. A path inside a
container is not a fact about the machine. /run/secrets/… and the directory a server keeps its
data in are the software's own contract, true in any mesh that runs it; only the host side of a mount
names where it landed. The first sweep matched path-shaped strings and so counted both halves of every
mount and every in-container location a value mentioned. Counted by role instead — directory and file
resources, the host side of mounts, accesses, and the targets of binds, grants, receives and secrets —
it is 698 across 70 definitions — of which 514 are the category at issue. The rest are a system
file the mesh owns (/etc/…, where the path is the fact and is the same on every machine) and the
operator's shared data, which ADR 0051 already answers as an access. Issue 119 carries that breakdown
and what a node's default layout would replace. Issue 119's own figure is role-counted already and close to this; it
additionally counts paths written into environment values, a few of which are container-side.
The rest of the table is this issue. Thirty of the seventy-one definitions name this installation in one of the first three ways, and the worst single case is not a domain at all: a mail module states the node's own public IPv4 as the address it trusts a real-IP header from, so a node that moves, or gains a second address, silently stops attributing mail to the right sender. A private subnet, the mail domain, the site name and the administrator's domain sit in the same block of values.
Two upstream resolvers are excluded from the count deliberately: naming a public DNS service is a policy default, true of any mesh that wants it, not a fact about this one.
So the three under review are the visible edge of a pattern the catalogue already follows, which changes what this issue is for. It is not a matter of refusing three changes; there is no version of this catalogue today that does not name the mesh it was written in, and a mechanism is the only thing that removes any of them.
What the mesh offers instead, and why none of it answers
A manifest may interpolate ${secret:…}, ${seat:…}, ${bound:…}, ${port:…} and
${machine:…}. The machine form resolves at, name and address — the machine's identity on the
private network. None of them yields a public name.
The mesh does compose public names: a route contribution's label is joined to the node's public
domain, <label>.<public-domain>, and the mesh interprets neither half. That happens inside the
controller when a declaration is built, and the result reaches the proxy that serves the route. It
does not reach the module that asked for the route, so a module that must tell its own software
what it will be reached at cannot read what the mesh already worked out.
So the workaround is the only expressible option: write the answer down, in the definition, for the one mesh it is true of.
Why it matters beyond these three
A module definition is meant to hold what is true of the module everywhere, with everything particular to an installation resolved at assignment — the argument ADR 0112 (proposed) makes in full, and what issue 119 found for paths. A hostname is the same kind of fact as a path, and arriving by the same route: not because anyone disagreed with the principle, but because the mechanism that would honour it does not exist yet.
The cost is concrete. A second mesh installing the identity provider from this catalogue gets the first mesh's hostname, and its login flow breaks in a way that looks like a proxy fault. Nothing checks for it: a literal hostname in an env value is a well-formed string, and no rule distinguishes it from a version number.
The bucket case is the same shape with a different subject — an adopted resource's real name is also particular to one installation, and also has nowhere to live but the definition.
Open questions
- Should a module be able to name what it will be reached at — a
route-scoped interpolation resolving to the composed public name of a route it contributes, so the answer the mesh already computes is the one the software is told? That is the smallest fix and it stays within the existing vocabulary. - Does the scheme belong to it? Every instance here wrote
https://, which is true of a route the proxy terminates and not of the module's own port. - For an adopted resource such as an existing bucket: is that a setting on the assignment (where ADR 0112 would put it), and if so what reads it — the provisioner, or the module's own values?
- What check would notice the next one? A definition naming a public domain is detectable in the shape of the value, which is more than nothing, and less than a rule.