refactor(state): compact verbose docstrings (rules/invariants kept)
This commit is contained in:
@@ -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).
|
||||
"""
|
||||
|
||||
+24
-33
@@ -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()
|
||||
|
||||
+26
-38
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user