d87bf0d07e
Every production close of a SessionDB goes through hermes_state_registry.release_or_close, whose teardown swallows any exception from close() at DEBUG. With the capture in place that meant a RetiredGenerationCaptureError (disk full, permissions) left the handle open silently and, on Python 3.11, skipped the retention pin: the raise happened before the pin, so the interpreter's exit still ran sqlite3_close's implicit checkpoint and wrote the stale frames over the newer generation (probe: 302 rows -> 4 after exit, worse than main). - close() now decides retention first and takes the pin BEFORE attempting the capture on runtimes without setconfig; the capture failure is logged at ERROR and re-raised, so a later close() retries it while the pin already protects the newer generation. - The registry logs RetiredGenerationCaptureError at ERROR instead of DEBUG (other teardown errors stay quiet). Same treatment on the release_or_close fallback path. - The lost-generation settlement moves out of close() into _settle_lost_generation_locked(); the sticky _close_checkpoint_disabled attribute and the dead "setconfig exists but failed" late-bind block are gone (_disable_close_time_checkpoint returns the call's outcome). Regression test drives release_or_close with a failing capture: no raise, error text in the log, pin taken exactly once (3.11), retry closes cleanly. Red on the salvaged head on both 3.11 and 3.12, green here.