fix(recovery): make the printed salvage command satisfy the real CLI contract

Review blocker on e62940d: every state-db guidance site printed

  hermes sessions recover --source <db>

but cmd_sessions rejects that shape with exit 2 ("--output is required
unless --inspect-only is used") before any snapshot is taken — the user
follows the instruction during a corruption incident and gets nothing.

All five state-db sites now print the established two-stage operator
contract (the same shape `sessions repair` failure output and
docs/state-db-recovery.md already use):

  hermes sessions recover --source <db> --inspect-only
  hermes sessions recover --source <db> --output recovered-state.db

with the stop-the-gateway precondition stated for the gateway/turn
banners, and --inspect-only leading in the hermes_state refusal strings
(inspection before writing anything).

New TestEmittedCommandsSatisfyCliContract dispatches the exact emitted
flag shapes through the real cmd_sessions and asserts they pass the
contract gate (rc != 2) on a scratch DB, plus a premise test pinning
that the v1 no-flag shape is still rejected with rc 2 — so a guidance
string can never again pass a source-substring test while the command
it prints deterministically fails.

Noted for merge order: #101423 and #101168 also touch
hermes_cli/session_recovery.py. They are complementary recovery-integrity
work, not duplicates of this guidance/gate fix; whichever lands second
should rebase and rerun the lost_and_found + session-recovery suites.

(cherry picked from commit 34dc59a284509e76a0342c36d03a2a437aa8a3b9)
This commit is contained in:
sal
2026-09-02 22:56:46 +05:30
committed by kshitij
parent 5d9a2110ba
commit a15f96450b
4 changed files with 164 additions and 16 deletions
+9 -5
View File
@@ -4430,11 +4430,15 @@ class AIAgent:
"have been lost on restart). Freeing disk space will "
"not help. Recovery options:\n"
"1. Run `hermes doctor --fix`\n"
"2. Recover with: `hermes sessions recover --source "
"~/.hermes/state.db` (it snapshots the damaged file "
"first — do NOT run `sqlite3 ... \".recover\"` against "
"the live state.db, a vulnerable sqlite3 CLI can "
"corrupt it further)\n"
"2. Stop the gateway, then recover with:\n"
" hermes sessions recover --source ~/.hermes/state.db "
"--inspect-only\n"
" (if it reports recoverable) hermes sessions recover "
"--source ~/.hermes/state.db --output recovered-state.db\n"
" — recovery snapshots the damaged file first; do NOT "
"run `sqlite3 ... \".recover\"` against the live "
"state.db, a vulnerable sqlite3 CLI can corrupt it "
"further\n"
"3. Restore from a backup in ~/.hermes/backups/\n"
"Then send your message again."
)