Fast-follow to #3727 (TX automation hardening). Two robustness items the review flagged as non-blocking; the first is a safety-backstop hardening worth doing.
1. Watchdog should re-issue the unkey each tick while still keyed-past-limit (safety)
AutomationServer::forceUnkey() resets m_txKeyedSinceMs = 0, and onTxWatchdog() re-arms from now whenever it sees keyed && m_txKeyedSinceMs == 0. So if an unkey doesn't take — the radio ignores stopTune()/setMox(false) — the watchdog grants another full m_txMaxKeyMs (~20s) window before it tries again, instead of re-issuing the unkey on the next tick.
The primary threat (a hung/abandoned script leaving TX keyed) is fully handled today — forceUnkey succeeds because the script isn't what's holding the key. This only degrades the rarer "radio ignored the unkey" case from continuous-retry to every-~20s-retry. But this is the last-resort transmitter safety rail, so for a "can never leave a live transmitter on" guarantee it should be airtight.
Fix: latch the limit-exceeded state instead of resetting the start timestamp in forceUnkey(), so onTxWatchdog() keeps issuing the unkey every tick while the radio remains keyed past the limit. Clear the latch only when the radio actually reports un-keyed.
2. Fail safe to defaults on a misconfigured env value (usability)
qEnvironmentVariableIntValue returns 0 for an empty/non-numeric value, so AETHER_AUTOMATION_TX_MAX_MS= (or a typo) sets m_txMaxKeyMs = 0 (unkey on the first watchdog tick of any transmit), and AETHER_AUTOMATION_TX_MAX_POWER=0 clamps all power to 0. Both fail safe (toward not transmitting), so this is a usability nit rather than a safety risk — but a bad value silently disabling TX is surprising.
Fix: only override the defaults when the parsed value is > 0:
bool ok = false;
const int ms = qEnvironmentVariableIntValue("AETHER_AUTOMATION_TX_MAX_MS", &ok);
if (ok && ms > 0) m_txMaxKeyMs = ms;
Both surfaced in the #3727 review (verified live on a FLEX-8400M into a dummy load). Scope: src/core/AutomationServer.cpp. ALLOW_TX-gated paths only.
🤖 Generated with Claude Code
Fast-follow to #3727 (TX automation hardening). Two robustness items the review flagged as non-blocking; the first is a safety-backstop hardening worth doing.
1. Watchdog should re-issue the unkey each tick while still keyed-past-limit (safety)
AutomationServer::forceUnkey()resetsm_txKeyedSinceMs = 0, andonTxWatchdog()re-arms fromnowwhenever it seeskeyed && m_txKeyedSinceMs == 0. So if an unkey doesn't take — the radio ignoresstopTune()/setMox(false)— the watchdog grants another fullm_txMaxKeyMs(~20s) window before it tries again, instead of re-issuing the unkey on the next tick.The primary threat (a hung/abandoned script leaving TX keyed) is fully handled today —
forceUnkeysucceeds because the script isn't what's holding the key. This only degrades the rarer "radio ignored the unkey" case from continuous-retry to every-~20s-retry. But this is the last-resort transmitter safety rail, so for a "can never leave a live transmitter on" guarantee it should be airtight.Fix: latch the limit-exceeded state instead of resetting the start timestamp in
forceUnkey(), soonTxWatchdog()keeps issuing the unkey every tick while the radio remains keyed past the limit. Clear the latch only when the radio actually reports un-keyed.2. Fail safe to defaults on a misconfigured env value (usability)
qEnvironmentVariableIntValuereturns 0 for an empty/non-numeric value, soAETHER_AUTOMATION_TX_MAX_MS=(or a typo) setsm_txMaxKeyMs = 0(unkey on the first watchdog tick of any transmit), andAETHER_AUTOMATION_TX_MAX_POWER=0clamps all power to 0. Both fail safe (toward not transmitting), so this is a usability nit rather than a safety risk — but a bad value silently disabling TX is surprising.Fix: only override the defaults when the parsed value is
> 0:Both surfaced in the #3727 review (verified live on a FLEX-8400M into a dummy load). Scope:
src/core/AutomationServer.cpp. ALLOW_TX-gated paths only.🤖 Generated with Claude Code