5 Commits

Author SHA1 Message Date
kshitijk4poor
2d70f583da fix(agent): user copy for the session_row_missing persistence cause
Without entries in _STORAGE_FAILURES and _PERSISTENCE_CAUSE_EXPLANATIONS a
failed heal fell back to the generic disk/lock advice, which sends users
chasing the wrong problem.
2026-09-26 22:39:42 +05:30
teknium1
6ba45b0e06 fix(sessions): storage maintenance refuses while a writer holds state.db; human-first retired-WAL guard text + recovery guide
`hermes sessions optimize`, `optimize-storage` and `prune` now run the same fail-closed
holder scan doctor and repair use before rewriting the store. While a gateway, Desktop,
dashboard or cron process holds state.db (or a WAL sidecar) they print each holder as
`PID N (command)` with the stop remedy and exit 1; `--force` overrides with a warning,
`--dry-run` previews are never gated. The Desktop console's `sessions optimize` gets the
same refusal. Why: a user ran `optimize-storage` under a fleet of eight live gateways and
every agent answered every turn with the retired-WAL refusal until all writers were
stopped by hand (#110054, maintainer follow-up 09-20).

The DeletedWalGenerationError text is now two layers: a first sentence for the person
reading a chat bubble or banner (what happened, nothing is lost, quit every Hermes
process on the profile, `hermes doctor` names the holders, never `doctor --fix` or delete
files while they run, docs link), then the operator detail. The classifier fingerprint
"deleted state.db-wal or state.db-shm" is unchanged. The cause table
(`hermes_state_user_copy`, feeding the CLI banner, TUI/Desktop RPC error and the gateway
home-channel notice) and the chat explainer carry the same first steps; the gateway
notice no longer hardcodes `doctor --fix` + `gateway restart` for every non-corrupt cause,
which for a held retired generation is the second-writer trap.

New user-guide page `session-storage-recovery.md` (registered in sidebars, linked from the
guard text, the developer state-db-recovery page and the sessions guide): the three steps,
the do-nots, why maintenance refuses, and what the files beside state.db are
(retired-wal captures + manifest.json, pre-update-emergency backups, corrupt backups,
snapshots).
2026-09-20 20:13:33 -07:00
kshitijk4poor
532b6d1cb1 fix(state): pin the session-db-unavailable fallbacks to the failing profile
format_session_db_unavailable consumes the now-pinned cause table but its own
two fallbacks (no recorded cause; network-drive gloss) still printed a bare
`hermes doctor`. Same class; one test covers both fallbacks.

Also: spell the corrupt action as plain concatenation instead of an f-string
with escaped braces, and fix the finalizer comment to state the invariant
(final_response is never rebound) rather than describe a local that no longer
exists.
2026-09-16 21:15:30 +05:30
kshitijk4poor
b6bba97f7b fix(state): pin the shared storage-failure action copy to the failing profile
hermes_state_user_copy.py is the one table feeding the CLI banner, gateway
warning and TUI/Desktop RPC errors, and its action strings were still bare
(`hermes doctor --fix`, `hermes gateway stop`, `hermes sessions recover`).
Substitute {profile_arg} once in describe_storage_failure so those surfaces
get the same pin as the turn explainer.

Also keep final_response unbound in the turn_finalizer error fallback: it
feeds the external-memory sync and the background-review gate, which must
still see an empty response on a persistence-failed turn. One test binds the
fallback (explainer stubbed empty) and the untouched final_response.
2026-09-16 21:15:30 +05:30
teknium1
23036e20a6 fix(ux): plain-language, actionable user-facing messages (core)
Squashed integration of the user-facing message audit for this surface set.
Full per-finding receipts: /tmp/ux-audit/lanes/*-receipt.md (campaign artifacts).
2026-09-15 04:12:13 -07:00