From 3cea88417de1e68b2b5b9520d2d419ced9efa40d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 11 Sep 2026 01:33:05 +0200 Subject: [PATCH] A running command is not re-stamped every tick The "kept existing capture stream" branch wrote the running command back with the current time on every tick, which made a running command the newest forever: no request sent tonight could outrank the July start until this was cut. The spawn transition keeps the command's stamp too. The teardown map records the audio result: 860 frames and 2,756 audio packets in 29 s, nothing expired, on a producer host at 93% CPU. Co-Authored-By: Claude Fable 5.1 --- crates/muninn-daemon/src/main.rs | 13 +++++++-- docs/teardown-map.md | 48 ++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/crates/muninn-daemon/src/main.rs b/crates/muninn-daemon/src/main.rs index f79138e..367a0fb 100644 --- a/crates/muninn-daemon/src/main.rs +++ b/crates/muninn-daemon/src/main.rs @@ -1256,9 +1256,17 @@ fn start_capture_stream_command( .find(|session| session.stream_id == command_stream_key) { if capture_stream_commands_start_equivalent(&session.command, &command) { + // The same running command comes through here every tick. Writing + // it back with a fresh stamp made a running command the newest + // forever, so no request could ever outrank it: a July start kept + // winning against every request sent tonight until this was cut. + if session.command_id == command.command_id && command.state == "running" { + return Ok(()); + } eprintln!( - "Muninn serve kept existing capture stream {} bitrate_kbps={} latency_budget_ms={}.", + "Muninn serve kept existing capture stream {} for command {} bitrate_kbps={} latency_budget_ms={}.", command.stream_id, + command.command_id, command_rudp_video_bitrate_kbps(&command), command_rudp_latency_budget_ms(&command) ); @@ -1268,7 +1276,6 @@ fn start_capture_stream_command( "Muninn serve kept existing activation child from command {}.", session.command_id ), - updated_at: timestamp()?, ..command.clone() }; node.put(&running.command_id, &running)?; @@ -1293,10 +1300,10 @@ fn start_capture_stream_command( command_rudp_latency_budget_ms(&command) ); let child = spawn_capture_stream_activation(options, &command)?; + // State changes; the stamp is the command's ordinal and stays. let running = MuninnCaptureStreamCommandRecord { state: "running".to_string(), detail: "Muninn serve spawned the local activation child.".to_string(), - updated_at: timestamp()?, ..command.clone() }; node.put(&running.command_id, &running)?; diff --git a/docs/teardown-map.md b/docs/teardown-map.md index 2fc8a86..4a894b5 100644 --- a/docs/teardown-map.md +++ b/docs/teardown-map.md @@ -558,12 +558,48 @@ had ever written, and a reaped command's rewritten stamp let a July command supersede the request that had stopped it and respawn with a Focusrite that no longer exists. Terminal commands no longer compete. -Open: **audio.** The loopback capture opens the requested endpoint (Realtek -and LG both selected cleanly) and then emits nothing; the producer never -queues an audio payload (`pending_audio=0` throughout). Sound played from an -SSH session does not reach the interactive session's endpoints, so the test -needs someone at Raven playing audio. Until then the audio leg is unproven, -not failed. +### Audio, same night (23:25Z) + +The "emits nothing" above was the wrong endpoint: Raven's sound goes out +through `Realtek HD Audio 2nd output`, not `Speakers (Realtek(R) Audio)`. +Running the capture script by hand for three seconds against each endpoint +settled it (1.1 MB from the second output, zero from the other two). With the +right source the producer queued audio at once, and the video leg collapsed: +7 frames in 9 s, thousands of repair requests, twice the bytes on the wire. + +Two causes, both fixed at their owners: + +1. **CultNet readers stopped at acknowledgements** (CultLib `47b9fc4`). Both + RUDP socket readers returned `None` after consuming a packet that carried no + frame or event: an ACK, a ping, an incomplete fragment. The producer's mux + loop reads once per payload sent, so it consumed one incoming datagram per + outgoing one. Video-only sat exactly at that edge (the receiver was acking + every unreliable frame, uselessly); reliable audio's ACKs pushed it over, + every unacknowledged fragment was resent, and the resends starved the sends. + Readers now return `None` only when the socket is empty, and unreliable + frames are not acknowledged. +2. **The command engine resurrected dead commands** (`0b8d738`, `bc43e1b`, and + the one after). A translated request carried the consumer's RFC 3339 stamp, which sorts + below every `unix-` stamp; and superseding or reaping a command re-stamped + it with the current time, so a July start outranked the stop that ended it + and respawned with a Focusrite that no longer exists. Stamps are Muninn's + own and terminal transitions keep the command's stamp. The last of it: the + "kept existing capture stream" branch re-stamped the running command every + tick, so a running command was always the newest and no request could ever + outrank it; a running command is now left alone until something changes. + +Also cut on the way: the 5 ms reliable resend delay (now 30 ms; a receiver +polling every 2 ms answers in 3-6 ms), and the activation child now runs +above normal priority so a game on the same host does not starve the mux loop +(`98b4f0b`). + +| run (12,000 kbps, display 0 + Realtek 2nd output) | seconds | frames | audio packets | expired | wire overhead | +|---|---|---|---|---|---| +| before the reader fix | 9 | 7 | 121 | 89 | 50% | +| readers fixed | 19 | 564 | 1,801 | 0 | 3% | +| readers fixed, stamps fixed, final build `bc43e1b`+ | 29 | 860 | 2,756 | 0 | 3% | + +Raven was at 93% CPU with a game running for every row. ## State at end of the 2026-09-09/10 pass