0108 — A hub relays host queries to satellites per request
A federation hub relays a host query that names one of its satellites, today LIST_DIRECTORY.host, over that satellite's link, one request at a time, and...
Full source summary
A federation hub relays a host query that names one of its satellites, today LIST_DIRECTORY.host, over that satellite's link, one request at a time, and answers with the satellite's own reply. It never relays metadata, never chains, and turns every routing failure into the query's own typed refusal (OTHER, message naming the host). Satellite links negotiate L3 so the satellite answers.
Status: Accepted Date: 2026-09-10
Context
LIST_DIRECTORY (docs/spec/L3.md §4) lists child directories on the
serving host. On a hub that is the hub’s host, so the TUI’s directory picker,
opened on a satellite pane, browsed the wrong machine. ADR-0107
made satellite sessions reachable through the pane relay; a pane opened that
way still could not open a sibling window at a directory on its own host.
L3 §1.3 said a satellite link “carries no L3 leg in either direction”, and
the hub dialed its satellites offering L1 only. A satellite drops a
LIST_DIRECTORY from a consumer that did not negotiate L3 (§1.2), so the
query had no route even in principle.
Decision
- Relay per request.
LIST_DIRECTORYgains an optionalhostfield. A hub that receives one naming a satellite in its registry forwards the request on that satellite’s link withouthost, under a link-siderequest_id, and answers the consumer with the satellite’s reply under the consumer’srequest_id. The reply is not rewritten: its paths are the satellite’s. Gated onServerFeature::LIST_DIRECTORY_HOST. - No chaining. A hub never forwards
host. A satellite that is itself a hub lists its own host. - One refusal shape. Every routing failure (an unknown host, any
hoston a server that is not a hub, a link that is down, connecting, or saturated, a satellite without the query, a correlatedERROR, the hub’s deadline) is aDIRECTORY_LISTINGrefusal withOTHERand a message naming the host, never anERRORand never silence. - Satellite links negotiate L3. The hub offers L3 in its link
HELLOand keeps the satellite’s advertised features, refusing at once a query the satellite does not implement. - Metadata still does not federate. The hub relays no
GET_METADATA,SET_METADATA,LIST_METADATA, orSUBSCRIBE_METADATAover a link; L3 §1.3’s refusals stand. - Bounded like the local query. The reference hub caps the path at 4096 bytes, holds at most 8 relayed listings server-wide and 2 per satellite, answers a silent satellite with a refusal after 10 s, and abandons a request whose consumer disconnects.
Why
- A host query is stateless. It stores nothing on either server and has one reply, so relaying it needs only a request-id remap, which the link already does for commands. A subscription would need a relayed lifecycle; a query does not.
- The consumer already knows the host. The focused pane’s id carries
SATELLITE { host, id }, so naming the host costs the consumer nothing and needs no new addressing. OTHERis the code a consumer can act on. Recovery is the same for every routing failure (list somewhere else), and a new code would read asOTHERon every receiver that predates it. The message says which failure.- L3 on the link is inert otherwise. The hub sends no metadata frames on a link, so the extra layer only lets the satellite answer what the hub asks.
- A per-host cap isolates a wedged satellite. Without it, one satellite holding permits for the whole deadline starves listings on healthy ones.
Tradeoffs
- An older hub is misleading, not broken. It skips
hostand lists itself. Consumers must check the feature bit and say which host they show. - The listing reads the satellite as its server user, the identity the hub already acts as when it relays a spawn. It exposes nothing a relayed shell could not, but it is a second route to that identity.
- Relayed spawns attach separately. A window spawned on a satellite from a listing needs an explicit attach before content flows; the TUI opens the window only when that attach succeeds.
Alternatives
- Tell the user to attach to the satellite directly (
phux --remote). Rejected: it leaves the hub’s picker wrong on every satellite pane. - Route by the focused pane’s id instead of a host field. Rejected: a directory query is not scoped to a pane, and a host field lets a consumer list a satellite with no pane open there.
- Relay all of L3. Rejected for now: metadata subscriptions need a relayed lifecycle and a decision about whose store answers. This ADR does not preclude it.