fix(sqlite): pre-aggregate every missing-index listing, UNC-safe read-only URI, portable index tool

Review follow-ups on #7445 (nesquena-hermes CHANGES_REQUESTED + Greptile).

api/agent_sessions.py
- The read-only pre-aggregated `latest_messages` candidate ordering now
  applies to every missing-index projection (default sidebar, gateway
  watcher, cron/webhook/kanban views), not only `include_sources ==
  ("cron",)`. Since the listing no longer self-heals the index, the
  correlated `MAX(mx.timestamp)` scan re-ran on every load: 9.86 s on a
  5,000-session / 20,000-message DB vs 0.044 s after this change, with
  identical selected rows and order. The indexed seek is unchanged.
- `state_db_file_uri()` / `state_db_readonly_uri()` replace
  `Path.as_uri()`: a UNC `HERMES_HOME` produced `file://server/share/...`
  and CPython's bundled SQLite (3.11-3.13 Windows builds, no
  SQLITE_ALLOW_URI_AUTHORITY) rejected the authority, so every agent-backed
  session vanished. The builder emits the empty-authority
  `file:////server/share/state.db?mode=ro`, keeps `file:///C:/...` for
  drive letters, strips `\\?\` / `\\?\UNC\` prefixes, quotes `?`/`#`, and
  leaves POSIX output byte-identical. Strict `mode=ro`, no writable
  fallback.

scripts/ensure_state_db_read_indexes.py
- `fcntl` / `msvcrt` are imported conditionally; the module imports and
  the no-`--lock-file` path runs on native Windows. `--lock-file` uses
  `flock` on POSIX, `msvcrt.locking(LK_NBLCK)` on Windows, and fails with
  a clear RuntimeError when neither exists. The rw open reuses the
  UNC-aware URI builder.

docs/troubleshooting.md
- Operator section: read-only contract, degraded missing-index listing,
  drained maintenance prerequisites, lock behaviour, failure modes, UNC.

Tests: tests/test_pr7445_readonly_review_followups.py (19 tests, red
before this change: correlated-subquery plan, missing URI builder,
ImportError on fcntl). Query-plan contract via EXPLAIN QUERY PLAN — no
CORRELATED SCALAR SUBQUERY on missing-index listings, identical rows to
the indexed listing; platform-parametrised URI cases; maintenance module
imported with `sys.modules["fcntl"] = None`. test_issue2628 no longer
pins the cron-only gate; the flock-held test skips without fcntl.
This commit is contained in:
Anthony Ruiz committed 2026-09-18 00:59:17 +00:00
1 parent ef9341b2ab
commit f5a7ef2049
6 files changed
+379 -12

No files matched your search

+1 -1
View File
@@ -11,7 +11,6 @@ Contract under test:
(``scripts/ensure_state_db_read_indexes.py``);
* the cron sidebar read in ``api/routes.py`` uses the read-only opener.
"""
import fcntl
import sqlite3
from contextlib import closing
@@ -94,6 +93,7 @@ def test_index_maintenance_without_lock_file_still_requires_drain(tmp_path):
def test_index_maintenance_refuses_when_lock_is_held(tmp_path):
fcntl = pytest.importorskip("fcntl", reason="flock-held scenario needs a POSIX interpreter")
from scripts.ensure_state_db_read_indexes import ensure_read_indexes
path = tmp_path / "state.db"
_maintenance_schema(path)