Skip to content

fix(gateway): stamp observed group transcript rows with epoch floats - #118106

Open
smalever wants to merge 1 commit into
NousResearch:mainfrom
smalever:fix/observed-transcript-epoch-timestamp
Open

smalever wants to merge 1 commit into
NousResearch:mainfrom
smalever:fix/observed-transcript-epoch-timestamp

Conversation

@smalever

Copy link
Copy Markdown

Fixes #118105.

Problem

The observe paths stamped the transcript entry with datetime.now(tz=timezone.utc).isoformat().
hermes_state_messages._coerce_timestamp → hermes_cli.timefmt.coerce_epoch trusts numbers,
numeric strings and datetime — but not a string spelling of one — so every observed row was
persisted with a substituted fallback and logged:

WARNING hermes_cli.timefmt: Ignoring corrupt message timestamp '2026-09-21T09:59:17.532760+00:00'

222 of them in one day in a Telegram group running observe_unmentioned_group_messages, in
errors.log — the WARNING+ channel operators read to find real problems.

Approach

Stamp time.time(), matching every other append_to_transcript caller (gateway/run_turn.py
already did). Three sites, the whole class:

  • plugins/platforms/telegram/adapter.py::_observe_unmentioned_group_message
  • gateway/platforms/yuanbao.py::GroupAtGuardMiddleware._observe_group_message
  • gateway/platforms/yuanbao.py recall system note

time is already imported in both modules; no new imports, no behaviour change beyond the stored
value being the adapter's own stamp instead of a fallback.

Excluded: gateway/mirror.py also builds an ISO timestamp key, but _append_to_sqlite never
forwards it to append_message — a dead field, not a corrupt write. Fixing it is a separate
question (drop the key or wire it through) and does not belong in this diff.

Tests

tests/gateway/test_observed_transcript_timestamp.py, parametrized over the Telegram and Yuanbao
observe paths. It asserts the relationship rather than a snapshot: the entry an observe path
produces is written through the real SessionDB and read back, and the stored value must equal
what the adapter stamped, with no Ignoring corrupt message timestamp in the log.

Sabotage run (restoring .isoformat() at both sites) — both parameters fail on pre-fix code:

FAILED tests/gateway/test_observed_transcript_timestamp.py::test_observed_group_message_timestamp_survives_the_write_path[telegram]
FAILED tests/gateway/test_observed_transcript_timestamp.py::test_observed_group_message_timestamp_survives_the_write_path[yuanbao]
  assert stored == pytest.approx(float(written), abs=1e-6)
  WARNING hermes_cli.timefmt:timefmt.py:38 Ignoring corrupt message timestamp '2026-09-21T10:37:51.269468+00:00'

With the fix, via scripts/run_tests.sh:

tests/gateway/test_observed_transcript_timestamp.py
tests/gateway/test_telegram_group_gating.py
tests/hermes_state/test_corrupt_row_robustness.py
=== Summary: 3 files, 32 tests passed, 0 failed (100% complete) ===

Risk

Low. The stored instant moves by microseconds (fallback was the write time); no schema, API or
config change. Readers are untouched — coerce_epoch keeps degrading genuinely corrupt rows to ?
as before.

_observe_unmentioned_group_message (Telegram) and _observe_group_message /
the recall system note (Yuanbao) wrote datetime.now(tz=timezone.utc).isoformat()
into the transcript entry's timestamp. hermes_state_messages._coerce_timestamp
trusts numbers, numeric strings and datetime only, so every observed row was
persisted with a substituted fallback and logged one
'Ignoring corrupt message timestamp' WARNING per message -- hundreds a day in a
group running observe_unmentioned_group_messages, drowning errors.log.

All other append_to_transcript callers (run_turn.py) already pass time.time().
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state P3 Low — cosmetic, nice to have labels Sep 21, 2026
Diaspar4u pushed a commit to Diaspar4u/hermes-agent that referenced this pull request Sep 24, 2026
_coerce_timestamp only trusts numbers and datetime, so the ISO string the
observe path wrote was replaced by the write-time fallback and logged one
'Ignoring corrupt message timestamp' WARNING per observed message (same bug
class as NousResearch#118105 on the Telegram/Yuanbao observe paths, fixed there by NousResearch#118106).
Diaspar4u pushed a commit to Diaspar4u/hermes-agent that referenced this pull request Oct 11, 2026
_coerce_timestamp only trusts numbers and datetime, so the ISO string the
observe path wrote was replaced by the write-time fallback and logged one
'Ignoring corrupt message timestamp' WARNING per observed message (same bug
class as NousResearch#118105 on the Telegram/Yuanbao observe paths, fixed there by NousResearch#118106).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Observed group messages are persisted with a substituted timestamp: adapters write an ISO string the write path rejects (one WARNING per message)

2 participants