Skip to content

fix(projects): refuse a folder-to-Git type change that would hide folder workspaces - #29257

Merged
brennanb2025 merged 2 commits into
mainfrom
brennan/sta-10638-bug-folder-to-git-conversion-leaves-old-workspaces-orphaned
Oct 16, 2026
Merged

brennanb2025 merged 2 commits into
mainfrom
brennan/sta-10638-bug-folder-to-git-conversion-leaves-old-workspaces-orphaned

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​22 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​21
Prod 6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​57 $\color{#cf222e}{\Huge{\mathbf{−}}}$​16 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​41

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 list returns, 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 init in a folder project) already refused when extra workspaces existed. The other five did not: the setup-update command 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 git succeeds, 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:

  • Keep listing folder workspaces after the switch to Git (keep each workspace's identity independent of whether the project is Git, the common pattern). That would also bring back workspaces for projects already converted, but it adds a new kind of workspace to Git projects (several workspaces sharing the main checkout), and many Git-only actions (delete runs 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.
  • Stop the tab cleanup from acting on these ids. That would leave tabs belonging to workspaces nobody can open.

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 e5d3537866acf1a1bfb01222e0fe341c2bb47b87 passed 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 at f670683b22503e7543e5a375050a0fa904d4bd18 accepted 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.

Main before conversion

Main after full reload, with first-run dialog obscuring part of the view

Branch after refused conversion and full renderer reload

Branch after real Git worktree creation and second full renderer reload

Testing

  • One real-store test drives the reported path (updateProjectHostSetup with kind: 'git'): refused with the message and nothing written while a folder workspace exists; converts once it is removed.
  • Existing tests for the automatic upgrade cover the watch's unchanged behavior.
  • Manually tested on a remote M4Air Electron rig; no local Electron test copy
  • Automated tests added/updated, or explained why not below

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 e5d3537866acf1a1bfb01222e0fe341c2bb47b87 was 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

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Intended behavior: a successful clone into an existing folder project with extra workspaces leaves it in folder mode, with folder workspace creation and without Git-only branch features. The files were cloned; the saved project type is preserved to retain its workspaces.
  • Temporary difference from the common pattern: workspace membership still depends on project type. This PR refuses the known destructive transition under that existing model. Listing shared-checkout workspaces inside Git projects remains a separate product decision.
  • Cross-host: the check runs inside the updated store that owns the project. No new saved field and no wire change; older clients see the refusal as an ordinary error message. A paired server that has not updated still runs the old behavior and remains vulnerable until updated; there is no minimum server version.
  • updateIndependentProjectHostSetup also sets a type, but on a setup with no project directory registered yet, so there are no workspaces to hide; intentionally unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after remote Electron screenshots attached
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • Full exact-head PR workflow passed, including lint/typecheck, all five test shards and packaging; 51 targeted tests also passed remotely

Author: @BrennanKB5

…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.
@brennanb2025

brennanb2025 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

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 e5d3537866acf1a1bfb01222e0fe341c2bb47b87: one adversarial round, architecture challenge, independent candidate validation, and readiness/performance review required no production fix. The author’s follow-up adds the missing test mock method; both added lines were reviewed. No review-agent commit or push was needed.

  • Final CI: the fresh PR workflow and headless workflow both passed on this unchanged head, including all six persistence platforms and Linux binary compatibility checks.
  • Verified: exact-head full PR workflow passed; three named remote test files passed 51 tests. No conflicts or unresolved review threads.
  • Remote Electron QA: the real command refused with the expected two-workspace message. Both original workspace IDs, both terminal tab IDs, sidebar order, and active workspace/tab survived a full renderer reload, a real Git worktree creation, and a second reload. The entire saved terminal-tab structure matches the baseline. Main accepted the same command and cleared both tabs and active selection after reload. Whole-window screenshots and saved state were inspected.
  • Nearby checks: ordinary folder-project creation and real Git worktree creation succeeded. A newly created root-only folder project ended in Git mode and accepted an explicit Git setup write; the CLI was not proven to initiate that conversion because the watcher could act first. The real-store test separately verifies root-only explicit conversion. Clone completion was source-reviewed, not exercised in rendered QA. Session History recovery was not tested with a signed-in agent.
  • Deferred: duplicate identities across hosts can conservatively refuse conversion while catalogs disagree about ownership; narrowing only this guard is unsafe. Clone success does not explain retained folder mode. No new saved fields or wire changes; older unupdated owning servers retain the old bug until updated.
  • Cleanup: all owned remote rigs, scratch worktrees and terminals were removed; final-run real config hashes matched after all owned app processes exited. All review workers are settled and released.
  • Scope: Git-to-folder refusal and manual Git-root proof remain separate follow-ups. Keeping shared-checkout folder workspaces inside Git projects remains a product decision; this PR does not implement it.

For Brennan’s review

Main before conversion:

Main before conversion with two extra folder workspaces

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:

Main after full reload

Branch after refused conversion and full reload:

Branch preserves both folder workspaces and terminal tab

Branch after real Git worktree creation and another full reload:

Branch preserves both folder workspaces after worktree creation and 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.

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4bdf5540-76fd-4c62-9287-d7c5bbb6390e
📥 Commits

Reviewing files that changed from the base of the PR and between 0fea878 and e5d3537.

📒 Files selected for processing: 8
  • src/main/folder-workspace-meta-presence.ts
  • src/main/ipc/folder-repo-git-upgrade.ts
  • src/main/ipc/repos-remote-test-harness.ts
  • src/main/ipc/repos/repo-clone-lifecycle.ts
  • src/main/persistence-update-repo.test.ts
  • src/main/persistence/tracking-repos/repo-update-host-guard.test.ts
  • src/main/persistence/tracking-repos/repo-update-operations.ts
  • src/main/runtime/runtime-repository-clone-controller.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

📝 Walkthrough

A shared helper identifies extra folder workspace IDs from repository metadata. The IPC detection path, persistence kind-change guard, and two clone upgrade paths use this check before changing a folder repo to Git. Tests cover rejection when extra workspace metadata exists and success after that metadata is removed.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to e5d35

No actionable blocker is established; the folder-workspace protection is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title is concise, specific, and accurately describes the primary change: preventing folder-to-Git conversions that would hide folder workspaces.
Description check Passed The description is complete and relevant. It covers the user impact, implementation, rationale, linked issue identifier, visual proof, testing, review findings, compatibility notes, and checklist stat…
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@brennanb2025
brennanb2025 merged commit 6a76068 into main Oct 16, 2026
61 checks passed
brennanb2025 added a commit that referenced this pull request Oct 16, 2026
…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)
@brennanb2025
brennanb2025 deleted the brennan/sta-10638-bug-folder-to-git-conversion-leaves-old-workspaces-orphaned branch October 16, 2026 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant