Skip to content

Support resuming from squash merge commits with multiple checkpoints#534

Merged
gtrrz-victor merged 25 commits intomainfrom
squash-merge-resume
Mar 4, 2026
Merged

Support resuming from squash merge commits with multiple checkpoints#534
gtrrz-victor merged 25 commits intomainfrom
squash-merge-resume

Conversation

@pfleidi
Copy link
Contributor

@pfleidi pfleidi commented Feb 26, 2026

Summary

  • Support entire resume on squash merge commits that contain multiple Entire-Checkpoint trailers
  • Fix checkpoint ordering bug where git CLI squash merges list trailers newest-first, causing the oldest transcript to overwrite the newest on disk
  • Deduplicate sessions by SessionID across checkpoints, keeping the most recent transcript

Problem

When a feature branch with multiple commits (each with its own Entire-Checkpoint trailer) is squash-merged, all trailers end up in a single commit message. entire resume previously only parsed the first trailer, losing all other sessions.

Additionally, GitHub squash merges list trailers chronologically (oldest first), but git CLI squash merges list them in reverse order (newest first). Since RestoreLogsOnly writes session files eagerly, the last checkpoint processed wins on disk — meaning reverse-ordered trailers caused the oldest transcript to overwrite the newest.

Changes

cmd/entire/cli/trailers/trailers.go — Add ParseAllCheckpoints() to extract all Entire-Checkpoint trailers from a commit message (not just the first).

cmd/entire/cli/resume.go

  • Switch from ParseCheckpoint (single) to ParseAllCheckpoints (multi) throughout findBranchCheckpoint and findCheckpointInHistory
  • Change branchCheckpointResult.checkpointIDcheckpointIDs []CheckpointID
  • Add resumeMultipleCheckpoints: reads metadata for all checkpoint IDs, sorts by CreatedAt ascending, then restores in order so the newest checkpoint always writes last
  • Add deduplicateSessions: merges sessions across checkpoints, keeping the one with the latest CreatedAt when a SessionID appears in multiple checkpoints
  • Extract displayRestoredSessions to share session display logic between single and multi-checkpoint paths

cmd/entire/cli/resume_test.go — Add unit tests for deduplicateSessions (including three-occurrence staleness edge case), findCheckpointInHistory with multiple trailers, findBranchCheckpoint with squash merge, and checkpoint timestamp sorting.

cmd/entire/cli/integration_test/resume_test.go — Add integration test simulating a full squash merge workflow: two sessions on a feature branch, squash merge to main, then entire resume restoring both sessions.

cmd/entire/cli/trailers/trailers_test.go — Add tests for ParseAllCheckpoints.

Caveat: Optimization

I thought about optimizing this process by only restoring the very latest checkpoint, but realized that this wouldn't work as expected:

A committed checkpoint only contains the sessions that were condensed at that specific commit. When a feature branch is squash merged, Git/GitHub preserves all Entire-Checkpoint trailers from the original commits in the squash commit body. Each trailer points to a different checkpoint on entire/checkpoints/v1, and different checkpoints may contain different sessions.

Since there is no single checkpoint that aggregates all sessions from the branch, the resume command must iterate over every checkpoint ID found in the squash commit and restore each one. Sessions are de-duplicated by ID, keeping the entry with the latest CreatedAt.

Optimizing by only restoring the latest checkpoint would silently drop any session whose last activity was on an earlier commit.

Test plan

  • mise run test:ci passes (unit + integration)
  • Integration test TestResume_SquashMergeMultipleCheckpoints covers the end-to-end squash merge flow
  • Unit test TestResumeMultipleCheckpoints_SortsByCreatedAt verifies reverse-ordered checkpoints are sorted correctly
  • Unit tests for deduplicateSessions cover no-duplicates, newer-wins, older-loses, three-occurrence, and mixed scenarios

pfleidi and others added 4 commits February 26, 2026 13:57
Change checkpointID field to checkpointIDs slice, update findBranchCheckpoint
and findCheckpointInHistory to use ParseAllCheckpoints, and add test for
squash merge commits with multiple Entire-Checkpoint trailers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: e49c84c2d596
Add ParseAllCheckpoints() to trailers package for extracting all
Entire-Checkpoint trailers from squash merge commits. Add
resumeMultipleCheckpoints() to resume.go that iterates over all
checkpoint IDs, restores sessions for each, and displays aggregated
resume commands. Refactor test helper to support custom checkpoint IDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 43abb5b45ab5
Entire-Checkpoint: c585b5e466a1
@pfleidi pfleidi requested a review from a team as a code owner February 26, 2026 23:11
Copilot AI review requested due to automatic review settings February 26, 2026 23:11
@cursor
Copy link

cursor bot commented Feb 26, 2026

PR Summary

Medium Risk
Changes entire resume restoration logic to process multiple checkpoints and overwrite transcripts based on checkpoint timestamps, which could affect which session logs end up on disk. The behavior is well-covered by new unit and integration tests but touches a core workflow and remote metadata fallback paths.

Overview
entire resume now supports squash-merge commits that include multiple Entire-Checkpoint trailers, restoring sessions from every referenced checkpoint instead of only the first.

The new multi-checkpoint path sorts checkpoints by metadata CreatedAt (so the newest transcript wins on disk even when trailer order is reversed) and deduplicates sessions by SessionID (keeping the latest). Output formatting is refactored into a shared displayRestoredSessions helper.

Adds trailers.ParseAllCheckpoints, a new integration test that simulates a full squash-merge workflow, and unit tests covering trailer parsing, checkpoint ordering, history scanning, and session deduplication; integration test helpers gain GitCommitWithMultipleCheckpoints to build squash-style commit messages.

Written by Cursor Bugbot for commit b0d0093. Configure here.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for resuming sessions from squash-merge commits that contain multiple Entire-Checkpoint trailers, enabling entire resume <branch> to restore more than one session when multiple checkpoints are embedded in a single commit message.

Changes:

  • Add trailers.ParseAllCheckpoints() to extract and deduplicate multiple checkpoint trailers from a commit message.
  • Update resume branch-checkpoint discovery to return multiple checkpoint IDs and add a multi-checkpoint resume flow.
  • Add unit + integration tests (including a squash-merge simulation) and a new integration test helper to create commits with multiple checkpoint trailers.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cmd/entire/cli/trailers/trailers.go Adds ParseAllCheckpoints() to return all checkpoint trailers (deduped, ordered).
cmd/entire/cli/trailers/trailers_test.go Adds unit tests covering single/multiple/dedup/invalid/mixed checkpoint trailers.
cmd/entire/cli/resume.go Switches checkpoint discovery to multiple IDs and introduces resumeMultipleCheckpoints().
cmd/entire/cli/resume_test.go Adds unit tests for multiple-checkpoint history/branch discovery and a helper to create distinct checkpoint metadata.
cmd/entire/cli/integration_test/testenv.go Adds GitCommitWithMultipleCheckpoints() helper for squash-merge style commit messages.
cmd/entire/cli/integration_test/resume_test.go Adds integration test validating restore from squash-merge commit containing two checkpoints.

pfleidi and others added 2 commits February 26, 2026 15:22
The sorting, header formatting, and resume command printing was
duplicated between resumeSession and resumeMultipleCheckpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 0ff68845c557
RestoreLogsOnly already resolves agents per-session from session-level
metadata, so an unknown checkpoint-level agent shouldn't block the
restore attempt. The session dir creation was also redundant since
RestoreLogsOnly handles it internally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 831e4afa5e83
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

pfleidi and others added 2 commits February 26, 2026 15:26
Split the error and empty-sessions cases into separate log entries
so the actual failure reason is visible in debug logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 932c2642d8ac
When a single session spans multiple commits, different checkpoint IDs
can contain the same session. In a squash merge this would produce
duplicate resume commands. Keep the entry with the latest CreatedAt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: e92b8f8525e9
@toothbrush
Copy link
Contributor

toothbrush commented Feb 26, 2026

As someone who prefers¹ squash-merge to messy merge-tennis with careless commit messages, this effort really pleases me.

  1. Out of an abundance of caution i want to add that doesn't mean it's my favouritest merge.

The inline dedup logic in resumeMultipleCheckpoints did not update the
seen map's CreatedAt after replacing a session, so a third occurrence
could incorrectly overwrite the newest entry. Extract to a standalone
function with a correct update and add targeted unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 7132c7b6328a
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@pfleidi pfleidi marked this pull request as draft February 27, 2026 02:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Entire-Checkpoint: 9c67547d59c3
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

pfleidi and others added 4 commits March 3, 2026 11:43
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…uash-merge-resume

Entire-Checkpoint: 4ff8bd5bc20c
Entire-Checkpoint: dc311b24d1d0
@pfleidi pfleidi marked this pull request as ready for review March 3, 2026 19:50
@pfleidi
Copy link
Contributor Author

pfleidi commented Mar 3, 2026

@cursor review

Add end2end tests for `entire resume` for squash merged commits
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@gtrrz-victor gtrrz-victor merged commit 256ba8b into main Mar 4, 2026
7 of 8 checks passed
@gtrrz-victor gtrrz-victor deleted the squash-merge-resume branch March 4, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants