Files
hermes-agent/tools
teknium1 d6c9191368 fix(review): replay the launch ledger regardless of the first consumer's profile scope (#123265)
Review finding (major): ProcessRegistry.restore_completions() is once-per-process but read
async_delegation._db_path() (ContextVar-aware) under whatever scope the FIRST consumer ran in.
In the TUI gateway both first consumers (the session notification poller and the prompt_turn
drain) run inside _session_profile_runtime_scope(session), so under multi-profile
`hermes serve` the first session's profile ledger was replayed and the LAUNCH profile's
undelivered completions were never replayed for the life of the process (origin/main's
import-time replay always covered the launch profile).

Fix: restore_completions() clears the hermes-home override for the duration of the replay
(set_hermes_home_override(None) + reset), so the once-per-process replay always reads the
launch ledger whoever gets there first; the caller's scope is restored afterwards. Smaller
than a per-home restored-set plus a tui_gateway boot hook: it restores exactly main's
invariant with no new boot seam, and secondaries stay where they were (gateway
_restore_secondary_completion_ledgers). Docstring states the invariant.

Tests:
- tests/tools/test_process_registry_lazy_restore.py::test_first_drain_under_secondary_scope_replays_the_launch_ledger
  (red on the PR head: replayed profiles/b/state.db; green now)
- tests/gateway/test_multiplex_unserved_shared_ingress.py::test_boot_replays_the_launch_ledger_before_secondaries_and_watchers
  (minor: pins the gateway boot hook — launch-scope replay in _start_secondary_profiles, i.e.
  before the secondary bind and before _async_delegation_watcher, the only production consumer
  that reads completion_queue.get_nowait() without drain_notifications)
2026-09-28 05:37:55 -07:00
..
…