Skip to content

feat(web): protocol v5, robot hello on an @control stream - #3567

Open
paul-nechifor wants to merge 1 commit into
paul/feat/w2-sdk-servingfrom
paul/feat/w3-protocol-v5
Open

feat(web): protocol v5, robot hello on an @control stream#3567
paul-nechifor wants to merge 1 commit into
paul/feat/w2-sdk-servingfrom
paul/feat/w3-protocol-v5

Conversation

@paul-nechifor

Copy link
Copy Markdown
Contributor

No description provided.

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.91358% with 5 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/web/relay_bridge/test_relay_e2e.py 82.75% 4 Missing and 1 partial ⚠️
@@                     Coverage Diff                      @@
##           paul/feat/w2-sdk-serving    #3567      +/-   ##
============================================================
+ Coverage                     77.39%   77.42%   +0.02%     
============================================================
  Files                          1266     1266              
  Lines                        121416   121551     +135     
  Branches                      11226    11235       +9     
============================================================
+ Hits                          93974    94114     +140     
+ Misses                        24364    24362       -2     
+ Partials                       3078     3075       -3     
Flag Coverage Δ
OS-ubuntu-24.04-arm 72.37% <96.91%> (+0.03%) ⬆️
OS-ubuntu-latest 74.25% <96.91%> (+0.02%) ⬆️
Py-3.10 74.25% <96.91%> (+0.02%) ⬆️
Py-3.11 74.25% <96.91%> (+0.02%) ⬆️
Py-3.12 74.25% <96.91%> (+0.03%) ⬆️
Py-3.13 74.25% <96.91%> (+0.02%) ⬆️
Py-3.14 74.25% <96.91%> (+0.02%) ⬆️
Py-3.14t 74.24% <96.91%> (+0.02%) ⬆️
SelfHosted-Large 29.89% <9.87%> (-0.03%) ⬇️
SelfHosted-Linux 34.96% <9.87%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/web/relay_bridge/_wt_session.py 86.25% <ø> (ø)
dimos/web/relay_bridge/manifest.py 98.55% <100.00%> (+0.03%) ⬆️
dimos/web/relay_bridge/protocol.py 100.00% <100.00%> (ø)
dimos/web/relay_bridge/test_protocol.py 100.00% <100.00%> (ø)
dimos/web/relay_bridge/test_wt_client.py 98.17% <100.00%> (+1.26%) ⬆️
dimos/web/relay_bridge/wt_client.py 88.93% <100.00%> (+2.14%) ⬆️
dimos/web/test_cockpit.py 100.00% <100.00%> (ø)
dimos/web/relay_bridge/test_relay_e2e.py 95.29% <82.75%> (-1.63%) ⬇️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The protocol v5 change moves robot hellos onto control streams, but two reliability failures remain. Large valid manifests can lead to subscription snapshots that exceed the datagram limit and are still sent as a single datagram. Separately, a delayed relay can have every pending hello stream reset before it consumes one, causing registration to time out.

Confidence Score: 3/5

Not safe to merge until robot hello retries preserve deliverable streams and oversized subscription state has a reliable delivery or rejection path.

Two independent blocking reliability failures were reproduced: delayed relay consumption can prevent robot registration, and large valid subscription sets are sent through a datagram path that cannot carry them.

Files Needing Attention: dimos/web/relay_bridge/wt_client.py, web/relay/registry.ts

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex ran the runtime reproduction script for a large subscription snapshot and compared outputs before the PR change, on the current PR, and with an existing registry test attempt.
  • T-Rex exercised the deterministic hello retry harness and ran multiple reproductions, including the delayed unread reset runs (first and second) and the focused existing robot hello test attempt.
  • T-Rex summarized proofs 2 and 4, documenting the two P1 findings described in those proofs.
  • T-Rex validated the general contract behavior for the over-budget reproduction, noting that a robot can accept subscriptions while the relay delivers an oversized snapshot, revealing the need for a reliable snapshot carrier or a budget enforcement mechanism.
  • T-Rex documented two independent successful executions of the same deterministic hello-unread-reset reproduction and captured related harness and environment context.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. General comment

    P1 Oversized subscription snapshots are still sent over the datagram-only robot contract

    • Bug
      • For a valid 100-channel declared manifest, public viewer subscription requests produce a 3,128-byte subs snapshot—well above the 1,200-byte relay budget. The registry logs the overflow but immediately forwards that exact snapshot through RobotPeer.sendMsg; the production robot session encodes it and writes it to wt.datagrams.writable. The harness observed sendMsgCalledForOversizedSnapshot:true and zero viewer errors.
    • Cause
      • Registry.#syncSubs treats the budget check as diagnostic-only (web/relay/registry.ts:513-521) even though RobotSession.sendMsg is datagram-only (web/relay/session.ts:90-92). Protocol v5 permits a large manifest over the control stream, removing the former implicit guarantee that a full subscription snapshot fits a datagram.
    • Fix
      • Do not send an over-budget subs payload through RobotPeer.sendMsg. Implement the intended reliable robot control carrier for snapshots, or reject/cap subscriptions before updating state with a clear response until that carrier exists. Add a regression test that asserts over-budget snapshots are not sent via the datagram path and that the selected fallback/rejection contract is observable.

    T-Rex Ran code and verified through T-Rex

  2. General comment

    P1 Robot hello retries reset streams that may still be deliverable to the relay

    • Bug
      • RelayClient.hello() retries every 200 ms and calls reset_if_in_flight() for the prior hello stream. stream_in_flight() only reports whether every byte/FIN has been transport-ACKed. It does not report relay application consumption. In the executed 350 ms delayed-consumption scenario, current code reset all hello streams before the relay could consume one, producing no welcome and a timeout.
    • Cause
      • retire_hello_stream() at dimos/web/relay_bridge/wt_client.py:203-209 treats the ACK-based sender state returned by _wt_session.py:296-306 as safe authority to retire a hello. Resetting a still-unacknowledged QUIC stream can withdraw buffered data that has not yet reached or been processed by the relay.
    • Fix
      • Do not reset the prior robot hello solely because it is transport-unacknowledged at the 200 ms resend boundary. Allow in-flight hello streams to remain deliverable (or use a relay/application-level idempotent acknowledgement and a retirement rule that cannot reset an unread hello); retain cleanup only when the connection/session is definitively closing or the protocol provides a safe delivery/consumption guarantee.

    T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "feat(web): protocol v5, robot hello on a..." | Re-trigger Greptile

Comment thread web/relay/registry.ts
Comment on lines 512 to 521
const msg: Msg = { t: "subs", chs, n: ++entry.n };
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// Unreachable while subs are manifest-validated (a manifest that fit
// its hello datagram implies a fitting snapshot). Loud if it ever
// happens: an oversized snapshot silently never reaches the robot.
// Reachable since v5: a stream hello can declare a channel set whose
// full snapshot no longer fits one datagram (W4 moves snapshots to the
// reliable carrier). Loud because an oversized snapshot silently never
// reaches the robot.
console.error(`[relay] subs snapshot for ${robotId} is ${size} B (over datagram budget)`);
}
entry.peer.sendMsg(msg);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Oversized subscription snapshots are undeliverable

A valid large manifest can produce a complete subs snapshot larger than the 1200-byte datagram budget. This branch only logs the overflow and still sends the single oversized datagram, so the robot never receives the authoritative subscription state; periodic snapshot retries remain oversized as the active set grows. Send this state on a reliable control stream, fragment it, or enforce a channel-count limit that keeps its encoded snapshot within the datagram budget.

Artifacts

Focused large-manifest reproduction source

  • Executes the registry subscription path with a valid 32-channel manifest, a 1200-byte datagram contract, and a follow-up teleop control message; takeaway: the source directly exercises the claimed oversized-snapshot path.

PR oversized-snapshot runtime output

  • Captured PR execution shows protocol v5 accepting the large manifest and sending a 1211-byte subscription snapshot over the 1200-byte budget while follow-up teleop remains accepted; takeaway: valid v5 manifests can produce an undeliverable subscription snapshot.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment on lines +203 to +219
def retire_hello_stream() -> None:
# In-flight check and reset in the same event-loop turn (the
# aioquic-safe reset rule, web/README.md bug 9); a delivered
# stream is left alone so a reset cannot destroy a hello the
# relay has yet to read.
if hello_stream is not None and self._session.stream_in_flight(hello_stream):
self._session.reset_if_in_flight(hello_stream)

try:
while True:
if control_payload is None:
self._session.send_msg(msg)
else:
retire_hello_stream()
hello_stream = self.send_frame(CONTROL_CHANNEL, control_payload)
with contextlib.suppress(asyncio.TimeoutError):
await asyncio.wait_for(self._session.welcomed.wait(), 0.2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hello retries reset live control streams

stream_in_flight() only means the sender has not received a transport ACK; it does not mean the relay has not yet consumed the stream. After each 200 ms wait, this retry path resets that still-deliverable hello stream before resending. When ACK and relay consumption are delayed beyond the retry interval, every hello is reset before the relay reads it and the robot handshake times out. Keep prior hello streams live until a terminal handshake result, connection close, or a protocol-level acknowledgement that proves they can be retired.

Artifacts

Focused delayed-ack robot hello reproduction source

  • The executed Python harness drives RelayClient.hello against a transport that delays ACK and relay consumption to 350 ms, showing whether reset destroys the still-deliverable stream.

Delayed-ack handshake without destructive stream resets

  • The identical delayed transport completed welcome at 351 ms and recorded relay consumption of stream 101 when resets did not cancel delivery, proving the stream remained deliverable.

Current retry behavior with destructive stream resets

  • The current RelayClient.hello behavior reset streams 101 through 104, recorded no relay consumption, and timed out after 803 ms, confirming the claimed failure.

View artifacts

T-Rex Ran code and verified through T-Rex

- Protocol v5. The robot's hello moves from lossy datagrams to an @control
  data frame on a fresh one-shot bidi stream, resent until welcome arrives.
- The hello payload keeps the datagram encoding but may now be 64 KiB, which
  frees the manifest from the ~1100 B datagram budget.
- Channel ids beginning with @ are reserved for protocol control. Manifests
  using them and datagram hellos are rejected with explicit reject reasons.
- Shared fixtures regenerated for v5. Relay session/forward/registry and the
  Python bridge client change together, pinned by the golden wire vectors.
- server_test.ts: the v5 handshake updates are applied on top of the deflaked
  backpressure test from main (#3555). This branch adds no flake fix of its own.
@paul-nechifor
paul-nechifor force-pushed the paul/feat/w3-protocol-v5 branch from 40fc6dd to 384d476 Compare August 22, 2026 02:12
Comment thread web/relay/registry.ts
Comment on lines 513 to 521
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// Unreachable while subs are manifest-validated (a manifest that fit
// its hello datagram implies a fitting snapshot). Loud if it ever
// happens: an oversized snapshot silently never reaches the robot.
// Reachable since v5: a stream hello can declare a channel set whose
// full snapshot no longer fits one datagram (W4 moves snapshots to the
// reliable carrier). Loud because an oversized snapshot silently never
// reaches the robot.
console.error(`[relay] subs snapshot for ${robotId} is ${size} B (over datagram budget)`);
}
entry.peer.sendMsg(msg);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Oversized subscription snapshots remain datagram-only

A valid large manifest can produce a complete subs snapshot larger than the 1200-byte datagram budget. This branch logs the overflow but still calls entry.peer.sendMsg(msg), which sends the snapshot over the robot datagram path. The robot therefore cannot receive the authoritative subscription state, so requested feeds can remain unsubscribed. Send these snapshots on a reliable control stream, fragment them, or reject/cap subscriptions before sending an oversized state.

Artifacts

Runtime reproduction script for a large subscription snapshot

  • Authored TypeScript harness registers a valid 100-channel robot and drives viewer subscription messages through the public registry API, ending with encoded-size and send observations. It demonstrates the precise oversized snapshot path.

Runtime reproduction output before the PR change

  • Captured output from the identical harness in detached `HEAD^`; it exits 0 and shows a 3,128-byte snapshot over the 1,200-byte budget still recorded as sent. The behavior existed before the PR change.

Runtime reproduction output on the current PR

  • Captured output from the identical harness on current `HEAD`; it exits 0, logs the over-budget condition, and reports that the 3,128-byte snapshot was still sent. The root finding is reproduced.

Existing registry test attempt

  • Captured attempt to run the existing registry tests with Bun; it fails before tests execute because Bun cannot resolve the Deno `@std/assert` import mapping. This does not block the standalone runtime reproduction.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment on lines +203 to +209
def retire_hello_stream() -> None:
# In-flight check and reset in the same event-loop turn (the
# aioquic-safe reset rule, web/README.md bug 9); a delivered
# stream is left alone so a reset cannot destroy a hello the
# relay has yet to read.
if hello_stream is not None and self._session.stream_in_flight(hello_stream):
self._session.reset_if_in_flight(hello_stream)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hello retry resets unread control streams

Robot hello retries reset the previous stream whenever it is still transport-unacknowledged after 200 ms. stream_in_flight() describes sender ACK state, not whether the relay has consumed the stream. With relay consumption delayed past that boundary, each retry withdraws the still-deliverable hello before the relay can read it, so registration times out. Keep prior hello streams live until a terminal handshake result, connection close, or an application-level acknowledgement establishes that retirement is safe.

Artifacts

Deterministic hello retry harness source

  • Review-authored source creates an ACK-pending stream whose relay consumption is deliberately delayed, then invokes current RelayClient.hello; it provides the executable reproduction.

Delayed unread hello reset reproduction, first run

  • Executed current-code harness with 350 ms relay consumption delay and persistent no-ACK state; it shows retries reset every hello and the handshake times out.

Delayed unread hello reset reproduction, second run

  • Independent executed current-code harness run reproduces the same timeout and reset sequence, while the 50 ms consumption control completes with welcome; it confirms the failure depends on passing the 200 ms retry boundary.

Focused existing robot hello test attempt

  • Attempted the repository's focused robot hello tests, but pytest collection stopped on missing unrelated reactivex dependency; it shows existing-test execution was environment-blocked rather than silently omitted.

View artifacts

T-Rex Ran code and verified through T-Rex

@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant