From 13874b60ee1934b1707990800a86d928d34a9770 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 26 Jul 2026 19:43:28 -0700 Subject: [PATCH] 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 --- .../folder-workspace-git-routing.test.ts | 20 +++++++-- src/main/runtime/orca-runtime.ts | 43 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main/runtime/folder-workspace-git-routing.test.ts b/src/main/runtime/folder-workspace-git-routing.test.ts index f4ca6e8271e..a0767c7e09a 100644 --- a/src/main/runtime/folder-workspace-git-routing.test.ts +++ b/src/main/runtime/folder-workspace-git-routing.test.ts @@ -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) diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index 15184274e95..5a8d215f7b1 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -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 } }