WIP: Checkpoints V2: add migration option#855
Conversation
Entire-Checkpoint: 209a37190167
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit f423519. Configure here.
| slog.String("error", taskErr.Error()), | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Task metadata never copied due to unpopulated fields
Medium Severity
The condition info.IsTask && info.ToolUseID != "" will always be false because ListCommitted (the source of info) never populates IsTask or ToolUseID on CommittedInfo. These fields stay at their zero values (false and ""). As a result, copyTaskMetadataToV2 is dead code — task metadata trees (subagent transcripts, checkpoint JSONs) are silently skipped during migration. The check likely needs to use session metadata (e.g., content.Metadata.IsTask) instead.
Reviewed by Cursor Bugbot for commit f423519. Configure here.
| // Remove trailing empty string from trailing newline | ||
| if len(prompts) > 0 && prompts[len(prompts)-1] == "" { | ||
| prompts = prompts[:len(prompts)-1] | ||
| } |
There was a problem hiding this comment.
Prompts split by wrong delimiter corrupts migration data
Medium Severity
buildMigrateWriteOpts splits content.Prompts by "\n", but the v1 store joins prompts with "\n\n---\n\n" when writing prompt.txt. When the v2 store re-joins the resulting slice with "\n\n---\n\n", multi-prompt checkpoints and prompts containing newlines get corrupted with extra separators injected into the output. The split delimiter needs to match the join delimiter ("\n\n---\n\n").
Reviewed by Cursor Bugbot for commit f423519. Configure here.
There was a problem hiding this comment.
Pull request overview
Adds an initial entire migrate CLI command intended to migrate v1 checkpoints to the v2 checkpoint ref/layout for testing and rollout prep.
Changes:
- Registers a new
migratesubcommand on the root CLI. - Introduces v1→v2 checkpoint migration logic, including transcript compaction and attempted task-metadata tree copying.
- Adds unit tests covering basic migration flows and idempotency.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| cmd/entire/cli/root.go | Registers the new migrate command in the root CLI. |
| cmd/entire/cli/migrate.go | Implements v1→v2 migration logic, transcript compaction, and task metadata tree splicing. |
| cmd/entire/cli/migrate_test.go | Adds tests for migration behavior (basic/idempotent/multi-session/flag validation). |
| // Copy task metadata trees from v1 to v2 /full/current | ||
| if info.IsTask && info.ToolUseID != "" { | ||
| if taskErr := copyTaskMetadataToV2(ctx, repo, v1Store, v2Store, info.CheckpointID, summary); taskErr != nil { | ||
| logging.Warn(ctx, "failed to copy task metadata to v2", | ||
| slog.String("checkpoint_id", string(info.CheckpointID)), |
There was a problem hiding this comment.
The task-metadata copy path is effectively unreachable: migrateCheckpointsV2 passes checkpoint.CommittedInfo values returned by GitStore.ListCommitted, but that method does not populate CommittedInfo.IsTask / ToolUseID (it only reads Agent/SessionID/CreatedAt). As a result, this if info.IsTask && info.ToolUseID != "" check will always be false and task metadata won’t be migrated.
Consider detecting task checkpoints from the v1 session metadata you already read (e.g., content.Metadata.IsTask / ToolUseID) or changing the gating condition accordingly, so copyTaskMetadataToV2 actually runs for task checkpoints.
cmd/entire/cli/migrate.go
Outdated
| prompts = strings.Split(content.Prompts, "\n") | ||
| // Remove trailing empty string from trailing newline | ||
| if len(prompts) > 0 && prompts[len(prompts)-1] == "" { | ||
| prompts = prompts[:len(prompts)-1] |
There was a problem hiding this comment.
Prompt parsing during migration doesn’t match how prompts are stored in v1/v2. prompt.txt content is written using the "\n\n---\n\n" separator (see checkpoint store implementations), but this code splits on single newlines, which will corrupt multi-prompt content by producing empty entries and a literal "---" prompt.
Split on the established separator (and trim/skip empty parts) to preserve the original prompt boundaries.
| prompts = strings.Split(content.Prompts, "\n") | |
| // Remove trailing empty string from trailing newline | |
| if len(prompts) > 0 && prompts[len(prompts)-1] == "" { | |
| prompts = prompts[:len(prompts)-1] | |
| parts := strings.Split(content.Prompts, "\n\n---\n\n") | |
| prompts = make([]string, 0, len(parts)) | |
| for _, part := range parts { | |
| part = strings.TrimSpace(part) | |
| if part == "" { | |
| continue | |
| } | |
| prompts = append(prompts, part) |
| // Verify task checkpoint exists in v2 | ||
| summary, readErr := v2Store.ReadCommitted(context.Background(), cpID) | ||
| require.NoError(t, readErr) | ||
| require.NotNil(t, summary) | ||
| } |
There was a problem hiding this comment.
This test claims to verify task checkpoint migration, but it only asserts the v2 checkpoint summary exists. It doesn’t assert that task metadata under tasks/ was copied/spliced into the v2 /full/current ref, so it won’t catch regressions (or cases where copyTaskMetadataToV2 never runs).
Add an assertion that expected task files/directories exist in the v2 full tree for this checkpoint/session after migration.
Entire-Checkpoint: c9595c52ab4a
Entire-Checkpoint: 9f07aeebbf93
Entire-Checkpoint: f1c37c8efc47


Adds the beginnings of a migration CLI command that allows for a
checkpointsparameter to be passed in to migrate from v1 to v2. I think this will be automated for end users when we are ready to green light v2, but for now, it'll be handy for testing.➜ test-repo git:(entire/checkpoints/v1) ✗ lentire migrate --checkpoints "v2"
Migrating v1 checkpoints to v2...
[1/25] Migrating checkpoint 528c39637ed4... skipped (already in v2)
[2/25] Migrating checkpoint e8e062073afb... skipped (already in v2)
[3/25] Migrating checkpoint 3ced2b94d513... skipped (already in v2)
[4/25] Migrating checkpoint 223e6f793eed... done
[5/25] Migrating checkpoint 699504f045e2... done (compact transcript skipped)
[6/25] Migrating checkpoint a0f8612fcb64... done (compact transcript skipped)
[7/25] Migrating checkpoint f55b1d3b434a... done
[8/25] Migrating checkpoint 943126df1f2a... done
[9/25] Migrating checkpoint e6b2f769a273... done
[10/25] Migrating checkpoint 4be62319bf98... done
[11/25] Migrating checkpoint b8b6fbd5f55f... done
[12/25] Migrating checkpoint b1b2d74d8ef1... done (compact transcript skipped)
[13/25] Migrating checkpoint 6215534dfb8e... done
[14/25] Migrating checkpoint 5a31697679ee... done
[15/25] Migrating checkpoint 581d7b2848de... done
[16/25] Migrating checkpoint 2151d9f18a50... done
[17/25] Migrating checkpoint ecf782729563... done
[18/25] Migrating checkpoint c81467b72ca0... done
[19/25] Migrating checkpoint c8eb421389c0... done
[20/25] Migrating checkpoint 14d75ebe3a6d... done
[21/25] Migrating checkpoint 729ac91fce19... done
[22/25] Migrating checkpoint 79d52455f160... done
[23/25] Migrating checkpoint edd2df3466e5... done
[24/25] Migrating checkpoint a18a21695d2e... done
[25/25] Migrating checkpoint 6284d02bfdae... done
Migration complete: 22 migrated, 3 skipped, 0 failed
➜ test-repo git:(entire/checkpoints/v1) ✗ git show-ref -- refs/entire/checkpoints/v2/main
c1641139fb51a64faec6434e804368e8d8006e00 refs/entire/checkpoints/v2/main
➜ test-repo git:(entire/checkpoints/v1) ✗ git show-ref -- refs/entire/checkpoints/v2/full/current
faf645d2b1f21aa6e019f6252a7d5d521a7acb4e refs/entire/checkpoints/v2/full/current
➜ test-repo git:(entire/checkpoints/v1) ✗ lentire migrate --checkpoints "v2"
Migrating v1 checkpoints to v2...
[1/25] Migrating checkpoint 528c39637ed4... skipped (already in v2)
[2/25] Migrating checkpoint e8e062073afb... skipped (already in v2)
[3/25] Migrating checkpoint 3ced2b94d513... skipped (already in v2)
[4/25] Migrating checkpoint 223e6f793eed... skipped (already in v2)
[5/25] Migrating checkpoint 699504f045e2... skipped (already in v2)
[6/25] Migrating checkpoint a0f8612fcb64... skipped (already in v2)
[7/25] Migrating checkpoint f55b1d3b434a... skipped (already in v2)
[8/25] Migrating checkpoint 943126df1f2a... skipped (already in v2)
[9/25] Migrating checkpoint e6b2f769a273... skipped (already in v2)
[10/25] Migrating checkpoint 4be62319bf98... skipped (already in v2)
[11/25] Migrating checkpoint b8b6fbd5f55f... skipped (already in v2)
[12/25] Migrating checkpoint b1b2d74d8ef1... skipped (already in v2)
[13/25] Migrating checkpoint 6215534dfb8e... skipped (already in v2)
[14/25] Migrating checkpoint 5a31697679ee... skipped (already in v2)
[15/25] Migrating checkpoint 581d7b2848de... skipped (already in v2)
[16/25] Migrating checkpoint 2151d9f18a50... skipped (already in v2)
[17/25] Migrating checkpoint ecf782729563... skipped (already in v2)
[18/25] Migrating checkpoint c81467b72ca0... skipped (already in v2)
[19/25] Migrating checkpoint c8eb421389c0... skipped (already in v2)
[20/25] Migrating checkpoint 14d75ebe3a6d... skipped (already in v2)
[21/25] Migrating checkpoint 729ac91fce19... skipped (already in v2)
[22/25] Migrating checkpoint 79d52455f160... skipped (already in v2)
[23/25] Migrating checkpoint edd2df3466e5... skipped (already in v2)
[24/25] Migrating checkpoint a18a21695d2e... skipped (already in v2)
[25/25] Migrating checkpoint 6284d02bfdae... skipped (already in v2)
Migration complete: 0 migrated, 25 skipped, 0 failed
Note
Medium Risk
Adds a new migration path that reads/writes checkpoint data and performs git tree/ref updates (including
/full/currenttree surgery for task metadata), so mistakes could corrupt or misplace checkpoint history despite being idempotent and tested.Overview
Introduces a new
entire migrate --checkpoints v2command to migrate committed v1 checkpoints into the v2 checkpoint storage format.The migration iterates all v1 checkpoints, writes each session into v2 (optionally generating compact transcripts when possible), skips checkpoints already present in v2 for idempotency, and reports migrated/skipped/failed counts with logging.
For task checkpoints, it additionally copies v1 task metadata directories into v2’s
/full/currentref via git tree splicing and commits the updated ref. Includes a focused test suite covering basic migration, idempotency, multi-session checkpoints, compaction-skipped output, and task checkpoints.Reviewed by Cursor Bugbot for commit f423519. Configure here.