hermes-agent/gateway
Robin Fernandes 7739f5fc5b feat(gateway): structured start-blocked telemetry + crash-loop visibility on /api/status
Implements the trace-point suggestions from the Hermes Cloud health report.

A live gateway plus a service supervisor (systemd Restart=, s6, Fly machine
restart) respawning a second 'gateway run' produces a tight crash-loop: every
losing starter refuses to claim the PID file / runtime lock and exits, while
the original gateway stays up. A point-in-time /api/status probe reports the
box as healthy (gateway_running: true) so the loop is invisible. Confirmed in
prod on girt-numbat-4665: probe healthy while emitting ~24k 'Gateway already
running' lines/24h, only detectable via a fragile ILIKE log scan.

- gateway/status.py: add record_start_blocked(reason, pid) and
  count_recent_start_blocks(window). record_start_blocked emits a single
  canonical, exact-match log token 'gateway.start_blocked' with stable
  reason=/pid=/version= key=value fields (replacing the ILIKE '%already
  running%' scan and making loops attributable to a release cohort), and
  persists a self-pruning, capped ring of recent block timestamps under
  HERMES_HOME so a separate process can observe the loop.
- gateway/run.py: instrument all four start-refusal sites (already_running,
  runtime_lock_held, pid_file_race, startup_race) with accurate reason tokens.
  Existing log messages are preserved unchanged (tests assert on them).
- hermes_cli/web_server.py + gateway/platforms/api_server.py: surface
  gateway_restarts_5m on /api/status and /health/detailed, read from the
  shared ring, so a wedged-but-looping box stops reading as cleanly healthy.

No outbound telemetry, no new env var, no third-party identifiers: this is
local log + existing public liveness fields only. version is already exposed
on /api/status, so the 'app_version cohort' suggestion is realized as the
version= field on the structured log token rather than a Prometheus label
(the repo ships no Prometheus exporter).

Tests: 9 new in tests/gateway/test_status.py (record/count, windowing,
self-prune, cap, corrupt-file degradation, canonical log token) and 2 in
tests/hermes_cli/test_web_server.py (field present + reflects the ring).
0 new failures in the gateway suite.
2026-06-24 00:05:59 +00:00
..
assets fix: improve telegram topic mode setup 2026-05-04 12:07:17 -07:00
builtin_hooks remove: BOOT.md built-in hook (#17093) 2026-04-28 09:50:27 -07:00
platforms feat(gateway): structured start-blocked telemetry + crash-loop visibility on /api/status 2026-06-24 00:05:59 +00:00
relay feat(relay): Phase 5 §5.3 going-idle / buffered-flip primitive (gateway side) (#51572) 2026-06-24 09:50:30 +10:00
__init__.py docs(gateway): mention Weixin in gateway help and docstrings 2026-05-12 17:08:51 -07:00
authz_mixin.py Address email pairing review feedback 2026-06-21 22:43:57 -07:00
channel_directory.py fix: harden WhatsApp target alias salvage 2026-06-15 05:51:47 -07:00
code_skew.py fix(gateway): refuse model switch on stale checkout to avoid env_float ImportError 2026-06-24 04:16:54 +05:30
config.py Address email pairing review feedback 2026-06-21 22:43:57 -07:00
delivery.py fix(delivery): drop env-var knob, flag all chunking adapters 2026-06-22 05:41:22 -07:00
display_config.py feat(discord): render reasoning as -# subtext via display.reasoning_style (#51168) 2026-06-23 10:44:02 -07:00
hooks.py feat(hooks): expose thread_id and chat_type in agent:start/end context (#41672) 2026-06-07 19:16:36 -07:00
kanban_watchers.py fix(kanban): honor kanban.auto_decompose toggle live, without a gateway restart (#50358) 2026-06-21 12:43:44 -07:00
memory_monitor.py Port from cline/cline#10343: periodic gateway memory logging (#27102) 2026-05-16 12:55:23 -07:00
message_timestamps.py feat(gateway): inject stable human-readable message timestamps 2026-06-16 15:49:59 -07:00
mirror.py refactor(gateway): drop _append_to_jsonl from mirror 2026-05-20 13:00:57 -07:00
pairing.py fix(gateway): preserve WhatsApp pairing approvals across JID/LID alias flips 2026-05-23 01:46:34 -07:00
platform_registry.py refactor(plugins): add apply_yaml_config_fn registry hook 2026-05-13 22:20:30 -07:00
response_filters.py fix(gateway): suppress exact silence tokens without mutating history 2026-06-14 03:25:08 -07:00
restart.py fix(gateway): address restart review feedback 2026-04-10 21:18:34 -07:00
rich_sent_store.py fix(telegram): resolve replies to rich (sendRichMessage) messages 2026-06-16 13:04:20 -07:00
run.py feat(gateway): structured start-blocked telemetry + crash-loop visibility on /api/status 2026-06-24 00:05:59 +00:00
runtime_footer.py chore: prune unused imports and duplicate import redefinitions 2026-05-28 22:26:25 -07:00
session.py refactor(session): simplify traversal guard to a helper + logger, harden non-leading separators 2026-06-21 15:23:36 -07:00
session_context.py fix(api-server): stop silently promising async delivery on stateless HTTP path (#50319) 2026-06-21 12:15:14 -07:00
shutdown_forensics.py chore: ruff auto-fixes — collapsible-else-if, if-stmt-min-max, dict.fromkeys (#23926) 2026-05-11 11:03:29 -07:00
slash_access.py feat(gateway): per-platform admin/user split for slash commands (salvage of #4443) (#23373) 2026-05-10 12:33:54 -07:00
slash_commands.py fix(gateway): refuse model switch on stale checkout to avoid env_float ImportError 2026-06-24 04:16:54 +05:30
status.py feat(gateway): structured start-blocked telemetry + crash-loop visibility on /api/status 2026-06-24 00:05:59 +00:00
sticker_cache.py fix: guard yaml.safe_load, flock unlock, TOCTOU races, and atomic writes 2026-05-19 00:12:41 -07:00
stream_consumer.py fix(gateway): respect adapter decline of fresh-final to prevent double delivery 2026-06-21 13:55:50 -07:00
stream_dispatch.py feat(gateway): structured stream-event protocol + Telegram draft formatting parity (#37250) 2026-06-02 00:33:50 -07:00
stream_events.py feat(gateway): structured stream-event protocol + Telegram draft formatting parity (#37250) 2026-06-02 00:33:50 -07:00
whatsapp_identity.py fix(whatsapp): normalize bare phone targets to JIDs before bridge send 2026-06-21 13:32:22 -07:00