Repository navigation
DS4 Context Engine 0.3.8
Release 0.3.8 — Indexed FTS key deletes via rowid mappings (schema 16)
Version analyzed: DS4 Context Engine 0.3.8
Commit: 18f36e1
Coordinated packages: ds4-context-core 0.3.8, ds4-context-reference-adapter 0.3.8, ds4-context-engine 0.3.8
Summary
Bugfix release: FTS deletes were full virtual-table scans (FTS5 UNINDEXED
key columns), making session-index rebuilds on large sessions stall for
hours. The FTS tables are now rebuilt over rowid mapping tables, turning
every keyed delete into an indexed lookup. No behavior, configuration or
search-surface change: the fix is transparent and addresses the
fork/resume stall on large sessions.
Root cause
DELETE FROM entries_fts WHERE entry_key = ? cannot use the FTS5
vocabulary because entry_key (and project_snippets_fts.snippet_id) are
declared UNINDEXED. Every row removal scanned the entire FTS index.
A rebuild of a session with ~11k entries performed thousands of those
scans: measured 65k pread64/s against a 615MB database and ~100 full
index passes per ~140s, with an estimated hours to completion —
surfacing as an indefinite hang of the agent session after a session
fork/resume. The behavior class pre-dates 0.3.7; the 0.3.7 work sessions
made it visible by pushing the database into the hundreds of MB.
Indexing the keys directly inside FTS5 was benchmarked and rejected:
it would make key text part of the MATCH vocabulary (false positives)
and shift the bm25 column weights. See ADR 063.
Changes
- Migration 16
fts-rowid-key-mappings: two derived mapping tables
(entries_fts_keys,project_snippets_fts_keys) backfilled from the
live FTS rows in one scan, inside a single transaction. SessionIndexRepository: per-row deletes go through the mapping
(DELETE … WHERE rowid = ?); the rebuild stale-row cleanup joins the
mapping withentriesand uses the session index; the mapping is
upserted from the FTSlast_insert_rowidin the same transaction.ProjectKnowledgeRepository: same pattern for per-snippet deletes
(replaceFile) and per-project cleanup (clearProject).- The FTS schemas, the
MATCHqueries and thebm25weights are
byte-identical to 0.3.7; search results do not change. - Tests:
tests/integration/fts-rowid-keys.test.tscovering the
v15 → v16 upgrade (data preservation, key ↔ rowid correctness, search
surface unchanged), rebuild/append/stale-cleanup consistency and the
snippetreplaceFile/clearProjectpaths; version-pinned tests moved
toCURRENT_SCHEMA_VERSION.
Compatibility and migration
- Non-destructive by design: the FTS indexes are derived state; the
migration is transactional, so on any failure the previous schema
remains intact and the extension keeps working with the old behavior. - No data stored in the mapping tables: the base tables remain the
single source of truth. - Upgrade runs automatically on first open after the extension update
(measured 467 ms on a 615MB database with 31k entries / 62k snippets;
no user-visible step required). - The mapping backfill is one scan; a very large database adds only
seconds to the first open after update. - Existing guarantees (fail-open, atomicity, privacy, pins, compaction,
hard limits) are unchanged.