Description
## Goal
Enable a full Hydra setup on one Windows machine — both `hydraheadflatscreen` and `hydrabody` running on the same node. When the head runs body discovery, it should prefer the local body first and connect via `127.0.0.1` rather than routing through the LAN IP.
## How same-machine is detected
Both agents enroll via `hydranode`, which reports the machine's LAN IP in every heartbeat. When head and body share a machine they both have `node.IP == <same IP>` in hydracluster. This is the zero-config signal.
## Changes shipped
### hydracluster v2.0.40 / v2.0.47
`pkg/api/handlers_api.go` — `handleEligibleBodies`:
- Added `SameMachine bool` to `eligibleBody` struct.
- Detects `sameMachine = n.IP != "" && n.IP == head.IP` during node iteration.
- Sort order updated: `same_machine → same_venue → idle_first → vram_desc`.
- `docs/runbooks/body-selection.md` updated.
### hydraheadflatscreen v2.0.47
`pkg/client/discovery.go`:
- Added `SameMachine bool` to `EligibleBody` struct.
- Probes `127.0.0.1:47990` first when `SameMachine` is true, falls through to LAN then WireGuard.
- `docs/runbooks/runbook.md` and `docs/testbooks/wireguard-path-validation.md` updated.
## Validation status
**Confirmed:**
- `GET /api/v1/bodies/eligible?head_id=node-11da9ea3&district=bxl1-test` returns `same_machine: true` for fluffy-dumpling-87 querying itself (hydracluster v2.0.47 live).
- hydraheadflatscreen v2.0.47 installed and started successfully on fluffy-dumpling-87.
**Pending (requires dedicated test machine):**
- Trigger a self-service stream and confirm agent log shows `routing via localhost (same machine): <body-name>`.
- Confirm stream launches successfully end-to-end over loopback.
## Pure head clients unaffected
A machine with only `hydraheadflatscreen` (e.g. Mac Mini kiosk) has no body node with its IP in hydracluster. `same_machine` is never set, localhost probe never triggered.