Skip to content

Prevent metadata writes from recreating removed workspaces - #26959

Closed
nwparker wants to merge 4 commits into
mainfrom
nwparker/followup-metadata-authority-10-09
Closed

nwparker wants to merge 4 commits into
mainfrom
nwparker/followup-metadata-authority-10-09

Conversation

@nwparker

@nwparker nwparker commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

Deleting a folder-project workspace could leave a terminal callback that brought the deleted workspace back. Metadata writes now update only an existing workspace on the intended host and instance.

What Changed

The Store checks durable membership and identity before using its existing metadata setter. Desktop and runtime handlers share that check. Activity, unread state, queued review notes and manual edits retain their owner across delivery and awaits; optimistic updates also preserve other publishers' rows. Folder-project catalogs expose their existing identity so valid paired edits still resolve. Terminal bell and keydown callbacks share one host and instance snapshot captured after their transport is created, so valid unread changes still work while callbacks from an old occupant stay refused.

Why

Checking the authoritative row prevents the resurrection at every covered writer, including runtime callers. Reusing the existing setters preserves normalization and registration behavior; filtering the sidebar would leave the recreated data on disk.

Linked Issue

Fixes #22712. Adapts the presence gate and reproduction from #26376 with source-verified Bing.Z credit.

Visual Proof

The current producer sends a real activity IPC held at a disposable timing gate. The real backend removes the secondary folder-project workspace before delivery. The before build replaces only the metadata handler with exact base 51e7181 source; the current handler is unchanged at this head. Before recreates a new instance and paints a second row; after returns null, keeps one row and leaves the locator absent in committed SQLite.

Original handler Current handler
Removed workspace recreated Removed workspace stays absent

A current workspace still renames through the real dialog, with its instance unchanged and the pinned name persisted in SQLite.

Current manual rename

Both owned apps stayed hidden and unfocused. This is local macOS with controlled actual IPC timing and a handler comparison using the current producer; it does not claim a spontaneous race, historical full checkout, remote sockets or whole-project deletion. Uploaded PNGs were read back with authentication and matched the reviewed local bytes exactly.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

Before the main sync, local macOS: 360 tests across 24 files pass, including production renderer→registered IPC/real SQLite and paired schema/runtime handler flows, actual mounted BEL callback and PTY bind/release ownership, child/parent await races, sort persistence and reload. Node/web/CLI and scoped producer test typechecks, full-file default/anti-slop lint, format and changed quality gates pass.

The first native run at d67aba passed all 360 tests on Linux. Windows passed 340 and failed 20: 19 failures in two unchanged suites also fail at exact base 51e718 with identical titles and errors (only random fixture directory names differ). The remaining failure was this new Git fixture comparing Windows path spellings as strings; its lookup now uses the runtime selector’s existing path comparator, with returned IDs and identity assertions unchanged. At final additive head b67c6d8, Linux passes all 360 tests in 24 files. Windows passes 341 and retains the same 19 exact-baseline failures in those two unchanged suites; both actual Git and folder integration cases now pass on both hosts. The final Windows comparison preserves the raw logs and normalizes only generated fixture directory names and rendered title-separator whitespace. This does not claim a green Windows suite.

Main at 62878c3 was merged in cc5eaf8. The merged tree passes 370 tests in 26 files, including the prior metadata producer/SQLite suites and shared remote PTY transport ownership controls. Node/CLI and scoped producer typechecks, full-file default/anti-slop lint and format checks, and all seven changed-code quality checks for the 46 PR files pass. The renderer typecheck also passes with a private Shiki 4.5.0 dependency shadow: official registry archives match the exact main lockfile, and its source-file set and all compiler options other than the dependency paths match the canonical check. This was needed because the shared dependencies predate main's new Shiki dependency. No lifecycle scripts, tracked source/configuration changes or shared dependency writes were used. The native Linux and Windows results above apply to b67c6d8 before this main sync; they are not results for the merged tree. Those local checks did not cover the full CI suite.

Full CI at cc5eaf8 exposed seven failing unit cases. Corrected owner fixtures reproduced a real initialization bug: bell and keydown callbacks captured an owner before their transport existed. Corrective commit e768c22 keeps the installation order and captures one fixed owner immediately after transport construction. Real bell and keydown callbacks now update the intended workspace, and the same old callbacks cannot change a replacement instance or send another metadata write. Existing isolated bell fixtures now supply the established session snapshot.

At the corrective head, all five affected suites pass under both Node and Bun: 1,383 tests pass and one existing test is skipped in each run. The 370-test, 26-file metadata gate also passes, retaining local/SSH and paired-publisher ownership, replacement refusal and SQLite reload assertions. Node/CLI, scoped producer and canonical renderer typechecks pass with the same verified private Shiki shadow. Full-file default/anti-slop lint, format and all seven changed-code quality checks pass for all 53 PR paths. Independent review checked the ten changed paths and reran the actual terminal lifecycle suite: all 12 tests pass. The earlier Linux packaging attempt failed while fetching the Docker Hub Node image with HTTP 504 before its fixture ran; its raw log is preserved. Fresh ordinary CI for this corrective head passes all five unit shards, static analysis and typechecks, relay integration and Linux/Windows packaging. Fully paged results contain 14 passing checks and 18 skipped checks, with no pending or failed checks. CI ran synthetic merge 4706a12 with newer main e88c8c7; the newer main adds an optional workspace-session callback in the only overlapping PR source file. Native Linux/Windows results above remain historical b67c6d8 results.

Hidden native Electron checked local macOS with disposable profiles and controlled real IPC timing. SSH and paired routing use production handlers with fixture Stores; remote sockets, rendered Windows/Linux/WSL checks and native-focus behavior are not claimed. Native-focus tests stay paused.

Review

Independent review of the exact source, production producer/handler tests, durable SQLite results, mixed-version boundaries, visual proof and contributor credit found no blockers.

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

Published IDs, persisted aliases/references and creation/discovery setters are preserved. Older callers and current legacy bulk/branch-review writers without an instance expectation cannot universally distinguish a remove/re-add at the same locator; absent or ambiguous rows are still refused. Qualified web/paired requests are never downgraded to a locator after peer refusal. Standalone FolderWorkspace records continue using their separate record mutation path. Setup publication and retired catalog cache cleanup are separate fixes.

Checklist

  • 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)

Repository checks were run through the actual Node binaries because the owned dependency symlink makes this environment's pnpm install wrapper refuse its hoist directory. The hidden Electron dev wrapper rebuilt for both phases; full lint, typechecks, unit shards and Linux/Windows packaging now pass in ordinary CI.

nwparker and others added 4 commits October 9, 2026 12:44
Require existing host and instance membership before metadata updates. Preserve captured producer ownership across callbacks, queued writes and awaits so removed or replaced workspaces and paired siblings stay untouched.

Co-authored-by: Bing.Z <zzb@gxsmjx.com>
Preserve shared remote PTY detection and captured metadata ownership. Keep the current Store domain context installation for the metadata admission domain.
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

The change adds host- and instance-qualified admission for worktree metadata updates in the store, runtime, IPC, and renderer. Renderer terminal and diff-comment flows capture and validate worktree ownership before updating metadata. Worktree displays include identity when host and instance metadata are available. The added tests cover admission, stale updates, persistence, terminal events, and diff-comment flows.


Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to e768c

Some metadata edits can now fail and be refused. This affects legacy workspaces without an instance ID in the web client, and runtime-hosted workspaces whose host ID differs from the durable host. Fix these two selector paths before merging.

Pre-merge checks | Passed 3 | Failed 1 | Inconclusive 1

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check Warning Issue #22712 requires removal of the workspace, its terminals, and all session state, with no remaining row. The PR implements and tests stale metadata-write refusal. The PR description explicitly lim… Implement or establish the folder-workspace removal path that removes terminal bindings and all workspace-session references, in addition to preventing stale metadata writes. Add an automated regression test that deletes an attached folder …
Docstring Coverage Inconclusive Docstring coverage is 13.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 73 functions across 50 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely summarizes the main change: preventing stale metadata writes from recreating removed workspaces.
Description check Passed The description is complete and relevant. It covers the user impact, implementation, rationale, linked issue, visual proof, testing results, known limitations, review notes, and checklist items.
Out of Scope Changes check Passed The changed runtime, IPC, renderer, terminal-callback, identity, and diff-comment code supports ownership checks for metadata writes or tests those checks. Sort-order batching and folder identity supp…

Full details: Linked Issues check

Explanation

Issue #22712 requires removal of the workspace, its terminals, and all session state, with no remaining row. The PR implements and tests stale metadata-write refusal. The PR description explicitly limits scope and does not claim terminal or session teardown. The reviewed changes provide no evidence that the removal path deletes terminal bindings or workspace-session references.

Resolution

Implement or establish the folder-workspace removal path that removes terminal bindings and all workspace-session references, in addition to preventing stale metadata writes. Add an automated regression test that deletes an attached folder workspace and verifies no workspace row or session state remains.


Full details: Docstring Coverage

Explanation

Docstring coverage is 13.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 73 functions across 50 files. (3 skipped: 3 over the file limit.)



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

@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: 2


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cc4689d9-95aa-4ef4-8a9b-a66d6d7b695c
📥 Commits

Reviewing files that changed from the base of the PR and between 62878c3 and e768c22.

📒 Files selected for processing (53)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • src/main/ipc/worktrees-test-ipc-surface.ts
  • src/main/ipc/worktrees-test-metadata-mutation-store.ts
  • src/main/ipc/worktrees-test-metadata-pruning-store.ts
  • src/main/ipc/worktrees/folder-workspace-model.ts
  • src/main/ipc/worktrees/metadata/register-worktree-metadata-handlers.ts
  • src/main/persistence/loading-store/store-domain-composition.ts
  • src/main/persistence/loading-store/worktree-metadata-admission.ts
  • src/main/runtime/orca-runtime-test-fixtures.spec.ts
  • src/main/runtime/orca-runtime-tests/lineage-and-scan-cache-part-03.spec.ts
  • src/main/runtime/runtime-folder-workspace.ts
  • src/main/runtime/runtime-managed-worktree-metadata.test.ts
  • src/main/runtime/runtime-managed-worktree-metadata.ts
  • src/main/runtime/runtime-metadata-mutation.test-fixture.ts
  • src/main/runtime/runtime-store-contract.ts
  • src/main/runtime/runtime-worktree-metadata-admission.integration.test.ts
  • src/main/worktree-metadata-admission.test.ts
  • src/preload/api/worktree-api.ts
  • src/renderer/src/components/terminal-pane/parked-terminal-byte-watcher.test.ts
  • src/renderer/src/components/terminal-pane/parked-terminal-byte-watcher.ts
  • src/renderer/src/components/terminal-pane/pty-connection-hook-completion-bell-arbitration.test.ts
  • src/renderer/src/components/terminal-pane/pty-connection-types.ts
  • src/renderer/src/components/terminal-pane/pty-connection/connect-pane-pty-session.ts
  • src/renderer/src/components/terminal-pane/pty-connection/pane-pty-visibility-bind.ts
  • src/renderer/src/components/terminal-pane/pty-connection/pty-input-recovery.ts
  • src/renderer/src/components/terminal-pane/pty-connection/terminal-keydown-fit.ts
  • src/renderer/src/components/terminal-pane/terminal-pane-lifecycle-types.ts
  • src/renderer/src/hooks/useUnreadDockBadge.test.ts
  • src/renderer/src/lib/unread-badge-count-selector.test.ts
  • src/renderer/src/runtime/runtime-worktree-selector.ts
  • src/renderer/src/store/slices/diff-comment-persistence.ts
  • src/renderer/src/store/slices/diff-comment-worktree-owner.ts
  • src/renderer/src/store/slices/diffComments.test.ts
  • src/renderer/src/store/slices/store-active-worktree-selection.test.ts
  • src/renderer/src/store/slices/worktree-helpers.ts
  • src/renderer/src/store/slices/worktree-meta-update-application.ts
  • src/renderer/src/store/slices/worktrees-unread-state.test.ts
  • src/renderer/src/store/slices/worktrees/listing/detected-worktree-meta.ts
  • src/renderer/src/store/slices/worktrees/listing/runtime-worktree-rpc-errors.ts
  • src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts
  • src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts
  • src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.test.ts
  • src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.ts
  • src/renderer/src/store/slices/worktrees/session/worktree-unread-activity.ts
  • src/renderer/src/store/terminals/terminal-pty-bindings.ts
  • src/renderer/src/store/terminals/terminal-pty-release.ts
  • src/renderer/src/store/terminals/terminal-worktree-metadata-owner.ts
  • src/renderer/src/web/preload-api/web-worktree-attachment-mutations.test.ts
  • src/renderer/src/web/preload-api/web-worktrees-api.ts
  • src/shared/worktree/display-name-provenance.ts
  • src/shared/worktree/identity.ts
  • tests/e2e/worktree-metadata-admission.unit.test.ts
  • tests/e2e/worktree-terminal-bell.fixture.ts

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

Comment on lines +174 to +181
worktree: identityKey
? `identity:${identityKey}`
: toRuntimeWorktreeSelector(
worktreeId,
executionHostId && expectedInstanceId
? { executionHostId, instanceId: expectedInstanceId }
: undefined
),

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
rg -nP -C8 'export function withRepoHostOwnership\b|export function withRuntimeWorktreeOwner\b' src/renderer
rg -nP -C5 "identity:" src/main/runtime/rpc/methods src/main/runtime --type=ts -g '!**/*.test.ts' | rg -n -C3 'wt2|canonicalWorktreeIdentity|identity:' | head -80

Repository: stablyai/orca

Length of output: 11516


🏁 Script executed:

set -u
printf '%s\n' '--- changed file and diff ---'
git diff --no-ext-diff --unified=35 62878c3b0c8a64519fa219b0282da9b64d83c540 e768c2213d4dc07e5d98e3a2e2e887501e13e2cf -- src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.ts
printf '%s\n' '--- ownership helper ---'
sed -n '1,180p' src/renderer/src/store/slices/worktrees/listing/worktree-host-ownership.ts
printf '%s\n' '--- runtime owner helper ---'
sed -n '80,145p' src/renderer/src/web/preload-api/web-runtime-calls.ts
printf '%s\n' '--- persistence callers ---'
rg -n -C5 -F -- 'persistWorktreeMeta(' src/renderer/src
printf '%s\n' '--- selector construction and consumers ---'
rg -n -C5 -F -- 'identity:' src/renderer/src/main src/main src/shared 2>/dev/null | rg -n -C3 'worktree|wt2|canonicalWorktreeIdentity|selector' | head -240
rg -n -C8 -F -- 'toRuntimeWorktreeSelector' src
rg -n -C8 -F -- 'selector_not_found' src/main src/renderer/src src/shared
printf '%s\n' '--- identity fields/types ---'
rg -n -C5 -P 'interface (Worktree|Repo)|type (Worktree|Repo)|identity\??:|instanceId\??:|hostId\??:' src/shared src/renderer/src src/main --glob '*.ts' | head -300

Repository: stablyai/orca

Length of output: 45662


🏁 Script executed:

set -u
printf '%s\n' '--- selector declaration and usages ---'
rg -n -C12 -F -- 'function toRuntimeWorktreeSelector' src
rg -n -C12 -F -- 'toRuntimeWorktreeSelector' src/renderer/src/store/slices/worktrees/metadata src/main src/shared
printf '%s\n' '--- runtime worktree.set declarations and selector resolution ---'
rg -n -C15 -F -- "'worktree.set'" src/main src/shared src/renderer/src
rg -n -C12 -F -- 'selector_not_found' src/main src/shared
rg -n -C12 -P 'wt2:|identity:' src/main/runtime src/main --glob '*.ts' | head -220
printf '%s\n' '--- identity and worktree declarations ---'
sed -n '1,220p' src/shared/worktree/identity.ts
rg -n -C12 -P 'export (type|interface) Worktree\b|type WorktreeIdentity|identity\??:.*Worktree|instanceId\??:' src/shared/worktree src/shared --glob '*.ts' | head -260
printf '%s\n' '--- exact persistence caller tails ---'
sed -n '245,305p' src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts
sed -n '80,125p' src/renderer/src/store/slices/worktrees/metadata/update-worktrees-meta.ts
sed -n '245,280p' src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts

Repository: stablyai/orca

Length of output: 45471


🏁 Script executed:

set -u
printf '%s\n' '--- runtime metadata update implementation ---'
rg -n -C12 -F -- 'updateManagedWorktreeMeta' src/main src/shared
printf '%s\n' '--- runtime selector parsing and identity lookup ---'
rg -n -C10 -P 'parse.*Worktree|resolve.*Worktree|canonicalWorktreeIdentity|WorktreeIdentity|wt2:' src/main/runtime src/main --glob '*.ts' | head -260
printf '%s\n' '--- runtime worktree list projection ---'
rg -n -C10 -P 'withRuntimeWorktreeOwner|runtimeOwnerEnvironmentId|identity:.*createWorktreeIdentity|createWorktreeIdentity' src/main src/renderer/src --glob '*.ts' | head -300
printf '%s\n' '--- expected instance source ---'
rg -n -C8 -F -- 'expectedInstanceId' src/renderer/src/store/slices/worktrees
sed -n '210,295p' src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts

Repository: stablyai/orca

Length of output: 42390


🏁 Script executed:

set -u
printf '%s\n' '--- owning files ---'
rg -l -F -- 'updateManagedWorktreeMeta' src/main/runtime src/main | head -30
printf '%s\n' '--- method definitions and exact nearby source ---'
rg -n -F -- 'updateManagedWorktreeMeta' src/main/runtime src/main --glob '*.ts' | grep -v '\.test\.ts' | head -40
printf '%s\n' '--- identity resolution definitions ---'
rg -n -F -- 'canonicalWorktreeIdentity' src/main/runtime src/main --glob '*.ts' | grep -v '\.test\.ts' | head -60
rg -n -P 'identity\.executionHostId|identity\?\.executionHostId|createWorktreeIdentity|instanceId' src/main/runtime --glob '*.ts' | grep -v '\.test\.ts' | head -160

Repository: stablyai/orca

Length of output: 21791


🏁 Script executed:

set -u
printf '%s\n' '--- managed metadata update ---'
sed -n '120,215p' src/main/runtime/orca-runtime-create-managed-remote-worktree.ts
printf '%s\n' '--- runtime folder workspace projection ---'
sed -n '1,85p' src/main/runtime/runtime-folder-workspace.ts
printf '%s\n' '--- runtime managed metadata resolver ---'
sed -n '1,155p' src/main/runtime/runtime-managed-worktree-metadata.ts
printf '%s\n' '--- metadata identity loading ---'
sed -n '55,110p' src/main/persistence/loading-store/worktree-identity-metadata.ts
sed -n '210,250p' src/main/persistence/loading-store/worktree-identity-metadata.ts

Repository: stablyai/orca

Length of output: 16531


Build the fallback selector from the durable execution host ID.

When identityKey is absent but expectedInstanceId is present, this code can encode the renderer transport ID (runtime:<environment>) into the wt2: selector. Runtime metadata can store the occupant under its durable host ID, such as local, so the selector does not match and worktree.set can fail with selector_not_found. Preserve the instance fence, but obtain the durable execution host or identity before constructing this selector. If that host is unavailable, refuse the write instead of guessing.

Comment on lines +176 to +186
updateMeta: async ({ worktreeId, updates, executionHostId, expectedInstanceId }) => {
const host = parseExecutionHostId(executionHostId)
if ((executionHostId || expectedInstanceId) && (!host || !expectedInstanceId?.trim())) {
throw new Error('selector_not_found')
}
const selector = toRuntimeWorktreeSelector(
worktreeId,
host && expectedInstanceId
? { executionHostId: host.id, instanceId: expectedInstanceId }
: undefined
)

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

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
rg -nP -C5 'activeRuntimeEnvironmentId' src/renderer/src/web | head -60

Repository: stablyai/orca

Length of output: 5655


🏁 Script executed:

set -u
printf '%s\n' '--- affected API and nearby definitions ---'
nl -ba src/renderer/src/web/preload-api/web-worktrees-api.ts | sed -n '130,215p'
printf '%s\n' '--- named symbols and selector fields in web sources ---'
for symbol in updateWorktreeMeta persistPassiveWorktreeMetaForOwner persistWorktreeMetaUntracked getActiveRuntimeTarget expectedInstanceId; do
  printf '%s\n' "--- $symbol ---"
  rg -n -F --glob '*.{ts,tsx}' -- "$symbol" src/renderer/src/web src/renderer/src || test "$?" -eq 1
done
printf '%s\n' '--- instanceId declarations/usages in web sources ---'
rg -n -F --glob '*.{ts,tsx}' -- 'instanceId' src/renderer/src/web src/renderer/src || test "$?" -eq 1

Repository: stablyai/orca

Length of output: 41896


🏁 Script executed:

set -u
printf '%s\n' '--- exact file candidates ---'
rg --files src/renderer/src | rg '(^|/)(update-worktree-meta|worktree-owner-settings|.*worktree.*persist|.*runtime.*target|.*worktree.*api).*\.tsx?$' || true
printf '%s\n' '--- exact symbol locations repository-wide ---'
for symbol in persistPassiveWorktreeMetaForOwner persistWorktreeMetaUntracked getActiveRuntimeTarget activeRuntimeEnvironmentId; do
  printf '%s\n' "--- $symbol ---"
  rg -n -F --glob '*.{ts,tsx}' -- "$symbol" src || test "$?" -eq 1
done
printf '%s\n' '--- update-worktree-meta and owner-settings source ---'
for file in $(rg --files src/renderer/src | rg 'update-worktree-meta|worktree-owner-settings'); do
  printf '%s\n' "--- $file ---"
  nl -ba "$file" | sed -n '1,380p'
done
printf '%s\n' '--- Worktree type and web updateMeta invocations ---'
for symbol in 'export type Worktree' 'interface Worktree' 'worktrees.updateMeta' 'api.worktrees.updateMeta'; do
  printf '%s\n' "--- $symbol ---"
  rg -n -F --glob '*.{ts,tsx}' -- "$symbol" src || test "$?" -eq 1
done

Repository: stablyai/orca

Length of output: 45667


🏁 Script executed:

set -u
printf '%s\n' '--- direct metadata persistence ---'
nl -ba src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.ts | sed -n '1,155p'
printf '%s\n' '--- owner settings persistence ---'
nl -ba src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts | sed -n '190,310p'
printf '%s\n' '--- active runtime target implementation ---'
rg -n -F --glob '*.ts' -- 'export function getActiveRuntimeTarget' src/renderer/src/runtime src/renderer/src/runtime/runtime-rpc-client.ts
nl -ba src/renderer/src/runtime/runtime-client-target.ts | sed -n '1,180p'
nl -ba src/renderer/src/runtime/runtime-rpc-client.ts | sed -n '1,180p'
printf '%s\n' '--- instanceId type declarations ---'
rg -n -P --glob '*.{ts,tsx}' '(^|[<({,[:space:]])instanceId\??\s*:' src/renderer/src src/shared src/main packages 2>/dev/null | head -120
printf '%s\n' '--- web metadata tests and direct invocations ---'
nl -ba src/renderer/src/web/web-preload-api-workspace-catalog.test.ts | sed -n '720,785p'
rg -n -F --glob '*.{ts,tsx}' -- 'expectedInstanceId:' src/renderer/src/store/slices/worktrees src/renderer/src/web | head -100

Repository: stablyai/orca

Length of output: 35393


🏁 Script executed:

set -u
printf '%s\n' '--- store-level updateWorktreeMeta definition ---'
nl -ba src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts | sed -n '1,360p'
printf '%s\n' '--- metadata persistence remainder ---'
nl -ba src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.ts | sed -n '150,230p'
printf '%s\n' '--- owner route declarations and resolution ---'
nl -ba src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts | sed -n '1,225p'
printf '%s\n' '--- instance ID helper declarations ---'
rg -n -F --glob '*.{ts,tsx}' -- 'function getWorktreeInstanceId' src
rg -n -F --glob '*.{ts,tsx}' -- 'getWorktreeInstanceId(' src/renderer/src/store/slices/worktrees | head -80
printf '%s\n' '--- focused metadata argument assertions ---'
nl -ba src/renderer/src/store/slices/worktrees-metadata-persistence.test.ts | sed -n '150,220p'
nl -ba src/renderer/src/store/slices/worktrees-activity-persistence.test.ts | sed -n '240,315p'
nl -ba src/renderer/src/web/preload-api/web-worktree-attachment-mutations.test.ts | sed -n '80,155p'

Repository: stablyai/orca

Length of output: 36332


🏁 Script executed:

set -u
printf '%s\n' '--- instance identity helper ---'
nl -ba src/shared/worktree/identity.ts | sed -n '1,65p'
printf '%s\n' '--- Worktree declaration ---'
nl -ba src/shared/worktree/types.ts | sed -n '70,110p'
printf '%s\n' '--- metadata type declaration ---'
nl -ba src/shared/worktree/meta-types.ts | sed -n '1,35p'

Repository: stablyai/orca

Length of output: 5382


Allow locator fallback when no instance ID exists.

A local row without an instance ID receives executionHostId: 'local' but no expectedInstanceId. The web preload then throws selector_not_found instead of using the locator selector. Preserve validation for invalid or explicitly blank instance IDs, but allow a valid host without an instance ID.

Suggested fix
-      if ((executionHostId || expectedInstanceId) && (!host || !expectedInstanceId?.trim())) {
+      if (
+        (executionHostId && !host) ||
+        (expectedInstanceId !== undefined && (!host || !expectedInstanceId.trim()))
+      ) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updateMeta: async ({ worktreeId, updates, executionHostId, expectedInstanceId }) => {
const host = parseExecutionHostId(executionHostId)
if ((executionHostId || expectedInstanceId) && (!host || !expectedInstanceId?.trim())) {
throw new Error('selector_not_found')
}
const selector = toRuntimeWorktreeSelector(
worktreeId,
host && expectedInstanceId
? { executionHostId: host.id, instanceId: expectedInstanceId }
: undefined
)
updateMeta: async ({ worktreeId, updates, executionHostId, expectedInstanceId }) => {
const host = parseExecutionHostId(executionHostId)
if (
(executionHostId && !host) ||
(expectedInstanceId !== undefined && (!host || !expectedInstanceId.trim()))
) {
throw new Error('selector_not_found')
}
const selector = toRuntimeWorktreeSelector(
worktreeId,
host && expectedInstanceId
? { executionHostId: host.id, instanceId: expectedInstanceId }
: undefined
)

@OrcaWin

OrcaWin commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Closing: the ghost-row bug in #22712 is real on current main, but this 53-file change (owner capture in terminal callbacks, unread/review-note plumbing, new admission layer) is far more surface than the fix needs and now conflicts with main. #26376 fixes the same root cause at the two metadata write boundaries in ~50 lines of product code, and its regression test fails on main and passes with the fix, so that is the PR to land.

@OrcaWin OrcaWin closed this Oct 11, 2026
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.

[Bug]: Deleting a folder-project workspace from the sidebar while a terminal is attached leaves an unremovable blank row named after the project

2 participants