fix(runtime): log the folder-workspace fan-out failures instead of swallowing them

A child repo whose status read fails silently vanished from the merged status
(indistinguishable from clean) and from the commit set (a "success" that
skipped staged files). A failed abort left a repo conflicted with no trail.
Each now warns with the repo path. Also gives the test fixture a unique temp
dir so concurrent runs stop rm -rf'ing each other mid-test.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-07-26 19:43:28 -07:00
co-authored by Orca
parent 928ab30919
commit 13874b60ee
2 changed files with 55 additions and 8 deletions
@@ -1,6 +1,14 @@
import { describe, expect, it, vi } from 'vitest'
import { afterAll, describe, expect, it, vi } from 'vitest'
import { execFileSync } from 'node:child_process'
import { mkdirSync, writeFileSync, appendFileSync, rmSync, realpathSync } from 'node:fs'
import {
mkdirSync,
mkdtempSync,
writeFileSync,
appendFileSync,
rmSync,
realpathSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { OrcaRuntimeService } from './orca-runtime'
import { folderWorkspaceKey } from '../../shared/workspace-scope'
@@ -15,7 +23,9 @@ vi.mock('electron', () => ({
app: { getPath: vi.fn(() => '/tmp') }
}))
const FIXTURE = `${realpathSync('/tmp')}/hotbugs/fixture-6357`
// Why: a fixed path collides when two runs of this file overlap (watch mode, CI
// shards), and each `buildFixture` rm -rf's the other's repos mid-test.
const FIXTURE = mkdtempSync(join(realpathSync(tmpdir()), 'orca-6357-'))
const CONTAINER = join(FIXTURE, 'fint')
const CHILD_API = join(CONTAINER, 'fint_api')
const CHILD_WT = join(FIXTURE, 'wt-fint_api-refund')
@@ -139,6 +149,10 @@ function makeStore(overrides: { repos?: Repo[] } = {}): unknown {
}
describe('#6357 monorepo folder workspace', () => {
afterAll(() => {
rmSync(FIXTURE, { recursive: true, force: true })
})
it('A: file explorer resolves for a folder workspace (merged #6569 path)', async () => {
buildFixture()
const runtime = new OrcaRuntimeService(makeStore() as never)
+38 -5
View File
@@ -24191,8 +24191,18 @@ export class OrcaRuntimeService {
if (!target) {
return null
}
// Why: one unreadable child repo must not blank the whole workspace list.
const status = await getRuntimeGitStatusForTarget(target, options).catch(() => null)
// Why: one unreadable child repo must not blank the whole workspace list,
// but it also must not vanish without a trace — its files silently go missing
// from the merged status, which looks identical to a clean repo.
const status = await getRuntimeGitStatusForTarget(target, options).catch(
(error: unknown) => {
console.warn('[runtime] folder-workspace status failed for child repo', {
repo: repo.path,
error
})
return null
}
)
if (!status) {
return null
}
@@ -24236,7 +24246,15 @@ export class OrcaRuntimeService {
if (!target) {
return null
}
const status = await getRuntimeGitStatusForTarget(target).catch(() => null)
// Why: a status failure here silently drops the repo from the commit, so the
// user sees a success that skipped their staged files. Log which one.
const status = await getRuntimeGitStatusForTarget(target).catch((error: unknown) => {
console.warn('[runtime] folder-workspace commit skipped a child repo', {
repo: repo.path,
error
})
return null
})
const hasStaged = status?.entries.some((entry) => entry.area === 'staged') === true
return hasStaged ? { repo, target } : null
})
@@ -24288,7 +24306,13 @@ export class OrcaRuntimeService {
}
const detected = await this.gitCommands
.getRuntimeGitConflictOperation(`id:${target.worktree.id}`)
.catch(() => 'unknown' as const)
.catch((error: unknown) => {
console.warn('[runtime] folder-workspace abort could not read conflict state', {
repo: repo.path,
error
})
return 'unknown' as const
})
// Why: belt-and-braces. Git already refuses `merge --abort` on a mid-rebase
// repo (and vice versa), so this narrows what we run rather than what we
// prevent — it keeps N-1 pointless failing git invocations off the wire.
@@ -24299,7 +24323,16 @@ export class OrcaRuntimeService {
// Why: aborting nothing is not an error — the conflict may have been resolved
// in a terminal already, and the renderer only needs the state to settle.
await Promise.all(
targets.map((target) => abortRuntimeGitForTarget(target, operation).catch(() => undefined))
targets.map((target) =>
abortRuntimeGitForTarget(target, operation).catch((error: unknown) => {
// Why: one repo refusing the abort must not block the others, but a
// still-conflicted repo the user believes is clean needs a trail.
console.warn(`[runtime] folder-workspace ${operation} abort failed`, {
repo: target.worktree.path,
error
})
})
)
)
return { ok: true }
}