Files
orca/src/shared/worktree/identity.ts
T
Neil b241a68ae4 Fix worktree identity collisions across hosts (#16691)
* fix(workspaces): add collision-safe worktree identity

* fix(workspaces): read worktree metadata per host and repair ambiguous identities

The canonical identity store landed write-only: getWorktreeMetaForHost had no
production callers while setWorktreeMetaForHost kept the legacy projection only
for the first known owner, so a second host's edits persisted and were never
read back. Wire the listing paths through host-qualified reads.

An ambiguous alias was also unrecoverable — reads returned undefined and writes
threw forever, and the throw escaped the detected-worktree loop, emptying the
whole repo's sidebar. Fail open onto the most recently active instance instead.

- collapse ambiguous aliases deterministically and persist the repair
- reclaim identity rows in the metadata GC so they cannot outlive their locator
  or resurrect onto a worktree recreated at the same path
- drop every host's rows when a locator is removed outright, not just the owner's
- honour an explicit instanceId so the stale-lineage rotation guard still works
- scope a rename to the moving host; other hosts keep their own locator
- prefer the project host setup matching the repo's own execution host, so a
  repoId registered on two hosts no longer stamps the wrong one durably
- reject an unencoded `|` in a host id, the invariant the alias delimiter needs
- drop the never-populated hostGeneration from the canonical key

* fix(workspaces): close remaining identity review gaps

* fix(workspaces): close remaining review gaps

* fix(workspaces): address review and CI regressions

* test(workspaces): update host-qualified metadata expectations

* fix(workspaces): preserve ambiguous identity records

* fix(workspaces): snapshot metadata during listing

* test(workspaces): mirror listing metadata snapshot in windows fixture

* fix(workspaces): preserve identity routing for metadata writes

* fix(workspaces): scope stale metadata cleanup by host

* fix(workspaces): rekey identities on SSH readoption

* fix(workspaces): fail closed for ambiguous board ids

* perf(workspaces): snapshot metadata across catalog listing

* fix(workspaces): retain neighboring manual order updates

* test(workspaces): cover ambiguous board id index

* fix(persistence): harden host-qualified worktree metadata

* refactor(shared): split project host setup lookup

* refactor(workspaces): simplify host-qualified metadata
2026-08-27 15:08:40 -07:00

30 lines
1.0 KiB
TypeScript

import type { ExecutionHostId } from '../execution-host'
/** Stable fields needed to identify one checkout occupant. */
export type WorktreeIdentityRef = {
/** Existing repo/path locator; mutable when the folder moves. */
worktreeId: string
/** Host that owns execution for this checkout. */
executionHostId: ExecutionHostId
/** Durable identity for this checkout occupant. */
instanceId: string
}
export type WorktreeIdentity = Omit<WorktreeIdentityRef, 'worktreeId'> & {
key: string
}
/**
* Canonical exact identity for one worktree occupant.
* The locator is deliberately excluded so a folder rename preserves identity.
*/
export function canonicalWorktreeIdentity(ref: WorktreeIdentityRef): string {
return `wt2:${encodeURIComponent(ref.executionHostId)}:${encodeURIComponent(ref.instanceId)}`
}
export function createWorktreeIdentity(ref: WorktreeIdentityRef): WorktreeIdentity {
return {
key: canonicalWorktreeIdentity(ref),
executionHostId: ref.executionHostId,
instanceId: ref.instanceId
}
}