Repository navigation
perf(server): storage cleanup no longer runs a full status or size walk for worktrees it keeps - #17911
Merged
Conversation
Contributor
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR materially changes the existing worktree cleanup path by introducing custom Git state detection and reordering safety checks before destructive removal. Although the change is localized and includes focused tests, its production impact and deletion-related control flow merit human review. Notes:
You can add or adjust custom eligibility rules. Learn more. |
…lk for worktrees it keeps A sweep that removed nothing still ran statusDetailsLocal (status, numstat diff, ahead count) per worktree just to read the branch, and walked every eligible worktree before the checks that most often cancel a removal. The branch comparison is now an index-path read and a symbolic-ref, and the thread, deletion and provider-session recheck runs before the size walk as well as after it, so a worktree kept for an open provider session is not measured. Refs pingdotgg#17814
tris203
force-pushed
the
t3code/cleanup-sweep-cost
branch
from
October 10, 2026 20:47
8efdee4 to
74ad9ee
Compare
github-actions Bot
added a commit
to omarcresp/t3code-flake
that referenced
this pull request
Oct 11, 2026
## What's Changed * perf(server): drive shell last-error lookup from thread bindings by @only21mil in pingdotgg/t3code#17842 * perf(server): skip parsing plain terminal history output by @StiensWout in pingdotgg/t3code#17179 * perf(server): batch terminal history writes every 250 ms by @StiensWout in pingdotgg/t3code#17183 * perf(server): storage cleanup no longer runs a full status or size walk for worktrees it keeps by @tris203 in pingdotgg/t3code#17911 * perf(usage): usage scans skip OpenCode legacy messages older than the window by @tris203 in pingdotgg/t3code#17254 * perf(usage): OpenCode legacy walk stats entries before checking for symlinks by @tris203 in pingdotgg/t3code#17638 * fix(web): MCP app permission prompts no longer overflow the screen by @juliusmarminge in pingdotgg/t3code#17962 * feat(provider-antigravity): support subscription quota and usage limits by @Maseeek in pingdotgg/t3code#17530 * fix(desktop): keep generated annotation styles in sync by @t3-code[bot] in pingdotgg/t3code#17838 * fix(web): Resume continues on the model picked in the composer by @akbarakma in pingdotgg/t3code#17867 * fix(devices): bump agent-device to 0.21.24 for native Windows hosts by @TanJeeSchuan in pingdotgg/t3code#17706 * fix(web): keybinding group headings no longer touch the group above by @fixfon in pingdotgg/t3code#17766 * feat(web): configure OpenTelemetry exports in diagnostics by @MatthewFeroz in pingdotgg/t3code#12538 * docs: update user count to 500k by @Kamkmgamer in pingdotgg/t3code#17783 * fix(mobile): working pill no longer bulges on its right end by @id0Sch in pingdotgg/t3code#16143 * perf(opencode): stop retaining every message of a loaded OpenCode thread by @tris203 in pingdotgg/t3code#17784 * fix(web): switch thumbs stay in their track while scrolling by @raphaelpra in pingdotgg/t3code#15240 * fix(keybindings): thread jumps no longer overlap model picker jumps by @Fluffy-Bunny-23 in pingdotgg/t3code#14475 * fix(mobile): restore QR scanning in iPad pairing sheet by @arhammahajan in pingdotgg/t3code#16019 * fix(server): delegated Muse tasks no longer ask approval for every command by @t3dotgg in pingdotgg/t3code#18065 * fix(codex): prevent unsupported agent history in ChatGPT sharing by @connwalk in pingdotgg/t3code#17499 * fix(server): disabled providers stop checking for CLI updates by @yordis in pingdotgg/t3code#16772 * fix(mobile): round Android queued message sheet corners by @PixPMusic in pingdotgg/t3code#14934 * fix(ssh): record the archive lock owner's real PID by @Gigioxx in pingdotgg/t3code#14598 * fix(desktop): keep annotation comment direction independent of host page by @abdelrhmanehab10 in pingdotgg/t3code#11005 * fix(ssh): qualify runner script builders in tunnel test by @juliusmarminge in pingdotgg/t3code#18078 * fix(web): keep thread links open until the shell is live by @saphid in pingdotgg/t3code#14697 * fix(web): scope PR title collapse to tab scrollers by @Adamulek123 in pingdotgg/t3code#14644 * fix(server): detect fork PRs for branches without upstreams by @Adamulek123 in pingdotgg/t3code#13894 * fix(search): find threads by their branch PR number by @tris203 in pingdotgg/t3code#14658 * feat(web): show Claude workflow phases and members in Lineage by @Bil0000 in pingdotgg/t3code#12598 * fix(mobile): round Android Agents sheet corners by @PixPMusic in pingdotgg/t3code#14925 * fix(web): the Usage page sends a signed-out browser to pairing by @AdEx-Partners-DE in pingdotgg/t3code#17938 * fix(server): OpenCode 2 continuations end after a reconnect took a Stop's end by @juliusmarminge in pingdotgg/t3code#14744 * fix(server): OpenCode 2 continuations replay only their own background reply by @juliusmarminge in pingdotgg/t3code#14752 * fix(server): ACP reapplies a model after a switch away from it failed partway by @juliusmarminge in pingdotgg/t3code#14723 * fix(web): focus settings search with command-f by @extoci in pingdotgg/t3code#17859 * fix(mobile): keep Android project paths on one line by @wellorbetter in pingdotgg/t3code#14178 * fix(web): unpin preview dragging on narrow chat canvases by @MatthewFeroz in pingdotgg/t3code#15556 * fix(web): thread details toggle no longer covers the thread title on Windows desktop by @freddy-d in pingdotgg/t3code#16869 * fix(server): a directory no longer resolves as the resource monitor binary by @Furox-Art in pingdotgg/t3code#16838 * fix(server): a Claude usage limit no longer resets the context meter to 0% by @Vantrongs in pingdotgg/t3code#16394 * fix(server): GitLab merge requests can expand unchanged lines by @ScottN-PV in pingdotgg/t3code#17528 * fix(provider-cursor): a skill tree deeper than the scan limit no longer hides every skill by @ScottN-PV in pingdotgg/t3code#17389 * fix(web): pass hex theme colors to HTML renders by @RustedAperture in pingdotgg/t3code#16325 * fix(web): align the API estimate info icon by @RakshithBhat03 in pingdotgg/t3code#15655 * test(server): ACP teardown tests pass on Windows hosts by @sheehanmunim in pingdotgg/t3code#17080 * fix(server): sync device tool license versions with installer pins by @Yash-Singh1 in pingdotgg/t3code#18121 * fix: sync model favorites and visibility across clients by @jakeleventhal in pingdotgg/t3code#16816 * chore(deps-dev): bump compression from 1.8.1 to 1.8.2 in the npm_and_yarn group across 1 directory by @dependabot[bot] in pingdotgg/t3code#16309 * fix(server): update fff to stop runaway watcher rescans by @realhasanshoaib in pingdotgg/t3code#14543 * fix(mobile): license generation works with filtered installs by @Yash-Singh1 in pingdotgg/t3code#18127 * fix(mobile): image-only messages ask the agent to respond, like desktop by @whoisaldo in pingdotgg/t3code#16480 ## New Contributors * @Maseeek made their first contribution in pingdotgg/t3code#17530 * @TanJeeSchuan made their first contribution in pingdotgg/t3code#17706 * @fixfon made their first contribution in pingdotgg/t3code#17766 * @id0Sch made their first contribution in pingdotgg/t3code#16143 * @raphaelpra made their first contribution in pingdotgg/t3code#15240 * @Fluffy-Bunny-23 made their first contribution in pingdotgg/t3code#14475 * @arhammahajan made their first contribution in pingdotgg/t3code#16019 * @connwalk made their first contribution in pingdotgg/t3code#17499 * @abdelrhmanehab10 made their first contribution in pingdotgg/t3code#11005 * @AdEx-Partners-DE made their first contribution in pingdotgg/t3code#17938 * @wellorbetter made their first contribution in pingdotgg/t3code#14178 * @freddy-d made their first contribution in pingdotgg/t3code#16869 * @Furox-Art made their first contribution in pingdotgg/t3code#16838 * @RustedAperture made their first contribution in pingdotgg/t3code#16325 * @sheehanmunim made their first contribution in pingdotgg/t3code#17080 * @realhasanshoaib made their first contribution in pingdotgg/t3code#14543 * @whoisaldo made their first contribution in pingdotgg/t3code#16480 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261011.2955...v0.0.46-nightly.20261011.2967 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261011.2967
github-actions Bot
added a commit
to davidvanderklay/t3code-flake
that referenced
this pull request
Oct 11, 2026
## What's Changed * perf(server): drive shell last-error lookup from thread bindings by @only21mil in pingdotgg/t3code#17842 * perf(server): skip parsing plain terminal history output by @StiensWout in pingdotgg/t3code#17179 * perf(server): batch terminal history writes every 250 ms by @StiensWout in pingdotgg/t3code#17183 * perf(server): storage cleanup no longer runs a full status or size walk for worktrees it keeps by @tris203 in pingdotgg/t3code#17911 * perf(usage): usage scans skip OpenCode legacy messages older than the window by @tris203 in pingdotgg/t3code#17254 * perf(usage): OpenCode legacy walk stats entries before checking for symlinks by @tris203 in pingdotgg/t3code#17638 * fix(web): MCP app permission prompts no longer overflow the screen by @juliusmarminge in pingdotgg/t3code#17962 * feat(provider-antigravity): support subscription quota and usage limits by @Maseeek in pingdotgg/t3code#17530 * fix(desktop): keep generated annotation styles in sync by @t3-code[bot] in pingdotgg/t3code#17838 * fix(web): Resume continues on the model picked in the composer by @akbarakma in pingdotgg/t3code#17867 * fix(devices): bump agent-device to 0.21.24 for native Windows hosts by @TanJeeSchuan in pingdotgg/t3code#17706 * fix(web): keybinding group headings no longer touch the group above by @fixfon in pingdotgg/t3code#17766 * feat(web): configure OpenTelemetry exports in diagnostics by @MatthewFeroz in pingdotgg/t3code#12538 * docs: update user count to 500k by @Kamkmgamer in pingdotgg/t3code#17783 * fix(mobile): working pill no longer bulges on its right end by @id0Sch in pingdotgg/t3code#16143 * perf(opencode): stop retaining every message of a loaded OpenCode thread by @tris203 in pingdotgg/t3code#17784 * fix(web): switch thumbs stay in their track while scrolling by @raphaelpra in pingdotgg/t3code#15240 * fix(keybindings): thread jumps no longer overlap model picker jumps by @Fluffy-Bunny-23 in pingdotgg/t3code#14475 * fix(mobile): restore QR scanning in iPad pairing sheet by @arhammahajan in pingdotgg/t3code#16019 * fix(server): delegated Muse tasks no longer ask approval for every command by @t3dotgg in pingdotgg/t3code#18065 * fix(codex): prevent unsupported agent history in ChatGPT sharing by @connwalk in pingdotgg/t3code#17499 * fix(server): disabled providers stop checking for CLI updates by @yordis in pingdotgg/t3code#16772 * fix(mobile): round Android queued message sheet corners by @PixPMusic in pingdotgg/t3code#14934 * fix(ssh): record the archive lock owner's real PID by @Gigioxx in pingdotgg/t3code#14598 * fix(desktop): keep annotation comment direction independent of host page by @abdelrhmanehab10 in pingdotgg/t3code#11005 * fix(ssh): qualify runner script builders in tunnel test by @juliusmarminge in pingdotgg/t3code#18078 * fix(web): keep thread links open until the shell is live by @saphid in pingdotgg/t3code#14697 * fix(web): scope PR title collapse to tab scrollers by @Adamulek123 in pingdotgg/t3code#14644 * fix(server): detect fork PRs for branches without upstreams by @Adamulek123 in pingdotgg/t3code#13894 * fix(search): find threads by their branch PR number by @tris203 in pingdotgg/t3code#14658 * feat(web): show Claude workflow phases and members in Lineage by @Bil0000 in pingdotgg/t3code#12598 * fix(mobile): round Android Agents sheet corners by @PixPMusic in pingdotgg/t3code#14925 * fix(web): the Usage page sends a signed-out browser to pairing by @AdEx-Partners-DE in pingdotgg/t3code#17938 * fix(server): OpenCode 2 continuations end after a reconnect took a Stop's end by @juliusmarminge in pingdotgg/t3code#14744 * fix(server): OpenCode 2 continuations replay only their own background reply by @juliusmarminge in pingdotgg/t3code#14752 * fix(server): ACP reapplies a model after a switch away from it failed partway by @juliusmarminge in pingdotgg/t3code#14723 * fix(web): focus settings search with command-f by @extoci in pingdotgg/t3code#17859 * fix(mobile): keep Android project paths on one line by @wellorbetter in pingdotgg/t3code#14178 * fix(web): unpin preview dragging on narrow chat canvases by @MatthewFeroz in pingdotgg/t3code#15556 * fix(web): thread details toggle no longer covers the thread title on Windows desktop by @freddy-d in pingdotgg/t3code#16869 * fix(server): a directory no longer resolves as the resource monitor binary by @Furox-Art in pingdotgg/t3code#16838 * fix(server): a Claude usage limit no longer resets the context meter to 0% by @Vantrongs in pingdotgg/t3code#16394 * fix(server): GitLab merge requests can expand unchanged lines by @ScottN-PV in pingdotgg/t3code#17528 * fix(provider-cursor): a skill tree deeper than the scan limit no longer hides every skill by @ScottN-PV in pingdotgg/t3code#17389 * fix(web): pass hex theme colors to HTML renders by @RustedAperture in pingdotgg/t3code#16325 * fix(web): align the API estimate info icon by @RakshithBhat03 in pingdotgg/t3code#15655 * test(server): ACP teardown tests pass on Windows hosts by @sheehanmunim in pingdotgg/t3code#17080 * fix(server): sync device tool license versions with installer pins by @Yash-Singh1 in pingdotgg/t3code#18121 * fix: sync model favorites and visibility across clients by @jakeleventhal in pingdotgg/t3code#16816 * chore(deps-dev): bump compression from 1.8.1 to 1.8.2 in the npm_and_yarn group across 1 directory by @dependabot[bot] in pingdotgg/t3code#16309 * fix(server): update fff to stop runaway watcher rescans by @realhasanshoaib in pingdotgg/t3code#14543 * fix(mobile): license generation works with filtered installs by @Yash-Singh1 in pingdotgg/t3code#18127 * fix(mobile): image-only messages ask the agent to respond, like desktop by @whoisaldo in pingdotgg/t3code#16480 ## New Contributors * @Maseeek made their first contribution in pingdotgg/t3code#17530 * @TanJeeSchuan made their first contribution in pingdotgg/t3code#17706 * @fixfon made their first contribution in pingdotgg/t3code#17766 * @id0Sch made their first contribution in pingdotgg/t3code#16143 * @raphaelpra made their first contribution in pingdotgg/t3code#15240 * @Fluffy-Bunny-23 made their first contribution in pingdotgg/t3code#14475 * @arhammahajan made their first contribution in pingdotgg/t3code#16019 * @connwalk made their first contribution in pingdotgg/t3code#17499 * @abdelrhmanehab10 made their first contribution in pingdotgg/t3code#11005 * @AdEx-Partners-DE made their first contribution in pingdotgg/t3code#17938 * @wellorbetter made their first contribution in pingdotgg/t3code#14178 * @freddy-d made their first contribution in pingdotgg/t3code#16869 * @Furox-Art made their first contribution in pingdotgg/t3code#16838 * @RustedAperture made their first contribution in pingdotgg/t3code#16325 * @sheehanmunim made their first contribution in pingdotgg/t3code#17080 * @realhasanshoaib made their first contribution in pingdotgg/t3code#14543 * @whoisaldo made their first contribution in pingdotgg/t3code#16480 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261011.2955...v0.0.46-nightly.20261011.2967 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261011.2967
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A storage cleanup sweep that removes nothing still costs about a minute on an install with a few dozen worktrees (#17814). Two things in
cleanWorktreesaccount for roughly two thirds of it:git.statusDetailsLocalis called per worktree only to readisRepoandbranch, but it runsgit status, a numstat diff and an ahead count.localChangesReasonruns the real dirty check straight after, and the heavy call is repeated before removal. In one measured 54.5 s sweep this was 21.4 s across 78 calls.measureWorktreewalks the whole worktree before the checks that most often cancel a removal. A worktree kept as "Provider session is still open" is fully walked on every sweep and then kept. About 16 s of the same sweep, for three worktrees.Expected: a sweep that removes nothing costs little more than a cheap branch read and one dirty check per worktree, and a worktree is not measured when it is about to be kept.
Change
One file,
apps/server/src/storageCleanup.ts, plus its test.statusDetailsLocalcalls are replaced by a localbranchChangedhelper that makes two small Git reads:rev-parse --git-path indexandsymbolic-ref --quiet HEAD. It keeps what the old call decided for cleanup: a non-repository, a missing directory or a detached HEAD is "Repository or branch changed", and a locked index is still a failure with the same message. No existingGitVcsDrivermethod fits; the only cheap branch read in the driver is internal and cached.measureWorktreeas well as after it. Running it first is what stops the wasted walk. It still runs afterwards because turn start does not take the workspace lease, so that recheck is the only thing that cancels a removal when a thread starts during the walk; the existing test "keeps a worktree when its thread starts during size measurement" covers this and is unchanged. The cost is one extra thread read and one or two queries, only for a worktree that reaches measurement.Not included, deliberately:
The kept or removed outcome and its reason are meant to be unchanged. One known difference: when Git itself fails for another reason (for example invalid config), the entry is still
failed, but the detail is now Git's own first error line rather than "Git status failed.", since no status runs any more.Scope and approval
Fixes #17814, which I reported with trace measurements from my own install. It has not been triaged by a maintainer yet, so this PR does not have that prerequisite and I understand it may wait on it. It is a performance fix for one problem (the cost of a sweep that removes nothing), with no intended behavior change.
Verification
Established from
server.trace.ndjsonspans on a Linux desktop host (about 160 worktrees, 7 projects); the table and span order are in #17814.Focused checks on Linux, on this branch:
vp test run apps/server/src/storageCleanup.test.tsstorageCleanup.tsrestored frommainvp linton the two filesvp run --filter t3 typecheckNew tests:
mainthis fails because the walk happens.(feature), and a broken.gitfile are all kept as "Repository or branch changed"; a locked index fails with "Git index is locked"; tags namedfeatureandHEADdo not stop the removal. It then assertsstatusDetailsLocalwas never called. Onmainevery outcome above is the same and only that last assertion fails (7 calls), which is the evidence that the cheap read decides the same way.Git processes spawned by one sweep of the single-worktree test fixture, counted with a logging
gitshim onPATH, fixture setup subtracted:mainNot checked:
Claude Opus 5.5 in Claude Code, running in T3 Code. Reviewed in four rounds by GPT-6.1-Sol in Codex.