Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/session_analytics/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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."""

Expand Down Expand Up @@ -705,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:
Expand Down
6 changes: 6 additions & 0 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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