fix: resolve entire explain hanging on repos with many checkpoints#551
fix: resolve entire explain hanging on repos with many checkpoints#551
entire explain hanging on repos with many checkpoints#551Conversation
Two performance regressions in getBranchCheckpoints caused `entire explain` (and any command that lists checkpoints) to hang indefinitely on repos with hundreds of checkpoints: 1. collectCheckpoint called ReadLatestSessionContent + extractPromptsFromTranscript for every checkpoint (236 on this repo's main branch). This reads multi-MB JSONL transcript blobs from git and parses them as JSON — just to extract the first user prompt for the list view. Replaced with readPromptFromMetadataTree which reads the tiny prompt.txt file directly from the metadata branch tree. Introduced in 0e7a05f (Feb 2, PR #130). 2. convertTemporaryCheckpoint called hasCodeChanges which does a full tree diff (parentTree.Diff(commitTree)) via go-git for every temporary checkpoint. Each diff resolves hundreds of tree/blob objects through go-git's slow pure-Go SHA1 packfile reader. Replaced with hasAnyChanges which compares tree hashes in O(1) — acceptable for list views where showing a few metadata-only checkpoints is better than hanging. Result: `entire explain` goes from hanging indefinitely to completing in ~350ms. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Entire-Checkpoint: ab4fe695467e
PR SummaryMedium Risk Overview Committed checkpoint prompts are now read by fetching the metadata branch tree once and pulling Written by Cursor Bugbot for commit eff1e18. Configure here. |
|
The second fix definitely fixed the problem. The first one might be a red herring
Check if reverting that bit makes a difference to timing. |
There was a problem hiding this comment.
Pull request overview
Improves the performance of entire explain list view by removing per-checkpoint expensive go-git operations (full transcript parsing and tree diffs) that don’t scale with hundreds of checkpoints.
Changes:
- Adds a fast path to read the session prompt preview directly from
prompt.txtin the metadata-branch tree (avoids reading/parsing transcripts per checkpoint). - Replaces diff-based temporary-checkpoint filtering with an O(1) tree-hash comparison to avoid repeated expensive go-git tree diffs.
Address PR feedback: - Move readPromptFromMetadataTree logic into strategy.ReadLatestSessionPromptFromCommittedTree to avoid hard-coding the metadata branch directory layout in explain.go - Add test for getBranchCheckpoints reading prompts from committed checkpoints - Add tests for hasAnyChanges (first commit, metadata-only, no-op tree) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Entire-Checkpoint: 019ae8860bb1
Entire-Checkpoint: 192b108bb2d7
Entire-Checkpoint: 372f4046ea3f
Entire-Checkpoint: 9fb87f0597df
Summary
entire explain(and any code path callinggetBranchCheckpoints) hangs indefinitely on repos that have accumulated hundreds of checkpoints. This repo has 236 checkpoints on main and the command never returns — requires Ctrl-Z + kill -9.Root cause: Two O(N) go-git operations that don't scale:
1. Full transcript parsing for list view prompts
collectCheckpointcalledReadLatestSessionContent+extractPromptsFromTranscriptfor every checkpoint — reading multi-MB JSONL transcript blobs from git and parsing them as JSON, just to extract the first user prompt for the list view display.Introduced in:
0e7a05f1(Feb 2, PR #130) — replaced the cheapReadSessionPromptFromTree(reads tinyprompt.txt) with full transcript parsing.Fix: New
readPromptFromMetadataTreereadsprompt.txtdirectly from the metadata branch tree. The metadata tree is fetched once and reused for all checkpoints — O(1) per checkpoint instead of O(transcript_size).2. Full tree diff for temporary checkpoint filtering
convertTemporaryCheckpointcalledhasCodeChangeswhich doesparentTree.Diff(commitTree)via go-git for every temporary checkpoint. Each diff resolves hundreds of tree/blob objects through go-git's pure-Go SHA1 packfile reader (no ARM64 assembly), making each call very slow.Fix: New
hasAnyChangescompares tree hashes in O(1). For the list view, showing a few metadata-only checkpoints is acceptable — the fullhasCodeChangesdiff is preserved for contexts that need precise filtering.Performance
entire explainTest plan
mise run fmt— cleanmise run lint— 0 issuesmise run test— all passmise run test:integration— all passentire explain --no-pagercompletes in 344msentire explain --checkpoint <id>detail view still works (uses different code path)@pfleidi — this was a gradual degradation (code introduced Feb 2, grew worse as checkpoints accumulated + large packfile created Feb 25). The fix is surgical — only changes the list view's data fetching strategy, doesn't touch the detail view or any other code paths.
🤖 Generated with Claude Code