238b6c1ab9
The #14694 recovery clock (`_anti_thrash_recovery_deadline`) was a process-local `time.monotonic()` value zeroed in `bind_session_state()`. The gateway rebuilds the AIAgent (and its ContextCompressor) on every cache eviction, so each fresh compressor bound to a durably tripped session row (#69872) re-armed a full 300s window and the half-open probe never fired — a long messaging conversation above the threshold stayed blocked permanently. Persist the deadline as a wall-clock epoch in a new `sessions.compression_recovery_deadline REAL` column (declarative column reconciliation; SCHEMA_VERSION 26 -> 27) with `SessionDB.get/set_compression_recovery_deadline`. The compressor loads it in `bind_session_state()` and writes it on change only via `_set_anti_thrash_recovery_deadline()`. A fresh compressor with no stored deadline still starts a full window blocked (#54923 restart contract); one that loads an armed deadline resumes that window. Backward clock jumps are bounded to one window. The 300s window is unchanged. Minimal salvage of #100185 (the probe-lease/fencing state machine and model_config-blob storage were not carried). Refs #100185 Co-authored-by: Komzpa <me@komzpa.net>