[Bug]: Orphaned workspaces are never swept — test-products for deleted project paths persist forever (126 GB past max age)
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 48/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- devtools
調査の方向性
まず pruneManagedTestProductsDirectory、workspace のライフサイクルのクリーンアップ、サーバー起動パスを見つけ、TEST_PRODUCTS_MAX_AGE_MS と TEST_PRODUCTS_MAX_COUNT がどのように適用されているかを確認します。プロジェクトパスが削除された孤立した workspace のケースを再現し、その後、各パスにサーバーを必要とせずに、古い workspace データが複数の workspace にわたって回収または上限管理されることを確認します。
索引モデルが issue の本文から書いたものです。
説明
Bug Description
~/Library/Developer/XcodeBuildMCP/workspaces reached 143 GB on my machine — 285 .xctestproducts bundles across 391 workspace directories, with 141 GB of that under */test-products/. It was the single largest consumer on a ~1 TB disk that had run down to its last 96 GB.
This is adjacent to #524, but I believe it is a distinct root cause, and the retention knobs proposed there would not reclaim any of this space.
A workspace is keyed by its project path, and it is never garbage-collected when that path stops existing. pruneManagedTestProductsDirectory only sweeps while a server is active for that workspace (with a 1 h cooldown). In agent-driven workflows that create and delete a git worktree per task, the worktree path is gone permanently once the task finishes — so no server ever starts for that workspace again, and neither TEST_PRODUCTS_MAX_AGE_MS nor TEST_PRODUCTS_MAX_COUNT is ever evaluated against its bundles. They become effectively immortal.
Evidence that the sweep never runs for these workspaces
| Bundle age | Bundles | Size |
|---|---|---|
> 3 days (TEST_PRODUCTS_MAX_AGE_MS) |
256 | 126.4 GB |
| > 7 days | 252 | 124.4 GB |
| > 14 days | 242 | 119.4 GB |
| > 30 days | 5 | 2.4 GB |
256 bundles are past the 3-day max age and still on disk. Had the age-based sweep run for those workspaces, all of them would have been removed.
Count-based GC cannot catch this either: the largest number of bundles in any single workspace is 16, far below TEST_PRODUCTS_MAX_COUNT = 100. Every workspace is individually "under limit" while the aggregate sits at 141 GB.
The orphan ratio
A single project accounts for 223 of the 391 workspace directories. That project currently has 17 git worktrees. The remaining ~206 workspaces are keyed to worktree paths deleted weeks ago that will never be built again.
Because each workspace is separately under both thresholds, total consumption is unbounded in the number of project paths ever built, rather than in builds per path. Heavy agent/worktree use makes that number grow monotonically and silently — this accumulated over roughly three months without ever surfacing anywhere a user would normally look, since ~/Library is hidden in Finder and macOS Storage settings folds it into an undifferentiated "Developer" bucket.
Steps to Reproduce
- Use an MCP client workflow that creates a fresh git worktree per task (
git worktree add), which is the default for several coding-agent harnesses. - Have the agent call
build_sim/build_run_sim/test_siminside that worktree. - Complete the task and
git worktree removethe worktree. - Repeat across a few hundred tasks over several months.
du -sh ~/Library/Developer/XcodeBuildMCP/workspaces
A quick way to see the orphaned share on an affected machine:
WS=~/Library/Developer/XcodeBuildMCP/workspaces
# bundles past the 3-day max age that are still present
find "$WS" -mindepth 3 -maxdepth 3 -name '*.xctestproducts' -type d \
! -newermt "$(date -v-3d +%Y-%m-%d)" -print0 | xargs -0 du -sch | tail -1
# most bundles retained in any single workspace (compare against MAX_COUNT = 100)
find "$WS" -mindepth 3 -maxdepth 3 -name '*.xctestproducts' -type d \
| awk -F/ '{print $(NF-2)}' | sort | uniq -c | sort -rn | head -1
Expected Behavior
Test-product bundles belonging to a workspace whose project path no longer exists should be reclaimed. Two options that would each fix this:
- A global sweep at server start that drops workspace directories whose keyed path is missing from disk, independent of whether a server is ever active for that workspace again.
- A total-size budget across all workspaces (e.g.
XCODEBUILDMCP_TEST_PRODUCTS_MAX_TOTAL_BYTES), rather than per-workspace age/count limits that each pass individually while the aggregate grows without bound.
Actual Behavior
Every workspace ever created persists indefinitely along with its bundles. 126 GB across 256 bundles sits well past the 3-day max age, completely untouched, because the only code path that would delete it requires an active server for a directory that no longer exists.
Notes
- Each workspace does carry
state/filesystem-lifecycle/last-cleanup, so the lifecycle bookkeeping is already in place — it simply never runs again once a workspace is orphaned. - A global sweep would also help users who do not use worktrees at all but who rename, move, or delete projects over time.
- Roughly 90% of the bytes are byte-identical across bundles (unchanged third-party dependency output recopied verbatim on every build), so content-addressed storage or hardlinking would be a further large win, though it is secondary to the missing GC.
- Related: #524 (retention limits too permissive in practice), #525 (DerivedData duplication between Xcode.app and the MCP).
Debug Output
XcodeBuildMCP Doctor
Server Version: 2.7.0
## Checks
- xcode: ok Xcode 26.6 - Build version 17F113 (/Applications/Xcode.app/Contents/Developer)
- process-tree: ok Running under Xcode: No; 5 process entries
- axe: ok Available: Yes; UI automation: Yes; Video capture: Yes
- xcodemake: ok Enabled: No; Binary: No; Makefile: Not checked
- mise: warning Running under mise: No; Available: No
- debugger-dap: ok Selected backend: lldb-cli; lldb-dap available: Yes
- manifest-tools: ok Total tools: 82; Workflows: 15
- runtime-registration: ok Enabled workflows: debugging, doctor, project-discovery,
session-management, simulator-management, simulator,
ui-automation, utilities, xcode-ide; Registered tools: 58
- xcode-ide-bridge: ok Workflow enabled: Yes; Connected: No; Proxied tools: 0
- sentry: ok Enabled: Yes
Editor/Client
Claude Code (desktop app)
MCP Server Version
2.7.0
LLM
Claude Opus 5
- 主要言語
- TypeScript
- スター
- 6.4k
- フォーク
- 320
- PR マージ指標
- 30日以内にマージされた PR はありません
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
getsentry/XcodeBuildMCP のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
getsentry/XcodeBuildMCP#520 ·
-
Warden weekly sweep オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
getsentry/XcodeBuildMCP#495 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
getsentry/XcodeBuildMCP#537 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
getsentry/XcodeBuildMCP#535 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
getsentry/XcodeBuildMCP#534 ·
getsentry/XcodeBuildMCP の issue をすべて見る
似ている issue
-
blocklist removal
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
MetaMask/eth-phishing-detect#296544 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
pastelsky/bundlephobia#1122 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
-
category/development priority/P2 scope/file-operations scope/testing type/enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
Enatega Customer and Rider app: Add-ons price is not visible to customer after order is placed. オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100