Skip to content

perf(home): read recent-meeting metadata from a SQLite index, not file re-parse#1329

Draft
r3dbars wants to merge 2 commits into
mainfrom
perf/home-list-index-read
Draft

perf(home): read recent-meeting metadata from a SQLite index, not file re-parse#1329
r3dbars wants to merge 2 commits into
mainfrom
perf/home-list-index-read

Conversation

@r3dbars

@r3dbars r3dbars commented Jun 25, 2026

Copy link
Copy Markdown
Owner

What

The Home capture list (RecentMeetingsScanner.loadRecent) re-parsed each visible meeting transcript on every refresh — full Markdown read + frontmatter parse + speaker-label regex + summary parse — which doesn't scale to a large library (NEXT_WORK #10).

This points the Home list at an index: a small SQLite cache (RecentMeetingMetadataCache) keyed by transcript path and validated by the transcript + summary-sidecar modification time and size (cheap stats, no content reads). On a warm hit the row is rebuilt straight from the index and no transcript content is read; on a miss or when the on-disk file changed it parses exactly as before and repopulates the index.

Why a new cache instead of an existing table

The Home row needs the summary preview, speaker-needs-review count, and audio-health hint — none of which the existing StatsDatabase.recordings table or the MCP TranscriptIndex (separate package, JSON-indexed, not app-linked) store. A pure "read the existing table" swap would drop fields and break the behavior-identical requirement. So this caches exactly the derived row, keyed by file identity, and falls back to the live parse whenever the file changes.

Scope / honesty

  • The scanner already only parsed the top limit rows (it breaks early), so this removes those per-row content reads/parses. The O(N) directory stat enumeration (needed for ordering + cache validation) is unchanged. A fully index-ordered ORDER BY date DESC LIMIT n query that skips the directory entirely would need an authoritative, save-path-synced index + migration — out of scope here and a bigger conflict surface.
  • Retained-audio attachments are still resolved live each refresh (cheap dir probe, already invalidation-managed by HomeCaptureRefreshObserver).
  • Degrades safely to the old cold-parse behavior if SQLite fails to open or a payload fails to encode/decode.

Test

Tests/RecentCaptureScannersTests.swift:

  • Warm index serves without re-reading: warm the index, chmod 000 the transcript, prove the row still loads with identical fields (impossible if it re-read the file), plus a control showing the unreadable file yields no row when the index is cold.
  • Invalidation: a changed transcript (new mtime) re-parses and reflects the new title.

Verification

  • bash build.sh --no-open
  • bash run-tests.sh ✅ (10167 passed)
  • bash run-e2e-smoke.sh ✅ (added the new file to its swiftc source list)
  • source-list validator ✅

Manual proof (Home feels fast with a big library) is for Justin.

Conflict note

Touches RecentCaptureScanners.swift (data-source swap only) — kept deliberately narrow to coexist with the in-flight UI-polish PRs that also touch Home. No Home view changes.

🤖 Generated with Claude Code

r3dbars and others added 2 commits June 25, 2026 06:09
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e re-parse

The Home capture list re-parsed each visible meeting transcript (full
Markdown read + frontmatter parse + speaker-label regex + summary parse)
on every refresh, which does not scale to a large library.

Add `RecentMeetingMetadataCache`, a small SQLite-backed index keyed by
transcript path and validated by the transcript + summary-sidecar
modification time and size. `RecentMeetingsScanner.loadRecent` now serves
a warm row straight from the index with no transcript content read; on a
miss or when the on-disk file changed it parses as before and repopulates
the index. Retained-audio attachments are still resolved live each refresh
(a cheap directory probe with its own invalidation path), so behavior is
identical to the file-scan path.

The cache degrades safely to the old cold-parse behavior if SQLite fails
to open or a payload fails to encode/decode.

Test: warm the index, chmod the transcript unreadable, and prove the row
still loads (impossible if it re-read the file), plus a control showing the
unreadable file yields no row when the index is cold, and an invalidation
test showing a changed transcript re-parses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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