Files
hq/04-ISSUES/094-a-port-published-as-the-machine-side-cannot-be-moved/00-report.md
jschoubben 668ce3ad62 Issue 094 resolved: a given port names either end and is answered once
The first pass answered under both ends, which review showed is the same fault seen
from the other side where two mappings share a number. Verified on the machine: the
forge is back on the port its own configuration has always advertised.
2026-09-23 02:37:07 +02:00

3.0 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
resolved 2026-09-23
mesh-controller internal/catalogue/filtering.go
mesh-controller cmd/mesh-controller/plan.go
mesh-controller — a node may move a port a module publishes as a mapping's machine side

094 — A port published as the machine side of a mapping cannot be moved, and trying blocks every push

What was observed

On the control-node, immediately after the first module was migrated, 2026-09-23.

A module publishes two ports. One is written short, so the machine's side and the software's side are the same number. The other is written long: a machine port mapped to a different port inside the container, because the software's own port is one the machine's own daemon already holds. The module's listens names the machine side of that mapping, deliberately, and says why.

The predecessor served that port on a different machine port. Moving the module's to match — the whole point of a port being a per-node setting (ADR 0100) — was refused:

gives port 2222 a machine port, and no container of its publishes 2222 —
the mesh cannot move a port the module does not publish

It does publish it. The check collects only the last segment of each published entry, which is the container's inner port, so for a long-form mapping it sees the wrong half. Naming the inner port instead is accepted and then never consulted, because the lookup is by what the module says it listens on — which is the machine side.

And the refusal is not confined to the setting. While that setting exists, composition fails, so every push to that node is refused until it is removed. A setting that cannot work should be refused where it is set, not where it is read.

The same blind spot appears one step further on: on an adopted node no opening was derived for that port either, and a per-node expose for it produced none, so the firewall never opened what the module serves.

Why it matters beyond this instance

Every module that maps a machine port to a different port inside its container has this hole, and the pattern is common precisely where it matters: a service whose own port collides with something the machine already runs. It is also exactly the case a migration hits, because matching the predecessor's port is how a service keeps working when it changes hands.

The push-blocking half is worse than the feature gap. One unusable setting stops a machine being told anything at all, and the message names a port rather than the setting that caused it.

Open questions

  • Should a setting name the port the software listens on, the machine port, or either, and what refuses the ambiguous case where a module publishes both halves of some other mapping?
  • Should settings set validate against the module's manifest at the moment it is set, so an impossible setting cannot be stored?
  • Should composition fail the whole node, or fail that module and send the rest?