Skip to content

fix(projects): keep nested workspaces out of their repository's row - #10922

Open
VIPlearner wants to merge 3 commits into
pingdotgg:mainfrom
VIPlearner:fix/nested-workspace-grouping
Open

fix(projects): keep nested workspaces out of their repository's row#10922
VIPlearner wants to merge 3 commits into
pingdotgg:mainfrom
VIPlearner:fix/nested-workspace-grouping

Conversation

@VIPlearner

@VIPlearner VIPlearner commented Sep 9, 2026

Copy link
Copy Markdown

Fixes #10930

A project is keyed by its workspace path, so two folders in one repository are two
projects. Sidebar grouping did not agree: in the default repository mode the group
key was the git remote alone, so every project sharing a remote collapsed into one row
named after the repository.

In a monorepo that row is unusable. Adding ~/code/app/services/api next to ~/code/app
produces a single owner/app row. The row targets one member, the project picker offers
one entry, and a thread started from it runs in the other folder. There is no way to aim
an agent at the folder you chose.

Repository grouping now keys on the repository and the repo-relative path. Checkouts of
one folder still share a row across environments and worktrees, which is what the
setting is for. A folder inside a repository keeps its own row.

That made repository_path behave exactly like repository, so the duplicate choice is
gone from the web sidebar dialog, Settings -> Projects, Settings -> Project defaults, and
the mobile grouping screen. The literal stays in the contract, and reading the preference
maps it onto repository, so stored preferences and per-checkout overrides still work.

A repository rooted at / or a Windows drive root already ends with its separator. The
repo-relative path check appended a second one, so no nested path matched and every
nested workspace collapsed anyway; that is fixed with tests for both root shapes.

Supersedes #8490, which diagnosed the same bug but also changed labels, search terms, and
added a setting.

Before

A demo workspace with four projects: the acme-platform monorepo, its apps/web and
services/api folders, and a separate toolbox repository. The three monorepo projects
collapse into one acme-corp/platform row, so web and api cannot be selected.

before

After

Each folder keeps its own row and is selectable. toolbox is unchanged.

after

Model: Claude Opus 5 (1M context), harness: Claude Code.

🤖 Generated with Claude Code

Repository grouping keyed the sidebar row on the git remote alone, so two
projects in one monorepo collapsed into a single row named after the
repository. That row targets one member and the project picker offers one
entry, so a thread started from it runs in a folder you did not choose.

Group keys now include the repo-relative path. Checkouts of one folder still
share a row across environments and worktrees, which is what the setting is
for. This made repository_path identical to repository, so the duplicate
choice is gone from the web and mobile pickers. The literal stays in the
contract, so stored preferences and per-checkout overrides still decode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 9, 2026
return canonicalKey;
}

const relativeProjectPath = deriveRepositoryRelativeProjectPath(project);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High state/projectGrouping.ts:113

For repositories rooted at / or a Windows drive root, nested workspaces such as /services/api receive the bare canonicalKey, so all nested projects collapse into one sidebar row. deriveRepositoryRelativeProjectPath builds a rootPrefix with a duplicate separator (// or c:\), causing the nested path check to fail; handle filesystem roots without appending another separator.

🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/projectGrouping.ts around line 113:

For repositories rooted at `/` or a Windows drive root, nested workspaces such as `/services/api` receive the bare `canonicalKey`, so all nested projects collapse into one sidebar row. `deriveRepositoryRelativeProjectPath` builds a `rootPrefix` with a duplicate separator (`//` or `c:\`), causing the nested path check to fail; handle filesystem roots without appending another separator.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 946a33e.

trimTrailingPathSeparators returns root paths unchanged, so / produced the prefix // and c:\ produced c:\\, and no nested path matched. rootPrefix now appends the separator only when the root does not already end with one.

Two tests cover it, one for / and one for a Windows drive root. Both fail against the previous rootPrefix line and pass now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

When persisted projectGroupingMode is "repository_path", no radio button is checked, so the settings screen shows grouping enabled with no selected choice. resolveMobileProjectGroupingSettings preserves this legacy value, but GROUPING_OPTIONS no longer includes it; normalize "repository_path" to "repository" before comparing or render it as the repository selection.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/settings/SettingsProjectGroupingRouteScreen.tsx around line 34:

When persisted `projectGroupingMode` is `"repository_path"`, no radio button is checked, so the settings screen shows grouping enabled with no selected choice. `resolveMobileProjectGroupingSettings` preserves this legacy value, but `GROUPING_OPTIONS` no longer includes it; normalize `"repository_path"` to `"repository"` before comparing or render it as the `repository` selection.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 946a33e.

Rather than patch the comparison in the mobile screen, the legacy value is normalized where the preference is read: selectProjectGroupingSettings on web (mode and per-checkout overrides) and resolveMobileProjectGroupingSettings on mobile both map repository_path onto repository. The pickers then only ever see the two modes that still differ, and ProjectDefaultsSettings, which reads client settings directly, normalizes its select value too.

Covered by a new client-runtime test for the selector and a mobile test for the persisted legacy value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

@macroscopeapp

macroscopeapp Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The change modifies the existing default repository-grouping behavior across web and mobile, so it affects users without opting into a new mode. Unresolved findings also identify failures for filesystem-root repositories and persisted legacy mobile preferences.

Not approved because:

  • 2 blocking correctness issues found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 05b40639-ed59-4e90-b805-b17d4ad5c628

📥 Commits

Reviewing files that changed from the base of the PR and between 946a33e and b19049d.

📒 Files selected for processing (1)
  • packages/client-runtime/src/state/projectGrouping.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change unifies repository grouping across runtime logic and settings surfaces. Nested workspaces remain separate, matching checkouts group together, and repository_path remains decodable as a legacy alias.

Changes

Repository grouping

Layer / File(s) Summary
Grouping keys and normalization
packages/client-runtime/src/state/projectGrouping.ts, packages/client-runtime/src/state/projectGrouping.test.ts, packages/contracts/src/settings.ts
Repository grouping normalizes repository_path to repository, preserves nested workspace separation, handles filesystem-root paths, and groups matching checkouts across environments.
Grouping settings and documentation
apps/web/components/..., apps/mobile/src/state/..., apps/mobile/src/features/settings/..., apps/web/src/logicalProject.ts, docs/user/project-settings.md
Web and mobile settings normalize legacy values, remove the selectable repository_path option, update labels and descriptions, and document repository grouping behavior.
Mobile grouping assertions
apps/mobile/src/features/home/homeThreadList.test.ts
Tests require Web and Mobile workspaces to remain separate across repository, repository_path, and separate modes.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to b1904

Repository grouping now keeps nested workspaces separate while preserving grouping for matching checkouts, including legacy preferences and filesystem-root repositories. No current merge-blocking risk is identified.

Suggested reviewers: maria-rcks

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 11 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 clearly summarizes the primary change: nested workspaces remain separate from their repository row.
Description check ✅ Passed The description clearly explains the problem, implementation, rationale, UI changes, compatibility behavior, and tests. It includes before-and-after screenshots. The template headings and checklist ar…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

VIPlearner and others added 2 commits September 9, 2026 12:20
…ries

A repository rooted at "/" or a Windows drive root already ends with its
separator, so appending another one built a "//" prefix that no nested path
matched. Every nested workspace fell back to the bare repository key and
collapsed into one row, the case this branch set out to fix.

Reading the grouping preference now maps the legacy repository_path value onto
repository. The mobile settings screen left no radio checked for a stored
repository_path, and the web pickers had no matching item.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@VIPlearner

Copy link
Copy Markdown
Author

Status for whoever picks this up: the Macroscope verdict above predates the fixes.

Both blocking findings are addressed:

  • Filesystem-root repositories (946a33e). trimTrailingPathSeparators returns root paths unchanged, so / produced the prefix // and a drive root produced c:\\. No nested path matched, so nested workspaces collapsed anyway. rootPrefix now appends a separator only when the root does not already end with one, with a test for each root shape.
  • Persisted legacy preference (946a33e). Reading the preference maps repository_path onto repository in selectProjectGroupingSettings (mode and per-checkout overrides) and resolveMobileProjectGroupingSettings, so no picker sees a mode it cannot render.

Local verification on the current head: 334 tests across the touched files, plus vp fmt --check, knip:check, and typecheck for client-runtime, web, and mobile. CI itself is still action_required, since Actions need approval for a first-time fork contributor.

On the approvability note that this "modifies the existing default": that is deliberate, and I think it is the only fix that works. Client settings are written to disk fully materialized, so changing DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE would not reach anyone who already has a stored value. The default mode is where the bug lives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Folders added from inside one repository merge into a single project, so I cannot start a thread in a specific folder

1 participant