Written 2026-09-28, answered the same week by mesh-controller bdf965d and c68d3a7, and never closed — so the mesh's own account said reach was declared nowhere while three readers were reading it: the filter, the proxy's names, and each authority's host policy. The resolution names them and what checks each. What is left is retiring the older per-port keys the block replaces, which is not a gap in what reach can say.
5.0 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design | |||||
|---|---|---|---|---|---|---|---|---|---|
| resolved | 2026-09-28 |
|
mesh-controller bdf965d (a module names its endpoints) and c68d3a7 (an assignment configures an endpoint as one thing) — the filter, the proxy's names and both authorities now read one statement | 03-DESIGN/01-to-be/08-connectivity.md |
140 — An endpoint's reach is not declared, so three mechanisms each decide it separately
What was observed
Preparing to converge the mesh's control-node — the last machine still running the firewall it had before the mesh — the question came up for one module: the forge serves git over ssh, and that port must stay reachable from outside the private network. Where is that said?
The manifest declares the port with a source of mesh, so the derived filter would close it to
everything but the private network. Looking for the place an assignment says otherwise, there are
two per-node settings keys: one that gives a module's declared port a machine port, and one that
overrides a declared port's source. The second has exactly one caller — the function that builds
the node's filter rules. Nothing else in the control plane reads it.
A module's routed endpoint is declared somewhere else entirely: a route contribution naming a label and a port. It says nothing about reach. The proxy composes a public name and an internal name for every route it is given, and obtains a certificate for each from a different authority. Measured on that machine the same day: an identity provider's public name signed by the public authority for 90 days, its internal name signed by the mesh's own intermediate for 24 hours and renewed daily. Both names exist, and both certificates, because the proxy makes every name it can. No assignment asked for either.
So the forge's ssh endpoint has a firewall source and nothing else — no name, no certificate, and no way to say it should be public other than a key the filter alone reads. And the forge's web endpoint has two names and two certificates that nobody requested.
Why it matters beyond this instance
Reach is stated twice, in two vocabularies, in two places that cannot disagree out loud. A port may be exposed to anywhere while the module contributes no public route; a public route may be served for a module whose own listen is private. Nothing reconciles the pair or refuses it. Each mechanism is separately defensible and the combination is unstated.
The vocabulary belongs to the filter, not to reachability. Public, internal, or both cannot be
expressed. A source of anywhere is one rule on one chain; it says nothing about which names should
exist or which authority should sign them. So "this endpoint must not be public" has no way to be
written, and is therefore enforced by nothing — while a public certificate for that very name is
obtained automatically.
An endpoint is not a thing in the model. A module has ports, and separately it has routes. Nothing binds a port to a name to a certificate, which is why three mechanisms each decide reach on their own and none of them is wrong. This is ADR 0045's fault one level up: that record closed "a declaration that reads as a restriction and restricts nothing" for the packet filter. Here the declaration is absent altogether and the mechanisms guess.
It blocks the certificate work. The open question recorded for certificates — a name that must not be public needs either DNS-01 or the internal authority only — cannot be answered while no assignment states whether a name should be public. Neither can expiry reporting, revocation, or what happens to a name when a machine leaves: all of them need to know which names were meant.
Open questions
- Should an assignment name each of a module's endpoints, bind it to a node-level port, and state whether it is reachable publicly, internally or both — with the filter, the proxy's names and the certificate authority all derived from that one statement?
- What is an endpoint that is neither routed nor certified? Git over ssh is public reach with no name and no certificate; the model has to hold that without inventing one.
- Are the two existing settings keys the same statement, half-built? If so, is this a new declaration or the completion of theirs?
- Does an internal-only endpoint get a certificate at all, and from which authority — and does that settle issue 129, where nothing installs the mesh's own root?
- Does declaring reach per assignment also settle issue 139, where an internal name resolves to the consumer's machine instead of the one serving the endpoint?