An assignment says how far an endpoint reaches #136

Merged
mesh-admin merged 1 commits from feat/an-assignment-says-how-far-an-endpoint-reaches into main 2026-09-29 00:47:28 +00:00
Contributor

novox/hq ADR 0138, answering issue 140. The vocabulary ships alone, a release ahead of any manifest
or assignment using it, so no build and no machine changes.

Reachability was settled three times over. The filter read a listen's source, which expose could
override, and Exposure had exactly one caller. The proxy composed a public name and an internal
name for every route it was given, because it could. And the certificate authority followed from
which names happened to exist. Each was defensible; the combination was unstated. So "this endpoint
must not be public" could not be written — and was therefore enforced by nothing, while a public
certificate for that very name was obtained automatically. Measured on the control node: an identity
provider holding a 90-day public certificate and a 24-hour internal one, neither requested by any
assignment.

reach is one value per endpoint per node — machine, internal, public or both — and both
readers follow it:

  • the filter: machine → this machine, internal → the private network, public and both → anywhere.
    Those last two are deliberately the same: the mesh's addresses are a subset of anywhere, and there
    is no reach that opens a port to the world and not to the mesh.
  • the names: internal composes only the internal name, public only the public one, both composes
    both.

The authority needed no work at all. The proxy already asks the world-trusted authority for a
route's own name and its internal authority for internal-name, and the internal one is optional.
So controlling which names are composed controls which authority is asked — which is why this change
is confined to name composition and the filter.

Joined by the port, which a route already names: 35 of the catalogue's 36 route entries name a port
the same module declares a listen on. The one that does not is gitea's path-level refusal, a rule
about a name rather than an endpoint, and it is left alone — asserted by a test, because narrowing an
endpoint must not silently drop the rule shadowing it.

Nothing said composes both names and follows the manifest's from, so every mesh already running
renders identically until an assignment speaks. A port that sets both reach and expose is refused:
they say the same thing in different words, and accepting both would have the filter follow one while
the names followed the other — the disagreement this record exists to remove, reintroduced by the
migration away from the older word.

Nine tests. Proved by reverting the name half once: exactly the two name assertions fail and the rest
pass.

Not in this change, and next: named endpoints in a manifest, so reach keys on a name rather than a
port and a route names the endpoint it serves. The port join works today, which is why the vocabulary
could land first — the name is about being explicit, not a prerequisite.

novox/hq ADR 0138, answering issue 140. The vocabulary ships alone, a release ahead of any manifest or assignment using it, so no build and no machine changes. Reachability was settled three times over. The filter read a listen's source, which `expose` could override, and `Exposure` had exactly one caller. The proxy composed a public name *and* an internal name for every route it was given, because it could. And the certificate authority followed from which names happened to exist. Each was defensible; the combination was unstated. So "this endpoint must not be public" could not be written — and was therefore enforced by nothing, while a public certificate for that very name was obtained automatically. Measured on the control node: an identity provider holding a 90-day public certificate and a 24-hour internal one, neither requested by any assignment. `reach` is one value per endpoint per node — `machine`, `internal`, `public` or `both` — and both readers follow it: - **the filter**: machine → this machine, internal → the private network, public and both → anywhere. Those last two are deliberately the same: the mesh's addresses are a subset of anywhere, and there is no reach that opens a port to the world and not to the mesh. - **the names**: internal composes only the internal name, public only the public one, both composes both. **The authority needed no work at all.** The proxy already asks the world-trusted authority for a route's own `name` and its internal authority for `internal-name`, and the internal one is optional. So controlling which names are composed controls which authority is asked — which is why this change is confined to name composition and the filter. Joined by the port, which a route already names: 35 of the catalogue's 36 route entries name a port the same module declares a listen on. The one that does not is gitea's path-level refusal, a rule about a name rather than an endpoint, and it is left alone — asserted by a test, because narrowing an endpoint must not silently drop the rule shadowing it. Nothing said composes both names and follows the manifest's `from`, so every mesh already running renders identically until an assignment speaks. A port that sets both `reach` and `expose` is refused: they say the same thing in different words, and accepting both would have the filter follow one while the names followed the other — the disagreement this record exists to remove, reintroduced by the migration away from the older word. Nine tests. Proved by reverting the name half once: exactly the two name assertions fail and the rest pass. Not in this change, and next: named endpoints in a manifest, so `reach` keys on a name rather than a port and a route names the endpoint it serves. The port join works today, which is why the vocabulary could land first — the name is about being explicit, not a prerequisite.
mesh-admin added 1 commit 2026-09-29 00:47:27 +00:00
novox/hq ADR 0138. Reachability was settled three times over: the filter read a
listen's source with expose able to override it; the proxy composed a public name
and an internal name for every route it was given, because it could; and the
certificate authority followed from which names existed. Each was defensible and
the combination was unstated, so "this endpoint must not be public" could not be
written and was enforced by nothing — while a public certificate for that name was
obtained anyway. Measured on the control node: an identity provider holding a
90-day public certificate and a 24-hour internal one, neither asked for.

`reach` is one value per endpoint, per node — machine, internal, public or both —
and the filter's source and the composed names both follow it. The authority needs
no work: the proxy already asks the public authority for a route's own name and its
internal authority for the internal one, so controlling the names controls the
authority.

Joined by the port, which a route already names: 35 of the catalogue's 36 route
entries name a port the same module declares a listen on, and the one that does not
is a path-level refusal — a rule about a name rather than an endpoint, left alone.

Nothing said composes both names and follows the manifest's `from`, so every mesh
already running is unchanged until an assignment speaks. A port that says both
reach and expose is refused: they say the same thing in different words, and the
filter would follow one while the names followed the other.
mesh-admin merged commit d5505fe3d4 into main 2026-09-29 00:47:28 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-controller#136