feat(sidecar): protocol 8 — the asset plane, and a bound on what the shard can send #41
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/asset-bridge-p1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Asset Bridge phase 1, sidecar half (docs/link/v8.md §3.3, §14).
Shard half: RunicGateway/servuo-plugins#28. Docs half: RunicGateway/docs#236.
Three things, one of which is not additive.
The inbound line cap (§3.3) — the one that matters
read_linehad no bound at all. That was survivable only because the shard hadnever had a reason to send a large line. Protocol 8 gives it one deliberately, and an
unbounded read facing a component that now sends megabytes is a memory-exhaustion
shape we would be inventing ourselves.
MAX_INBOUND_LINE_BYTESis 1 MiB — symmetric with the capBridgeLink.cshasalways applied to its own inbound lines, so both directions of this link now read the
same. The shard's batch budget is 512 KiB, and the factor of two is load-bearing: a
page always admits its first item even when that item alone exceeds the budget (the
alternative is an oversized item skipped for the budget on every page forever), so the
wire needs room for one overshoot.
An over-long line is discarded and the connection kept —
BridgeLink.cs's owndisposition in the other direction. Tearing the link down would take the live event
feed with it over one malformed frame, and the lost reply just times out and is
re-requested; everything on this plane is idempotent.
LineReaderholds its state in a struct rather than in locals, and that is thesubtle part. This is polled inside a
tokio::select!, so the future is droppedwhenever a command wins the race. A
discardingflag in a local would be lost withit — and losing it turns the tail of an over-long line into a line of its own, silently.
There is a test for exactly that, and another for an over-long line whose terminator
lands in the very chunk that crosses the cap.
GET /assets/sourcesStage 1 of the import gate, forwarded verbatim like everything else.
respond_assetsmaps
bridge.busy→ 425 and a disabled plane → 403.425 deserves a note: on this plane it is not an idempotency collision, it is flow
control, and it is the ordinary answer mid-import rather than a rare one. The shard
serves one asset request at a time because its outbound queue is bounded in lines, not
bytes. A caller treating it as an error would abandon a healthy transfer.
403 for the same reason the event plane's gate is a 403:
Bridge.AssetsEnabledoff isan operator declining to let the website read their client files, not a malformed
request, and 400 would send an administrator hunting a bug in a correct call.
PROTOCOL_VERSION7 → 8Paired with
servuo-plugins/overlay.tomlin the linked PR — the installer refuses tocompose a bundle whose halves disagree, so a split bump fails silently at the next
release.
Also
docs/link/INTEGRATION.mdstill advertisedX-UOLink-Version: 6; it was already twoversions stale before this change. Fixed in the docs PR.
61 tests pass,
cargo fmt --checkandcargo clippy -- -D warningsclean. Verifiedagainst the real shard:
/healthreports protocol 8,/assets/sourcesreturns 200 withX-UOLink-Version: 8, and live events kept flowing through the new reader with nowarnings logged.
🤖 Generated with Claude Code
https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4