[Bug]: evictLowestPriority deletes the most critical events first (ORDER BY priority ASC on a 1=critical scale)

Author: avireddy0Created Sep 13, 2026Updated Sep 13, 2026

Platform

Claude Code. The defect is in the shared SQLite layer (src/session/db.ts), so every platform that reaches MAX_EVENTS_PER_SESSION is affected.

context-mode version

v1.0.169 (tag 589d8214). Re-checked against main @ ba5f5dfd1a0cd3e8a8f812c219d50390ed0a61c8 (2026-09-13): identical code.

Debug script output (REQUIRED)

Not attached. This is a static finding in one SQL statement and its writers, reproducible from the source alone; ctx-debug.sh prints local settings that do not bear on it. I can run a narrowed command if you need something specific.

Exact prompt that triggered the bug (REQUIRED)

None. Found while reading src/session/db.ts and src/session/extract.ts during an adoption review. An independent reviewer flagged the sort direction; it was confirmed against the lines cited below.

Full error output (REQUIRED)

No error is raised. The failure is silent: at capacity the wrong rows are deleted.

Summary

At MAX_EVENTS_PER_SESSION = 1000 (db.ts:639), both insertEvent (db.ts:1181) and bulkInsertEvents (db.ts:1280) run evictLowestPriority:

sql
DELETE FROM session_events WHERE id = (
  SELECT id FROM session_events WHERE session_id = ?
  ORDER BY priority ASC, id ASC LIMIT 1)        -- db.ts:973

The scale is documented as 1=critical (rules, files, tasks) … 5=low (extract.ts:24), and the most important events are written at priority 1:

  • user_prompt (hooks/userpromptsubmit.mjs:66)
  • rule / rule_content captures of CLAUDE.md and rules at session start (hooks/sessionstart.mjs:355-356, extract.ts:206,215)
  • session_start, session-resume, resume_completed (hooks/sessionstart.mjs:72,236,242)
  • compaction_summary (hooks/precompact.mjs:71,77), turn_end (hooks/stop.mjs:42)
  • file_read, file_edit, file_write (extract.ts:225-259)

ORDER BY priority ASC deletes the lowest priority number first. So once a session holds 1000 rows, each new routine event (priority 2 or 3 tool metadata) evicts a priority-1 row: the oldest user prompt, rule, or CLAUDE.md capture goes first, while priority-4 rows survive longest: intent (extract.ts:2431), goal (:2460), mcp_tool_call (:1057), and raw data blobs over 1 KB (:2533).

The comments say the opposite of what the SQL does: "evicts the lowest-priority (then oldest) event" (db.ts:1134-1135) and "FIFO eviction of lowest priority" (db.ts:1178).

The codebase disagrees with itself on the scale direction

extract.ts:2442, in the /goal directive extractor (PR #695), says "priority 4 = critical in the DB eviction contract" and writes the goal event at priority 4 so it survives eviction. That reading matches the SQL and contradicts extract.ts:24, which every hook and the other extractors follow. Whichever direction is intended, half the writers are wrong today.

Steps to reproduce (REQUIRED)

Unit test against SessionDB, no platform needed:

  1. Open a fresh session DB and insert 1000 events at priority: 5 (or 3).
  2. Insert one event at priority: 1 (a user_prompt).
  3. Insert one more priority-5 event.
  4. Read the session's events back.

Expected: the priority-1 row survives and one priority-5 row was evicted. Actual: the priority-1 row is gone; 1000 low-priority rows remain.

Impact

Session continuity degrades in exactly the long sessions the feature targets. Past 1000 events, buildSessionDirective and the resume snapshot lose the earliest prompts, rules, and CLAUDE.md captures first, with no warning. #902 reports the stale-snapshot symptom from the same statement; this issue pins the direction bug and the conflicting scale comments behind it.

What have you tried to fix it?

Nothing in-tree yet. Two internally consistent fixes:

  • Keep 1 = critical (matches extract.ts:24, every hook, and most extractors): change the statement to ORDER BY priority DESC, id ASC LIMIT 1; move the four priority-4 writers (intent, goal, mcp_tool_call, oversized data) to the values they actually intend (goal presumably 1, data presumably 5); fix the comment at extract.ts:2442.
  • Or declare higher-is-more-important and flip every writer plus the doc comment at extract.ts:24.

Either way, add the test above; it fails today and would have caught the #695 comment. I can open a PR against next if that is the route you prefer.