forked from unom/punktfunk
A field host streamed 1919 frames into a black screen while its own log blamed the client. Four faults, each of which alone makes the failure invisible. The Windows firewall rules are `localport=`-scoped (47998-48010, 9777, 5353), but the media data plane binds an EPHEMERAL port per session. No such rule can ever cover it, so Windows Firewall drops the client's hole-punch on EVERY session on EVERY Windows host — `punched=false` on the "data plane bound" line, in all six sessions of two field logs. The punch then never opens the return path and video is sent blind to an address the client merely reported. `service install` now also adds a program-scoped inbound UDP rule for the host executable, which covers whatever port a session picks. Program-scoped rather than a pinned port: pinning into 47998-48010 would collide with Sunshine/Apollo. `LossReport` carried only `loss_ppm`, which is ambiguous at zero — loss is a ratio over the packets that arrived, so a flawless link and a link delivering NOTHING both report 0. The host read total silence as perfect and decayed adaptive FEC to its floor. Clients now also send a `DeliveryReport` with the session's received-packet count. It is a new type byte, NOT a field appended to `LossReport`: that message is length-checked exactly, so lengthening it would make every shipped host reject the loss reports its FEC runs on. Sent every window while the count is zero, once when the first packets land, then never — an older host warns per unknown message and must not be flooded on a good session. `NO_VIDEO_RETRY` (client got nothing) and `FLUSH_COOLDOWN` (client drowning) were both 2000 ms, so the host's cadence classifier could not tell two opposite faults apart and picked the wrong one out loud. The no-video cooldown moves to core beside `FLUSH_COOLDOWN` at 2600 ms, and both sides compare against the shared constant rather than a copy. The diagnosis now leads with the delivery count: zero is an error naming the data plane, a confirmed count keeps the old confident wording, and an old client that cannot answer gets a warning that says so instead of guessing. A punch that never arrives is also its own warning now, rather than a debug field on an info line.