From e1569dd87084b70c4616dfe2b39210abc419ee27 Mon Sep 17 00:00:00 2001 From: vybe Date: Fri, 22 May 2026 06:34:08 +0000 Subject: [PATCH] fix: eliminate toggle decision staleness via poll-then-act (no cached desired state) (#42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - toggleTailscale() now forces a fresh statusCheck instead of reading possibly-stale root.isConnected - The actual up/down decision happens in statusCheck.onExited using the just-received value - _pendingToggle is a transient one-shot flag (reset immediately after use) — not a persistent 'desired state' cache - Complies with AGENTS.md rule 1 / #11 Written by AI agent working for @jtmorris. Model: Grok build-0.1. --- tailscalectl/TailscaleWidget.qml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tailscalectl/TailscaleWidget.qml b/tailscalectl/TailscaleWidget.qml index e9d5f27..4bdc647 100644 --- a/tailscalectl/TailscaleWidget.qml +++ b/tailscalectl/TailscaleWidget.qml @@ -18,6 +18,7 @@ PluginComponent { property string _copyText: "" property string _copyCurrentTool: "" property int _copyAttempted: 0 + property bool _pendingToggle: false // transient one-shot for poll-then-act (#42) — reset immediately after use, no "desired state" cache layerNamespacePlugin: "tailscalectl" popoutWidth: 360 @@ -111,12 +112,21 @@ PluginComponent { root.peers = [] ToastService.showError("tailscalectl", TailscaleLib.errorMessage("status")) } + + // #42 poll-then-act: if a toggle was requested, use the *fresh* state we just received + if (root._pendingToggle) { + root._pendingToggle = false + toggleProcess.command = TailscaleLib.buildToggleCommand(root.isConnected) + toggleProcess.running = true + } } } function toggleTailscale() { - toggleProcess.command = TailscaleLib.buildToggleCommand(root.isConnected) - toggleProcess.running = true + // #42: poll-then-act — never decide up/down from potentially stale root.isConnected. + // Force a fresh statusCheck; the decision happens in its onExited using the just-received value. + root._pendingToggle = true + statusCheck.running = true } function setExitNode(hostname) {