commit e448979a2ff5feb58131ef93b2d466a2eab7e3fe
parent f614d20ea12f729656d8177321ae43bae8dd4098
Author: Michael Camilleri <[email protected]>
Date: Mon, 25 May 2026 19:57:32 +0900
Make engagement channel delivery reliable
The WebRTC bridge was creating an unordered, zero-retry data channel, so live
cell edits and cursor updates were explicitly allowed to disappear in transit.
That made the device logs ambiguous: a channel could open successfully, but a
missing peer update could mean transport loss, send gating, decode failure or a
local apply rejection.
This commit switches the engagement data channel back to WebRTC's reliable
defaults and adds diagnostic breadcrumbs around the realtime path. Cell edit
and selection sends now log on success, inbound selections log when decoded,
and rejected realtime cell edits log with their row/column/device context.
Co-Authored-By: Codex GPT 5.5 <[email protected]>
Diffstat:
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/Crossmate/Services/AppServices.swift b/Crossmate/Services/AppServices.swift
@@ -709,6 +709,11 @@ final class AppServices {
"engagement: applied cellEdit \(engagementID.uuidString) " +
"r=\(edit.row) c=\(edit.col) device=\(edit.deviceID.prefix(8))"
)
+ } else {
+ syncMonitor.note(
+ "engagement: rejected cellEdit \(engagementID.uuidString) " +
+ "r=\(edit.row) c=\(edit.col) device=\(edit.deviceID.prefix(8))"
+ )
}
case .selection:
guard let selection = envelope.selection else {
@@ -716,6 +721,10 @@ final class AppServices {
return
}
engagementStore.set(selection)
+ syncMonitor.note(
+ "engagement: received selection \(engagementID.uuidString) " +
+ "r=\(selection.row) c=\(selection.col) device=\(selection.deviceID.prefix(8))"
+ )
}
}
diff --git a/Crossmate/Services/EngagementHost.html b/Crossmate/Services/EngagementHost.html
@@ -149,10 +149,7 @@
async function createOffer(engagementID) {
try {
const peer = createPeer(engagementID);
- const channel = peer.pc.createDataChannel("crossmate", {
- ordered: false,
- maxRetransmits: 0
- });
+ const channel = peer.pc.createDataChannel("crossmate");
attachChannel(engagementID, channel);
await peer.pc.setLocalDescription(await peer.pc.createOffer());
await waitForIceComplete(peer.pc);
diff --git a/Crossmate/Sync/EngagementCoordinator.swift b/Crossmate/Sync/EngagementCoordinator.swift
@@ -353,6 +353,10 @@ actor EngagementCoordinator {
do {
let message = EngagementMessage(cellEdit: edit)
try await host.send(engagementID: engagementID, message: message.encodedData())
+ await log(
+ "engagement: sent cellEdit \(engagementID.uuidString) " +
+ "r=\(edit.row) c=\(edit.col) device=\(edit.deviceID.prefix(8))"
+ )
} catch {
await log("engagement: cell edit send failed \(engagementID.uuidString): \(error.localizedDescription)")
}
@@ -363,6 +367,10 @@ actor EngagementCoordinator {
do {
let message = EngagementMessage(selection: selection)
try await host.send(engagementID: engagementID, message: message.encodedData())
+ await log(
+ "engagement: sent selection \(engagementID.uuidString) " +
+ "r=\(selection.row) c=\(selection.col) device=\(selection.deviceID.prefix(8))"
+ )
} catch {
await log("engagement: selection send failed \(engagementID.uuidString): \(error.localizedDescription)")
}