Link Pressure
A robot’s uplink is not a fixed pipe. The bridge measures what the socket actually drains and shapes what it sends to fit — smaller snapshots, dropped frames on the lower-priority tiers, a video budget it holds itself to. All of that is invisible from the outside: an app whose camera looks soft, or whose datapoints arrive in gaps, cannot tell a struggling link from a struggling robot.
bridge_pressure is the bridge reporting its own shaping, as an ordinary
built-in datapoint. It is what the console’s pressure indicator reads, and
your app can read it too.
The third built-in datapoint
Alongside bridge_state and robot_details,
every robot has:
bridge_pressure— the bridge’s own bandwidth-shaping state: what the link measures, what each priority tier sent and dropped, and where the video budget stands.
No configuration turns it on; a robot has it because it is connected, not because a developer set it up.
The value
{
"link": {
"rate_bps": 125000,
"snapshot_max_bytes": 1500000
},
"tiers": {
"0": { "sent": 10, "bytes": 500, "drops": 0, "high_water": 2 },
"2": { "sent": 42, "bytes": 12000, "drops": 3, "high_water": 5 }
},
"video": {
"active_streams": 1,
"bitrate_sum_kbps": 500,
"uplink_kbps": 2000,
"override_kbps": null,
"video_budget_kbps": 1600,
"reserve_kbps": 400
}
}
link — rate_bps is what the socket demonstrably drains, folded only
from sends of at least 64 KiB, so it is null until the session has made
one. null here means not measured yet, never zero: do not render it as
a healthy link, and do not render it as a broken one either.
snapshot_max_bytes is the byte target camera snapshots are currently
encoded to fit — below the flat ceiling means the bridge is actively
shrinking them.
tiers — the send queue’s six priority tiers, keyed "0" to "5" as
strings, because JSON has no integer keys. Per tier: sent, bytes,
drops and high_water (the deepest that tier’s queue has been).
Two things about these counters:
- They are cumulative per session, and reset on reconnect. A meaningful “drops in the last minute” is the difference between two samples, not a reading off one. Across a reconnect that difference is meaningless — the counters started over — so treat a decrease as a new session, not as negative drops.
- A tier missing from the object reads as zeros. Not every tier appears
in every sample.
tiers["4"]?.drops ?? 0is the right way to read one; an unconditionaltiers["4"].dropsis not.
video — uplink_kbps is the budget the bridge was configured with
(FLEETLESS_UPLINK_KBPS), null if none was set and 0 if it was set to
zero, which means no video budget at all. video_budget_kbps is what is
left for video after reserve_kbps; bitrate_sum_kbps above it means the
bridge is over budget and dropping video.
Cadence, and what silence means
The bridge sends one sample every 10 seconds while connected. The first one lands about 10 seconds after connect — not immediately — so a freshly connected robot has no pressure reading yet, and that is normal.
A session shorter than 10 seconds emits nothing at all. A link that
flaps faster than the cadence therefore looks absent, not bad. This is
deliberate: the alternative is a partial first sample whose counters mean
nothing, and a datapoint that reports noise is worse than one that reports
nothing. It does mean silence has two causes — a bridge package too old to send it,
and a robot that is not staying connected long enough — and nothing in the value distinguishes them. Read
bridge_state beside it: online-and-silent is the second case.
Granting it
bridge_pressure is granted to a role like any other slug, and a role that
grants no datapoints sees no pressure. It appears in the roles matrix
alongside the other built-ins, and it is
MCP-visible once granted — an agent with the right
role can ask why a robot’s camera looks poor and get the link’s own answer.
Realtime, history and REST all work the same way they do for a configured datapoint. There is no configuration to write, and nothing to publish.
Retention
bridge_pressure is always retained. There is no retention flag to
turn off, because there is no configuration entry to put one in — its
history is queryable for every robot with no developer setup.
That storage is not free, and there is no TTL for it yet: at one sample
every 10 seconds, a connected robot writes roughly 8,640 samples a day,
and those rows count against your org’s retention quota like any other
recorded datapoint. An org that leaves the quota where it is and never
prunes will, eventually, exhaust it — and when a retention quota is
exhausted the platform stops recording every retained datapoint for that
org, not only this one. If you record a lot and keep it a long time, watch
retention_bytes on GET /api/org/quotas.
A per-slug retention policy that lets bridge_pressure’s own rows expire
independently is not built yet. This page says so rather than implying a
bound that does not exist.