Skip to content

0.5.4: send handshake on replacement transports in _createPeer#23

Merged
sym-bot merged 2 commits intomainfrom
fix/handshake-on-replace
Apr 29, 2026
Merged

0.5.4: send handshake on replacement transports in _createPeer#23
sym-bot merged 2 commits intomainfrom
fix/handshake-on-replace

Conversation

@sym-bot
Copy link
Copy Markdown
Owner

@sym-bot sym-bot commented Apr 29, 2026

Summary

Companion fix to v0.5.3. When the dual-dial dedup or stale-prior swap path in `_createPeer` replaced an existing transport, the new transport was registered in `existingPeer.transports` but no handshake was sent on it — `_addPeer` (which sends the handshake) is only called for brand-new peers, not transport replacements.

The remote (sym-swift) saw the new connection reach `.ready`, sent its own handshake, and waited for ours. Ours never arrived. ~10 seconds later the heartbeat tick fired `ping` on every transport, the remote saw `ping` as the first frame, and disconnected with `[SYM] session: expected handshake, got ping` — protocol violation.

Field evidence

```
[SYM] session: expected handshake, got ping
[SYM] session: disconnected: Connection closed
```

That log line on Mac Catalyst MeloMove was the closing-disconnect every ~10 seconds in the flap loop. Every reconnect after a dedup-replace was killed by the protocol-violation trip-wire.

Fix

Extracted handshake-build into `_buildHandshake()` helper; the existing-peer branch in `_createPeer` now sends the handshake on every newly-registered transport. Idempotent — if the remote already sent its handshake from its side, it processes both fine.

Tests

150/150 existing unit tests pass.

Test plan

  • All existing unit tests pass (`npm test`)
  • Verified end-to-end on Mac Catalyst MeloMove ↔ claude-code-mac (Node) on the same Mac. Connection stays stable, peers persist in the UI, CMBs flow continuously without the periodic 10s drop.

🤖 Generated with Claude Code

sym-bot and others added 2 commits April 29, 2026 18:56
Companion fix to v0.5.3. When the dual-dial dedup or stale-prior swap
path in _createPeer replaced an existing transport, the new transport
was registered in existingPeer.transports but no handshake was sent on
it — _addPeer (which sends the handshake) is only called for brand-new
peers, not transport replacements.

The remote (sym-swift) saw the new connection reach .ready, sent its
own handshake, and waited for ours. Ours never arrived. ~10 seconds
later the heartbeat tick fired `ping` on every transport, the remote
saw `ping` as the first frame, and disconnected with
"[SYM] session: expected handshake, got ping" — protocol violation.

Net result: every reconnect after a dedup-replace was killed within
10 seconds by the protocol-violation trip-wire, producing the flap
loop visible on Mac Catalyst MeloMove.

Fix: extracted handshake-build into _buildHandshake() helper; the
existing-peer branch in _createPeer now sends the handshake on every
newly-registered transport. Idempotent — if the remote already sent
its handshake, it processes both fine.

Verified end-to-end on Mac Catalyst MeloMove ↔ claude-code-mac on
the same Mac. Connection stays stable, peers persist in the UI,
CMBs flow continuously without the 10s drop.

150/150 unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sym-bot sym-bot merged commit 118fcd2 into main Apr 29, 2026
2 checks passed
@sym-bot sym-bot deleted the fix/handshake-on-replace branch April 29, 2026 18:03
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