d1770c3476
Networking-audit deferred plan §5. Both planes spread a frame's wire
packets across a time budget in chunked bursts; the schedule logic,
PUNKTFUNK_VIDEO_DROP loss injection, and percentile helper were duplicated
between punktfunk1::paced_submit and gamestream::stream::spawn_sender. Now
one host-local send_pacing::pace_frame carries the policy; each plane keeps
its exact historical parameterization and its own syscall layer (GSO
Session vs sendmmsg over the RTP socket — policy shared, plumbing not):
native burst_bytes = PUNKTFUNK_PACE_BURST_KB (microburst stage),
fixed 16-packet chunks, budget = 0.9 × time-to-deadline
gamestream no burst stage, bounded steps (≤ 12, chunk ≥ 16, the old
pace_layout), fixed budget = 0.75 × frame interval
Deterministic-schedule unit tests pin both parameterizations against
verbatim transcriptions of the legacy math (burst split, chunk layout,
step counts — including pace_layout's historical test anchors) and the
sleep-target formula (GameStream's legacy per_step form agrees to
≤ steps/2 ns; the unified fraction form is used for both). Deliberate
sub-observable normalizations, all on test-knob or ns-scale paths:
PUNKTFUNK_VIDEO_DROP is now parsed once per process and clamped to 1..=90
on the GameStream plane too (was per-stream, unclamped), and the native
sleep floor comparison is now >= (was >, differs only at exactly 500 µs).
Validation:
- 263 host tests green, incl. the end-to-end sender_delivers_batches
(spawn_sender → pace_frame → sendmmsg, byte-identical delivery)
- PUNKTFUNK_VIDEO_DROP FEC sweep at 5 % and 8 % injected wire loss:
all 11 punktfunk1 integration tests (full host↔client roundtrips
through send_loop → paced_submit) recover and pass
- pending: one real Moonlight smoke session against this build (the
legacy-plane timing gate) — recipe handed to the operator
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>