Files
hermes-agent/agent
Halldrix ac0b07597d fix(tui_gateway): harden the off-turn session-key fixes from a parallel review (#123545)
Four independent reviewers swept the #123635 diff. These are the findings that
changed code; each was verified before applying, not taken on report.

Register the recorded key instead of relying on the underscore sweep. The
staged dict becomes the turn's live user message, so _submit_row_session_id
rides every replay of that row. turn_context.py pops PERSISTENCE_ONLY_MESSAGE_FIELDS
from every outgoing copy and its comment says only chat-completions strips
underscore keys — an unregistered key survives to the transport, so a strict
OpenAI-compatible backend could 400 on it. Verified by execution: the registry
pop leaves the key in place and the transport sweeper is what removes it. The
membership is the contract; the underscore is the accident.

Gate each write on the key it writes to. _write_submit_user_row checked
session_key and appended to _submit_row_target_key(session); the two can
disagree after a rotation, so the guard described a write that was not the one
performed. The dead `key` local is gone.

Drop the isinstance/Any guard on _submit_row_owner_key. All three callers
narrow to a dict and check _row_id immediately before; the annotation existed
only to permit the non-dict the guard then rejected.

Log a failed model-switch marker persist at warning, not debug. Filing the
pivot in the live session means the write can now hit CompressionSessionClosedError
on a closed parent, which the old session_key target could not. At debug a
model switch silently loses its durable notice and nothing reaches errors.log —
the sibling persist one screen up already logs at warning.

Test-file: replace the E731 lambda with a named helper, and move _rotated_session
above its first use.

Verified: 7/7 in the regression file, 2113/2113 across the tui_gateway siblings
plus tests/hermes_state, 79/79 in the message-metadata/turn-context suites.
2026-09-29 19:42:46 -05:00
..
…