Skip to content

feat(transmit): expose PTT Mic Override and document the v4.3 hardware-PTT default. Principle I. - #6445

Merged
jensenpat merged 8 commits into
mainfrom
feat/ptt-mic-override
Oct 14, 2026
Merged

jensenpat merged 8 commits into
mainfrom
feat/ptt-mic-override

Conversation

@ten9876

@ten9876 ten9876 commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #6442. Implements the PTT Override item in FlexLib v4.3.16 tracker #6437.

SmartSDR v4.3 changed hardware PTT to transmit the selected TX source, including DAX and PC audio. AetherSDR now exposes the radio-wide PTT Mic Override setting so an operator can restore the last-used analog microphone for hardware PTT.

  • Decode ptt_mic_override only for valid 0/1 values. Track whether the radio has reported the field, distinguishing an unsupported firmware session from a reported false value.
  • Route a typed configuration request through the Flex backend as transmit set ptt_mic_override=<0|1>. Other families return Unsupported. This configuration write does not key TX and is never sent on connect or restore.
  • Add PTT Mic Override to Radio Setup → Transmit → Interlocks - TX REQ. The control mirrors radio status; a click requests the setting and waits for the echo. Unsupported sessions show a disabled control with an accessible reason. Search terms include “mic override.”
  • Clear the value and report latch on disconnect and backend replacement, with safe refresh of an open page. Conditional bridge and troubleshooting fields omit unreported values.
  • Document the firmware default, correct PTT input connectors, and Multi-Flex condition in TX Controls, Radio Setup, Before You Transmit, and WSJT-X Integration.

Protocol authority: official FlexLib v4.3.16 source, Radio.cs:10302-10320 and 11151-11163, independently checked during landing. FlexRadio's PTT Override guidance confirms the default and Multi-Flex condition.

Validation

  • Final local ARM64 Qt 6.12 RelWithDebInfo app build at 8a05e990770a1067535c69d14e958e30a6bbec31, clean working tree. Shared core; ASR, RADE, DSTAR, DFNR and QtKeychain disabled for this validation build.
  • 4/4 focused offscreen CTests passed: aetherd_transmit_decode_test, transmit_model_test, model_control_routing_test, and full radio_setup_tx_timing_fields_test. These cover valid/invalid input, reported-zero presence, typed encoding, non-optimistic UI, disconnect reset and family replacement.
  • Mutation checks: replacing the strict decoder with the permissive carrier caused four malformed-input failures; removing the teardown clear failed the production dialog's family-switch assertion. Restored both guards, rebuilt, and reran all four successfully.
  • Isolated, TX-disabled demo bridge at final clean build identity: connected only to DEMO-0001; searching “mic override” selected Transmit; the button was visible, disabled and unchecked with an accessible reason; get transmit omitted the field. The open page stayed unavailable after disconnect. All five landing demo instances were stopped.
  • Engine boundary, touchpoint manifest, capability and command-plane checks passed on current-main base and head with identical findings: 102 tracked engine warnings/zero blockers, 70 capability booleans, 296 command sites. Bridge-doc registry, test registration, diff whitespace and user-doc production build passed.
  • Author-reported hardware evidence: FLEX-8600 firmware 4.3.16.42034 showed the echoed value and UI through 0 → 1 → 0, with TX unkeyed. This landing pass did not independently connect to hardware. Ordinary demo mode does not report the new field; echoed enabled-state behavior is independently covered by injected, socket-free production model/widget tests.

The bridge currently cannot click this non-keying PTT configuration control because its keying-name fallback refuses it. No automation TX-guard change or new bridge verb is included. No CHANGELOG or versioned documentation changes.

Generated with OpenAI Codex (GPT-6 Astra)

…e-PTT default. Principle I. (#6442)

SmartSDR v4.3.16 (SMART-9340/12931) changed what a hardware PTT transmits.
A footswitch, ACC or mic-jack PTT now sends the selected TX source, DAX and
remote audio included, instead of always forcing the analog mic. The new
radio-wide setting `ptt_mic_override` restores the old behavior
(FlexLib v4.3.16.42034 Radio.cs:10310-10320, status Radio.cs:11151-11163).

- Parse the `ptt_mic_override` transmit-status key into TransmitDelta and
  TransmitModel. Its presence is latched, so firmware before 4.3, which never
  reports the key, is told apart from a reported 0.
- Add the typed TransmitControlRequest::Field::PttMicOverride. The Flex
  backend encodes it as `transmit set ptt_mic_override=<0|1>`; HL2 and Icom
  return Unsupported. The setter is not optimistic: the model changes only on
  the radio's echo.
- Radio Setup → Transmit → Interlocks - TX REQ gets a "PTT Mic Override"
  toggle that follows the radio's value. Before 4.3 it is grayed out, with a
  tooltip saying why.
- Add the setting to the bridge's `get transmit` snapshot and to the slice
  troubleshooting report, only once it has been reported.
- Document the setting and the default flip in TX Controls, Radio Setup,
  Before You Transmit and WSJT-X Integration.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ten9876
ten9876 marked this pull request as ready for review October 13, 2026 22:04
@ten9876
ten9876 requested a review from a team as a code owner October 13, 2026 22:04
@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@ten9876 ten9876 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR substantially implements #6442: status decoding and presence tracking, typed control dispatch, a radio-authoritative UI, conditional diagnostics, and documentation of the firmware default change. Request changes for two reproduced edge cases below. Reviewed head 6d59c776d against merge base 47aa4098d.

Scope

File/group Claimed in body? Verdict
TransmitDelta.h, TransmitModel.{h,cpp}, Flex status decoder Yes: parse, latch, reset In scope
ModelControlRequest.h, Flex encoder, HL2/Icom dispatch Yes: typed setter and unsupported families In scope; sim/ANAN/RTL inherit Unsupported
RadioSetupDialog.cpp Yes: toggle, echo-driven value, unavailable reason In scope; dimming rather than hiding follows GUI canon
AutomationServer.cpp, RadioModel.cpp, SliceTroubleshootingDialog.cpp Yes: conditional bridge/diagnostic field In scope; additive bridge output explicitly disclosed
Four user documentation pages Yes: default flip and operator guidance In scope
Three test files Yes: decoder, model latch/reset, encoder In scope; socket-free injected seams

Everything in the diff is explained by the issue and disclosed in the body. The single commit's author date matches this work. No unrelated restyling, client persistence, dependency, thread, default, CHANGELOG, or versioned-doc changes.

Blockers

  1. Reject malformed override status instead of confirming “off” — src/core/backends/flex/FlexBackend.cpp:1337.

    carry(..., optional<bool>) engages the field for every present string and maps anything except "1" to false. Injecting each of garbage, -1, and 2 through the production decoder produced:

    HOSTILE value=garbage engaged=1 value=0
    HOSTILE value=-1 engaged=1 value=0
    HOSTILE value=2 engaged=1 value=0
    

    All three added socket-free assertions requiring a disengaged delta failed. Applying these deltas will latch support and overwrite a previously true model value with false. FlexLib v4.3.16 Radio.cs:11151–11163 explicitly rejects failed integer parses and values outside 0/1. Constitution I says “FlexLib C# source is the source of truth”; VII says “validates ranges, and fails closed on malformed input.” The new field does not follow either parser contract.

    Replace the added carrier with a validated parse (the existing namespace import exposes parseInt):

        if (const std::optional<int> value = parseInt(kvs, "ptt_mic_override");
            value && (*value == 0 || *value == 1)) {
            d.pttMicOverride = (*value == 1);
        }

    Add decoder cases for malformed/out-of-range input, alongside valid 0/1 and absence. Confirm rejected input preserves both an unreported model and an existing true value.

  2. Refresh the cached control when the session resets — src/gui/RadioSetupDialog.cpp:3278.

    The new sync subscribes only to stateChanged. TransmitModel::resetState() clears both fields at lines 52–53 but emits no stateChanged, so the open page retains its last value and availability after disconnect.

    Reproduced on the scratch GUI against DEMO-0001 with a temporary, explicitly enabled fixture that emits only TransmitDelta{pttMicOverride=true} from the demo's initial-state path. No firmware peer or hardware was used. Before disconnect, get transmit reported pttMicOverride: true, and the button was checked/enabled. After the real bridge disconnect completed:

    get radio: connected=false
    get transmit: pttMicOverride absent
    dumpTree: {"accessibleName":"PTT Mic Override",
               "checked":true,"enabled":true,"text":"Enabled","visible":true}
    

    This contradicts the body's claim that the button always shows the radio/model value. Have reset notify this observer, or subscribe to the notification reset already emits. A small local correction next to the existing connection is:

            connect(&tx, &TransmitModel::micStateChanged, pttOvrBtn, syncPttOverride);

    Add a socket-free UI lifecycle assertion for reported true → reset, requiring an unchecked, disabled control. The existing model test checks cleared members but misses the notification/UI consequence.

Nits — non-blocking

  • src/models/RadioModel.cpp:13000: brace the new if, per AGENTS.md's “Braces on all control flow.”
  • src/models/TransmitModel.cpp:927: remove the Constitution citation from the code comment; AGENTS.md puts principle tags in commit subjects. The radio-wide/echo explanation is useful and can stay.

Verification and limits

  • Built the named GUI and three focused targets in a scratch worktree using Qt 6.12, shared core and -O2 -g1; all three original CTests passed. Independently reran the existing clean-head build's three binaries, also passing. No broad suite was run, and the body's 789/793 claim was not independently reproduced.
  • Mutation checks: removing the decoder line failed aetherd_transmit_decode_test:61; breaking the presence latch failed the reported-zero assertion; forcing encoder output to zero failed setPttMicOverride. Restored production code and reran all three successfully. The hostile-input assertions above were temporary review probes, not changes proposed in this review.
  • Drove the clean-head GUI on isolated offscreen DEMO-0001: verified conditional snapshot omission and the disabled button's tooltip/accessibility description. Drove the shared-core scratch GUI with the single demo status fixture for the disconnect finding. All review instances were closed, TX was disabled, and the scratch source modifications were restored. Real hardware PTT audio selection and live firmware set→echo convergence cannot be independently verified in ordinary demo mode; I did not connect to hardware. The author's live evidence remains reported evidence, not my reproduction.
  • Checked FlexLib's setter, parser and semantics directly. Read unsupported sibling dispatch, no automatic setter/restoration paths, signal blocking, thread admission and teardown. No extra wire text above the seam or baseline changes: all four boundary gates pass on base and head with identical per-file findings (102 tracked engine warnings, 297 command-plane sites, 70 capability booleans); touchpoint manifest unchanged.
  • No invocable automated code-review skill was available; performed the manual pass and an independent parallel audit. The accessibility bot's warning count does not identify a defect in the new button: it has both accessible name and description.
  • CI is still running its platform builds; Static checks and Docs passed. Earliest workflow creation was 2026-10-13T22:04:37Z, while current main 7d82707e was committed at 22:05:01Z. The pull-request runs test an older merge snapshot; strict up-to-date checks are not enforced, so their eventual green should retain that qualification.

Recommendation: Request changes. Correct parser validation and reset notification, then rerun the focused tests and the open-page disconnect scenario. The main feature path, scope and protocol command are otherwise consistent with #6442 and the reference.

… control on reset. Principle I. (#6442)

Review of #6445:
- Parse ptt_mic_override as FlexLib does (Radio.cs:11151-11163): only 0 or 1
  is accepted. Garbage, -1, 2 and an empty value are dropped, never applied
  as a confirmed "off" or a reported key.
- The Radio Setup control also listens to micStateChanged, the signal
  resetState() sends on disconnect, so an open page drops the last
  session's value and dims again.
- Tests: decoder cases for malformed input; a dialog case for unreported →
  reported → click (typed request, no optimistic flip) → echo → reset.
- Nits: brace the diagnostics if; drop the principle tag from a comment.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ten9876

ten9876 commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

Both blockers and both nits are addressed in a63ef5bd1:

  1. Malformed override status (FlexBackend.cpp): the key is now parsed with parseInt and accepted only as 0 or 1, matching FlexLib Radio.cs:11151-11163. New decoder cases cover garbage, -1, 2 and an empty value, each leaving the delta disengaged, so the model is neither latched as reported nor overwritten. A valid 0 is pinned as well.
  2. Stale control after reset (RadioSetupDialog.cpp): the control now also follows micStateChanged, the signal resetState() emits. New case radio_setup_tx_timing_fields_test::pttMicOverrideFollowsTheRadioAndResets walks the control through: dimmed while unreported → enabled once 0 is reported → click emits the typed PttMicOverride=true request but the button stays unchecked → echo checks it → resetState() leaves it unchecked, dimmed and showing "Disabled".
  3. Nits: the diagnostics if now has braces, and the principle tag is gone from the setter comment.

Mutation checks:

  • Restoring the bare carry makes the decoder test fail (4 failures).
  • Removing the micStateChanged connection makes the new dialog case fail at the reset assertion.
  • With both restored, all four focused tests pass: radio_setup_tx_timing_fields_test, aetherd_transmit_decode_test, transmit_model_test and model_control_routing_test.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@Ozy311 Ozy311 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head a63ef5bd1b10dfd45449093617c834143e51675f, including the incremental fixes since 6d59c776, against merge base 47aa4098d2b3182c8608d9bd7f4b6d842758d84a. The patch implements #6442 within its stated scope.

P3 — Name the PTT input correctly (docs/user/docs/tx-controls.md:153–154).

The new hardware-PTT instructions put a footswitch on the “RCA TX jack.” FlexRadio defines the RCA PTT connector as the footswitch input; TX/TX1/TX2/TX3 are outputs used to key external amplifiers or transverters. Following the new text would connect the footswitch to the wrong port and fail to key the radio. Replace “RCA TX jack” with “RCA PTT input.”

Reference: FlexRadio's input/output connector definitions.

Earlier findings addressed in the current revision.

The earlier review covered malformed status parsing and stale UI after reset. I independently reproduced the stale UI on the previous head; the current micStateChanged subscription addresses that path. The updated parser drops malformed/out-of-range values instead of engaging a false delta. Both now have focused regression coverage, which passed locally. I am not repeating these as outstanding findings.

Verification and limits.

  • Rebuilt the current code locally on Mac with Qt 6.12/shared core. All three focused CTests passed: transmit_model_test, model_control_routing_test, and aetherd_transmit_decode_test, including the new malformed-input cases.
  • Built radio_setup_tx_timing_fields_test and ran specifically pttMicOverrideFollowsTheRadioAndResets: passed. This verifies unreported availability, reported zero, request without optimistic change, echoed true, and reset to disabled/unchecked using production widgets/models without a radio connection.
  • Engine-boundary strict check passed again on the updated head. On the original patch, all four boundary checks passed against merge base with identical tracked findings; bridge-docs registry check also passed. The follow-up introduces no new boundary sites or registry entries.
  • Governance manifest passed at fetched main 7d82707e, with matching Constitution mirrors. The newly pushed commit has a verified/valid signature.
  • This is focused local validation, not a full test suite, release package, completed platform matrix, or live-radio test. Optional ASR/RADE/DSTAR/DFNR were disabled. No RF/TX or hardware audio-selection test was performed. The current-head CI run is still incomplete; earlier-head green checks do not establish current-head platform success.

Verdict: COMMENT. The reproduced reset defect and parser issue are addressed. The connector correction above is the remaining finding from this review; full platform CI and the required owner-review path still govern merge readiness.

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the protocol work is careful, the non-optimistic choice is right, and the "latch on presence, not on change" reasoning is the correct read of the pre-4.3 detection problem. One blocker: the new latch is cleared on disconnect but not on a family switch, which is the exact hazard teardownBackend() already documents for its sibling latch.

1. Issue fit

Solves #6442, with one gap. Every plan bullet maps to a hunk: parse (FlexBackend.cpp:1337-1340), latch (TransmitModel.cpp:210-216), typed control (ModelControlRequest.h:51, FlexModelControls.cpp:141-142), other backends Unsupported (Hl2Backend.cpp:3291-3292, IcomCivBackend.cpp:4523-4524), Radio Setup control, bridge snapshot, troubleshooting line, and all four doc pages. Principle VI holds: no key-on path is added and nothing sends the command on connect or restore.

The gap is the body's own claim — "Both appear only once the radio has reported the key, so a radio before 4.3 doesn't look like it has the override off". That is true across a disconnect and false across a family switch (Blocker 1).

2. Scope

File / group What it changes Claimed? Verdict
ModelControlRequest.h Field::PttMicOverride + bool validity arm + label Yes In scope. Appended before Count and at the end of the list, so no existing enumerator renumbers and m_controlIntentRevisions (sized on Field::Count, TransmitModel.h:551) still fits.
TransmitDelta.h, FlexBackend.cpp optional + guarded decode Yes In scope
FlexModelControls.cpp transmit set ptt_mic_override= Yes In scope. New public wire surface, but it is FlexLib's own verb, not an AetherSDR invention — no maintainer call needed beyond the Principle I citation (see nit 2).
Hl2Backend.cpp, IcomCivBackend.cpp new case → Unsupported Yes In scope; these are the only other requestTransmitControl implementations, so no exhaustive-switch gap remains
TransmitModel.{h,cpp} state, latch, setter, reset Yes In scope
RadioSetupDialog.cpp the toggle Yes In scope. Lands at grid row 1 of the Interlocks group, which was free (row 0 only, :3224-3237); no widget collision.
AutomationServer.cpp, RadioModel.cpp, SliceTroubleshootingDialog.cpp observability, both presence-gated Yes In scope. Key names match (mic["ptt_mic_override"] written and read).
4 docs pages the default flip Yes In scope. versioned_docs and CHANGELOG.md correctly untouched.
4 tests decode, model, routing, GUI Yes In scope

Nothing in the diff is unexplained by #6442. No new config key, no persistence (correct — this is radio-owned state, Principle III), no removed guard, no default changed on our side, no deleted comment, no dead additions. The raw sendCommand("transmit set show_tx_in_waterfall=…") sibling at RadioSetupDialog.cpp:3360 is pre-existing and not this PR's to convert.

Socket tests: none added or removed. tests/radio_setup_tx_timing_fields_test.cpp:28,173 includes QHostAddress and builds QHostAddress::LocalHost, but it is an inert value — the file's own comment says "never dialled" and there is no bind/listen/connectToHost in any of the four touched tests.

3. Blockers

1. m_havePttMicOverride survives a family switch — the control stays live, and keeps the old Flex radio's value, on an HL2/Icom/demo. src/models/TransmitModel.cpp:52-53

The latch is cleared only in resetState():

    m_pttMicOverride = false;
    m_havePttMicOverride = false;

and resetState() has exactly one caller, RadioModel::onDisconnected() (RadioModel.cpp:7930). A family switch never reaches it. RadioModel::connectToRadio() calls rebuildBackendForFamily() directly when the picked radio's family differs (RadioModel.cpp:3441-3444), which calls teardownBackend() — and teardownBackend() disconnects m_connection from this before destroying the backend specifically so status slots fail closed, so no onDisconnected() fires.

teardownBackend() already documents this exact class of bug for the latch yours is modelled on (RadioModel.cpp:1731-1735):

    // A family switch starts a new session without onDisconnected(), so clear the
    // power-provenance latches here or the old radio's drive publishes as the new
    // radio's confirmed drive. resetPowerProvenance(), not resetState(): one caller
    // is ~RadioModel(), and resetState() emits TX signals.
    m_transmitModel.resetPowerProvenance();

and resetPowerProvenance() (TransmitModel.h:89-93) clears m_haveTransmitStatus and m_haveMaxPowerLevel — the two existing presence latches. Yours is a third of the same shape and is not cleared there.

Failure scenario: connect to a FLEX-8600 on 4.3.16, let it report ptt_mic_override=1, then pick the Hermes-Lite 2 (or the demo radio) in the connection panel without disconnecting first. havePttMicOverride() is still true, so on the HL2: Radio Setup → Transmit shows PTT Mic Override enabled and reading Enabled; get transmit still returns pttMicOverride: true; the troubleshooting bundle reports a PTT mic override line for a radio that has none. Click it and the request routes to Hl2Backend::requestTransmitControl → ReceiveDispatch::Unsupported, which spends the session's one-shot unsupported notice on a control that should not have been clickable. Reasoned from code, not reproduced at runtime.

Fix — a non-emitting clear, safe from ~RadioModel(), alongside the existing one. In src/models/TransmitModel.h, next to resetPowerProvenance():

    // Cleared on a family switch as well as a disconnect (#6442): the latch is
    // radio-reported, so the old radio's report must not confirm the new one.
    // Non-emitting, like resetPowerProvenance() and for the same caller
    // (~RadioModel via teardownBackend); the next radio's first transmit status
    // re-announces through stateChanged.
    void    resetPttMicOverrideReport() {
        m_pttMicOverride = false;
        m_havePttMicOverride = false;
    }

and in RadioModel::teardownBackend() (src/models/RadioModel.cpp:1735):

    m_transmitModel.resetPowerProvenance();
    m_transmitModel.resetPttMicOverrideReport();

resetState() can then call the new method instead of repeating the two lines. The new test covers resetState() only; a case driving rebuildBackendForFamily("hl2") after a reported ptt_mic_override=1 and asserting the control goes back to disabled would pin this path — radio_setup_tx_timing_fields_test already builds the dialog against a bare RadioModel, and rebuildBackendForTest() exists, so this is a model/GUI-state assertion in a socket-free CTest, squarely within the test-layer boundary.

4. Nits (non-blocking)

  • The mutation-check bullet describes code that no longer exists. The test plan says "deleting the carry(kvs, "ptt_mic_override", …) line fails aetherd_transmit_decode_test:61", but after a63ef5b there is no carry call for this key — the decode is the guarded parse at src/core/backends/flex/FlexBackend.cpp:1339. The mutation evidence is worth restating against the line that shipped (deleting it, or swapping it for carry, should both fail the test; the second is the more interesting mutation since carry's bool overload would accept "2" as false).
  • Principle I citations are unverifiable from here. There is no reference/FlexLib tree in the PR checkout or on main, so I could not confirm Radio.cs:10310-10320 / 11151-11163, the TX_PTT_MIC_OVERRIDE_DEFAULT name, or the claim at FlexBackend.cpp:1337-1338 that "FlexLib rejects anything but 0/1". The live FLEX-8600 readings in the body are the stronger evidence for the wire grammar; a maintainer with the 4.3.16.42034 tree should spot-check the line numbers, especially as the in-repo reference has been 4.2.18 historically.
  • The strict 0/1 guard is the only one of its kind in this decoder. src/core/backends/flex/FlexBackend.cpp:1334-1336 — met_in_rx, mic_boost and mic_bias all go through carry(…, std::optional<bool>&), which maps anything that is not "1" to false (FlexKvCarry.h:44-48). Being stricter here is the better behavior and I would not ask you to loosen it; if it is worth keeping, a carryBool01() helper in FlexKvCarry.h would let the rest of the family converge on it later instead of leaving one hand-rolled exception.
  • The branch base is ~2 commits behind main. .github/workflows/static-checks.yml in the PR tree is still at the pre-#6439 word-splitting form ($FILES rather than "${FILES[@]}"), and the hl2_adc_pairing_test work from #6441 is absent. Neither file is in your diff and CI tests the PR merged with main, so nothing is broken — but a rebase onto 47aa4098d+2 keeps local static-check runs honest.
  • No automation path to set it. The bridge gains the read but, per the body, the TX guard's name fallback classifies anything containing "ptt" as keying, so there is no way to exercise the write from the bridge even with AETHER_AUTOMATION_ALLOW_TX=1. Disclosed and correctly left out of this PR; worth its own issue so the next TX-configuration toggle does not rediscover it.

5. What I tried to break (and could not)

  • Signal recursion in the toggle. RadioSetupDialog.cpp:3275-3278 calls setPttMicOverride(on) then syncPttOverride(), which calls setChecked() — but under QSignalBlocker (:3256), so toggled cannot re-enter. Lifetimes are fine too: the lambda's pttOvrBtn is the connection's context object and a child of the dialog.
  • Stale GUI after disconnect. The comment at :3281-3282 is right — resetState() emits only micStateChanged() (TransmitModel.cpp:75), never stateChanged(), and the PR wires both. Without the second connect the page would keep the last session's value; with it the test's reset assertions hold.
  • The latch firing on a reported 0. if (d.pttMicOverride && !m_havePttMicOverride) is a has_value() test, assign() then returns false because the value matches the default, and changed = true still reaches the single if (changed) emit stateChanged(); at TransmitModel.cpp:231 — so the stateEdges == 1 assertion in transmit_model_test is testing the real thing, and it would fail if the latch were keyed on change instead of presence.
  • Malformed and hostile status values. parseInt (FlexKvCarry.h:21-28) requires contains + toInt(&ok), and the extra (*v == 0 || *v == 1) drops "2"/"-1"; "" and "garbage" fail ok. All four are pinned in aetherd_transmit_decode_test, and that loop would fail if the guard were replaced by carry.
  • Exhaustive-switch and ratchet breakage. requestTransmitControl has exactly three implementations (Flex, HL2, Icom) and all three are updated, so no -Werror=switch gap — and build, check-windows and check-macos are all green on the head a63ef5b (they are cancelled on 6d59c77 only because the second push superseded it). tools/check_command_plane.py excludes src/core/backends/, so the new encode site cannot move the 297 baseline. tools/gen_bridge_docs.py generates only the verb table, not snapshot keys, so no doc regeneration is owed for pttMicOverride.
  • Command injection into the Flex plane. The payload is QString::number(int(std::get<bool>(request.value))) with the field pinned to the bool arm by TransmitControlRequest::valid(), so the wire text is literally 0 or 1. The security-audit (CodeGuard) pass agrees and returned no findings. Every flagged src/core/AutomationServer.cpp line (299–2398, 6196, 6986, 7474, 8437, 9463, 11484, 11847, 12249-12250, 12406, 13040) sits outside this PR's only hunk there (1925-1928), and .github/workflows/static-checks.yml is not in the diff at all — whole-file scan noise, dropped.
  • Could not check: runtime behavior of any kind (no build, no test run, no GUI here), the FlexLib line citations (no reference tree, nit 2), and the four touched tests' actual results — none of aetherd_transmit_decode_test, transmit_model_test, model_control_routing_test or radio_setup_tx_timing_fields_test appear in any ctest -R filter in ci.yml, so CI compiles them but does not run them. The body's local 789/793 is the only evidence they pass, and I cannot confirm it.

6. Recommendation

Request changes — for Blocker 1 only. Everything else here is solid work: the presence latch, the non-optimistic setter, the fail-closed decode and the four-page documentation of the default flip are all the right calls, and the GUI wiring handles the reset path that is easy to miss. The fix is the two-line clear in teardownBackend() above, ideally with a family-switch test case next to the existing resetState() one; after that I would recommend merge.


🤖 aethersdr-agent · cost: $11.0376 · model: claude-opus-5

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Cisco CodeGuard — static analysis of this PR (354 finding(s))

  • [CRITICAL] CS-VLN-CMDI-SUBSHELL — Vulnerability: CS-VLN-CMDI-SUBSHELL in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:496
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:14
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:36
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:81
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:172
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:309
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:332
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:340
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:355
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:399
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:414
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:469
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:531
  • [MEDIUM] CS-VLN-CMDI-ENVVAR — Vulnerability: CS-VLN-CMDI-ENVVAR in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:534
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:6986
  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12249
  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12250
  • [MEDIUM] CS-VLN-SSRF-HEX — Vulnerability: CS-VLN-SSRF-HEX in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:6196
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1759
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:7474
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:13040
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2398
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:8437
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:9463
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:11484
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:11847
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12406
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:299
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:463
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:840
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:949
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1306
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1379
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1531
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1608
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1755
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1785
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1789
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2007
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2117

Automated static scan by Cisco DefenseClaw CodeGuard on the changed files. Advisory — some may be false positives; the review above verifies them.


🤖 aethersdr-agent · cost: $11.1808 · model: claude-opus-5

@rfoust rfoust left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR substantially addresses #6442: it adds guarded decoding, a typed configuration request, radio-echoed model/UI state, presence-gated diagnostics, and user documentation. One reproduced lifecycle defect remains: a radio-family switch retains the previous Flex radio's override value and availability. Recommendation: request changes.

Scope

File/group Change Claimed in title/body? Verdict
TransmitDelta, ModelControlRequest, Flex backend Decode and encode override Yes In scope
HL2/Icom backends Explicit unsupported handling Yes In scope
TransmitModel Value, presence latch, setter and reset Yes In scope; lifecycle blocker below
RadioSetupDialog Radio-following toggle Yes In scope
AutomationServer, RadioModel diagnostics, SliceTroubleshootingDialog Presence-gated reporting Yes In scope
Four user-doc pages Firmware behavior and setting Yes In scope
Four tests Decoder, model, routing and dialog coverage Yes In scope

Everything in the PR diff is explained by #6442. No unrelated change, client persistence, client-side default change, or added TX-keying path was found. CHANGELOG and versioned_docs are correctly untouched.

Blocker

  1. [P2] Override state survives radio-family replacement — see the inline comment on TransmitModel.cpp. I independently reproduced the existing review's family-switch concern with the production model and dialog, injecting override=true and calling rebuildBackendForTest("sim"). The returned state was:
AFTER FAMILY SWITCH: reported= true value= true button enabled= true button checked= true

The PR's existing disconnect/reset case passed. Backend replacement therefore needs its own clear and UI notification, plus a socket-free regression case.

Non-blocking findings

  • Correct the RCA connector name in TX Controls: PTT is the input; TX/TX1–3 are outputs (inline).
  • Document the Multi-Flex condition on hardware override (inline).
  • Add braces around the new decoder if (inline).

Verification and attacks

  • Reviewed unchanged head a63ef5b; tested merge 4fadf73 against main 7d82707.
  • Built the ARM64 desktop app with the local ARM64 toolchain and RADE enabled. Host/system processors and executable were ARM64; no RNNoise x86 sources were in build.ninja. Sandboxed iconutil failed initially; the native build completed.
  • All four restored focused CTests passed: aetherd_transmit_decode_test, transmit_model_test, model_control_routing_test, radio_setup_tx_timing_fields_test. No broad suite was run. The four modified tests passed the socket-boundary preflight.
  • Mutation checks: removing the micStateChanged subscription failed the dialog reset assertion; replacing the guarded decoder with carry produced four malformed-input failures. Both sources were restored and rebuilt before the final passing test run.
  • Reported-zero detection, malformed-input rejection, typed encoding, non-optimistic request behavior and disconnect reset survived testing. Family replacement did not.
  • Engine-boundary, touchpoint-manifest, capability-record and command-plane checks passed on current main and the merge result with identical findings. Bridge-doc registry check passed.
  • Current-head hosted required checks are green; owner review is still required. Green per-PR CI does not establish execution of these four focused tests.
  • Full-app demo validation was attempted with isolated settings, an explicit socket, offscreen mode and TX disabled, but the app did not reach bridge startup. A local QtKeychain/Qt version mismatch was observed; a scratch linkage correction did not resolve startup. No full-app demo success, hardware audio-selection behavior, or fresh FlexLib v4.3 source verification is claimed. The lifecycle failure above was reproduced in the running production model/dialog test, not inferred solely from code.
  • No hardware connection or TX validation occurred. All review app instances were stopped. No invocable automated-review skill was available; existing bot findings were checked independently, with a second manual lifecycle/failure-path pass.

Comment thread src/models/TransmitModel.cpp Outdated
Comment thread docs/user/docs/tx-controls.md Outdated
Comment thread docs/user/docs/tx-controls.md Outdated
Comment thread src/core/backends/flex/FlexBackend.cpp Outdated
…itch. Principle I. (#6442)

Review of #6445:
- A family switch rebuilds the backend through teardownBackend() and never
  reaches resetState(), so the old Flex radio's reported override (value and
  presence) carried over to an HL2, Icom or the demo. teardownBackend() now
  clears it with a non-emitting resetPttMicOverrideReport(), beside
  resetPowerProvenance(), and resetState() uses the same helper. The open
  Radio Setup control also follows RadioModel::backendRebuilt.
- Docs: a footswitch goes on the RCA PTT jack (TX1-3 are outputs). Note that
  under Multi-Flex FlexRadio applies the override when the client whose
  hardware PTT is pressed is the transmitting client. The tooltip and
  WSJT-X note drop "always".
- Braces on the guarded parse.
- Test: radio_setup_tx_timing_fields_test switches to the sim family after
  a reported override and requires the model unreported and the control
  unchecked and dimmed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@ten9876

ten9876 commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed in c2416ffc4. All four threads have replies and are resolved.

  • @rfoust / @aethersdr-agent, the family-switch blocker: teardownBackend() now clears the report, without emitting, beside resetPowerProvenance(). The open control follows backendRebuilt. A socket-free regression case switches to sim, and it was mutation-checked.
  • @Ozy311 / @rfoust, connector naming: it's now the RCA PTT jack, with a Multi-Flex qualification. I couldn't read the FlexRadio article (403), so that wording rests on the reviewer's summary.
  • @aethersdr-agent, stale mutation bullet: the test plan now lists the mutations for the code as it is now, including swapping back to carry (4 failures, since the bool carry reads 2 as off).
  • Not taken, with reasons:
  • FlexLib citations: they refer to the v4.3.16.42034 tree on the maintainer's machine (reference/FlexLib, version recorded in VERSION.md). The CI/bot checkout still has the older tree, which is why those lines didn't resolve there.

🤖 Generated with Claude Code

@Ozy311 Ozy311 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review of exact head c2416ffc46a58dbc08588d60e48c22d39ae02c20, compared with my previously reviewed a63ef5bd and the complete PR against merge base 47aa4098d2b3182c8608d9bd7f4b6d842758d84a.

No remaining actionable findings from this review. The PR implements #6442 within its stated scope. My connector-documentation finding is fixed, and the lifecycle/parser findings discussed in the earlier reviews are addressed in the current code.

Fixes verified

  • Family replacement: teardownBackend() now clears both the override value and its reported-presence latch through the non-emitting resetPttMicOverrideReport(). rebuildBackendForFamily() emits backendRebuilt after replacement, and the open control subscribes to it. This clears the old radio's value and availability without introducing destructor-time TX notifications. The new production-model/dialog family-switch assertions pass.
  • Disconnect: resetState() uses the same clear helper; the micStateChanged subscription refreshes the button. The reset assertions still pass.
  • Input and request behavior: guarded 0/1 decoding, rejection of malformed/out-of-range input, reported-zero presence detection, typed encoding, and waiting for the radio echo remain covered by passing tests.
  • Documentation: TX Controls now correctly names the RCA PTT input, avoids assuming every model has a front-panel mic jack, and includes the Multi-Flex condition. The tooltip/WSJT-X text no longer promises “always.” I could read FlexRadio's current PTT Override guidance; it supports the added condition. The decoder conditional is now braced.

Verification

  • Updated the isolated scratch snapshot to this exact head and verified all 20 PR-changed files match it. Rebuilt the four focused targets with local ARM64 Qt 6.12/shared core.
  • 4/4 CTests passed: model_control_routing_test, radio_setup_tx_timing_fields_test (the full target, including the new family-switch case), aetherd_transmit_decode_test, and transmit_model_test.
  • Current-head strict engine-boundary, touchpoint-manifest, capability-record, and command-plane checks pass: 102 tracked engine warnings/zero blockers, manifest current, 70 capability booleans, 297 command-plane sites. Bridge-doc registry check passes.
  • Refreshed trusted main to 709093e269766cca8f0dacda5ad55708cb490bb7. Governance manifest PASS; the governance-file hashes are unchanged from the earlier review and the Constitution mirrors match. Inspected intervening main changes in overlapping files: the hardware-PTT observation work is separate from this override configuration/reset path. Local tests cover the PR head, not a newly built merge with that main revision.
  • All three PR commits have verified/valid signatures. Current-head Static checks, docs, sanitizer configuration, and CodeQL are green. Required build, check-windows, and check-macos remain in progress; their actual job steps were inspected and are not counted as passing.

Verdict: COMMENT, no new findings. The earlier defects are fixed in the reviewed code. Platform CI is incomplete, so this is not a merge-readiness approval; the required owner-review path and existing change-request state still need to be satisfied. No hardware connection, RF/TX, full suite, or release-package validation was performed. Local ASR/RADE/DSTAR/DFNR options remained disabled. No contributor-branch changes were made.

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue fit

Yes. #6442 asks for seven things and the diff does all seven: parse ptt_mic_override into TransmitDelta/TransmitModel with a presence latch (TransmitModel.h:189-190), a typed Field::PttMicOverride encoded only by Flex (FlexModelControls.cpp:141-142), Unsupported everywhere else, a Radio Setup control gated on reported rather than on value, the bridge snapshot key, the troubleshooting key, and the docs for the v4.3 default flip.

It also lands all three corrections the maintainer-review triage comment on #6442 called out in advance, which is the part I most expected to find missed:

  • "A plain bool cannot do the pre-4.3 detection" → m_havePttMicOverride latches on presence, so assign() returning false for a reported 0 into a false default still flips the latch (TransmitModel.cpp:210-215). transmit_model_test.cpp pins exactly that case, including the stateEdges == 1 edge.
  • "Do not copy the micBias write path" → setPttMicOverride (TransmitModel.cpp:920-928) deliberately does not pre-set the member, unlike setMicBoost/setMicBias at :898-918 which are optimistic because #1045 says the radio sends no echo. Correct: this key is a transmit-status key.
  • "The bridge snapshot should omit or null the field when unreported" → AutomationServer.cpp:1925-1928 omits it.

Scope

File / group What it changes Claimed? Verdict
docs/user/docs/tx-controls.md New ### Hardware PTT and the TX source section Yes (issue plan) In scope
docs/user/docs/{before-you-transmit,wsjt-x-integration}.md Pre-flight checklist line, WSJT-X caveat Yes (issue plan names both) In scope
docs/user/docs/radio-setup.md One table cell for the Transmit page Not named, but the companion edit In scope
ModelControlRequest.h, TransmitDelta.h New enumerator + delta field Yes In scope
FlexBackend.cpp, FlexModelControls.cpp Status decode + wire encode Yes In scope
Hl2Backend.cpp, IcomCivBackend.cpp Add the enumerator to the Unsupported arm Yes In scope (required — these switches are exhaustive)
TransmitModel.{h,cpp} Value, presence latch, setter, reset helper Yes In scope
RadioModel.cpp teardownBackend() clear + diagnostics key Partly — teardown clear came from review of this PR In scope
SliceTroubleshootingDialog.cpp Render the diagnostics key Yes In scope
RadioSetupDialog.cpp The toggle Yes In scope
AutomationServer.cpp New bridge snapshot key pttMicOverride Yes In scope — but see below
4 test files Encoder routing, decode, model latch, dialog Yes In scope

Nothing in the diff is unexplained by the issue, and no CHANGELOG.md entry was added. Two rows deserve a maintainer's eye rather than mine:

  • New public surface: pttMicOverride in the bridge transmit snapshot and ptt_mic_override in the troubleshooting snapshot. Both are named in the issue plan and the triage comment endorsed the omit-when-unreported shape, but that triage is aethersdr-agent[bot], not a human ruling. Flagging per the new-surface rule, not as an objection — the design is right (absent ≠ false), and setPttMicOverride has exactly two callers (RadioSetupDialog.cpp:3275 and tests), so the bridge gains a reader and no writer.
  • Branch base. The branch is on 47aa4098d; main is three commits ahead (dc7cdc1b5, 7d82707eb, 709093e26). git merge-tree is conflict-free, and the 95 lines 709093e26 changed in Hl2Backend.cpp do not touch the requestTransmitControl switch this PR edits. No action needed — noting it because it explains the next section.

Blockers

None.

Nits (all non-blocking)

  • src/core/backends/flex/FlexBackend.cpp:1337 — the comment pins line numbers in a FlexLib copy nobody here can open:

    // FlexLib rejects anything but 0/1 (Radio.cs:11151-11163): a malformed value

    There is no reference/FlexLib in my workspace at all, and the #6442 triage comment establishes the in-tree copy is 4.2.18, where grep ptt_mic_override returns nothing and Radio.cs:11151 is _dockerWaveforms. The citation is presumably correct for 4.3.16.42034, but as written it reads as checkable and isn't. Suggest naming the version, or pointing at the primary evidence instead — the FLEX-8600 capture at software_ver=4.3.16.42034 in #6437:

        // FlexLib 4.3.16.42034 rejects anything but 0/1 (Radio.cs:11151-11163; the
        // in-tree reference is 4.2.18 and predates the key): a malformed value
        // must not confirm "off" or mark the key as reported.
  • tests/aetherd_transmit_decode_test.cpp:70-76 — const TransmitDelta d inside the for (const char* bad : …) loop shadows the const TransmitDelta d declared at :58 in the same block. I checked before reporting this: -Wshadow at CMakeLists.txt:2252 is scoped to the vendored aether_crdv C target only, and there is no -Werror anywhere, so this costs nothing at build time. Readability only — dBad would read better.

  • src/gui/RadioSetupDialog.cpp:3241-3283 — the issue plan says the control "shows only once the radio has reported the key, so firmware before 4.3 never sees it"; the PR instead always shows it and grays it with an explanatory tooltip. I think the PR's choice is the better one (a dimmed control with "Requires SmartSDR v4.3 firmware or later" teaches; an absent one doesn't), the docs say "grayed out" to match, and tx-controls.md is consistent. Naming it only because it's a deliberate departure from the written plan.

  • docs/user/docs/tx-controls.md:166-168 — the Multi-Flex sentence ("the override applies when the client whose hardware PTT is pressed is also the transmitting client") is, by @ten9876's own note in this thread, sourced from @rfoust's summary of a helpdesk article that returns 403 to the author, and FlexLib's doc comment says only that the setting is radio-wide. I can't test it either. Worth one maintainer confirmation before it ships as documented behavior — the rest of the section is grounded in the live capture.

  • src/models/RadioModel.cpp:3441-3447 — a same-family Flex→Flex swap takes neither path that clears the latch: wantFamily != m_family is false so rebuildBackendForFamily() (and its teardownBackend()) is skipped, and resetState() only runs from onDisconnected() at :7931. If connecting to a second Flex radio without an intervening disconnect is reachable from the UI — the RTL special-case just above at :3437 exists precisely because same-family swaps happen — radio A's reported override survives into radio B's session, and a pre-4.3 radio B keeps an enabled control. This is a pre-existing shape shared with m_haveMaxPowerLevel and every other latch in resetState(), not something this PR introduces, so it isn't a blocker on this PR; I couldn't confirm from code whether the picker always disconnects first.

  • src/gui/RadioSetupDialog.cpp:1376 — the Transmit page's search keywords are "tx transmit rf power tune ptt band settings", so searching "ptt" finds the page but "mic override" or "override" does not. One word would fix it.

Security audit

Ran the required security-audit subagent against /tmp/aetherclaude/pr-6445 with the harness file list. Verdict: no findings. Credited to security-audit (CodeGuard):

  • FlexModelControls.cpp:142 is the only new command sink and its operand is QString::number(int(std::get<bool>(...))) — literally 0 or 1, to the radio's TCP command socket, never a shell.
  • FlexBackend.cpp:1339 is the only new parser of radio-controlled data and applies a positive allow-list before engaging the optional.
  • The new bridge key is read-only and reachable only over the QLocalServer at AutomationServer.cpp:2304-2320, which sets QLocalServer::UserAccessOption — not one of the unauthenticated TCP listeners.

Every CodeGuard hit above is refuted, and I spot-checked rather than taking that on faith. The CMDI-BACKTICK/SEMI/AMP hits in AutomationServer.cpp (1755, 1759, 1785, 1789, 2398, …) land on comment prose and Qt string literals — e.g. :1757 is QJsonArray slotArr; // not "slots" — that's a Qt macro. SSRF-PRIV-192 at :6986 is a comment containing 192.168.50.255 inside the guard that rejects broadcast addresses; SSRF-LOCALHOST at :12249-12250 is a hardcoded ws://127.0.0.1:%1 with only the port substituted, which is not SSRF (no host control). All of them are pre-existing and none intersect this PR's single touched hunk at :1925-1928. static-checks.yml is not in this PR's diff at all — those hits are a whole-file scan of main's tip.

What I tried to break

  • The presence latch against the thing it exists for. if (d.pttMicOverride && !m_havePttMicOverride) tests has_value(), not the value, so a 4.3 radio reporting the 0 default into a model already at false still latches and still emits — the exact case a change-keyed latch would miss. transmit_model_test.cpp asserts it with stateEdges == 1, and that assertion fails if the latch is moved after the assign().
  • Both clear paths, and whether either can fire from a destructor. resetState() (disconnect) and teardownBackend() (family switch, and ~RadioModel() at :2491) both call the non-emitting resetPttMicOverrideReport(). backendRebuilt() is emitted from exactly one place — rebuildBackendForFamily() at :10097, after teardown — and never from the destructor path, so the refresh connection can't run against a dying model. setBackendForTest() tears down without emitting, but that is test-only.
  • The three refresh signals, for a hole between them. stateChanged carries the latch, micStateChanged carries resetState() (confirmed: resetState() emits it at TransmitModel.cpp:75, and not stateChanged), backendRebuilt carries the family switch. I could not find a fourth way for the value or latch to move. The one gap I did find is the same-family swap, noted above as pre-existing.
  • Click reentrancy and a stale button. QSignalBlocker in syncPttOverride means the snap-back setChecked(false) cannot re-enter setPttMicOverride(false). All three model/radio connections use pttOvrBtn as the context object so they die with the button; the toggled connection uses this but its sender is the button, so a destroyed button can't fire it.
  • Malformed wire input. parseInt (FlexKvCarry.h:21-29) is ok-guarded, and the PR adds a (*v == 0 || *v == 1) range check on top. This is deliberately stricter than the house carry(…, std::optional<bool>&) overload at :44-48, which treats anything ≠ "1" as false — so ptt_mic_override=2 is dropped here where mic_boost=2 would be applied as off. Correct for a tri-state (unreported / 0 / 1); the decode test pins garbage, -1, 2 and "".
  • Sibling implementations left behind. requestTransmitControl has exactly three overrides repo-wide (Flex, HL2, Icom) — IRadioBackend.h:144 is the default — and all three are updated. ANAN, RTL and Sim don't override it. valid() and label() both gained the arm. The only other exhaustive consumer of Field is m_controlIntentRevisions, declared std::array<quint64, static_cast<size_t>(Field::Count)> at TransmitModel.h:559, so the new enumerator sizes the array automatically — no out-of-bounds write from captureControlIntent(PttMicOverride).
  • Static-analysis gates the diff could trip. The new wire text lives in src/core/backends/, which tools/check_command_plane.py excludes via BACKENDS_PREFIX, so the shrink-only baseline of 41 for RadioSetupDialog.cpp is untouched — the typed-control route is what keeps that green. The accessible name and description are set on the one new interactive widget. Static checks, Build docs site and the three CodeQL jobs are green on c2416ff; build, check-macos and check-windows were still in_progress when I looked, so I am not calling the compile clean.
  • Test layer and coverage. All four are socket-free CTests at the right layer per AGENTS.md (wire encoding → model_control_routing_test; parsing → aetherd_transmit_decode_test; model state → transmit_model_test; UI state machine → radio_setup_tx_timing_fields_test, QT_QPA_PLATFORM=offscreen, TIMEOUT 60). All four are registered in tests/tests.cmake. I grepped both modified test files for QTcpServer|QUdpSocket|QTcpSocket|QLocalServer|connectToHost|listen(|bind( — no socket tests added or removed; the <QHostAddress> include in the dialog test is pre-existing and inert. None of the four are in .github/ci-test-gate.txt, so they run on full-suite-on-main and weekly sanitizers, not on this PR.
  • Would the new dialog test pass against the unfixed code? No. pttMicOverrideFollowsTheRadioAndResets applies pttMicOverride=true, calls rebuildBackendForTest("sim") and then requires !tx.havePttMicOverride() and the button unchecked and disabled — which is precisely the state @rfoust reproduced as wrong before c2416ff. Deleting the resetPttMicOverrideReport() line from teardownBackend() fails it at that assertion.
  • Doc-link integrity. The #hardware-ptt-and-the-tx-source anchor used from three pages matches the ### Hardware PTT and the TX source heading. I also checked whether docs/automation-bridge.md enumerates transmit snapshot fields that would now be stale — it doesn't (no micBias/amCarrier/metInRx rows), so no doc update is owed for the new key.

Everything above is reasoned from the head checkout at /tmp/aetherclaude/pr-6445; I have no build and no way to drive the GUI, so none of it was reproduced at runtime. What I could not test at all: the Multi-Flex claim (no access to the helpdesk article), the FlexLib 4.3.16 line citations (no reference copy in this workspace), and whether the radio actually echoes a set in transmit status — the #6437 capture proves the key is reported, not that a write is echoed, which is the single assumption the whole non-optimistic UI rests on.

Recommendation

Approve with nits, with one maintainer decision attached. The implementation is careful in the places that matter — presence-latched rather than value-latched, mirrored rather than optimistic, cleared on both teardown paths, stricter-than-house parsing — and the two review rounds already closed the real defect (@rfoust's family-switch carryover) with a test that fails without the fix. Every nit above is cosmetic or a request to confirm something neither the author nor I can read.

Next step: a maintainer signs off on the new bridge snapshot key pttMicOverride (shape is right; it's the public-surface precedent that needs a human), confirms or attributes the Multi-Flex sentence, and waits for build / check-macos / check-windows to finish. Nice work on the presence latch — it's the one part of this that was easy to get subtly wrong, and the test pins it at the exact value where a change-keyed latch would have silently failed.


🤖 aethersdr-agent · cost: $10.9030 · model: claude-opus-5

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Cisco CodeGuard — static analysis of this PR (470 finding(s))

  • [CRITICAL] CS-VLN-CMDI-SUBSHELL — Vulnerability: CS-VLN-CMDI-SUBSHELL in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:496
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:14
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:36
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:81
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:172
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:309
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:332
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:340
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:355
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:399
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:414
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:469
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:531
  • [MEDIUM] CS-VLN-CMDI-ENVVAR — Vulnerability: CS-VLN-CMDI-ENVVAR in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6445/.github/workflows/static-checks.yml:534
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:6986
  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12249
  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12250
  • [MEDIUM] CS-VLN-SSRF-HEX — Vulnerability: CS-VLN-SSRF-HEX in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:6196
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1759
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:7474
  • [CRITICAL] CS-VLN-CMDI-SEMI — Vulnerability: CS-VLN-CMDI-SEMI in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:13040
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2398
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:8437
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:9463
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:11484
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:11847
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:12406
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:299
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:463
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:840
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:949
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1306
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1379
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1531
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1608
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1755
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1785
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:1789
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2007
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/AutomationServer.cpp /tmp/aetherclaude/pr-6445/src/core/AutomationServer.cpp:2117

Automated static scan by Cisco DefenseClaw CodeGuard on the changed files. Advisory — some may be false positives; the review above verifies them.


🤖 aethersdr-agent · cost: $11.0442 · model: claude-opus-5

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@jensenpat

Copy link
Copy Markdown
Collaborator

Landing validation at exact head 186c2cd34ba96fec036bb2b60b8a2a469148fbb3 (includes author repair c2416ffc46a58dbc08588d60e48c22d39ae02c20 and refreshed main 704bf822d9560ff008cd8850805d1b6c70103dda):

  • All four review threads already have author replies and are resolved. The family-switch finding is fixed at src/models/RadioModel.cpp:1738 through non-emitting TransmitModel::resetPttMicOverrideReport() and the dialog's backendRebuilt refresh (src/gui/RadioSetupDialog.cpp:3283). Final offscreen radio_setup_tx_timing_fields_test passed; removing the teardown clear failed pttMicOverrideFollowsTheRadioAndResets at line 354. Restoring it and rebuilding yielded 4/4 CTests passed, including decoder, model and routing targets.
  • Strict decoding at src/core/backends/flex/FlexBackend.cpp:1352 rejects malformed/out-of-range inputs. Replacing it with carry produced exactly four decoder failures at tests/aetherd_transmit_decode_test.cpp:75; restored code passed. The model waits for status and latches presence even on zero. Disconnect refresh remains covered by the production dialog test.
  • Connector wording and Multi-Flex qualification are confirmed by FlexRadio's guidance. Downloaded the official FlexLib v4.3.16 source and verified both cited setter/parser ranges. Cleanup commit 186c2cd34 versions the citation, avoids the shadowed test variable and adds searchable “mic override” keywords.
  • Final clean app identity sha=186c2cd34, dirty=false, explicitly connected to DEMO-0001 only. Bridge search selected Transmit, and dumpTree returned visible=true, enabled=false, checked=false, text=Disabled, with accessible “Requires SmartSDR v4.3…” reason. get transmit omitted pttMicOverride, and transmitting=false; disconnect preserved the unavailable control. Both landing instances stopped. No live radio or RF/TX evidence is claimed.
  • The same-family concern cannot open a second Flex connection while connected: RadioConnection::connectToHost() returns unless the transport is Disconnected (RadioConnection.cpp:234). Actual disconnect reaches model reset. The bridge separately refuses connection while connected. No broader lifecycle redesign is needed for this patch.
  • CodeGuard's whole-file shell/SSRF annotations do not describe the changed code. The only automation hunk inserts a read-only JSON bool; command encoding is the typed bool to 0/1 on the radio socket, not a shell. The cited backtick/punctuation sites are pre-existing comments/string literals, and static-checks.yml is absent from this PR diff. The decoder has a positive range guard. No security defect was reproduced.
  • Existing maintainer-authored issue/PR scope explicitly includes the conditional bridge reader; this invocation authorizes landing that accepted feature. Disabled rather than hidden availability follows the existing GUI canon. A shared sibling-parser refactor and new automation permission mechanism are unnecessary to satisfy the scoped feature; no change to sibling parser semantics or TX permissions was made.
  • Four boundary gates passed base/head with byte-identical findings (102 tracked engine warnings, 70 capability booleans, 297 command sites); bridge docs, registration and docs production build passed. No invocable automated code-review pass was available; the adversarial source pass was manual. Local optional ASR/RADE/DSTAR/DFNR/QtKeychain were disabled. Hardware source selection and set→echo remain author-reported; injected model/widget tests prove the client behavior.

Fresh exact-head platform CI is required before approval/arming; older green runs are not reused.

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@jensenpat

Copy link
Copy Markdown
Collaborator

Current-main integration revalidated at ae2deea136324aeba76ea074f1ffaf334c883c72 after main advanced to 91ddeb87f with #6462:

  • Complete local ARM64 Qt 6.12 app rebuild passed, clean tree; 4/4 focused offscreen CTests passed again. No additional source change was needed. The prior parser and family-teardown mutation evidence remains valid because those implementations are unchanged by this main update.
  • Isolated TX-disabled bridge reported sha=ae2deea13, dirty=false, connected only to DEMO-0001, and confirmed pttMicOverride omitted; search “mic override” selected Transmit; the button was visible, disabled and unchecked with its accessible unavailable reason. Disconnect preserved the open control’s unavailable state, and transmitting=false. All three landing demo instances are stopped.
  • Boundary checks were rerun on the new main and head, with identical findings: 102 tracked warnings/zero blockers, 70 capability booleans, 297 command sites; manifest current. Updated docs production build passed.
  • The renewed accessibility warning was checked by running check_a11y.check_file against both updated main and head. Both have the same nine RadioSetupDialog findings and zero SliceTroubleshootingDialog findings; none belongs to the added PTT Mic Override control, which has an accessible name and description.
  • All current PR commits, including the update merge, have GitHub verified/valid signatures. Fresh required CI was created at 2026-10-14T05:29:10Z, after main’s 05:25:55Z commit; platform builds are still running. No obsolete run is counted as current-head evidence.

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@github-actions

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 9 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 2
Files with findings: 1
Total findings : 9

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@jensenpat jensenpat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved exact head 8a05e99 after rebuilding and validating its merge with current main ae699be.

  • Author repair c2416ff fixes strict 0/1 decoding, disconnect notification and family-replacement state clearing. The non-emitting teardown clear and backendRebuilt UI refresh retire the reproduced blocking finding. Full production radio_setup_tx_timing_fields_test passes, including request-without-optimistic-state, echoed true, family replacement and reset. Deliberately removing the teardown clear failed its family-switch assertion; restoring it passed.
  • Permissive decoder mutation produced four malformed-input failures; restored final decoder, transmit model and typed routing tests all pass. Final head: 4/4 focused offscreen CTests, complete ARM64 Qt 6.12 app build and user-doc production build passed.
  • Cleanup 186c2cd versions the independently verified official FlexLib 4.3.16 citation, removes test-variable shadowing and adds “mic override” search terms. Final clean app identity 8a05e99 was driven only on isolated TX-disabled DEMO-0001. Search selected Transmit; the unreported field was omitted, the visible button was disabled/unchecked with an accessible reason, and the open page remained unavailable after disconnect. All five landing instances are stopped.
  • FlexRadio official guidance confirms correct PTT input names and the Multi-Flex qualification. The conditional read-only bridge field is within the maintainer-authored issue/PR scope. Existing GUI canon requires unavailable controls to remain visible. No new maintainer decision, new TX permission, persistence/default change, dependency or architecture change was made.
  • All four review threads have evidence-bearing author replies and remain resolved. The blocking review was dismissed with independent test/mutation evidence. Whole-file CodeGuard and nine accessibility warnings are pre-existing; base/head accessibility findings match exactly. Same-family connection cannot open a new Flex transport while connected; actual disconnect clears the model. No remaining actionable finding.
  • Four boundary gates pass on updated base/head with identical findings: 102 tracked warnings, 70 capability booleans, 296 command sites. Touchpoint manifest, bridge registry, test registration, whitespace and Constitution mirror checks pass. Manual adversarial review performed; no invocable automated code-review pass was available.

Local optional ASR/RADE/DSTAR/DFNR/QtKeychain are disabled. No full local suite, release package, live radio or RF/TX evidence is claimed. The client’s enabled-state/echo path is covered by injected socket-free production model/widget tests; actual firmware set-to-echo and hardware source selection remain author-reported evidence. Main’s squash-commit CI is a separate mandatory post-merge check.

Fresh required PR checks were verified before posting this approval. The earliest head workflow was created at 2026-10-14T06:30:00Z (required CI/Static at 06:30:02Z), after current main ae699be committed at 06:27:57Z. No stale-green exemption was used.

@jensenpat
jensenpat merged commit fc43451 into main Oct 14, 2026
10 checks passed
@jensenpat
jensenpat deleted the feat/ptt-mic-override branch October 14, 2026 06:55
@jensenpat

Copy link
Copy Markdown
Collaborator

Post-merge verification complete for squash fc434510e45fe751e65e9cede63a29205c3c6198 (verified signature; source tree identical to reviewed head 8a05e9907):

  • Main CI SUCCESS: Linux build, Windows and macOS checks all passed.
  • Full Suite SUCCESS: 799 selected, 792 passed, 7 skipped, 0 failed. The decoder, model, routing and full dialog targets all passed independently on the squash commit.
  • CodeQL, Code Quality, Docs and System Libraries Canary also completed successfully on this SHA.
  • Static Checks is PR-only; its required pre-merge result passed. No separate main Static Checks run is claimed.

No live-radio or RF/TX test was performed during this landing pass. The isolated TX-disabled demo sessions are stopped. The independently rerun software evidence completes the pass under Principle XI.

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.

PTT Override: expose transmit ptt_mic_override and document the v4.3 hardware-PTT default flip

4 participants