Root cause of the Web UI wedge on /conversations/1 (and every other
authenticated page when the reactor is busy): SQLiteSessionStore and
SQLiteUserStore routed every read through the single-connection
write pool. On every authenticated request RequireSession does a
GetSession + GetUserByID — both hit the write pool, so each one
queues behind every reactor / tracer / messaging write. Observed
/api/conversations/1 returning 401 after 113 seconds and login
POST timing out for 15+ seconds.
- SQLiteSessionStore: new NewSQLiteSessionStoreWithRead that takes
separate write + read handles. GetSession routes SELECTs through
readDB; the last_active_at bump and expired-session cleanup now
fire-and-forget on a background goroutine so HTTP handlers never
wait on the write pool for a non-critical liveness poke.
- SQLiteUserStore: same split. GetUserByID / GetUserByEmail /
GetUserByUsername go through readDB.
- main.go: wires db.QueryDB() (the query_only=ON read pool) into
both stores via the new constructors.
Verified: /api/conversations/1 now returns 200 in <2ms even while
the coordinator subprocess is blocking on a long Gemini call.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>