Skip to content

fix(server): clean status fetch temporary packs#4338

Open
nateEc wants to merge 3 commits into
pingdotgg:mainfrom
nateEc:codex/fix-4296-git-status-pack-leak
Open

fix(server): clean status fetch temporary packs#4338
nateEc wants to merge 3 commits into
pingdotgg:mainfrom
nateEc:codex/fix-4296-git-status-pack-leak

Conversation

@nateEc

@nateEc nateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Snapshot temporary pack entries before the status poller starts a remote fetch.
  • Remove only newly created tmp_pack files when that fetch times out or exits unsuccessfully.
  • Preserve pre-existing temporary packs and add focused regression coverage.

Why

A status refresh that exceeded the five-second timeout could leave a full temporary pack behind every polling cycle, eventually filling the disk.

Closes #4296

Checklist

  • Focused test passes: GitVcsDriverCore.test.ts
  • Server typecheck passes
  • Targeted lint and formatting pass

Note

Medium Risk
Changes core Git object/ref handling for background status fetches; incorrect promotion or ref updates could corrupt remote-tracking state, though CAS update-ref and ensuring cleanup limit blast radius.

Overview
Replaces the simple background git fetch used for status upstream refresh with an isolated fetch so interrupted or timed-out polls no longer leave large tmp_pack_* files in the shared .git/objects/pack directory (fixes disk growth from repeated 5s timeouts).

Each refresh fetches into a per-operation directory under objects/t3-status-fetch/<uuid> via GIT_OBJECT_DIRECTORY / alternates, fetches only the upstream branch into a temporary ref under refs/t3-status-fetch, then on success promotes packs and loose objects into the real object store and updates the remote-tracking ref with a compare-and-swap update-ref. Temporary refs and directories are always torn down in Effect.ensuring.

Before starting a fetch, legacy tmp_pack_* entries in the shared pack dir older than one hour are removed via exported isStaleGitTemporaryPackFile. The status refresh cache key now includes branchName. Tests cover the stale-pack helper and assert no leftover isolated fetch artifacts after a successful remote status refresh.

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

Note

Fix status fetch to use isolated object directories and clean up stale temporary pack files

  • fetchRemoteForStatus now performs fetches into a per-operation isolated object directory (objects/t3-status-fetch/<uuid>) with a temporary ref, then promotes fetched objects into the main store and atomically updates the remote-tracking ref before cleaning up.
  • Stale tmp_pack_* files older than 1 hour in the shared pack directory are opportunistically removed before each fetch.
  • StatusRemoteRefreshCacheKey is expanded to include branchName, so cache entries are now per-branch rather than shared across branches.
  • Adds isStaleGitTemporaryPackFile utility to identify stale temporary pack files by prefix and mtime.
  • Risk: The fetch mechanism is substantially rewritten; the atomic ref update uses a 40-zero OID as the expected old value when the ref is absent, and cleanup failures are silently ignored.

Macroscope summarized 46ac662.

- Track temporary pack files that exist before each status refresh.
- Remove only new tmp_pack files when the refresh times out or fails.
- Add focused regression coverage for preserving pre-existing pack files.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

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 Plus

Run ID: 30585bf0-f360-438b-b00b-259000575f99

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-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 23, 2026
Comment thread apps/server/src/vcs/GitVcsDriverCore.ts Outdated
Comment thread apps/server/src/vcs/GitVcsDriverCore.ts Outdated
Comment thread apps/server/src/vcs/GitVcsDriverCore.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR rewrites the status fetch mechanism with significant new logic for isolated object directories and cleanup. Multiple unresolved review comments identify potential bugs including orphaned directories (high severity) and incorrect refspec handling (medium severity), warranting human review.

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

- Replace operation-scoped pack deletion with a one-hour stale-file grace period.
- Run best-effort cleanup before fetches and in an interruption-safe finalizer.
- Cover active, stale, completed, and unknown-mtime pack entries.
Comment thread apps/server/src/vcs/GitVcsDriverCore.ts Outdated
- Fetch upstream status into a per-operation object store and temporary ref.
- Remove failed or timed-out fetch objects immediately without touching concurrent Git work.
- Promote complete pack and loose objects before atomically updating the tracking ref.
- Verify successful refreshes leave no temporary refs or object directories.
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 23, 2026

@cursor cursor Bot 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.

Reviewed by Cursor Bugbot for commit 46ac662. Configure here.

fetchedCommit,
expectedTarget,
]);
}).pipe(Effect.ensuring(cleanupIsolatedFetch));

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.

Orphaned fetch dirs never reaped

High Severity

The new isolated status-fetch mechanism creates temporary directories under objects/t3-status-fetch/. Its cleanup is best-effort (Effect.ignore) and lacks a stale-reaping mechanism for these new directories, unlike the legacy tmp_pack_* files. This can leave behind accumulated directories if cleanup fails, leading to disk space exhaustion.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 46ac662. Configure here.

"--no-write-fetch-head",
"--refmap=",
remoteName,
`+refs/heads/${branchName}:${temporaryRef}`,

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.

Wrong remote refspec assumed

Medium Severity

The new status fetch builds +refs/heads/${branchName}:… from the remote-tracking shorthand. That assumes a 1:1 refs/heads/* mapping, unlike the previous git fetch &lt;remote&gt; which honored configured refspecs, so custom upstreams (for example pull-request refs) can fail to refresh and leave behindCount stale.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 46ac662. Configure here.

"--no-write-fetch-head",
"--refmap=",
remoteName,
`+refs/heads/${branchName}:${temporaryRef}`,

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.

Default-branch tip goes stale

Medium Severity

Status refresh now fetches only refs/heads/${branchName} into a temporary ref, instead of refreshing the whole upstream remote. On a feature branch, aheadOfDefaultCount still compares against local origin/main (via computeAheadCountAgainstBase), so that metric can stay wrong until some other full fetch updates the default remote-tracking tip.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 46ac662. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Git status poller can fill the disk with orphaned tmp_pack_* files when the upstream fetch exceeds its 5s timeout

1 participant