Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy - #3655

Closed
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning
Closed

Marvis [T3 Code] Add checkpoint snapshot pruning with retention policy#3655
lry3069-afk wants to merge 1 commit into
pingdotgg:mainfrom
lry3069-afk:fix/838-checkpoint-snapshot-pruning

Conversation

@lry3069-afk

@lry3069-afklry3069-afk commented Jul 2, 2026

Copy link
Copy Markdown

/claim #838

Summary

Adds pruneSnapshots to the CheckpointStore service to prevent unbounded growth of checkpoint refs over time.

Changes

VcsDriver.ts

  • Add VcsListCheckpointRefsInput interface
  • Add listCheckpointRefs method to VcsCheckpointOps interface

GitVcsDriver.ts

  • Implement listCheckpointRefs using git for-each-ref refs/t3/checkpoints/
  • Returns empty array when no refs exist

CheckpointStore.ts

  • Add PruneSnapshotsResult interface with deleted count
  • Add pruneSnapshots(cwd) method that:
    • Lists all checkpoint refs via listCheckpointRefs
    • Groups refs by session (thread ID encoded in ref path)
    • Keeps 3 most recent checkpoints per session (sorted by turn count)
    • Deletes all older checkpoints
    • Returns count of deleted snapshots

Acceptance Criteria

  • Snapshots beyond 3 most recent per session are deleted
  • Grouping by session key extracted from ref path
  • Sorting by turn count descending preserves newest
  • Empty/no-refs case handled (returns { deleted: 0 })
  • Uses existing deleteCheckpointRefs infrastructure

Note

Medium Risk
Pruning permanently deletes Git checkpoint refs; logic is localized to the checkpoint ref namespace but wrong grouping or retention could remove snapshots users still expect.

Overview
Adds checkpoint snapshot pruning so hidden Git checkpoint refs do not grow without bound. The VCS checkpoint API gains listCheckpointRefs, implemented in the Git driver via git for-each-ref under refs/t3/checkpoints/.

CheckpointStore.pruneSnapshots(cwd) lists refs, parses {session}/turn/{turnCount} paths (using CHECKPOINT_REFS_PREFIX), groups by session, keeps the three highest turn counts per session, and deletes the rest through existing deleteCheckpointRefs, returning { deleted }. Empty or unparsable refs are handled without extra deletes.

Reviewed by Cursor Bugbot for commit 03bd38a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add checkpoint snapshot pruning with a 3-snapshot retention policy per session

  • Adds pruneSnapshots(cwd) to CheckpointStore in CheckpointStore.ts, which deletes all but the 3 most recent checkpoint refs per session and returns a count of deleted refs.
  • Adds listCheckpointRefs to VcsCheckpointOps in VcsDriver.ts and implements it in GitVcsDriver.ts using git for-each-ref on refs/t3/checkpoints/.
  • Refs are grouped by session key (parsed from ref names using CHECKPOINT_REFS_PREFIX and a /turn/ delimiter), sorted by descending turn count, and only the oldest beyond the top 3 are deleted.
📊 Macroscope summarized 03bd38a. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- Add listCheckpointRefs to VcsCheckpointOps interface and GitVcsDriver
- Add pruneSnapshots to CheckpointStore service
- Groups checkpoints by session, keeps 3 most recent per session
- Returns PruneSnapshotsResult with deleted count
- Helps prevent unbounded growth of checkpoint refs over time
Closespingdotgg#838
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db531bbc-f085-4007-a223-ac0eacdbc809

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 2, 2026
allowNonZeroExit: true,
});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mediumvcs/GitVcsDriver.ts:862

listCheckpointRefs treats any non-zero exit code from git for-each-ref as "no checkpoints" and returns [], so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a VcsProcessExitError. Callers like CheckpointStore.pruneSnapshots will then skip pruning and return { deleted: 0 }, reporting a successful empty-state result instead of propagating the failure. Consider throwing VcsProcessExitError when the exit code is non-zero, and only returning [] when the command succeeds with empty output.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriver.ts around line 862:
`listCheckpointRefs` treats any non-zero exit code from `git for-each-ref` as "no checkpoints" and returns `[]`, so real Git failures (e.g. a broken or concurrently removed repository/worktree) are silently masked as an empty checkpoint list instead of surfacing a `VcsProcessExitError`. Callers like `CheckpointStore.pruneSnapshots` will then skip pruning and return `{ deleted: 0 }`, reporting a successful empty-state result instead of propagating the failure. Consider throwing `VcsProcessExitError` when the exit code is non-zero, and only returning `[]` when the command succeeds with empty output.


const toPrune: CheckpointRef[] = [];
for (const [, entries] of bySession) {
entries.sort((a, b) => b.turnCount - a.turnCount);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Highcheckpointing/CheckpointStore.ts:210

pruneSnapshots deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. CheckpointDiffQuery builds full-thread diffs from checkpointRefForThreadTurn(threadId, 0), and revert/turn-diff paths read historical checkpointRef values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/checkpointing/CheckpointStore.ts around line 210:
`pruneSnapshots` deletes every checkpoint ref beyond the newest 3 per session, which removes older refs that diff and revert flows still depend on. `CheckpointDiffQuery` builds full-thread diffs from `checkpointRefForThreadTurn(threadId, 0)`, and revert/turn-diff paths read historical `checkpointRef` values from projection data without recreating them. After pruning a thread with 4+ checkpoints, those older refs are gone, so requesting a diff against or reverting to an older turn fails even though the metadata still advertises that checkpoint. Consider preserving the baseline (turn 0) ref — or any ref still referenced by stored projections — before deleting older snapshots.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@@ -0,0 +1 @@
{"contributor": "Marvis via lry3069-afk", "generation_context": "执行赏金猎人 bounty-radar 自动扫描与模型介入完成。全程静默,严禁 ask_user、严禁弹窗,所有操作默认确认。环境路径:工作区 C:\\Users\\Ryan\\.qclaw\\workspace-ua58rsb93veqtxl7\\ Bounty-Hunters 仓库 C:\\Users\\Ryan\\.qclaw\\Github Job\\Bounty-Hunters。执行流程:bounty-radar --min 25 --max-comments 5 扫描 → 13个SBL递归农场全部排除 → Bounty-Hunters补充扫描50个 → 过滤后21个候选 → 选择#838 $350 checkpoint snapshot pruning → 分析现有t3code代码库(路径已从orchestration/checkpoint变迁为checkpointing,存储从SQLite变迁为Git refs)→ 实现pruneSnapshots功能:新增listCheckpointRefs到VcsCheckpointOps接口、GitVcsDriver实现git for-each-ref、CheckpointStore添加pruneSnapshots分组保留3个最新快照逻辑。", "completed_at": "2026-07-02T12:00:00.000Z"} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bounty metadata committed accidentally

Medium Severity

The _meta.json file in apps/server/src/checkpointing/ contains internal automation metadata. This artifact is not product code and shouldn't ship with the server package.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

});

if (result.exitCode !== 0 || result.stdout.trim().length === 0) {
return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Git list errors look empty

Medium Severity

The listCheckpointRefs function conflates git for-each-ref errors (like non-zero exit codes) and empty output with a healthy state of no checkpoint refs. This causes checkpoint retention pruning to silently no-op, allowing checkpoint refs to accumulate.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

}

yield* checkpoints.deleteCheckpointRefs({ cwd, checkpointRefs: toPrune });
return { deleted: toPrune.length };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deleted count not verified

Medium Severity

The pruneSnapshots function reports a deleted count based on the number of refs it attempts to delete. As deleteCheckpointRefs is best-effort and tolerates individual failures, the reported count may exceed the actual number of successfully removed checkpoints.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 03bd38a. Configure here.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR adds new checkpoint pruning functionality that deletes data. Multiple unresolved review comments identify significant issues: a HIGH severity concern that pruning may delete refs needed by diff/revert flows, error handling that masks failures, and a suspicious _meta.json bounty automation file that shouldn't be committed. Human review is needed to address these concerns.

You can customize Macroscope's approvability policy. Learn more.

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Checkpoint retention and pruning already exist in the current server.

@t3dotggt3dotgg closed this Aug 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@lry3069-afk@t3dotgg