proximo

Every route answers on a qualified host

Two containers claiming api.test is the ordinary case in local development — two worktrees of one repository, or a stale container nobody stopped. proximo's glossary already said a Collision is reported, never silently resolved, but the watcher drops the loser by lexicographic order, logs it where nobody looks, and proximo status omits it entirely. Every fix for that stood on the same unanswered question: if proximo may not pick a winner, what does the loser get?

Decision. Every route answers on two hosts. The bare host (api.test) is the short name a developer writes, and it is the only contested one. The qualified host (api.shop.test) inserts the route's Namespace — the container's Compose project name — before the TLD, is always present, and is never moved by a Collision. A Collision therefore costs a bare host, never a service: both claimants stay reachable, and proximo reports the contest instead of hiding it.

Considered options

Refuse to serve a contested bare host at all. The most literal reading of "reports, never resolves", and rejected: it turns a forgotten container into a broken environment, punishing the developer for a leftover.

Serve the winner and report the loser, with no qualified host. Honest, but it leaves the arbitrariness intact — the winner is whoever sorts first, so renaming a container moves traffic, and the report has no remedy to offer. It is this option plus the qualified host that makes the report actionable.

Qualify only on collision (api.test becomes api.shop.test when a second claimant appears). Rejected: a name that materializes during an incident is a name nobody puts in a README or an .env, so nobody relies on it — which was the whole point.

A second TLD instead of a namespace (api.test and api.loc). Rejected: it is a second mechanism for what the Namespace already means, and the worse one — a privileged resolver per TLD, multiplied SANs and routers, and an ambiguous qualified host. The TLD stays exactly one per machine.

api-shop.test instead of api.shop.test. Rejected for readability, at a real cost recorded below.

Consequences