Skip to content

feat(platform): add threadMetadata shadow table for efficient thread queries#509

Merged
larryro merged 3 commits into
mainfrom
feat/thread-metadata-shadow-table
Feb 21, 2026
Merged

feat(platform): add threadMetadata shadow table for efficient thread queries#509
larryro merged 3 commits into
mainfrom
feat/thread-metadata-shadow-table

Conversation

@larryro

@larryro larryro commented Feb 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a threadMetadata shadow table to eliminate expensive multi-page agent component queries when listing/filtering threads
  • Thread CRUD operations (create, update, delete) now write to both the agent component and the shadow table in sync
  • Includes a backfill migration (migrations/backfill_thread_metadata) to populate shadow records for existing threads
  • Wraps ChatHistorySidebar in an error boundary for resilience

Changes

  • New schema: threadMetadata table with indexes on threadId and composite (userId, chatType, status, createdAt)
  • list_threads.ts: Replaced multi-page agent component iteration with a single indexed query on the shadow table
  • get_latest_thread_with_message_count.ts: Uses shadow table index instead of agent component query
  • create_chat_thread.ts: Inserts shadow record on thread creation
  • update_chat_thread.ts: Patches shadow record on title update
  • delete_chat_thread.ts: Archives shadow record on thread deletion
  • Tests: Added comprehensive tests for listThreads and isGeneralThread

Test plan

  • Run npx vitest run for unit tests
  • Deploy to dev and verify thread list loads correctly
  • Create, rename, and delete threads — confirm shadow table stays in sync
  • Run backfill migration on a dev instance and verify existing threads appear

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Stability

    • Improved error handling for the chat history panel with better fault recovery and display reliability.
  • Performance

    • Optimized chat thread retrieval and loading performance.
  • Improvements

    • Enhanced thread management with improved data consistency and synchronization across creation, deletion, and update operations.

…queries

Replace direct agent component thread queries with a local threadMetadata
shadow table indexed by userId/chatType/status. This eliminates the need
to paginate and filter through all agent threads client-side, enabling
efficient single-index lookups for listing, latest-thread, and filtering.

- Add threadMetadata table schema with composite indexes
- Update create/delete/update thread helpers to maintain shadow records
- Rewrite listThreads to query shadow table with pagination
- Rewrite getLatestThreadWithMessageCount to use shadow table index
- Add backfill migration for existing threads
- Add list_threads tests and error boundary in chat layout
@greptile-apps

greptile-apps Bot commented Feb 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR implements a shadow table pattern to optimize thread queries. The threadMetadata table eliminates expensive multi-page agent component queries by maintaining denormalized thread metadata with proper indexes.

Key Changes:

  • New threadMetadata shadow table with indexes on threadId and composite (userId, chatType, status, createdAt)
  • listThreads now uses single indexed query instead of iterating multiple agent component pages
  • CRUD operations maintain sync between agent component and shadow table
  • Backfill migration to populate existing threads
  • Error boundary around ChatHistorySidebar for resilience

Issues Found:

  • Timestamp mismatch in create_chat_thread.ts: uses Date.now() for shadow table but agent component has its own _creationTime, causing inconsistency

Confidence Score: 4/5

  • Safe to merge with one timestamp synchronization issue that should be fixed
  • The shadow table pattern is well-implemented with proper indexing, comprehensive tests, and idempotent migration. All CRUD operations correctly sync both tables. However, there's a timestamp mismatch bug in thread creation that could cause ordering inconsistencies between the shadow table and agent component.
  • services/platform/convex/threads/create_chat_thread.ts needs timestamp sync fix before merge

Important Files Changed

Filename Overview
services/platform/convex/threads/schema.ts defines threadMetadata shadow table with appropriate indexes for efficient queries by threadId and composite (userId, chatType, status, createdAt)
services/platform/convex/migrations/backfill_thread_metadata.ts idempotent migration that backfills shadow records from agent component, correctly handles pagination and chatType extraction from summary JSON
services/platform/convex/threads/create_chat_thread.ts creates thread in agent component and shadow table synchronously; has timestamp mismatch issue between Date.now() and agent _creationTime
services/platform/convex/threads/update_chat_thread.ts updates title in both agent component and shadow table; correctly handles missing shadow records with optional update
services/platform/convex/threads/delete_chat_thread.ts archives thread in both tables and schedules sub-thread cleanup; handles missing shadow records gracefully
services/platform/convex/threads/list_threads.ts replaced multi-page agent component iteration with single indexed shadow table query, dramatically improving performance for thread listing

Sequence Diagram

sequenceDiagram
    participant Client
    participant listThreads
    participant threadMetadata
    participant AgentComponent
    
    Note over Client,AgentComponent: Before: Multi-page agent query
    Client->>listThreads: Get threads (old)
    loop Up to 5 pages
        listThreads->>AgentComponent: Query page
        AgentComponent-->>listThreads: Raw threads
        listThreads->>listThreads: Filter by status & chatType
    end
    listThreads-->>Client: Filtered threads
    
    Note over Client,AgentComponent: After: Single shadow table query
    Client->>listThreads: Get threads (new)
    listThreads->>threadMetadata: Query with index
    threadMetadata-->>listThreads: Pre-filtered threads
    listThreads-->>Client: Threads (much faster)
    
    Note over Client,AgentComponent: CRUD keeps tables in sync
    Client->>AgentComponent: Create/Update/Delete thread
    AgentComponent-->>Client: Success
    Client->>threadMetadata: Mirror operation
    threadMetadata-->>Client: Success
Loading

Last reviewed commit: 997b591

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread services/platform/convex/threads/create_chat_thread.ts Outdated
@coderabbitai

coderabbitai Bot commented Feb 21, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces a new thread metadata storage layer and refactors thread management to use it. Changes include: creating a new threadMetadata Convex table with indices for querying by thread ID and by user/chat type/status; inserting metadata records when threads are created; archiving metadata when threads are deleted; updating metadata when thread titles are modified; refactoring list_threads to query directly from threadMetadata instead of using agent-based pagination; and refactoring get_latest_thread_with_message_count to query the new metadata table. Tests are added for the new logic, and the isGeneralThread function is exported and reimplemented to parse JSON. A chat route is wrapped with an error boundary.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely describes the main change: adding a new threadMetadata shadow table to enable efficient thread queries, which is the core objective across multiple modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/thread-metadata-shadow-table

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/platform/convex/threads/delete_chat_thread.test.ts`:
- Around line 74-88: The test currently sets dbQueryChain.first to always
resolve to null so the code path that calls ctx.db.patch for threadMetadata
archival is never hit; update or add a test where dbQueryChain.first (or
mockRunQuery for threadMetadata) resolves to a mock metadata record (e.g., { id:
'meta123', archived: false, ... }) and then assert that mockPatch (ctx.db.patch)
is called with the expected selector and patch payload to mark the
threadMetadata archived; locate the mocks defined (mockPatch,
dbQueryChain.first, mockDb, ctx) and modify the setup for that test to return
the metadata and include an assertion on mockPatch being invoked with correct
arguments.

Comment thread services/platform/convex/threads/delete_chat_thread.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant