Repository navigation
fix(server): storage cleanup skips stale worktree paths under a regular file - #26594
Conversation
…r a regular file Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A stored worktree path whose ancestor is now a regular file makes access() fail with ENOTDIR, which surfaced as a "failed" report entry on every pass. Treat ENOTDIR like a missing path; every other error still fails. Fixes #26585 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Storage cleanup now skips stale worktree paths beneath regular files instead of treating ENOTDIR as an existence-check failure. Cleanup policies and safeguards for existing worktrees remain unchanged. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
…ar file (upstream pingdotgg#26594) Cherry-picked from pingdotgg#26594 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The automated pipeline stopped on this pull request and will not merge it: someone else pushed to fix/issue-26585 (head is now d7cfd98); the pipeline does not build on commits it did not review It stays open for a person to finish or close. |
EvidenceCreate retained and archived conversations with stored worktree paths beneath a disposable root. Stop the app, replace that root with a regular file, restart, enable inactive-worktree cleanup, then select Settings → Maintenance → Delete now and expand Last run. Both captures use Chromium at 1280×800 with the light theme and fresh synthetic data. Displayed fixture paths are redacted; report counts, errors, titles, and server behavior are unchanged.
Reproduction driver and seed scripts · Preservation results Base reports both stale candidates as BadResource failures. Head omits both and emits no storage-cleanup failure warning. Both conversations and the parent file survive on both sides. AI-assisted; verified with the tests and tools listed above. Not shown:
|
**v0.1.10-nightly.20261111.4529** · 54 changes from 29 contributors - **Find in browser.** Search pages in the desktop integrated browser with Cmd+F or Ctrl+F. - **GitLab overview threads.** Resolve merge request overview threads from Summary and Timeline. - **Faster worktree updates.** Checkpoint captures and status refreshes avoid rereading every file in newly created worktrees. - **Imported session history.** Imported agent sessions now show their existing history instead of opening as empty threads. - **SSH reconnect prompts.** Expired SSH verification prompts no longer stack up and force an app restart. - **Large reasoning traces.** Opening a thread with a large collapsed reasoning trace no longer freezes the app. - **Terminal scrollback.** Terminal history retains substantially more output instead of silently discarding older lines. ### Plus 45 more bug fixes and performance improvements. <details> <summary>Full changelog</summary> ## What's Changed * fix(server): new worktrees refresh their index once, so captures and status stop re-hashing every file by @josephv123 in pingdotgg/t3code#21341 * fix(usage): Grok and Cursor usage limits show pace and the even-spend line by @wookiist in pingdotgg/t3code#21897 * fix(web): retain diff selection across navigation by @aleo113 in pingdotgg/t3code#22347 * fix(mobile): subscription widget no longer expires on a window that already reset by @juliusmarminge in pingdotgg/t3code#22993 * fix(opencode): verify CLI updates when loopback server is still running by @intrepid37 in pingdotgg/t3code#22839 * fix(usage): Claude subagent output is no longer undercounted by @rfrost-xyz in pingdotgg/t3code#20276 * fix(server): a remote update points the service unit at the runtime it committed by @Marve10s in pingdotgg/t3code#19652 * fix(server): a limited provider's queue stays held after another provider's turn succeeds by @Marve10s in pingdotgg/t3code#22425 * fix(shared): keep spreadsheet shorthand as inline code by @juliusmarminge in pingdotgg/t3code#23203 * fix(web): offer retry while an environment reconnects by @juliusmarminge in pingdotgg/t3code#23194 * fix(server): custom Codex providers no longer report native quota by @fixfon in pingdotgg/t3code#18622 * fix(desktop): Cmd+F now searches the page in the integrated browser by @armanarutiunov in pingdotgg/t3code#22960 * fix(desktop): an SSH password prompt that ended leaves the dialog instead of stacking by @Umais-Adeed in pingdotgg/t3code#34192 * fix(web): render Claude insight blocks as a callout by @macodev00 in pingdotgg/t3code#22239 * fix(scheduler): show short server timezone on fixed-time labels by @shawk08033 in pingdotgg/t3code#23111 * fix(web): focus the primary action when confirmation dialogs open by @rgrvlsk in pingdotgg/t3code#18187 * fix(web): Changes row matches the diff comparison by @whoisaldo in pingdotgg/t3code#19553 * fix(server): imported ACP sessions show their native history by @only21mil in pingdotgg/t3code#22155 * fix(preview): always return evaluated results by value by @juliusmarminge in pingdotgg/t3code#22948 * fix(provider-core): a model reply of "title" no longer replaces the thread title by @juliusmarminge in pingdotgg/t3code#25743 * fix(desktop,web): Open in runs locally for a background service sharing the desktop's T3 home by @KinanLak in pingdotgg/t3code#21661 * fix(web): question answers submit while normal sends are blocked by @t3dotgg in pingdotgg/t3code#22874 * fix(server): cancelling a background-only delegated task reports it interrupted by @only21mil in pingdotgg/t3code#21676 * fix(web): fall back to a readable server for shared repositories by @sanjaibalajee in pingdotgg/t3code#21530 * fix(web): composer follows an optionless thread instead of the settings default by @f4llenz in pingdotgg/t3code#16546 * fix(web): don't save retention age until committed by @macodev00 in pingdotgg/t3code#22208 * fix(server): one dropped probe no longer lists a live linked peer as unreachable by @juliusmarminge in pingdotgg/t3code#34208 * fix(server): preview automation reports ambiguous selectors instead of calling them invalid by @juliusmarminge in pingdotgg/t3code#34205 * fix(opencode): a context overflow that OpenCode compacts no longer fails the turn by @juliusmarminge in pingdotgg/t3code#26743 * fix(web): Ctrl + "+" zooms on keyboard layouts with a dedicated plus key by @juliusmarminge in pingdotgg/t3code#26408 * fix(ci): release version bump push retries when main moves by @t3dotgg in pingdotgg/t3code#34326 * fix(server): CLI commands no longer migrate the database of a running server by @juliusmarminge in pingdotgg/t3code#26763 * fix(web): keep saved default model when changing effort by @macodev00 in pingdotgg/t3code#22193 * fix(web): reveal expanded work rows hidden behind the composer by @ln-bodicherla in pingdotgg/t3code#21968 * fix(composer): steer instead of queueing during automatic compaction by @NikitaMGrimm in pingdotgg/t3code#24138 * feat(gitlab): resolve overview threads from Summary and Timeline by @TonybynMp4 in pingdotgg/t3code#30575 * fix(web): pull request search keeps partial-word matches after GitHub answers by @juliusmarminge in pingdotgg/t3code#26992 * fix(server): Claude subagents no longer show the parent's effort by @juansuaya17 in pingdotgg/t3code#17042 * fix(server): runs cancelled by a server restart say why in the thread by @juliusmarminge in pingdotgg/t3code#27192 * fix(client-runtime): server updates stop waiting 32 minutes when the host returns without this update's outcome by @juliusmarminge in pingdotgg/t3code#27275 * fix(web): Stop shows a pending state and repeat clicks no longer resume by @voida6 in pingdotgg/t3code#20809 * fix(web): collapsed reasoning previews no longer process the whole block by @juliusmarminge in pingdotgg/t3code#23001 * fix(server): storage cleanup skips stale worktree paths under a regular file by @juliusmarminge in pingdotgg/t3code#26594 * fix(terminal): use a byte budget for Ghostty scrollback by @zero-two-rafaeltab in pingdotgg/t3code#8766 * fix(server): storage cleanup keeps worktrees whose file listing exceeds the inspection limit by @juliusmarminge in pingdotgg/t3code#26593 * fix(server): delete temporary ACP health probe sessions by @juliusmarminge in pingdotgg/t3code#25397 * perf(client): streamed text no longer republishes thread queue and checkpoints by @juliusmarminge in pingdotgg/t3code#27425 * fix(web): convert composer list markers completed later by @juliusmarminge in pingdotgg/t3code#22997 * test: remove tests that repeat another case or restate the source by @shivamhwp in pingdotgg/t3code#34170 * fix(server): drop stale queued pull-request watch wakes by @Sinan53x in pingdotgg/t3code#21239 * fix(web): preview recordings stay decodable after a viewport resize by @MansTomb in pingdotgg/t3code#10495 * fix(server): only offer claude update for native Claude installs by @AI091 in pingdotgg/t3code#14170 * fix(server): tell outside agents which MCP tools need a thread and that t3_thread_list takes allProjects by @juliusmarminge in pingdotgg/t3code#26525 ## New Contributors * @wookiist made their first contribution in pingdotgg/t3code#21897 * @aleo113 made their first contribution in pingdotgg/t3code#22347 * @intrepid37 made their first contribution in pingdotgg/t3code#22839 * @rfrost-xyz made their first contribution in pingdotgg/t3code#20276 * @armanarutiunov made their first contribution in pingdotgg/t3code#22960 * @KinanLak made their first contribution in pingdotgg/t3code#21661 * @sanjaibalajee made their first contribution in pingdotgg/t3code#21530 * @ln-bodicherla made their first contribution in pingdotgg/t3code#21968 * @juansuaya17 made their first contribution in pingdotgg/t3code#17042 * @zero-two-rafaeltab made their first contribution in pingdotgg/t3code#8766 * @MansTomb made their first contribution in pingdotgg/t3code#10495 * @AI091 made their first contribution in pingdotgg/t3code#14170 **Full Changelog**: pingdotgg/t3code@v0.1.9-nightly.20261111.4515...v0.1.10-nightly.20261111.4529 </details> Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.1.10-nightly.20261111.4529


Problem
Storage cleanup reports a thread as
failedon every pass when its stored worktree path sits below something that is now a regular file.fs.existsmaps only ENOENT tofalse.access()on a path under a file fails with ENOTDIR, which Effect maps toBadResource, so the error propagates and the entry becomesBadResource: FileSystem.access (<path>). The reporter had 467 of these stale legacy paths filling the report. A missing path (ENOENT) is already skipped quietly.Reproduced on main 30eb7e7 with the real server (
bin.ts serveon a fresh base dir,worktreeAfterDays: 30). One thread's storedworktreePathwas<base>/legacy-root/stored-workspace, wherelegacy-rootis a file, and a control thread's was<base>/missing-root/stored-workspace.server.runStorageCleanupreturnedfailed: 1for the ENOTDIR thread and nothing for the ENOENT one, for both archived and unarchived threads.Change
The worktree pass's first existence check now treats a
PlatformErrorwhosecause.codeisENOTDIRas "does not exist". It reuses thecatchIferrno pattern this file already uses forEINVAL. Nothing can exist below a regular file, so the candidate is skipped like a missing path. Every other error, including otherBadResourcecauses andEACCES, still fails as before. No thread data or history is changed.Scope and approval
Fixes #26585
Verification
storage cleanup reports and local file policies > skips a stored worktree path whose parent is a regular fileinapps/server/src/storageCleanup.test.ts.outcome: "failed",reason: "BadResource: FileSystem.access (…/legacy-root/stored-workspace)".vp run check:changedpasses: format, lint, knip, typecheck and tests.failed: 1with the BadResource entry, plus a server-log warning showingcode: 'ENOTDIR'.failed: 0, no entries, no warning.Model and harness: Claude Opus 5.5 (lead, test, fix, review B) and GPT-6.1 Sol (review A), run through Claude Code and Codex in T3 Code.
🤖 Generated with Claude Code