Skip to content

fix: --host over ssh no longer evicts a session host started with CODEAF_SYNC_URL - #2067

Merged
AbirAbbas merged 2 commits into
devfrom
fix/host-relay-engine-pingpong
Oct 30, 2026
Merged

AbirAbbas merged 2 commits into
devfrom
fix/host-relay-engine-pingpong

Conversation

@AbirAbbas

Copy link
Copy Markdown
Collaborator

What was wrong

codeaf chat --host <machine> runs codeaf engine on that machine under a non-interactive ssh shell. That process attaches to the machine's per-workspace session host — the same one a local codeaf window there uses.

Since Wormhole (#1888), the attach check (clearStaleEngineHostAs → enginehost.SyncDiffers) compares the relay the attaching process resolves with the relay the host resolved at startup. The ssh shell usually lacks the CODEAF_SYNC_URL the person exported for a self-hosted relay. So the ssh launch resolved the saved or hosted relay, saw a "different sync setting", and retired the idle host, or refused with the background engine for this folder started with a different environment… when the host was busy. The local window's next launch did the same in reverse. The two took the workspace from each other in turn.

--host and the relay are separate features: --host is ssh transport, and the relay is chat sync. They meet only at that host-compatibility check.

The fix

Only a relay the attaching process names counts as a choice.

  • CODEAF_SYNC_URL set: the full resolved relay is compared, as before. An explicit different address or off still retires an idle host and refuses a busy one (C10 unchanged).
  • CODEAF_SYNC_URL unset: only what both sides read from the same home is compared: the address a pairing saved, else the hosted default. The host now records that value as sync-unnamed next to sync-environment. A changed pairing still restarts an idle host.
  • The provider environment fingerprint no longer includes the relay, so the same launch cannot restart an idle host through EnvironmentDiffers instead. EnvironmentMAC (used by the automations clock) is unchanged.

The manual's A different sync setting on an existing engine section now covers this. It also quotes the refusal exactly as the code spells it, since the old quote had drifted.

Validation contract

  1. A launch with no CODEAF_SYNC_URL joins a host that a terminal started with CODEAF_SYNC_URL=<url>, idle or busy. The PID is unchanged and there is no note and no refusal. Covered by TestC10ALaunchThatNamesNoRelayJoinsTheHostATerminalStarted, which fails on dev for both busy states and passes here.
  2. A launch with no variable still restarts an idle host after the pairing's saved relay changes. Covered by TestC10AChangedSavedRelayStillRetiresAnIdleHost.
  3. An explicit different address or off still retires an idle host and refuses a busy one, for same, older and newer builds. Covered by the existing TestC10* tests, which pass unchanged.

Local: go build ./..., go vet on the touched packages, and focused TestC10|TestSameOrUnknown…|TestEngineStatusReports…|TestDifferentEnvironment in cmd/codeaf, plus the enginehost and syncsetup relay tests, all green. Touched-package suites are left to CI.

Not changed (follow-up if wanted)

  • A host started first by the ssh launch (no variable, so the saved or hosted relay) is still refused by a later local terminal that explicitly sets a different CODEAF_SYNC_URL while the --host window is attached. That is the explicit-choice rule working as designed. Saving the relay with a pairing, instead of exporting it per shell, avoids it.
  • Provider keys exported only in an interactive shell are the same shape for idle hosts, but that predates the relay and never refuses busy work.

🤖 Generated with Claude Code

AbirAbbas and others added 2 commits October 30, 2026 09:00
…of evicting it

`codeaf chat --host` runs `codeaf engine` under a non-interactive ssh shell,
which rarely carries the CODEAF_SYNC_URL a person exported in their own
terminal. The session host compared that launch's resolved relay (the saved
or hosted one) with the relay the terminal's variable had named, read the
silence as a different sync setting, and retired the idle host or refused a
busy one. The terminal's next launch did the same back, so --host and a local
window on a self-hosted relay took the workspace from each other in turn.

Only a relay this process names is a choice now. With CODEAF_SYNC_URL set the
full resolved answer is compared, as before. With it unset, only what both
sides read from the same home — a pairing's saved address, else the hosted
default — is compared, recorded by the host as `sync-unnamed`. The provider
fingerprint no longer carries the relay, so the same launch cannot restart an
idle host through EnvironmentDiffers either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AbirAbbas
AbirAbbas merged commit 9508f1e into dev Oct 30, 2026
7 checks passed
@AbirAbbas
AbirAbbas deleted the fix/host-relay-engine-pingpong branch October 30, 2026 13:11
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.

1 participant