Hub side of nescore's 2026-10-16 video-rate spec.
nesprotocol: a per-frame feedback datagram (kind 3, client to hub on the
video connection) carrying bytes, fragments, send time, first-fragment
arrival, arrival spread and first-fragment queueing delay. The hub stats
breakdown gains measured capacity and delivered share.
neshub:
- rate.rs, a per-client path model. Capacity is measured from each
frame's train dispersion. The bottleneck counts as busy when the next
train lands no later than its first fragment's own serialisation after
the last one, and as overloaded when, during a busy run, the first
fragments' queue grows and more is sent than delivered. Overload drops
the rate at once to drain at the rate the queue built, then settles at
the measured share. Steps up go to the measured capacity, or the
highest rate the path has proven quiet at for longer than its own
longest gap between overloads at or below it. Silence holds at the
last share. Tested against a modelled FIFO bottleneck: above the path,
below it, CBR keyframes, a capacity drop and recovery, recurring cross
traffic.
- control.rs: the slowest client's path decides, per frame as feedback
arrives. Gone: the loss thresholds, back-off factor, climb fraction,
deadband and queue thresholds. Ceiling, floor, manual and constant
quality behave as before.
- congestion.rs: an endpoint congestion controller that holds nothing
back (window above u32::MAX, where noq stops pacing), so frames leave
as trains for the client to measure.
media-transport.md now says the hub turns transport pacing off, and why.
The client does not send feedback yet (nescore step 2). Until it does,
the rate stays where the session started.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
send_many_datagrams queues a frame's fragments under one lock hold and
one driver wake instead of one per fragment. It also rejects the whole
frame on TooLarge, so a path that shrinks mid-frame no longer leaves half
a frame on the wire for the client to time out. Eviction behaviour is
unchanged. A refused PyroWave frame now keeps its sequence number, since
nothing went out under it. pyro_bench mirrors both ends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>