Files
hermes-agent/hermes_cli
Adam Durham 0788e759dd fix(state): session recovery must recognize cron_/bg_/room_ ids
session recovery's salvage classifier decided "is this cell a session id?"
with SESSION_ID_PATTERN alone (^\d{8}_\d{6}_), which only covers ids minted
by new_session_id. Several first-class surfaces DERIVE an id instead:

  cron/scheduler.py                 f"cron_{job_id}_{now:%Y%m%d_%H%M%S}"
  hermes_cli/cli_commands_mixin.py  f"bg_{now:%H%M%S}_{uuid4().hex[:6]}"   (/bg)
  gateway/.../api_server_room_dispatch.py  f"room_{sha256(seed)[:32]}"

Measured against a copy of a real 3,373-session store: 379 ids (11.2%)
failed the pattern -- 375 cron, 1 bg, plus 3 non-session test artifacts.
job_id is normally uuid4().hex[:12] (cron/jobs.py) but legacy/user ids like
"job-1" are real and still present in live stores, so the cron recognizer
accepts a general job-id token.

Two distinct consequences, both fixed:

1. DROPPED SESSIONS. classify_lost_and_found_row() returned None for those
   rows, so recovery silently discarded every cron/bg/room session. On the
   real store: 2994 of 3373 rows kept before, 3370 after (the 3 still
   dropped are 's'/'session-key'/'pre-compress-key' -- not sessions,
   correctly rejected).

2. POISONED LAYOUT INFERENCE. parent_session_id is a _TEXT_SHAPE_RULES
   column checked with the same predicate. A cron job's CHILD session has an
   ordinary timestamp id, so it classifies fine and becomes layout evidence
   -- while carrying the unrecognised cron id in parent_session_id. Since one
   bad sampled value vetoes a candidate layout, a single such row collapsed
   inference for the whole sessions table, i.e. the positional-guessing path
   #101409's fix exists to prevent. Proven on a synthetic store: 20 clean +
   cron parent + child-of-cron -> EMPTY before, 59/59 columns named and 0
   wrong after.

Fix: hermes_state_ids gains SESSION_ID_RECOGNIZERS + is_known_session_id(),
the recognition side of the minting contract; _is_session_id() consults it.
Each pattern is anchored on exactly what its minting site fixes -- these are
layout sentinels, so a loose pattern would buy recall at the cost of
wrong-column mappings.

Tests: tests/hermes_state/test_session_id_recognition_recovery.py (new, 43
cases) covers recognition, non-dropping, the parent_session_id poisoning
path, and adversarial wrong-layout rejection (rotated layouts still vetoed;
near-miss and arbitrary text still rejected). Mutation-checked: with the
added recognizers removed, 12 of 43 fail -- including the end-to-end
poisoning test.

(cherry picked from commit f82b7182f03e1eee55c832a3f90fffbe580d1f5c)
2026-10-04 12:05:37 +05:30
..
…
…
…
…
…
…
…
…