The client generates the traffic and the server counts it. No grant is involved - the client is sending its own packets, so there is nothing to amplify - but it does need the server's tally, because only the far end knows how much arrived. Without that number a sender measures how fast it can transmit, which is usually just the speed of the local NIC and is not the question being asked. A new wire type the server counts and deliberately never answers: a reply would double the traffic and drag the return path into a measurement that is specifically about the outbound one. The tally is a counter, not a list, and short-circuits before the observation log. A five-second run at 20 Mbps is around ten thousand packets; one struct each would turn a measurement into an allocation storm on a shared server, and nothing needs the per-packet detail since the client holds the send-side record. The gap between the two counts is the loss. direction=up on the throughput action sends nothing - it zeroes the counter, so a second run in one session measures itself instead of inheriting the first. Same honesty rule as downstream: measures_network is false when what arrived matches what was offered, because then the path was never the constraint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>