---
name: infinibot-federation-routing
description: Route gateway methods and UI actions to the correct federation node (master vs satellite) using nodeId + hub.invokeOnNode, and selectively proxy handler methods to master.
---
# InfiniBot Federation Routing

## When to use
- A gateway handler in `src/gateway/server-methods/*` performs an action (spawn agent, run command, write file) that must execute on the node the user picked in a "Device" dropdown — not blindly on the local process.
- A UI control calls `renderFederationNodeSelect` (or otherwise exposes a node picker) and the selected `nodeId` needs to round-trip to the backend.
- You're adding a new gateway method that touches per-node side effects (PTYs, processes, filesystem) or shared state (notes, kanban, channels) and need to decide where it runs.
- Symptoms: user selects a satellite from the dropdown but the work runs locally on the master.

## How to apply
1. **Audit first, fix second.** Before editing, grep for every caller of the affected gateway method and every `renderFederationNodeSelect` usage. Write a short audit doc under `docs/` listing call sites, current routing behavior, and whether each handler is local-only, master-only, or per-node. Skipping this step causes regressions in unrelated callers (e.g. workflow runner, orchestrator) that don't have `nodeId` in scope.
2. **Server-side routing pattern** for per-node gateway methods:
   - Accept optional `nodeId` in the method args.
   - If `nodeId` is empty, `'local'`, or matches the current node → run the existing local code path unchanged.
   - If `nodeId` is non-local AND this process is master → forward via `hub.invokeOnNode` (use the helper `src/federation/hub-forward.ts::forwardGatewayCallToNode`).
   - If `nodeId` is non-local but no hub is available → fall back to local with a warn log (don't throw — keeps non-federated installs working).
3. **Handler-level proxying** for files that mix shared state with per-node side effects: use `src/federation/satellite-context.ts::proxyMethodsToMaster(handlers, methodNames)` and pass only the specific method names that must hit master. Never blanket-wrap a whole handler module — local-only handlers like webhook delivery will break.
4. **UI side** is usually already correct if the page uses `controllers/terminals.ts` or `views/masonry-grid.ts` patterns — they round-trip `nodeId` through `federation.node.invoke`. Verify by reading the controller before assuming the bug is in the UI.
5. **Tests:** add unit tests under `src/federation/` covering local/empty/missing/master-forwarding/no-hub-fallback branches. Run `pnpm vitest run src/federation/ src/gateway/server-methods/<changed-file>` and `pnpm tsc --noEmit` before committing.
6. **Federation node list** is already canonical at `federation.nodes.list` — do not create a duplicate gateway method.

## Rules
- Never blanket-wrap a handler module with `proxyMethodsToMaster` — list the method names explicitly.
- Never throw when `nodeId` is non-local and no hub is available; fall back to local with a warn log so single-node installs keep working.
- Never switch branches mid-task or use `--no-verify` when committing federation routing changes.
- Always audit every caller (workflows, orchestrator, continuous-runner, terminal tool) before changing a gateway method signature; many callers don't have `nodeId` in scope and silently regress.
- Always treat `nodeId` as optional — empty/`'local'`/matching-current-node must preserve the pre-existing local code path byte-for-byte.
- Always verify whether the bug is server-side routing or UI dropdown wiring before editing — recent UI controllers already pass `nodeId` correctly.
- Always note in the PR/commit that end-to-end verification on a live master+satellite pair is still required; unit tests don't cover real PTY parity.