From 5340109e61a76504b87339ac1bbc33a14ba7045f Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:14:33 -0700 Subject: [PATCH] refactor(state): compact verbose docstrings (rules/invariants kept) --- hermes_state_portability.py | 15 ++++----- hermes_state_schema.py | 57 ++++++++++++++------------------- hermes_state_search.py | 64 +++++++++++++++---------------------- 3 files changed, 56 insertions(+), 80 deletions(-) diff --git a/hermes_state_portability.py b/hermes_state_portability.py index bd74b6e443..7cb754b6a9 100644 --- a/hermes_state_portability.py +++ b/hermes_state_portability.py @@ -242,15 +242,12 @@ class SessionPortabilityMixin: Stranded-bot-session heal: before the desktop routed session RPCs by target session, a profile bot's rows accumulated in the DEFAULT profile's state.db; this moves the conversation to where routing now - looks. Pure composition: ``donor_db.export_session_lineage()`` -> - ``self.import_sessions()`` — routing/handoff/activity fields reset, - already-present ids skipped (idempotent re-adoption). - - With ``retire_donor`` and a complete adoption, donor rows are ARCHIVED - (never deleted) with ``end_reason='adopted_by_profile'``. That - end_reason is deliberately NOT in the recoverable set - (agent_close/ws_orphan_reap): resurrection must not undo an adoption. - + looks. Pure composition ``donor_db.export_session_lineage()`` -> + ``self.import_sessions()``: routing/handoff/activity fields reset, + already-present ids skipped (idempotent re-adoption). With + ``retire_donor`` and a complete adoption, donor rows are ARCHIVED + (never deleted) with ``end_reason='adopted_by_profile'`` — deliberately + NOT in the recoverable set, so resurrection cannot undo an adoption. Returns the ``import_sessions`` dict plus ``adopted`` and ``donor_retired`` (True only when EVERY segment's retirement applied). """ diff --git a/hermes_state_schema.py b/hermes_state_schema.py index 44e91983bb..b2c2152944 100644 --- a/hermes_state_schema.py +++ b/hermes_state_schema.py @@ -134,18 +134,14 @@ def schema_read_probe_statements() -> tuple: """SELECT statements that fail iff a live store is behind SCHEMA_SQL. Read-only opens skip ``_reconcile_columns()`` by design (no DDL against - another profile's live DB), so a store created before a schema addition - keeps failing on read paths until something opens it writable. Healing - callers (``_open_session_db_at_path`` in the web server) run these probes - after a read-only open: a missing table/column raises at prepare time. - - Derived from SCHEMA_SQL so a column added there is covered automatically - (a hand-maintained list went stale within days). Each statement is - ``LIMIT 0`` (resolution at prepare time, zero rows read). Column - references are table-qualified: an unqualified double-quoted identifier - that fails to resolve silently degrades to a string literal (SQLite - misfeature), which would make the probe pass on exactly the stale store - it exists to catch. + another profile's live DB), so healing callers (``_open_session_db_at_path`` + in the web server) run these probes after a read-only open: a missing + table/column raises at prepare time. Derived from SCHEMA_SQL so a column + added there is covered automatically (a hand-maintained list went stale + within days); ``LIMIT 0`` so zero rows are read. Column references are + table-qualified: an unqualified double-quoted identifier that fails to + resolve silently degrades to a string literal (SQLite misfeature), which + would make the probe pass on exactly the stale store it exists to catch. """ global _READ_PROBE_STATEMENTS if _READ_PROBE_STATEMENTS is None: @@ -470,19 +466,15 @@ class SessionSchemaMixin: return self._recover_stale_fts_locked(cursor, legacy=legacy) def retry_deferred_fts_recovery(self) -> bool: - """Retry a deferred stale-FTS rebuild on this open SessionDB. - - ``_recover_stale_fts`` fails closed at open when holders or the rebuild - lock are busy, leaving ``_fts_stale`` set and search on LIKE. Live - write/search paths must never start a full rebuild, and a gateway - opens state.db once for days, so "next open" never comes. This is the - in-process retry from the gateway housekeeping tick: bounded backoff - (``_FTS_STALE_RETRY_SECONDS`` doubling to the max), non-blocking - admission (``timeout=0``), no new thread. - + """Retry a deferred stale-FTS rebuild on this open SessionDB (gateway + housekeeping tick). ``_recover_stale_fts`` fails closed at open when + holders or the rebuild lock are busy, leaving ``_fts_stale`` set and + search on LIKE; live write/search paths must never start a full + rebuild, and a gateway opens state.db once for days, so "next open" + never comes. Bounded backoff (``_FTS_STALE_RETRY_SECONDS`` doubling to + the max), non-blocking admission (``timeout=0``), no new thread. Returns True only when the index was rebuilt and sync triggers - restored. Never raises. - """ + restored. Never raises.""" if not self._fts_stale or self.read_only or self._conn is None: return False now = time.monotonic() @@ -1130,15 +1122,14 @@ class SessionSchemaMixin: Reached when the sync triggers were missing and the DDL just recreated them: the index has a gap of unknown extent. Two processes opening the - same DB after an update commonly hit this simultaneously — the - concurrent-rebuild interleaving that structurally corrupted state.db - in production — so this admits through ``fts_rebuild_admission`` and - FAILS CLOSED. On deferral the just-repaired triggers are dropped again - and the stale breadcrumb persisted (``_enter_fts_fail_open``'s - ordering contract: triggers must never be live over an unrebuilt gap); - the winner's rebuild, ``retry_deferred_fts_recovery``, or - ``_recover_stale_fts`` at next startup restores index and triggers. - """ + same DB after an update commonly hit this simultaneously (the + interleaving that structurally corrupted state.db in production), so + this admits through ``fts_rebuild_admission`` and FAILS CLOSED. On + deferral the just-repaired triggers are dropped again and the stale + breadcrumb persisted — triggers must never be live over an unrebuilt + gap (``_enter_fts_fail_open``'s ordering contract); the winner's + rebuild, ``retry_deferred_fts_recovery`` or ``_recover_stale_fts`` at + next startup restores index and triggers.""" with fts_rebuild_admission(self.db_path) as admitted: if admitted: rebuild_fn() diff --git a/hermes_state_search.py b/hermes_state_search.py index 468b00b19f..e534f01265 100644 --- a/hermes_state_search.py +++ b/hermes_state_search.py @@ -662,19 +662,15 @@ class SessionSearchMixin: self, session_id: str, around_message_id: int, window: int = 5, bookend: int = 3, keep_roles: Optional[Tuple[str, ...]] = ("user", "assistant"), ) -> Dict[str, Any]: - """Anchored window (``get_messages_around``) plus session bookends. - - - ``window``: filtered to ``keep_roles``, EXCEPT the anchor itself is - always kept regardless of role. - - ``bookend_start`` / ``bookend_end``: first/last ``bookend`` messages - with ids strictly outside the window (empty when the window already - overlaps the head/tail). Empty-content rows (tool-call-only turns) - are skipped so they don't crowd out prose. - - Bookends let a hit anywhere in a long session yield the goal and the - resolution in one call. Empty slices + zero counts when the anchor - isn't in the session. ``keep_roles=None`` disables role filtering. - """ + """Anchored window (``get_messages_around``) plus session bookends, so a + hit anywhere in a long session yields the goal and the resolution in + one call. ``window`` is filtered to ``keep_roles`` EXCEPT the anchor, + which is always kept; ``bookend_start`` / ``bookend_end`` are the + first/last ``bookend`` messages with ids strictly outside the window + (empty when the window already overlaps the head/tail), skipping + empty-content rows (tool-call-only turns) so they don't crowd out + prose. Empty slices + zero counts when the anchor isn't in the + session. ``keep_roles=None`` disables role filtering.""" bookend = max(bookend, 0) primitive = self.get_messages_around(session_id, around_message_id, window=window) window_rows = primitive["window"] @@ -1345,15 +1341,12 @@ class SessionSearchMixin: def rebuild_fts(self) -> int: """Rebuild FTS5 indexes from ``messages`` (``'rebuild'``) — the documented recovery for a corrupt index that rejects writes while - reads succeed. - - A full structural rebuild must never run concurrently in two processes - sharing one state.db (that interleaving corrupted production DBs), so - this admits through ``fts_rebuild_admission`` and FAILS CLOSED, - returning 0 on deferral; callers treat 0 as "no progress" and fall - back to the stale-FTS breadcrumb path. Skips absent tables. Returns - the number of indexes rebuilt. - """ + reads succeed. A full structural rebuild must never run concurrently + in two processes sharing one state.db (that interleaving corrupted + production DBs), so this admits through ``fts_rebuild_admission`` and + FAILS CLOSED, returning 0 on deferral (callers treat 0 as "no + progress" and fall back to the stale-FTS breadcrumb path). Skips + absent tables; returns the number of indexes rebuilt.""" rebuilt = 0 with fts_rebuild_admission(self.db_path) as admitted: if not admitted: @@ -1379,22 +1372,17 @@ class SessionSearchMixin: """Run bounded FTS5 ``'merge'`` commands against each present index. A positive merge rank stops after ~that many output pages, so each - command holds the write lock for milliseconds regardless of index - size — unlike ``'optimize'`` (9-18 s per index on a 10 GB DB, enough - to exhaust a competing writer's lock-retry patience). - - - ``usermerge`` is lowered to its minimum of 2 (persisted in the - ``%_config`` shadow table, once per instance) so a positive merge - acts on ANY level with >= 2 segments; at the default 4 a fragmented - index cannot converge. - - Up to *max_commands* per index, stopping on the documented - no-progress signal: ``total_changes`` delta < 2 (the command's own - INSERT is 1 change). - - Each command is its own implicit transaction (``isolation_level=None``), - so competing processes interleave mid-pass. Missing tables are valid - variants (optimize_fts_storage drops + backfills them live) and are - skipped; other SQLite errors propagate. Returns commands executed. + command holds the write lock for milliseconds regardless of index size + (``'optimize'`` takes 9-18 s per index on a 10 GB DB, exhausting a + competing writer's lock-retry patience). ``usermerge`` is lowered to + its minimum of 2 (persisted in ``%_config``, once per instance) so a + positive merge acts on ANY level with >= 2 segments; at the default 4 a + fragmented index cannot converge. Up to *max_commands* per index, + stopping on the no-progress signal ``total_changes`` delta < 2 (the + command's own INSERT is 1 change). Each command is its own implicit + transaction, so competing processes interleave mid-pass. Missing tables + are valid variants (optimize_fts_storage drops + backfills them live) + and are skipped; other SQLite errors propagate. Returns commands executed. """ if isinstance(max_pages, bool) or not isinstance(max_pages, int): raise TypeError("max_pages must be an integer")