`cass search` misses sessions you know happened
Source: Troubleshooting reference
Symptom: history you remember from Codex or Cursor never surfaces, even on exact phrases, while Claude Code sessions from the same week come back fine.
Root cause: cass ingest is append-only per conversation. Once a conversation is
in the canonical DB it is never re-read, so every parser improvement since it was
first indexed only reaches new sessions. Old ones keep whatever subset the parser
of the day extracted. cass index --full does not fix this — it forces a full
scan and a lexical rebuild, then logs skipping historical salvage because canonical database is already populated.
Confirm — compare the DB against a fresh parse of the same files:
sqlite3 -readonly ~/.cass/agent_search.db \ "select a.name, count(m.id) from messages m join conversations c on c.id=m.conversation_id join agents a on a.id=c.agent_id group by 1 order by 2 desc;"wc -l < ~/.codex/sessions/2026/*/*/rollout-*.jsonl # rough upper bound per fileMeasured 2026-08-01: codex held 15,037 messages where the same 88 rollouts parse to 85,488 today, and cursor 3,384 vs 6,949 — 82% and 51% of that history unsearchable.
Fix, one connector at a time. Every step matters:
# 0. verify each source file still exists — forget is only safe if it can come backsqlite3 -readonly ~/.cass/agent_search.db \ "select c.source_path from conversations c join agents a on a.id=c.agent_id where a.name='codex';" | while read -r p; do [ -f "$p" ] || echo "MISSING: $p"; done
# 1. back up via sqlite, NOT cp — a plain copy can tear a live WALsqlite3 ~/.cass/agent_search.db ".backup '$HOME/.cass/agent_search.db.bak'"
# 2. drop the stale rows (dry-run first: omit --apply)cass forget --source-glob "$HOME/.codex/sessions/**" --apply
# 3. reset the connector watermark — --full still honours it, and rollouts dated# months ago never beat a watermark stamped today, so the scan finds nothingsqlite3 ~/.cass/agent_search.db \ "update meta set value='0' where key='last_scan_ts:connector:codex';"
# 4. re-ingest, then clean up after a cass bug: forget leaks tail-state rows keyed# by the deleted conversation_id, and that column is a plain rowid — SQLite# reuses freed ids, so a future conversation would inherit a stale# "ingested through idx N" marker and be silently truncatedcass index --fullsqlite3 ~/.cass/agent_search.db \ "delete from conversation_tail_state where conversation_id not in (select id from conversations);"
# 5. rebuild vectors in bounded batches; repeat until the backlog is emptybash ~/dotfiles/install/memory.sh semanticSkipping step 3 is the usual failure — the run exits 0, having ingested nothing.