From c9c422d5367010c008cfe6c533831d8bc8ba4a67 Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Thu, 9 Jul 2026 14:37:13 -0700 Subject: [PATCH] Foreground Connection Delay Adjustment Nucleic-Session: CB658C4F-A19F-447C-B313-7CB21783BD94 Co-authored-by: Nucleic --- .../NucleicRemote/Models/RemoteStore.swift | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/NucleicRemote/NucleicRemote/Models/RemoteStore.swift b/NucleicRemote/NucleicRemote/Models/RemoteStore.swift index 3a87b72..d4864c1 100644 --- a/NucleicRemote/NucleicRemote/Models/RemoteStore.swift +++ b/NucleicRemote/NucleicRemote/Models/RemoteStore.swift @@ -924,18 +924,35 @@ final class RemoteStore: ObservableObject { ?? WireCapabilities(canModifyToolInput: false, allowAlwaysScopes: [])) setIfChanged(\.modelCatalog, ctx?.modelCatalog ?? .empty) + var targetConnectivity: Connectivity + var targetScope: DeviceScope if let id = openSessionHostID, let conn = connections[id] { // While a transcript is open, the composer/controls act on *that* Mac — its connectivity // gates send and its scope drives the control affordances. - setIfChanged(\.connectivity, conn.connectivity) - setIfChanged(\.grantedScope, conn.grantedScope) + targetConnectivity = conn.connectivity + targetScope = conn.grantedScope } else { - setIfChanged(\.connectivity, aggregateConnectivity()) + targetConnectivity = aggregateConnectivity() // Optimistic new-chat gating: enabled if *any* Mac grants control (the owning Mac still // enforces scope when the intent lands there). - setIfChanged(\.grantedScope, connections.values - .filter { $0.connectivity.isLive }.map(\.grantedScope).max() ?? .approve) + targetScope = connections.values + .filter { $0.connectivity.isLive }.map(\.grantedScope).max() ?? .approve } + if targetConnectivity.isLive { + // Truly live — remember this projection so the optimistic overlay can present it across + // the next foreground/relaunch. + captureLastLive(transport: targetConnectivity.transport ?? .lan, scope: targetScope) + } else if isOptimisticActive, let last = lastLive { + // Right after launch/foreground the link is re-handshaking (or a suspended socket woke up + // looking dead). Rather than flash "Disconnected" for the beat it takes to reconnect, keep + // presenting the last known-good live state — the app assumes it's connected. Actions + // taken now are queued in `send` and replayed once a link is up (or discarded when the + // window lapses without one). + targetConnectivity = .connected(last.transport) + targetScope = last.grantedScope + } + setIfChanged(\.connectivity, targetConnectivity) + setIfChanged(\.grantedScope, targetScope) } /// Assign a `@Published` property only when the value actually differs, so a no-op rebuild