Skip to content

Retry failed catalog reads when SSH hosts move to Remote - #26531

Merged
OrcaWin merged 3 commits into
mainfrom
nwparker/ssh-consolidation-phase35-validation
Oct 9, 2026
Merged

OrcaWin merged 3 commits into
mainfrom
nwparker/ssh-consolidation-phase35-validation

Conversation

@nwparker

@nwparker nwparker commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​253 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​251
Prod 5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​76 $\color{#cf222e}{\Huge{\mathbf{−}}}$​20 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​56

ELI5

Moving a machine to Remote updates Orca's address book. If reading that address book fails once, Orca currently remembers it as successfully loaded. Reconnecting then leaves the machine labeled with an opaque ID. Let failed reads retry when the machine reconnects.

What Changed

Clear a failed conversion-catalog load from the per-host cache. Keep successful and in-progress loads deduplicated, and ignore an old load when that host returns to the relay or changes servers. Conversion requests now ask the existing repository, project-group and folder-workspace loaders to propagate errors, so the renderer removes its old workspace rows only after those catalog reads succeed. Ordinary refresh callers retain their existing error handling.

Why

Retrying the existing conversion refresh fixes the stale host list without adding another poller or requiring an app restart. Keeping each load's identity also prevents a late failure from invalidating a newer load. This changes renderer coordination only; no remote wire fields, Git commands, persisted migration state or process-liveness decisions change.

Linked Issue

Follow-up to #26483, based on OrcaWin/phase35 at 544fffe9214.

Visual Proof

Same journey against a real Linux SSH container, with the local environment-list IPC made temporarily unavailable during conversion, then restored before reconnect. The SSH server, migration and subsequent catalog reads are real. This is controlled fault injection, not a claim that a physical network outage was reproduced.

Before: reconnect leaves the managed host labeled 4f49f65… / Orca server.

Before

After: reconnect restores the machine's name and SSH connection detail.

After

The folder shown under Local Mac is a separate finding recorded in the local consolidation tracker and being investigated separately.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated

macOS arm64 client, hidden Electron renderer, isolated profiles, real Debian arm64 OpenSSH container, packaged Phase 3.5 Linux server template. Every launch used ORCA_BACKGROUND_LAUNCH=1.

  • Rendered regression fails on the unchanged integration renderer: after restoring the production IPC handler and reconnecting, the expected named Remote host header is absent. The fixed renderer passes the same journey.
  • Unit regressions fail before the fix for repository, project-group and folder-workspace RPC errors. They now verify retention and retry; additional tests cover environment-list failure and cancellation when the host returns to relay.
  • All 6 real-host conversion tests pass: live relay-era state, upgrade startup, refused TCP forwarding with stdio fallback, occupied server port, server update and the new catalog-failure recovery.
  • 45 affected store/conversion tests pass.
  • 11 SSH settings UI tests pass: config import/re-adoption, host picker and long-list add/edit modal.
  • pnpm tc, pnpm lint, changed-code quality against origin/OrcaWin/phase35, and electron-vite build --mode e2e pass.
  • The standalone typecheck:e2e reports existing errors in unrelated fixtures; no new-test errors were reported. Windows client/host execution was not run locally.

Reproduction command after providing a Linux orcad template:

ORCA_BACKGROUND_LAUNCH=1 SKIP_BUILD=1 ORCA_E2E_SSH_DOCKER=1 \
ORCA_E2E_ORCAD_CONVERT_HOST=docker \
ORCA_E2E_ORCAD_CONVERT_TEMPLATE=/absolute/path/to/orcad-template \
pnpm run test:e2e tests/e2e/ssh-orcad-auto-convert.spec.ts \
--workers=1 -g 'reconnect restores the managed host name'

The regression is inside the existing conversion spec, so the dedicated Linux conversion CI job runs it.

Unfixed failure log · All six fixed real-host tests

AI Disclosure

Review

Self-reviewed error propagation, per-host isolation, cancellation and unchanged ordinary refresh behavior.

Agent skill upstream boundary

  • Not applicable; no upstream skill source copied.

Notes

No disk data is deleted by this change. Existing migration retention and rollback remain host-owned. Folder workspaces are explicitly covered. No provider-specific or OS-specific production code was added.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • Before/after screenshots attached
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered
  • Local lint, typecheck, affected tests and Electron build pass; CI will cover the broader suite

@OrcaWin
OrcaWin force-pushed the nwparker/ssh-consolidation-phase35-validation branch from fab5d3b to 515aabf Compare October 9, 2026 02:04
@OrcaWin
OrcaWin changed the base branch from OrcaWin/phase35 to main October 9, 2026 02:04
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a2900c72-c7d5-4117-ba38-3d4bd535d838
📥 Commits

Reviewing files that changed from the base of the PR and between 515aabf and a5c5860.

📒 Files selected for processing (2)
  • src/renderer/src/hooks/ipc-events/ssh-managed-server-converted-catalogs.test.ts
  • src/renderer/src/hooks/ipc-events/ssh-managed-server-state-effects.ts

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


📝 Walkthrough

Walkthrough

Managed-server catalog fetches can now propagate errors to the load tracker. Loads are tracked by identity and checked during catalog and worktree refreshes. Tests cover retrying failed catalog requests after reconnect, stopping stale loads after a relay transition, and recovering from a failed catalog refresh during conversion.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to a5c58

A catalog response started before a host returns to relay may leave obsolete repository rows visible. The remaining risk is bounded, but the catalog-fencing fix should be made or explicitly accepted before merging.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: retrying failed catalog reads when SSH hosts move to Remote.
Description check Passed The description is complete and focused. It includes the user impact, implementation details, rationale, issue reference, visual proof, testing results, limitations, review notes, and checklist status…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · 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: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2050493e-85dc-4966-826f-5300c0b6b26b
📥 Commits

Reviewing files that changed from the base of the PR and between 37833ce and 515aabf.

📒 Files selected for processing (7)
  • src/renderer/src/hooks/ipc-events/ssh-managed-server-converted-catalogs.test.ts
  • src/renderer/src/hooks/ipc-events/ssh-managed-server-state-effects.ts
  • src/renderer/src/store/folder-workspaces/folder-workspace-catalog-actions.ts
  • src/renderer/src/store/project-groups/project-group-catalog-actions.ts
  • src/renderer/src/store/repos/repo-catalog-actions.ts
  • src/renderer/src/store/repos/repo-state.ts
  • tests/e2e/ssh-orcad-auto-convert.spec.ts

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

Comment on lines +26 to 41
// Starts and wakes keep the same owner; only a new server or a failed load needs a refresh.
if (catalogLoadByTarget.get(targetId)?.environmentId !== next.environmentId) {
const load = { environmentId: next.environmentId }
catalogLoadByTarget.set(targetId, load)
void loadManagedServerCatalogs(targetId, load).catch((error: unknown) => {
if (catalogLoadByTarget.get(targetId) === load) {
catalogLoadByTarget.delete(targetId)
}
console.warn('[ssh] Could not load the managed server catalogs:', error)
)
})
}
return
}
if (next?.kind === 'relay') {
loadedEnvironmentByTarget.delete(targetId)
catalogLoadByTarget.delete(targetId)
}

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

Fence catalog commits when the target enters relay.

When a managed-server catalog load is pending, the relay transition deletes catalogLoadByTarget, but it does not invalidate the repository catalog action. A pending fetchRepos can therefore pass its unchanged host-specific generation check and merge the old server's repositories into repos. The later load-identity check only prevents converted-row cleanup and workspace rehoming; it does not undo that repository commit.

Invalidate the pending catalog actions at this transition, or pass the load identity into their commit guards so obsolete results cannot commit after the target enters relay.

@OrcaWin
OrcaWin merged commit bfd9858 into main Oct 9, 2026
43 checks passed
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.

2 participants