The rust-link sidecar: it owns the loopback listener the Oxide bridge plugin
dials into, and serves the website a WebSocket feed plus store-backed reads.
Protocol 1 is deliberately three frames — server.hello, ping/pong, and one
correlated server.status — because phase 1's job is to get every seam working at
once with almost nothing in them.
What is load-bearing rather than incidental:
* The plugin is the TCP client and this process owns the listener, so a Rust
server opens no extra port. Loopback is the trust boundary on that link and
there is no token on it; the website-facing surface is the opposite, with auth
always on and a token generated and persisted on first start.
* Inbound lines are capped at 1 MiB from the start rather than after the first
large frame arrives. An over-long line is discarded and the connection stays
up: one malformed frame is not a reason to drop a link live events flow over.
* Store-backed reads answer while the game is off, which is what lets a website
render a server list during a wipe. /status is the one route that fails when
the game is down, and /server answers 204 rather than a null when the game has
never connected -- those are different answers and a client that cannot tell
them apart renders a server that does not exist.
* The two RPC failures get distinct codes. 503 means the game is down; 504 means
it is up and did not answer. Different fixes.
* rpc::REPLY_TIMEOUT is a ceiling every later command budget sits under: core
classifies a budget overrun as retryable unconditionally, so an action whose
budgetMs does not exceed it can never report retry:false.
One defect found while building, which no unit test would have caught: a
four-connection SQLite pool over :memory: hands out four separate empty
databases, because an in-memory database is per connection. It presents as
'no such table' from a random subset of queries. The pool is now capped at one
connection for an in-memory path, which is the only coherent reading of
:memory: and is what makes it usable at all.
Exercised end to end against a live Rust server: a server.hello travelled game
-> sidecar -> module -> the public website API, and killing this process left
the game untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4