Skip to content

refactor(projects): repo, project group and folder catalog calls route by their owner - #27288

Merged
OrcaWin merged 1 commit into
mainfrom
OrcaWin/d4-g1-catalog
Oct 10, 2026
Merged

OrcaWin merged 1 commit into
mainfrom
OrcaWin/d4-g1-catalog

Conversation

@OrcaWin

@OrcaWin OrcaWin commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 28 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​456 $\color{#cf222e}{\Huge{\mathbf{−}}}$​218 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​238
Prod 38 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​235 $\color{#cf222e}{\Huge{\mathbf{−}}}$​307 $\color{#cf222e}{\Huge{\mathbf{−}}}$​72

ELI5

Orca keeps a list of projects, project groups and folder workspaces from every computer it knows about: this computer, plus any paired Orca servers. Some actions on that list still asked "which server is picked in the Active Server setting?" instead of "which computer owns this project?". If you picked a different server, renaming, moving or deleting a project or group could therefore be sent to the wrong computer. Now each of these actions goes to the computer that owns the row. Only adding a brand-new project, where nothing has an owner yet, still uses that setting as its default.

What Changed

  • Before (user): with a server picked as Active Server, these could be sent to that server even when the project or group lived somewhere else:
    • a project group's rename or delete when the group's id exists on two hosts;
    • creating a group from a project's context menu;
    • moving a project into a group;
    • a local Windows project's "Project Runtime" preference;
    • a project row with no host stamp.
  • After (user): each of those goes to the host that owns the row. Creating a group from a project creates it on that project's host. Rows on a single host with nothing picked behave exactly as before.
  • Mechanism:
    • Catalog fetches now name their host. fetchRepos, fetchProjectGroups and fetchFolderWorkspaces require { runtimeEnvironmentId: string | null }, where null is this app. Every caller already knew the host, except:
      • this app's own repos:changed event, which now refreshes this app's catalog;
      • a failed issue-source write and a "project added" dialog whose repo hasn't loaded yet, which now refresh every host;
      • switching the default host, which hydrates the newly chosen host.
    • Folder path-status reads and their cache keys take the owner explicitly. A folder row whose group hasn't loaded is skipped instead of being asked of the focused host. Cache key strings are unchanged.
    • Project-group mutations route through runtimeTargetForProjectGroupOwner, which replaces settingsForProjectGroupOwner. An id that two hosts both own, with no host given, is refused instead of following focus.
    • createProjectGroup(name, hostId) and moveProjectToGroup(…, hostId) take the project's host. updateProject(projectId, updates, hostId) updates the project row on the host the caller names.
    • Repo update and removal route by the row's own host id. An unstamped row is this app's own, because ingest stamps every server row.
    • Folder-workspace update and delete use the focus-free runtimeTargetForWorkspaceOwner. Nested-repo scan, cancel and import take the host picked in Add Project.
    • New projects with no picked host, through addRepoPath without a host or the OS folder picker, go through defaultCreationHost, the one approved reader of the setting.
    • Deleted: settingsForProjectGroupOwner, getAddRepoPathRouteSettings, getFolderWorkspacePathStatusRouteSettings, getRuntimeTargetCachePrefix, getProjectUpdateRuntimeTarget, and the settings parameter of resolveAddRepoRuntimeTarget, which always resolved to this app anyway.
    • The two places that mirror the default host's worktree-visibility defaults into Settings now compare the id directly. The redundant focus-routing call is gone; the read itself stays counted.
  • Ratchets (whole repo): owner-routing goes from 165 to 136, and focus-read from 1343 to 1294. No file grew.

Why

This is one slice of making the owner-routing count reach zero. The setting becomes "Default host for new projects", and only creation flows that have no source row may read it.

We considered keeping the optional runtimeEnvironmentId and treating "missing" as this app. That would compile without the caller ever saying which host it meant, which is the bug this work removes. Making the field required lets the compiler find every caller that hadn't decided.

An unresolved or ambiguous owner is refused, rather than run on this computer or on the focused host. Running it either way would be a guess.

Linked Issue

None. This is part of the host-ownership routing stack (D4 G1).

Visual Proof

N/A. The visible UI is unchanged; only the host each call reaches changes. That is covered by unit tests, and the machine is load-capped, so the app wasn't launched.

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • repos-project-runtime.test.ts has a new case. A local Windows project's runtime preference stays on this computer even while a server with a setup for it is the default host; the old code sent it to that server.

  • repos-project-groups-owner-routing.test.ts: a group id that two hosts both own, with no host given, is now refused. It used to follow focus.

  • Several repos.test.ts and repos-project-groups-delete.test.ts cases relied on an unstamped row following focus to a server. They now stamp the row the way ingest does, so they assert owner routing.

  • Other tests pass the owner explicitly.

  • Ran: pnpm tc:web, focused pnpm test (store, sidebar, settings, hooks, lib: 1853 files), oxlint, oxfmt, pnpm run check:code-quality:changed, pnpm check:owner-routing-ratchet, and check:max-lines-ratchet.

Review

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

  • Wire: no change to RPC params or IPC channels. The nested import already sent runtimeEnvironmentId.
  • SSH: direct SSH rows and groups keep going through this app's IPC with their connectionId. Server-owned SSH targets route to their server.
  • Folder workspaces: covered by the path-status, update and delete changes.

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 screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

Repository and project operations now use explicit runtime-environment or execution-host values to select targets. Catalog fetches and folder path-status requests require explicit owner options. Renderer flows and store interfaces pass these values, and tests now provide them in fetch, mutation, and scan calls. Some catalog hydration paths now fetch across all hosts, while catalog-change handling explicitly fetches the local catalog.


Priority: ➖ Normal

Merge Risk: 🔵 Low · up to 575c5

The project-added dialog can close prematurely during overlapping catalog refreshes. This is a bounded issue, but the hydration result should be made authoritative before merge or accepted for follow-up.

Pre-merge checks | Passed 4 | Inconclusive 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage Inconclusive Docstring coverage is 30.61% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 49 functions across 50 files. (13 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly summarizes the main change: routing repository, project-group, and folder catalog calls by their owning host.
Description check Passed The description is mostly complete and covers the user impact, implementation, rationale, testing, visual proof, compatibility considerations, and checklist. The Linked Issue section says "None"; an a…
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.

Full details: Docstring Coverage

Explanation

Docstring coverage is 30.61% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 49 functions across 50 files. (13 skipped: 1 unsupported, 12 over the file limit.)


✨ 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.

…e by their owner

Catalog fetches, path-status probes, project and group mutations, nested
scans and imports now take the owner's host explicitly instead of falling
back to the Active Server setting. A new project with no picked host still
goes to the default host, through defaultCreationHost.
@OrcaWin
OrcaWin force-pushed the OrcaWin/d4-g1-catalog branch from 4253520 to 575c55e Compare October 10, 2026 19:43

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 20a296aa-2dba-4888-8b7a-51c3414cab14
📥 Commits

Reviewing files that changed from the base of the PR and between 81867c8 and 575c55e.

📒 Files selected for processing (66)
  • config/focus-setting-read-baseline.txt
  • config/owner-routing-baseline.txt
  • src/renderer/src/components/settings/settings-project-section-renderer.tsx
  • src/renderer/src/components/sidebar/AddRepoSteps.tsx
  • src/renderer/src/components/sidebar/ProjectAddedDialog.test.tsx
  • src/renderer/src/components/sidebar/ProjectAddedDialog.tsx
  • src/renderer/src/components/sidebar/add-repo-runtime-owner.ts
  • src/renderer/src/components/sidebar/folder-workspace-composer-path-status.test.tsx
  • src/renderer/src/components/sidebar/folder-workspace-composer-path-status.ts
  • src/renderer/src/components/sidebar/use-worktree-context-menu-commands.ts
  • src/renderer/src/components/sidebar/useAddRepoCloneFlow.ts
  • src/renderer/src/components/sidebar/useAddRepoNestedImportFlow.test.ts
  • src/renderer/src/components/sidebar/useAddRepoNestedImportFlow.ts
  • src/renderer/src/components/sidebar/useAddRepoNestedReviewController.ts
  • src/renderer/src/components/sidebar/useAddRepoNestedReviewState.ts
  • src/renderer/src/components/sidebar/useAddRepoServerPathFlow.ts
  • src/renderer/src/components/sidebar/useCreateRepo.ts
  • src/renderer/src/components/sidebar/worktree-list/listing/use-folder-path-statuses.ts
  • src/renderer/src/components/sidebar/worktree-list/rows/use-project-group-dialogs.ts
  • src/renderer/src/hooks/composer-state/composer-store-actions.ts
  • src/renderer/src/hooks/ipc-events/project-catalog-ipc-bridge.ts
  • src/renderer/src/lib/workspace-activation-path-gate.test.ts
  • src/renderer/src/store/folder-workspaces/folder-path-status-actions.ts
  • src/renderer/src/store/folder-workspaces/folder-workspace-catalog-actions.ts
  • src/renderer/src/store/folder-workspaces/folder-workspace-mutations.ts
  • src/renderer/src/store/folder-workspaces/folder-workspace-routing.ts
  • src/renderer/src/store/github/work-item-mutation-actions.ts
  • src/renderer/src/store/project-groups/nested-repository-operations.ts
  • src/renderer/src/store/project-groups/project-group-catalog-actions.ts
  • src/renderer/src/store/project-groups/project-group-mutations.ts
  • src/renderer/src/store/projects/project-host-routing.ts
  • src/renderer/src/store/projects/project-update.ts
  • src/renderer/src/store/repos/all-host-repo-catalog-actions.ts
  • src/renderer/src/store/repos/owner-routing.ts
  • src/renderer/src/store/repos/repo-add-actions.ts
  • src/renderer/src/store/repos/repo-catalog-actions.ts
  • src/renderer/src/store/repos/repo-removal.ts
  • src/renderer/src/store/repos/repo-state.ts
  • src/renderer/src/store/repos/repo-update.ts
  • src/renderer/src/store/repos/runtime-repo-catalog-actions.ts
  • src/renderer/src/store/slices/folder-workspace-owner-routed-mutations.test.ts
  • src/renderer/src/store/slices/project-group-owner-routing.ts
  • src/renderer/src/store/slices/repos-add-races.test.ts
  • src/renderer/src/store/slices/repos-all-hosts-generation.test.ts
  • src/renderer/src/store/slices/repos-all-hosts.test.ts
  • src/renderer/src/store/slices/repos-catalog-merge-identity.test.ts
  • src/renderer/src/store/slices/repos-catalog-notifications.test.ts
  • src/renderer/src/store/slices/repos-cross-host-refresh-identity.test.ts
  • src/renderer/src/store/slices/repos-module-lifetime-coordinators.test.ts
  • src/renderer/src/store/slices/repos-nested-import-refresh-failures.test.ts
  • src/renderer/src/store/slices/repos-nested-ssh-projection.test.ts
  • src/renderer/src/store/slices/repos-project-group-create-race.test.ts
  • src/renderer/src/store/slices/repos-project-groups-delete.test.ts
  • src/renderer/src/store/slices/repos-project-groups-owner-routing.test.ts
  • src/renderer/src/store/slices/repos-project-groups.test.ts
  • src/renderer/src/store/slices/repos-project-host-capability.test.ts
  • src/renderer/src/store/slices/repos-project-host-lifecycle.test.ts
  • src/renderer/src/store/slices/repos-project-runtime.test.ts
  • src/renderer/src/store/slices/repos-refresh-identity.test.ts
  • src/renderer/src/store/slices/repos-runtime-project-groups.test.ts
  • src/renderer/src/store/slices/repos-selected-owner-routing.test.ts
  • src/renderer/src/store/slices/repos-setup-script-dismissals.test.ts
  • src/renderer/src/store/slices/repos-stale-fetch.test.ts
  • src/renderer/src/store/slices/repos.test.ts
  • src/renderer/src/store/slices/runtime-catalog-merge-removed-env-guard.test.ts
  • src/renderer/src/store/slices/settings.ts
💤 Files with no reviewable changes (3)
  • config/owner-routing-baseline.txt
  • src/renderer/src/store/projects/project-host-routing.ts
  • src/renderer/src/store/repos/owner-routing.ts

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

void (async () => {
await fetchRepos()
// Why: no row yet names the new project's host, so look on every host.
await fetchReposForAllHosts()

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not close the dialog after a superseded catalog load.

If another all-host load supersedes this call before remote catalogs are fetched, fetchReposForAllHosts() returns early. The subsequent lookup can miss a remote repo that the newer load is still fetching, so the dialog closes before its project handoff. Wait for an authoritative hydration result before treating the repo as absent.

@OrcaWin
OrcaWin merged commit 4f03c23 into main Oct 10, 2026
29 checks passed
LINDECKER-Charles added a commit to LINDECKER-Charles/orca that referenced this pull request Oct 12, 2026
Upstream now routes project group catalog calls by their owner host
(stablyai#27288): createProjectGroup takes the seeding project's host, and rows
are adopted through adoptFromEndpoint. Subgroup creation moves to its own
createProjectSubgroup action, routed by the parent group's owner like
moveProjectGroup, and the update/move helper uses the new owner routing.

protocol-version.ts re-exports the attention capabilities with a star,
as stablyai#27493 did for the resume ones, to stay within the line limit.
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