Skip to content

fix(ssh): reconnecting a host after stopping its managed server no longer fails the move (#29560) - #29586

Merged
nwparker merged 1 commit into
mainfrom
nwparker/29560-dormant-id-reimport
Oct 16, 2026
Merged

nwparker merged 1 commit into
mainfrom
nwparker/29560-dormant-id-reimport

Conversation

@nwparker

@nwparker nwparker commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

If you stopped an SSH host's managed server and then connected that host again, Orca tried to move the host's projects onto the new server a second time. The server still had the projects from the first move, and it refused the second copy. Resume could never succeed. Now Orca notices that the server already has those projects and uses its copy.

What Changed

  • Before: connect a host so its project moves to a managed server, run orca environment stop, then reconnect. Every Resume failed with orcad_migration_dormant_id_conflict:worktree_meta:<repo>::<path>, and the host showed "Host locked".
  • After: the reconnect completes. The server keeps its copy of the project, including anything changed while it was managed. The connect shows the existing "this host's server already had , so this desktop now uses the server's copy" line.

Mechanism: src/main/ssh/orcad-migration-repository-link.ts. Stopping a server unlinks it on this desktop but leaves its profile on the host, rows from the first move included. The conversion already links a project the server holds at the same host path, but only when the server's row has a different id. A row with the same id was left to the import, on the assumption that it was identical. That stops holding once the server has been used: a worktree's metadata changes, and the import (assertOrcadDestinationCanonicalMetadata) refuses it. Now a same-id, same-path project is linked like a different-id one, unless the server reports that this migration already committed. That case is a lost reply after the commit, and it has to resume rather than relink.

Why

  • Linking loses nothing. The server's rows stay as they are, and this desktop's retained rows stay on disk, as they already do for every moved or linked project.
  • Alternatives:
    • Let the import overwrite the server's rows with this desktop's older copy. That throws away whatever changed on the server while it was managed.
    • Make stop wipe the server's profile. That deletes data on the host and does nothing for profiles already left behind.
    • Loosen the destination's conflict check. That would weaken a guard other paths rely on, and it changes what an older server accepts.

Fixes #29560 (the dormant-id conflict. The leftover ssh -L after quit is a separate issue, handled separately.)

Visual Proof

N/A. No UI change: the existing linked-project status line is reused.

Testing

  • Automated tests added/updated
  • New test moving the host again after its server was stopped: does a first move, edits the project on the server, runs stop's local unlink, then reconnects. It fails on main with exactly the reported orcad_migration_dormant_id_conflict:worktree_meta:desktop-repo::/root/migrepo and passes with this change. The server keeps its edited metadata, and this desktop keeps its retained copy.
  • New guard test: a move whose commit landed but whose reply was lost resumes under the same migration id and is not relinked. Without the committed check it fails with orcad_migration_committed_source_cannot_be_released.
  • pnpm tc:node and check:code-quality:changed pass.
  • Live, on a real Linux host (omarchy, isolated HOME), using the same profile that reproduced the conflict on main after stop: a build of this branch connected and returned linked:[{path:/tmp/upg227-remote/home/repo}]. The repo and both worktrees kept their ids, and there was no dormant_id_conflict. The first connect was refused, correctly, because old relay-era shells were still running on the host; it connected once they were ended. A second desktop (main build) was connected to the same host in both the main repro and this run, so the two runs are like-for-like.

Review

Codex (gpt-6.1-sol, high): no findings.

Agent skill upstream boundary

  • Not applicable

Notes

  • SSH: the change is client-only. There is no wire change, and it uses the existing readState call, so older servers are unaffected.
  • Folder workspaces are not path-linked today, and they still are not. This PR is scoped to the reported repository case.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • N/A visual proof, with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote impact considered
  • CI will cover lint/typecheck/test/build

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.

[Bug]: Resume fails with orcad_migration_dormant_id_conflict after stopping a managed server and reconnecting its SSH host (Linux, 1.4.227)

1 participant