test(tui): fix stale mocks + xdist flakes in TUI test suite

All 61 TUI-related tests green across 3 consecutive xdist runs.

tests/tui_gateway/test_protocol.py:
- rename `get_messages` → `get_messages_as_conversation` on mock DB (method
  was renamed in the real backend, test was still stubbing the old name)
- update tool-message shape expectation: `{role, name, context}` matches
  current `_history_to_messages` output, not the legacy `{role, text}`

tests/hermes_cli/test_tui_resume_flow.py:
- `cmd_chat` grew a first-run provider-gate that bailed to "Run: hermes
  setup" before `_launch_tui` was ever reached; 3 tests stubbed
  `_resolve_last_session` + `_launch_tui` but not the gate
- factored a `main_mod` fixture that stubs `_has_any_provider_configured`,
  reused by all three tests

tests/test_tui_gateway_server.py:
- `test_config_set_personality_resets_history_and_returns_info` was flaky
  under xdist because the real `_write_config_key` touches
  `~/.hermes/config.yaml`, racing with any other worker that writes
  config. Stub it in the test.
This commit is contained in:
Brooklyn Nicholson
2026-04-16 19:07:49 -05:00
36 changed files with 4514 additions and 52 deletions

View File

@@ -1590,6 +1590,8 @@ class BasePlatformAdapter(ABC):
"reset",
"background",
"restart",
"queue",
"q",
):
logger.debug(
"[%s] Command '/%s' bypassing active-session guard for %s",

View File

@@ -235,6 +235,7 @@ class VoiceReceiver:
# Calculate dynamic RTP header size (RFC 9335 / rtpsize mode)
cc = first_byte & 0x0F # CSRC count
has_extension = bool(first_byte & 0x10) # extension bit
has_padding = bool(first_byte & 0x20) # padding bit (RFC 3550 §5.1)
header_size = 12 + (4 * cc) + (4 if has_extension else 0)
if len(data) < header_size + 4: # need at least header + nonce
@@ -278,6 +279,31 @@ class VoiceReceiver:
if ext_data_len and len(decrypted) > ext_data_len:
decrypted = decrypted[ext_data_len:]
# --- Strip RTP padding (RFC 3550 §5.1) ---
# When the P bit is set, the last payload byte holds the count of
# trailing padding bytes (including itself) that must be removed
# before further processing. Skipping this passes padding-contaminated
# bytes into DAVE/Opus and corrupts inbound audio.
if has_padding:
if not decrypted:
if self._packet_debug_count <= 10:
logger.warning(
"RTP padding bit set but no payload (ssrc=%d)", ssrc,
)
return
pad_len = decrypted[-1]
if pad_len == 0 or pad_len > len(decrypted):
if self._packet_debug_count <= 10:
logger.warning(
"Invalid RTP padding length %d for payload size %d (ssrc=%d)",
pad_len, len(decrypted), ssrc,
)
return
decrypted = decrypted[:-pad_len]
if not decrypted:
# Padding consumed entire payload — nothing to decode
return
# --- DAVE E2EE decrypt ---
if self._dave_session:
with self._lock: