fix(worktree): skip retirement backfill on every non-local host (#15023)

The backfill guard tested repo.connectionId, but a runtime-owned repo
carries executionHostId with no connectionId, so it read as local. The
scan then walked this machine's workspace and agent-transcript
directories and filed the result under the runtime host's namespace —
retiring names never used there while missing the ones that were.

Guard on the execution host id instead. Ongoing retirement was already
correct for these repos; only the one-time historical seed was wrong.
This commit is contained in:
Brennan Benson
2026-08-17 01:23:08 -07:00
committed by GitHub
parent 1aa51f6914
commit 7fad71e448
2 changed files with 64 additions and 3 deletions
+56
View File
@@ -336,4 +336,60 @@ describe('ensureRetiredWorktreeNamesBackfilled', () => {
expect(merged).toEqual([])
})
it('skips a runtime-owned repo, which has no connectionId but is still not local', async () => {
// Why: a `connectionId` check calls this repo local, so the scan reads THIS machine's
// directories and files them under the runtime's namespace — retiring names never used there
// while missing the ones that were. The host id is the only reliable local test.
const root = await mkdtemp(join(tmpdir(), 'orca-retirement-runtime-'))
const workspaceRoot = join(root, 'workspaces')
await mkdir(join(workspaceRoot, FIRST), { recursive: true })
const merged: string[] = []
const store = {
mergeRetiredWorktreeNames: (_repoId: string, names: Iterable<string>) => {
merged.push(...names)
return true
}
}
const runtimeRepo = {
...makeRepo('repo-runtime', '/repos/runtime'),
executionHostId: 'runtime:env-1'
} as Repo
try {
const collisionKey = await ensureRetiredWorktreeNamesBackfilled(store, runtimeRepo, {
workspaceDir: workspaceRoot,
nestWorkspaces: false
})
expect(merged).toEqual([])
expect(collisionKey).toBeNull()
} finally {
await rm(root, { force: true, recursive: true })
}
})
it('still backfills a plain local repo, so the skip is scoped to non-local hosts', async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-retirement-local-'))
const workspaceRoot = join(root, 'workspaces')
await mkdir(join(workspaceRoot, FIRST), { recursive: true })
const merged: string[] = []
const store = {
mergeRetiredWorktreeNames: (_repoId: string, names: Iterable<string>) => {
merged.push(...names)
return true
}
}
try {
await ensureRetiredWorktreeNamesBackfilled(store, makeRepo('repo-local', '/repos/local'), {
workspaceDir: workspaceRoot,
nestWorkspaces: false
})
expect(merged).toEqual([FIRST])
} finally {
await rm(root, { force: true, recursive: true })
}
})
})
+8 -3
View File
@@ -1,7 +1,7 @@
import { readdir } from 'node:fs/promises'
import { homedir } from 'node:os'
import { join } from 'node:path'
import { getRepoExecutionHostId } from '../shared/execution-host'
import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../shared/execution-host'
import {
creatureNameTier,
EMPTY_RETIRED_NAME_REGISTRY,
@@ -239,8 +239,13 @@ export async function ensureRetiredWorktreeNamesBackfilled(
settings: RetirementPathSettings
): Promise<string | null> {
// Remote workspaces keep their agent state on the execution host, which this scan cannot see, so
// a re-added SSH repo does not recover its retirements the way a local one does.
if (isFolderRepo(repo) || repo.connectionId) {
// a re-added remote repo does not recover its retirements the way a local one does.
//
// Why the host id and not `connectionId`: a runtime-owned repo carries `executionHostId` with no
// `connectionId`, so a connectionId check calls it local, scans THIS machine's directories, and
// files the result under the runtime's namespace — retiring names never used there while missing
// the ones that were.
if (isFolderRepo(repo) || getRepoExecutionHostId(repo) !== LOCAL_EXECUTION_HOST_ID) {
return null
}
const probePath = await computeWorktreePathAsync(