Live recording panel reports every track six times too short and warns "timeline is falling behind" on every session #565
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Seen on prod, 2026-09-09 02:28 UTC, during a live session ("The Northward Labyrinth", six speakers, ~36 minutes in). The Recording panel showed the amber warning "Recording timeline is falling behind. Ryan, Joe, Aidan, Michael, Brandon, Melon have less audio on the timeline than the session has been running", and per-speaker "captured" figures of 0:34 to 5:39.
The capture was fine. Read-only checks on the host: all six raw tracks in the audio volume were about 64.6 MB and were being appended within seconds of the check; a 10-second sample showed growth of ~326 KB per track, i.e. the 32,000 bytes/second of 16 kHz mono. At that rate 64.6 MB is ~33:40, level with the elapsed clock. The Redis marker, container health and logs were all clean.
Cause.
bot/questboard_bot/services/recording_status.pystill divides both counters by_BYTES_PER_SECOND = 192_000(48 kHz stereo). Since #176 the sink converts to 16 kHz mono in the capture path, sobytes_written()andspeech_bytes_written()both count 16 kHz mono bytes (_speech_bytes[uid] += len(pcm)after the resampler, and the padding target is computed with the sink's ownBYTES_PER_SECOND = 32_000). The status helper predates that change (7d2c4ec) and was not updated with it, so:track_secondsis reported at one sixth of the true timeline position. The panel's tripwire (track_seconds < elapsed_seconds - 60, judged onceelapsed_seconds > 120) therefore fires for every speaker on every recording once it passes about two minutes. The warning has been a false alarm since #176 shipped (v4.1.0); prod is on 4.3.0.seconds_captured(the "captured" figure shown per speaker) is also one sixth of the true value.Fix. Use the sink's rate rather than a private constant: import
PerUserPCMSink.BYTES_PER_SECOND(or have the sink expose seconds directly), delete the 192,000 literal, and add a test that a sink reporting N × 32,000 bytes yields N seconds for both fields. Theaudio_filesdocstring incogs/recording.py(line ~755, "48 kHz stereo s16le path") is stale for the same reason and should say 16 kHz mono. No API contract change: the payload's field names and meanings stay as documented, only the numbers become right.Why it matters. The warning tells a GM to "stop and report it before relying on the transcript", which is exactly the wrong advice for a healthy recording, and a real clock loss (#320, #327) would now be indistinguishable from the false alarm. Bot-only change; deploy after the current session has been stopped and handed off, not during it.