Repository navigation
fix(projects): refuse a folder-to-Git type change that would hide folder workspaces - #29257
Conversation
…der workspaces (STA-10638) A folder project's extra workspaces exist only as metadata rows that the folder listing shows. Changing the project to Git switches it to `git worktree list`, so those workspaces drop out of the next refresh and their saved tabs are purged as if they had been deleted. Only the automatic upgrade checked for this; `orca project setup-update --kind git`, repo updates and clone-into-folder did not. The check now lives in the one repo write every type change goes through, so any caller gets the same refusal and nothing is written. The automatic upgrade and both clone paths use the same check and keep the project as a folder project.
|
Changing a folder project to Git could hide its extra workspaces on refresh, causing Orca to clear their saved terminal and chat tabs. This PR refuses that change before writing when extra folder workspaces exist. Automatic detection and successful clones retain folder mode instead. Review completed on
For Brennan’s review Main before conversion: Main after full reload; the first-run dialog obscures the center, while the saved session and renderer snapshot confirm both tabs and workspace rows were lost: Branch after refused conversion and full reload: Branch after real Git worktree creation and another full reload: Human judgment points: the refusal and actionable message, successful clone retaining folder mode, and membership matching the current folder catalog. The catalog remains a temporary difference from the common pattern pending the separate product decision. The retained folder behavior is intended. |
…lone path now uses
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to
|
…der workspaces (#29257) * fix(projects): refuse a folder-to-Git type change that would hide folder workspaces (STA-10638) A folder project's extra workspaces exist only as metadata rows that the folder listing shows. Changing the project to Git switches it to `git worktree list`, so those workspaces drop out of the next refresh and their saved tabs are purged as if they had been deleted. Only the automatic upgrade checked for this; `orca project setup-update --kind git`, repo updates and clone-into-folder did not. The check now lives in the one repo write every type change goes through, so any caller gets the same refusal and nothing is written. The automatic upgrade and both clone paths use the same check and keep the project as a folder project. * test(repos): give the repo handler store mock the metadata read the clone path now uses (cherry picked from commit 6a76068)




ELI5
A project in Orca is either a plain folder or a Git repository. A folder project can hold several workspaces that all share the same directory. Switching such a project to Git made those extra workspaces disappear, and Orca then wiped their saved tabs as if they had been deleted. Now Orca refuses that switch and says why, so nothing is lost.
What Changed
The bug a user hit. They had a folder project with several named workspaces in a directory that was already a Git repo, and ran
orca project setup-update --setup <id> --kind git. The CLI immediately stopped listing the old workspaces. The desktop showed them for a while, then they vanished, and 12 saved tabs (11 terminals and one Codex chat) were cleared. Their names survived; the conversations survived on disk; the tab layout did not.Why it happened. Which workspaces a project has is worked out from its type every time Orca lists them. A folder project lists its extra workspaces from saved metadata rows; a Git project lists only what
git worktree listreturns, which never includes those rows. When a refreshed list stops showing a workspace, Orca treats that as "the workspace was deleted" and clears its tabs. That cleanup is right for real deletions; the problem is that changing the type silently removed live workspaces from the list.Six places can change a project's type. The automatic upgrade (which notices a
git initin a folder project) already refused when extra workspaces existed. The other five did not: thesetup-updatecommand the user ran, the general repo update over IPC and over the runtime protocol, and the two "clone into an existing folder project" paths.The change. The check moved into the one function every type change goes through (
updateRepo). Changing a folder project to Git while it has other workspaces is refused before anything is written, with: "This folder project has N other workspaces that a Git project can't show, so its type was not changed. Delete those workspaces first, or keep it as a folder project." The automatic upgrade and both clone paths use the same check and simply keep the project as a folder project, so a finished clone never fails on this.What you see. Before:
setup-update --kind gitsucceeds, and the extra workspaces and their tabs are gone after the next refresh. After: the command fails with the message above and the project, its workspaces and their tabs are untouched. A folder project with only its main workspace still converts as before.Why
The precise cause is that the "would this hide workspaces?" decision lived in one of six callers instead of at the write, so every new caller could bypass it. This is the third bug in this mechanism (#20653 and #26791 each fixed it for the automatic upgrade only). Putting the check at the write means a future caller can't skip it.
Alternatives considered:
git worktree remove, branch and PR linking) would need to learn about it. That is a product decision, so it is not in this PR.Follow-ups planned as separate stacked PRs: the same refusal for Git to folder when linked Git worktrees have saved tabs, and making every manual folder-to-Git change prove the folder is the Git root (as the automatic upgrade does) so the main workspace keeps its id.
Projects already converted. Their tabs were already cleared before this fix. Source review shows Session History matches sessions by folder, not by workspace id, so it should list the old conversations under the project for resuming into a workspace. Recovery with a real signed-in agent was not exercised in this QA run.
Linked Issue
Linear STA-10638
Visual Proof
Remote M4Air Electron QA at
e5d3537866acf1a1bfb01222e0fe341c2bb47b87passed the reported data-loss scenario. The real setup-update command refused with the expected two-workspace message. Both original folder workspace IDs, both terminal tab IDs, sidebar order and active workspace/tab survived a full renderer reload, real Git worktree creation, and a second full reload. The main comparator atf670683b22503e7543e5a375050a0fa904d4bd18accepted the conversion and then cleared both saved tabs on full reload. The coordinator inspected screenshots and saved-session evidence. Ordinary folder-project creation succeeded; that root-only project ended in Git mode and accepted an explicit Git setup write, although the automatic watcher may have converted it before the command. The real-store test separately covers direct root-only conversion. All owned remote rigs, scratch worktrees and terminals have been removed.Testing
updateProjectHostSetupwithkind: 'git'): refused with the message and nothing written while a folder workspace exists; converts once it is removed.Review
One adversarial review round, architecture challenge, independent candidate validation, and final readiness/performance review found no confirmed in-scope production fixes. The author’s two-line test-harness mock addition at
e5d3537866acf1a1bfb01222e0fe341c2bb47b87was checked separately; production code is unchanged from the reviewed head. Deferred concerns: conservative duplicate-host refusal while desktop and runtime catalogs disagree about ownership, and clone messaging that does not explain retained folder mode.The exact-head PR Checks workflow passed, including static analysis/typecheck, all five test shards, packaging and selection evidence. Three targeted test files passed on M4Air, 51 tests total. The workflow’s aggregate gate intentionally skips its runner on the successful fast path; all selected jobs passed. Remote QA and cleanup are complete. The fresh ready-for-review PR workflow and headless workflow also passed on this unchanged head, including all six persistence platforms and Linux binary compatibility checks. Clone completion was source-reviewed but not exercised in rendered QA. Session History recovery was not tested with a signed-in agent.
Agent skill upstream boundary
Notes
updateIndependentProjectHostSetupalso sets a type, but on a setup with no project directory registered yet, so there are no workspaces to hide; intentionally unchanged.Checklist
Author: @BrennanKB5