Skip to content

perf: tapes deck eliminates N+1 queries, extend cache coverage, add created_at index#132

Merged
bdougie merged 5 commits intomainfrom
perf/deck-query-cache-and-index
Feb 25, 2026
Merged

perf: tapes deck eliminates N+1 queries, extend cache coverage, add created_at index#132
bdougie merged 5 commits intomainfrom
perf/deck-query-cache-and-index

Conversation

@bdougie
Copy link
Contributor

@bdougie bdougie commented Feb 23, 2026

Summary

  • Fix N+1 in SessionDetail / SessionAnalytics — both now check the session candidate cache by ID before falling back to loadAncestry(), eliminating per-session parent-chain DB round-trips
  • O(1) session candidate index — added a map[string]*sessionCandidate index to the cache struct, replacing O(n) linear scans in SessionDetail and SessionAnalytics with direct map lookups on the hot path
  • Overview() and AnalyticsOverview() use cache — switched from allowCache=false to true; rapid TUI/dashboard refreshes reuse the in-memory candidate set instead of triggering a full DB scan
  • Deduplicate extractToolCalls in analytics loop — called once per node instead of twice, result reused for both counting and error attribution
  • Bump sessionCacheTTL 10s → 30s — aligns with TUI refresh cadence and reduces cold-load frequency
  • Add created_at index to Node schema — enables future time-range predicate pushdown; applied automatically via client.Schema.Create on startup
  • Exponential backoff for facet polling — replaces fixed setInterval(fn, 3000) with a recursive setTimeout that grows 1.5× per tick up to 30s, reducing background network pressure during slow backfills

Benchmark results (Apple M4 Max, 6×5s runs, benchstat)

Benchmark main branch Δ
Overview warm 240µs 13µs −94%
SessionDetail warm 255µs 15µs −93%
SessionAnalytics warm 234µs 10µs −95%
AnalyticsOverview warm 305µs 89µs −70%
Overview warm (50 sessions) 1074µs 65µs −93%
SessionDetail warm (50 sessions) 161µs 7µs −95%

Overall geomean: −70.74%

Cold-path calls (cache miss) incur a small constant overhead (+9–11%) from writing to the cache on each full load — acceptable given warm-path savings.

Test plan

  • go test ./pkg/deck/... — 121 specs pass, no regressions
  • go build ./... — clean build

Continue Tasks: ✅ 1 no changes — View all

- SessionDetail/SessionAnalytics now look up cached candidates by ID
  before falling back to loadAncestry(), eliminating per-session N+1
  DB round-trips
- Overview() and AnalyticsOverview() switched to allowCache=true so
  rapid TUI/dashboard refreshes reuse the in-memory candidate set
- extractToolCalls() deduplicated to one call per node in analytics loop
- sessionCacheTTL bumped from 10s to 30s
- Add created_at index to Node schema for future time-range pushdown
- Facet polling uses exponential backoff (3s→30s) instead of fixed 3s interval
@bdougie bdougie changed the title perf: eliminate N+1 queries, extend cache coverage, add created_at index perf: tapes deck eliminates N+1 queries, extend cache coverage, add created_at index Feb 23, 2026
Replace linear scans in SessionDetail and SessionAnalytics with a
map[string]*sessionCandidate index on the cache, turning repeated
keyed lookups from O(n) to O(1).
Copy link
Contributor

@oppegard oppegard left a comment

Choose a reason for hiding this comment

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

This looks awesome :D

My primary concern is lack of test coverage. I prompted codex with:

Based on the changes this branch made to query.go , can you suggest some high value tests?

It came up with this perf/deck-query-cache-and-index...oppegard:tapes:perf/deck-query-cache-and-index

(It's wild that it can just generate this)

Before this new test suite, query.go had 27% test coverage. These tests push it to 78% coverage, and they run in ~250 ms (I don't love that). There are still some conditionals not being exercised, and functions like groupSessionDetail() and appendGroupedText() have nearly zero coverage.

That's the extent of what I've reviewed.

Copy link
Contributor Author

@bdougie bdougie left a comment

Choose a reason for hiding this comment

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

Tests pushed — 166 specs now (up from 126), covering the new cache index, buildSessionMessages, buildGroupedMessages, buildSessionAnalytics, matchesFilters, and the text grouping helpers. All pass in ~30ms.

@bdougie bdougie merged commit 0c29838 into main Feb 25, 2026
11 of 12 checks passed
@bdougie bdougie deleted the perf/deck-query-cache-and-index branch February 25, 2026 17:56
@continue
Copy link

continue bot commented Feb 25, 2026

No docs update needed. This PR is a pure performance optimization that doesn't change any user-facing behavior:

  • Internal caching improvements: N+1 query elimination and session cache index are implementation details
  • Cache TTL change (10s → 30s): This is an internal constant, not user-configurable
  • Database index: Applied automatically on startup via schema migration
  • Frontend polling optimization: Exponential backoff is transparent to users

All API responses and CLI behavior remain unchanged. Users will experience faster dashboard/TUI performance without any action required.

PR #132 was merged: perf: tapes deck eliminates N+1 queries, extend cache coverage, add created_at index
PR URL: #132
Merged by: bdougie

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.

2 participants