From d849ec5864e36a2ac38b041dc4a48862cfcd0988 Mon Sep 17 00:00:00 2001 From: Evan Senter Date: Thu, 8 Jan 2026 21:40:49 +0000 Subject: [PATCH 1/3] perf: Add tool_id index for 77x faster error queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_error_details() was taking 25s on 160K events due to self-join on tool_id without an index. Migration v7 adds idx_events_tool_id, reducing query time to 0.3s. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/session_analytics/storage.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/session_analytics/storage.py b/src/session_analytics/storage.py index 1c8d1af..ea86753 100644 --- a/src/session_analytics/storage.py +++ b/src/session_analytics/storage.py @@ -166,7 +166,7 @@ class BusEvent: DEFAULT_DB_PATH = Path.home() / ".claude" / "contrib" / "analytics" / "data.db" # Schema version for migrations -SCHEMA_VERSION = 6 +SCHEMA_VERSION = 7 # Migration functions: dict of version -> (migration_name, migration_func) # Each migration upgrades FROM version-1 TO version @@ -379,6 +379,17 @@ def migrate_v6(conn): conn.execute("CREATE INDEX IF NOT EXISTS idx_bus_events_repo ON bus_events(repo)") +@migration(7, "add_tool_id_index") +def migrate_v7(conn): + """Add index on tool_id for faster self-joins. + + The query_error_details() function joins events to itself on tool_id + to correlate tool_result errors with their tool_use parameters. + Without this index, queries took ~25s on 160K events. + """ + conn.execute("CREATE INDEX IF NOT EXISTS idx_events_tool_id ON events(tool_id)") + + class SQLiteStorage: """SQLite-backed storage for session analytics.""" From 2c62ad9ed6a00c061a49b463d0efae4e9402ec65 Mon Sep 17 00:00:00 2001 From: Evan Senter Date: Thu, 8 Jan 2026 21:47:00 +0000 Subject: [PATCH 2/3] fix: Add tool_id index to _init_db() for fresh installs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address reviewer feedback: schema elements must be in both migrations AND _init_db() to ensure identical schemas for fresh vs migrated DBs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/session_analytics/storage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/session_analytics/storage.py b/src/session_analytics/storage.py index ea86753..02f9514 100644 --- a/src/session_analytics/storage.py +++ b/src/session_analytics/storage.py @@ -716,6 +716,9 @@ def _init_db(self): conn.execute("CREATE INDEX IF NOT EXISTS idx_events_parent_uuid ON events(parent_uuid)") conn.execute("CREATE INDEX IF NOT EXISTS idx_events_agent_id ON events(agent_id)") + # Performance index for tool_use ↔ tool_result self-joins (migration v7) + conn.execute("CREATE INDEX IF NOT EXISTS idx_events_tool_id ON events(tool_id)") + # Event operations def add_event(self, event: Event) -> Event: From 6b8d920604db20b957f88051ecf1d56595b0e996 Mon Sep 17 00:00:00 2001 From: Evan Senter Date: Thu, 8 Jan 2026 21:49:18 +0000 Subject: [PATCH 3/3] test: Add test_index_on_tool_id for regression prevention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address reviewer suggestion for test coverage consistency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- tests/test_storage.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_storage.py b/tests/test_storage.py index f2cc54c..18e80c5 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -982,3 +982,9 @@ def test_index_on_agent_id(self, storage): rows = storage.execute_query("PRAGMA index_list(events)") indexes = {row[1] for row in rows} assert "idx_events_agent_id" in indexes + + def test_index_on_tool_id(self, storage): + """Verify that idx_events_tool_id index exists for self-join performance.""" + rows = storage.execute_query("PRAGMA index_list(events)") + indexes = {row[1] for row in rows} + assert "idx_events_tool_id" in indexes