fix(state): classify FTS-scoped corruption as fts_index, never whole-file damage
classify_persistence_error bucketed every _DB_CORRUPTION_MARKERS hit as "corrupt", so an error SQLite itself scoped to the FTS5 index layer (SQLITE_CORRUPT_VTAB, or an `fts5: corrupt structure record for table "messages_fts"` report) that escaped the write path — the detach in _enter_fts_fail_open refused (generation/lock check), or a read/search path with no fail-open at all — reached the turn boundary and the gateway startup notice as structural corruption: the turn ended with `.recover` / restore-backup advice on a file whose canonical tables were provably healthy. One provenance rule, hermes_state_errors.is_fts_scoped_corruption_error, now feeds both the write-repair gate (SessionDB._is_fts_write_corruption_error delegates to it, so the gateway transcript retry inherits it) and the classifier: a known result code outranks prose (only SQLITE_CORRUPT_VTAB is FTS-scoped; bare SQLITE_CORRUPT/NOTADB and any contradictory code fail closed), and without a code the text must both carry a corruption marker and name a messages_fts* object. The new "fts_index" cause renders index-scoped guidance (doctor --fix / restart, do not run recovery) in the turn explainer and the home-channel notice. The structural fail-close is untouched: bare malformed / not-a-database still quarantine and still classify "corrupt". Salvaged from PR #97843 (SulthanZahran1), trimmed: the quick_check-backed "corrupt_unconfirmed" tier is dropped — on a live handle that just observed an unscoped SQLITE_CORRUPT, PRAGMA quick_check on a damaged shadow b-tree raises rather than reports on 3.53.1, so the probe could never downgrade the exact shape it was built for, and a verdict that softens quarantine guidance on prose alone weakens the fail-close. #97841 (Finn763) reached the same fts_index cause via text markers only; its LIKE-degradation intent already lives in _search_messages_impl (_fts_stale). Fixes #97794 Co-authored-by: finn763 <165816600+finn763@users.noreply.github.com>
This commit is contained in:
@@ -151,6 +151,16 @@ _PERSISTENCE_CAUSE_EXPLANATIONS: Dict[str, str] = {
|
||||
"3. Restore from a backup in {backups_dir}/\n"
|
||||
"Then send your message again."
|
||||
),
|
||||
# SQLite scoped the corruption to the FTS index and the derived indexes could not be
|
||||
# detached, so this write did not land; the message store itself is intact (#97794).
|
||||
"fts_index": (
|
||||
"the turn was stopped because the session search index (FTS5) "
|
||||
"is corrupt and could not be detached, so this message was not "
|
||||
"saved. The message store itself is not damaged: do not run "
|
||||
"recovery tools or restore a backup. Run `hermes doctor --fix` "
|
||||
"(or restart Hermes, which repairs the index on open), then "
|
||||
"send your message again."
|
||||
),
|
||||
"disk": (
|
||||
"the turn was stopped because session storage could not "
|
||||
"be written (the transcript would have been lost on "
|
||||
|
||||
Reference in New Issue
Block a user