Skip to content

feat(web): subs snapshots on a relay-opened carrier stream - #3568

Open
paul-nechifor wants to merge 1 commit into
paul/feat/w3-protocol-v5from
paul/feat/w4-robot-carrier
Open

feat(web): subs snapshots on a relay-opened carrier stream#3568
paul-nechifor wants to merge 1 commit into
paul/feat/w3-protocol-v5from
paul/feat/w4-robot-carrier

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 95.95960% with 8 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 84.61% 6 Missing ⚠️
dimos/web/relay_bridge/_wt_session.py 96.00% 1 Missing and 1 partial ⚠️
@@                     Coverage Diff                      @@
##           paul/feat/w3-protocol-v5    #3568      +/-   ##
============================================================
+ Coverage                     77.42%   77.45%   +0.03%     
============================================================
  Files                          1266     1266              
  Lines                        121551   121739     +188     
  Branches                      10716    10733      +17     
============================================================
+ Hits                          94116    94299     +183     
- Misses                        24359    24364       +5     
  Partials                       3076     3076              
Flag Coverage Δ
OS-ubuntu-24.04-arm 72.42% <95.95%> (+0.04%) ⬆️
OS-ubuntu-latest 74.29% <95.95%> (+0.03%) ⬆️
Py-3.10 74.29% <95.95%> (+0.03%) ⬆️
Py-3.11 74.29% <95.95%> (+0.03%) ⬆️
Py-3.12 74.29% <95.95%> (+0.04%) ⬆️
Py-3.13 74.29% <95.95%> (+0.04%) ⬆️
Py-3.14 74.29% <95.95%> (+0.03%) ⬆️
Py-3.14t 74.28% <95.95%> (+0.03%) ⬆️
SelfHosted-Large 29.85% <11.11%> (-0.04%) ⬇️
SelfHosted-Linux 34.92% <11.11%> (-0.05%) ⬇️

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

Files with missing lines Coverage Δ
dimos/web/relay_bridge/protocol.py 100.00% <ø> (ø)
dimos/web/relay_bridge/test_protocol.py 100.00% <100.00%> (ø)
dimos/web/relay_bridge/test_wt_session.py 100.00% <100.00%> (ø)
dimos/web/relay_bridge/wt_client.py 88.98% <100.00%> (+0.04%) ⬆️
dimos/web/relay_bridge/_wt_session.py 92.19% <96.00%> (+5.94%) ⬆️
dimos/web/relay_bridge/test_relay_e2e.py 93.77% <84.61%> (-1.53%) ⬇️

... and 4 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

This change moves relay-to-robot subscription snapshots onto a reliable carrier stream and updates bridge-side control-frame handling. Two robot-disconnection paths remain: an oversized aggregate subscription snapshot is confirmed to fail the carrier, and rapid subscription changes can exhaust the carrier queue while its stream is flow-controlled.

T-Rex validation blocked

The queue-overflow reproduction could not execute because the required Deno tool is not installed or available on PATH; the harness and focused relay tests exited before loading application code.

Confidence Score: 1/5

Not safe to merge until relay subscription updates are bounded against both carrier payload and pending-queue limits.

Two independent robot availability failures require separate fixes: aggregate snapshots can exceed the control-frame budget, and changed snapshots can accumulate beyond the carrier queue limit during a stalled write.

Files Needing Attention: web/relay/registry.ts, web/relay/carrier.ts, web/relay/session.ts

Security Review

Viewer-controlled subscription activity can affect robot availability. A confirmed manifest-less subscription set can exceed the carrier control-payload budget and terminate the robot session. The carrier also closes the session when its pending-frame queue overflows, leaving flow-controlled subscription churn as a second availability risk.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced proofs for three posted P1 findings and linked each to its review comment.
  • An environment check attempted to run the registry-carrier flow-control repro and related tests, but the Deno runtime was unavailable, so nothing executed.
  • The manifestless subscriptions flow validation documented the payload boundary behavior, showing below-boundary 65,487 B for 977 subscriptions and above-boundary 65,554 B for 978 subscriptions, with an over-cap control payload message.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. General comment

    P1 Manifest-less subscriptions can aggregate past the control-payload limit and close the robot session

    • Bug
      • Each channel ID is limited to 64 characters, but the registry does not limit the number or aggregate serialized size of distinct subscriptions for a robot with no manifest. The focused runtime reproduction shows 977 active subscriptions serialize to 65,487 B without failure, while 978 serialize to 65,554 B and trigger the carrier's over-cap failure path.
    • Cause
      • onViewerMsg enforces only per-ID length for undeclared subscriptions (web/relay/registry.ts:259-294). #activeChs aggregates every viewer's distinct subscriptions and #syncSubs sends the entire union without a total-size guard (web/relay/registry.ts:501-526). RobotCarrier.sendControl then fails the robot session when the encoded snapshot exceeds 64 KiB (web/relay/carrier.ts:58-67).
    • Fix
      • Enforce an aggregate subs snapshot budget before accepting a manifest-less subscription (using the production encoder and snapshot counter), or impose a bounded total distinct-subscription count/serialized-byte budget and reject the new subscription without sending an over-cap snapshot. Retain the carrier guard as defense in depth.

    T-Rex Ran code and verified through T-Rex

  2. General comment

    P1 Focused reproduction blocked because the Deno runtime is unavailable

    • Bug
      • The repository's relay and the authored TypeScript harness require Deno, but deno is not installed or on PATH. Both requested comparison runs and the existing focused Deno tests terminate with exit code 127 before executing changed code.
    • Cause
      • The validation environment lacks an executable Deno runtime.
    • Fix
      • Provide a compatible Deno runtime in PATH, then run the uploaded harness at 256 and 257 snapshot counts plus deno test --allow-net --allow-read relay/carrier_test.ts relay/registry_test.ts from /home/user/repo/web.

    T-Rex Ran code and verified through T-Rex

Reviews (3): Last reviewed commit: "feat(web): subs snapshots on a relay-ope..." | Re-trigger Greptile

Comment thread web/relay/registry.ts
Comment on lines 523 to +526
const chs = this.#activeChs(robotId, entry.delivery);
if (!force && chs.join("\n") === entry.lastChs.join("\n")) return;
entry.lastChs = chs;
const msg: Msg = { t: "subs", chs, n: ++entry.n };
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// 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);
entry.peer.sendControl({ t: "subs", chs, n: ++entry.n });

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 security Unbounded subscription snapshots terminate robots

For a manifest-less robot, the relay accepts arbitrary distinct channel IDs up to the per-ID limit but does not limit the aggregate active-channel snapshot before forwarding it to sendControl. Once that encoded union exceeds the carrier's control-payload limit, RobotCarrier fails and the session layer closes the robot connection. Reject or otherwise bound a prospective subscription update when the deduplicated subs payload would exceed the carrier budget, rather than letting valid viewer requests terminate the robot session.

Artifacts

Script source

  • Runs the real registry subscription path and RobotCarrier cap check with unique, individually valid 64-character IDs, ending with the aggregate-cap outcome.

Under-cap observed output

  • Executed 977 manifest-less subscriptions from `/home/user/repo/web`; the 65,487-byte snapshot remained below the cap and the carrier recorded no failure, establishing the boundary baseline.

Over-cap observed output

  • Executed 978 manifest-less subscriptions from `/home/user/repo/web`; the 65,554-byte snapshot exceeded the cap and RobotCarrier failed once, confirming the defect.

View artifacts

T-Rex Ran code and verified through T-Rex

@paul-nechifor
paul-nechifor force-pushed the paul/feat/w4-robot-carrier branch from a35211d to 9e7202c Compare August 22, 2026 02:12
Comment thread web/relay/registry.ts
Comment on lines +263 to +270
if (msg.ch.length > MAX_MANIFEST_ID_LEN) {
reply({
t: "error",
code: "unknown_channel",
message: `channel ids are at most ${MAX_MANIFEST_ID_LEN} chars`,
});
break;
}

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 security Aggregate snapshots exceed the carrier cap

For a manifest-less robot, this guard limits each channel ID but not the accumulated active-channel set. A viewer can add enough individually valid distinct channels for the subs snapshot forwarded at line 526 to exceed MAX_CONTROL_PAYLOAD_BYTES; RobotCarrier.sendControl then fails the carrier and the session closes the robot connection. Bound or reject the prospective aggregate snapshot before sending it.

Comment thread web/relay/registry.ts
Comment on lines 523 to +526
const chs = this.#activeChs(robotId, entry.delivery);
if (!force && chs.join("\n") === entry.lastChs.join("\n")) return;
entry.lastChs = chs;
const msg: Msg = { t: "subs", chs, n: ++entry.n };
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// 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);
entry.peer.sendControl({ t: "subs", chs, n: ++entry.n });

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 security Subscription churn exhausts the carrier queue

Every changed subscription set is immediately enqueued as a complete carrier snapshot. If the active stream write is flow-controlled, a viewer alternating valid sub and unsub requests can enqueue more than the carrier's 256-frame or 4 MiB limit. Its overflow path invokes carrier_failed, which closes the watched robot session. Coalesce pending snapshots, apply backpressure, or reject mutations before the queue limit is reached.

@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Aug 22, 2026
- Subscription snapshots move from datagrams to @control frames on the
  carrier: one relay-opened reliable uni stream per robot session.
- Snapshots are now ordered and size-unbounded. The periodic resend loop and
  the ~1200 B datagram budget are deleted.
- Relay-opened uni streams are the direction proven to work on both legs.
  Handshake and teleop control stay on datagrams.
- The carrier is a control dependency. A relay-side write failure or overflow
  fails the whole robot session (carrier_failed error + close).
- The bridge treats corrupt carrier framing, a reset, or an early end the same
  way. It reconnects and the fresh registration re-baselines subs.
- New web/relay/carrier.ts plus tests. The README gains a per-leg transport
  table.
@mustafab0
mustafab0 force-pushed the paul/feat/w4-robot-carrier branch from 9e7202c to 4c1d5a1 Compare August 22, 2026 20:49
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Aug 22, 2026
Comment thread web/relay/registry.ts
Comment on lines 523 to +526
const chs = this.#activeChs(robotId, entry.delivery);
if (!force && chs.join("\n") === entry.lastChs.join("\n")) return;
entry.lastChs = chs;
const msg: Msg = { t: "subs", chs, n: ++entry.n };
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// 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);
entry.peer.sendControl({ t: "subs", chs, n: ++entry.n });

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 security Aggregate subscription snapshots exceed the carrier cap

For a manifest-less robot, the per-channel length check does not bound the aggregate active-channel snapshot. The executed boundary reproduction accepted 978 distinct 64-character subscriptions, then encoded the subs control payload to 65,554 bytes—above the 65,536-byte control limit—which invokes the carrier failure path and closes the robot session. Reject a prospective subscription update when the production-encoded union would exceed the control budget, rather than forwarding an over-cap snapshot.

Artifacts

Drained carrier boundary reproduction harness

  • Runs actual Registry and RobotCarrier code with one awaited drain per snapshot and calculates the adjacent serialized control-payload boundary, proving the aggregate behavior.

Control snapshot immediately below the payload limit

  • The executed below-boundary run accepts 977 subscriptions at 65,487 B without carrier failure, showing the control path remains live below the cap.

Control snapshot immediately above the payload limit

  • The executed above-boundary run accepts 978 subscriptions at 65,554 B then reports the production over-cap carrier failure, proving the robot session close condition.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment thread web/relay/registry.ts
Comment on lines 523 to +526
const chs = this.#activeChs(robotId, entry.delivery);
if (!force && chs.join("\n") === entry.lastChs.join("\n")) return;
entry.lastChs = chs;
const msg: Msg = { t: "subs", chs, n: ++entry.n };
const size = encodeDatagram(msg).byteLength;
if (size > DATAGRAM_BUDGET_BYTES) {
// 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);
entry.peer.sendControl({ t: "subs", chs, n: ++entry.n });

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 security Subscription churn exhausts the carrier queue

Every changed subscription set is immediately enqueued as a complete carrier snapshot. If the active stream write is flow-controlled, a viewer alternating valid sub and unsub requests can enqueue more than the carrier's 256-frame or 4 MiB limit. Its overflow path invokes carrier_failed, which closes the watched robot session. Coalesce pending snapshots, apply backpressure, or reject mutations before the queue limit is reached.

Artifacts

Drained carrier boundary reproduction harness

  • Runs actual Registry and RobotCarrier code with one awaited drain per snapshot and calculates the adjacent serialized control-payload boundary, proving the aggregate behavior.

Control snapshot immediately below the payload limit

  • The executed below-boundary run accepts 977 subscriptions at 65,487 B without carrier failure, showing the control path remains live below the cap.

Control snapshot immediately above the payload limit

  • The executed above-boundary run accepts 978 subscriptions at 65,554 B then reports the production over-cap carrier failure, proving the robot session close condition.

View artifacts

T-Rex Ran code and verified through T-Rex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant