Skip to content

feat(kat500): add tuner applet and Advanced maintenance - #6452

Merged
jensenpat merged 2 commits into
mainfrom
codex/kat500-applet
Oct 17, 2026
Merged

jensenpat merged 2 commits into
mainfrom
codex/kat500-applet

Conversation

@Ozy311

@Ozy311 Ozy311 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Adds the Elecraft KAT500 tuner applet and Advanced configuration/maintenance tools over serial or raw TCP. Completes the KAT500 portion on the merged KPA500 foundation (#5991). Closes #4953.

  • Full/Mini applets provide confirmed power, mode, antenna, tuner-only Tune/Cancel, faults, SWR, physical bypass/attenuator/key-line toggles, manual C/L, Recall/Memorize, history and diagnostics.
  • Settings → Pre-tune bands… opens a dedicated sweep without sending commands. An explicit start uses captured Tune authorization and the existing Tune Pwr, confirms internal-ATU bypass and tuner readiness, and stops the owned carrier on abort, timeout, disconnect or invalidated intent.
  • Advanced provides staged configuration with verified readback, atomic native .KAT500Config backup/validated restore, stored fault history/CSV, memory inspection/confirmed erase, and separately confirmed reset. Firmware-dependent maintenance is restricted to the verified 02.16 schema. Opening the panel performs no maintenance write.
  • TX Controls retains the radio’s ATU/MEM controls, measurements and scale, following the direction recorded in withdrawn RFC [RFC] Elecraft integration direction: dedicated controls and VU metering #6477. Confirmed KEY BLOCK selects radio VU/PWR measurements instead of KPA500 output; integrated-amplifier priority and main’s KPA500 telemetry-freshness guard are preserved.

Serial/raw TCP requests, receive buffering, endpoint validation, timeouts and readback are bounded. Reconnection discards queued mutations. Telnet/RFC2217 and Elecraft Remote authentication are unsupported. Protocol and maintenance implementations use public documentation and isolated Utility I/O observations; no proprietary implementation was copied. Settings use AppSettings and live state remains device-authoritative.

Validation:

The native app and 10 focused tests below were verified at e83398b19b80f7fc4fcc2649282ce98b2d79d0c6. Current head 2892e7d037092bfb68a4906fa278fa2bca5b2738 changes only the existing operations-test source list; its production source is identical. The newly added radio_setup_operations_test source dependency compiles and its headless CTest passes (22.8 seconds), fixing the Linux/macOS CI link failure. All 14 peripheral-page test targets were audited for that dependency.

  • Native macOS ARM64 application build passed. All 10 selected headless tests passed: seven KAT500 tests plus KPA500 connection/freshness, Radio Setup pair grid and TX power reconciliation.
  • TX-disabled automation bridge connected only to DEMO-0001: one slice/pan, transmitting=false, native radio ATU/MEM labels; disconnected KAT500 Advanced read/restore/erase/reset controls were disabled with accessible reasons. The review app exited.
  • Four architecture checks passed on main and head with unchanged normalized legacy findings; generated references, Log Analyzer rules, registration and frozen CI gate checks passed. Hosted Docs and Static checks passed. Main-target Linux/Windows/macOS CI is tracked in this PR’s checks.
  • New peripheral tests inject transport/time or refuse invalid endpoints; no synthetic socket/serial peer was run. Actual tuner communication, EEPROM persistence, RF/TX and cross-platform runtime operation were not revalidated in this landing pass. The demo cannot prove device convergence.

KAT500 Full applet

Generated with OpenAI Codex (GPT-6 Astra)

@github-actions

Copy link
Copy Markdown

Accessibility check findings

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

Files scanned : 16
Files with findings: 2
Total findings : 10

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 marked this pull request as ready for review October 14, 2026 00:38
@Ozy311
Ozy311 requested review from a team as code owners October 14, 2026 00:38
@github-actions

Copy link
Copy Markdown

Accessibility check findings

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

Files scanned : 16
Files with findings: 2
Total findings : 10

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.

@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.

Reviewed the PR head at 38718c8c8, diffed against the stacked base 453240e9 so only this PR's work is in scope. Findings below are reasoned from code, not reproduced at runtime — I have no build, no test run and no way to drive the GUI here.

This is genuinely careful work. The TX sequencing in Kat500TxController is the strongest part: the carrier is a captured TxController::Input (a TxCoordinator::Request taken at the operator's click), every stop() path calls carrier.stop(), and the destructor stops the carrier before cancelling the tuner. I went looking for a key-on path that escapes the coordinator and did not find one. Two things still need to change before merge, and two need a maintainer's call.

1. Issue fit

Partially — and deliberately so. The PR says Refs #4953, not "Fixes", which is right: #4953 asks for KPA500 and KAT500, and this PR is the KAT500 half (KPA500 is #5991). Against the KAT500 half of that request — tuner status, initiate tuning, SWR, antenna selection, bypass state, frequency/band sync, connection status — every item is addressed, and the implementation follows the issue's own architectural preference ("a separate hardware integration module, rather than mixing KPA500/KAT500 commands into the FlexRadio code"). Nothing in the issue is left untouched.

Test coverage for the layer is right and not merely decorative. tests/kat500_tx_controls_test.cpp asserts the negative cases that matter: tune:off on tuner disconnect (:204), on mode change (:210), on sweep abort (:329); "timeout cannot be revived by a late tuner reply" (:218); "SAVE never requests a search or carrier" (:237); "one captured radio carrier; internal ATU never starts" (:143). Those would fail against an unfixed implementation. All seven new targets have add_test (tests/tests.cmake:4601,4609,4622,4633,4643,8445) and none sets an explicit TIMEOUT, so they inherit the retrofit default rather than opting out.

Socket-test disclosure (reporting only, not a finding): none. grep for QTcpServer/QTcpSocket/QSerialPort across all six tests/kat500_*.cpp returns nothing — the body's "inject transport and time; no fake radio/tuner socket peer enters the default graph" holds.

2. Scope

File / group What it changes Claimed? Verdict
src/core/Kat500{Protocol,Maintenance}.*, src/models/Kat500{Model,Types,TxController}.* New tuner protocol, model, maintenance, TX sequence Yes In scope
src/gui/Kat500{Applet,AdvancedWidget}.* New applet + Advanced pane Yes In scope
src/gui/{AppletPanel,MainWindow,MainWindow_Wiring,RadioSetupDialog*}.* Registration/wiring for the above Yes In scope
src/gui/AtuPreTuneDialog.*, TxApplet.cpp KAT500 routing External-tuner route + sweep Yes In scope
docs/superpowers/plans/ + specs/ New top-level docs dir; agent planning artifacts No Blocker — see #2
TxApplet.cpp:198,223,382,389,780,786 % suffix Unconditional % on RF Pwr / Tune Pwr for every radio Body says "when the KPA500 is powered" Undisclosed — see nits
docs/user/docs/tx-controls.md "20 W" → "20%" Pre-tune warning wording No In scope — genuine fix (AtuPreTuneDialog.cpp:91 kAutoModeTunePowerWarnPercent = 20; the old "W" was wrong)
tests/tests.cmake ×11 existing targets Kat500AdvancedWidget.cpp added to unrelated radio_setup_* / firmware_close_dialog / flex_control_visibility targets No In scope — link consequence of RadioSetupDialog_Peripherals.cpp referencing it
docs/user/src/components/LogAnalyzer/rules.json 14 RadioModel.cpp line renumbers No Generated; conflict-prone (nit)
docs/architecture/aetherd-touchpoint* Manifest totals 259→262; one unrelated row re-encodes — as — No Generated; nit
tools/docs/gen_reference.py (1 line) — No Trivial, generator-side

Process, independent of the code: the base is the temporary branch codex/kpa500-5991-base, and the body says "Do not merge into the temporary base branch." Consistent with that, only 4 checks ran on this head — Static checks, Sanitizer-option-configures, Build-docs-site, and a skipped PDF step. The cross-platform build matrix never executed, so there is no CI compile evidence on Linux, macOS or Windows for ~7,400 new lines. The body discloses this. As insurance I grepped the new sources for the usual Windows-only breaks (M_PI, bare std::min/std::max with windows.h, missing NOMINMAX) and found none, which is consistent with the claimed local MSVC build.

Blockers

1. docs/user/docs/kat500-tuner-control.md:37 + src/gui/Kat500Applet.cpp:766 and :503 — the documented "hold Space" gesture on the SWR pill does not preview bypass SWR; it keys the transmitter.

The user guide says:

Press and hold its pill (or hold Space while it has keyboard focus) to preview the last bypass SWR in the same meter

and the same claim is in the pill's tooltip and its accessible description (Kat500Applet.cpp:766):

tr("%1. Hold this pill or Space to view the last bypass SWR; release to return to adjusted SWR. "

m_swr is a QPushButton (Kat500Applet.h:72) wired on pressed/released (Kat500Applet.cpp:290-291), so the gesture depends entirely on Qt's native Space activation reaching the widget. There is no Key_Space handler anywhere in the applet, and Kat500Applet::eventFilter (:952) only handles FocusOut/Hide/WindowDeactivate to release a stuck setDown.

The Space key never arrives. MainWindow installs an application-level filter (MainWindow.cpp:1491 qApp->installEventFilter(this)), which runs before the target widget; that filter calls handlePttHoldShortcut and consumes the event (MainWindow_Shortcuts.cpp:736):

        if (handlePttHoldShortcut(ke, event->type()))
            return true;

Qt::Key_Space is registered as ptt_hold with keysTx=true (MainWindow_Shortcuts.cpp:1236), and the only gate on a new press is textEntryCaptured() (:324) — a focused QPushButton is not text entry, so the step resolves to PttHoldKeyStep::KeyTx. The design intent is explicit in the comment right above it (:322-325): "so a focused non-editable combo ... doesn't swallow the first Space/PTT press." Space is meant to win over focused non-editable widgets.

Failure scenario: radio connected, keyboard shortcuts on, operator tabs or clicks to the SWR pill, follows the documentation and holds Space. The radio keys (PTT hold, via the Quindar/PTT coordinator path); releasing un-keys. The bypass-SWR preview never happens. A screen-reader user gets this instruction read to them as the control's accessible description.

The cheap and correct fix is to stop claiming it — the mouse press-and-hold works fine and is the real gesture. Three edits:

docs/user/docs/kat500-tuner-control.md:37:

The single **SWR** meter shows adjusted SWR. Press and hold its pill to preview the last bypass SWR in the same meter; the pill becomes yellow and reads **BYP**.

and drop "or Space" from the tooltip/accessible description at Kat500Applet.cpp:766 and the Settings help text at :503. Making Space actually work would require an exemption inside handlePttHoldShortcut, which is a TX-path change and a maintainer's call — not something to land inside this PR.

2. docs/superpowers/plans/2026-10-13-kat500.md and docs/superpowers/specs/2026-10-13-kat500.md — agent planning artifacts in a directory that does not exist on main, carrying private infrastructure details into a public repo.

git ls-tree origin/main docs/superpowers/ is empty — there is no such convention in the tree. These two files are workflow residue, and they publish:

  • /Users/ozy/Documents/AetherSDR/elecraft-rea/kat500-investigation/{runtime-findings.md,...} — local paths referenced as the "Research authority", so the spec cites sources no reader can open
  • KAT500 bridge 100.100.216.93:4001; KPA500 :4004 — a private address and port map
  • echo-ms300prd via ozy SSH — a private hostname and access method

They also read as internal task tracking ("Do not claim ready for review if checks are incomplete", unchecked - [ ] task boxes, "User authorizes stopping bridge temporarily"), which will confuse a reader who finds them under docs/. Please delete both files from the PR. If any of the design rationale is worth keeping, the right home is the PR body or an RFC under the existing docs/architecture/, with the private addresses and local paths stripped.

Needs maintainer decision

  • Use KAT500 for TX Controls defaults ON. A connected KAT500 reporting Auto or Manual silently takes over the TX Controls applet: AUTO/ATU retarget to the tuner, MEM becomes SAVE, and a KAT500 pill replaces the Mem indicator. No issue describes the current radio-ATU behavior as defective, so this is a new default on an existing TX control surface rather than a fix. The body already flags defaults as "subject to maintainer/CODEOWNERS review" — this is the one that matters most, because it changes what an existing button does. The implementation is honest about it (TxApplet.cpp:507-515: explicit Bypass restores the radio controls, and Kat500TxController::refresh at :140-144 deselects when useTxControls() is off), so flipping the default to OFF would be a one-line change if that is the call.
  • No RFC. #4953 is a feature request (labeled maintainer-review, assigned to @Ozy311) whose body is largely AI-drafted architectural speculation; it is not a ruling. This PR adds a new peripheral family, a new log category, a new Advanced maintenance surface with EEPROM write paths, and a route takeover of an existing TX control. GOVERNANCE.md wants an RFC for architectural changes. I am raising this as a maintainer call rather than a blocker because #4953 carries maintainer-review and an assignment, which may already constitute the ruling — I could not find a comment that settles it either way.

Nits (non-blocking)

  • src/gui/TxApplet.cpp:198 and :223 — the % suffix is unconditional, not KPA500-gated. The body says "RF Power/Tune Pwr show percentages when the KPA500 is powered", but percentText (:95-98) is QStringLiteral("%1%").arg(value) with no gate, and it is applied in both valueChanged handlers (:382, :389), both syncFromModel paths (:780, :786) and both drag formatters (:195, :220). Every radio and every backend now shows 100% where it showed 100. I think the change is correct — the sliders' own accessible descriptions already say "0 to 100 percent of maximum", and kAutoModeTunePowerWarnPercent confirms the unit — but it changes existing UI for all users and the body describes it as conditional. Please correct the body; no code change needed.
  • src/models/Kat500Model.cpp:14 — Q_LOGGING_CATEGORY(lcKat500, "aethersdr.kat500") is the only category not under the aether.* prefix every sibling uses. I checked that this is harmless: LogManager holds an explicit category list (LogManager.cpp:71) and does no prefix filtering, so the category still appears in the picker and support bundles. Still worth renaming to aether.kat500 for consistency, in both Kat500Model.cpp:14 and LogManager.cpp.
  • src/models/Kat500TxController.cpp:223 — the Carrier-phase watchdog assumes a synchronous Tune readback. setPhase(Phase::Carrier, 30000) runs before m_carrier.start(), with the comment "the radio publishes Tune state synchronously." The 100 ms watchdog (:24) then calls refresh(), which stops the carrier if !m_radio->transmitModel().isTuning() (:147-151). On a backend whose tune readback lags more than 100 ms, the sequence would abort itself immediately. This fails safe — it stops the carrier rather than leaving it up — so it is a robustness/flakiness note, not a safety issue. Worth a comment naming which backends the synchronous assumption holds for.
  • Regenerated artifacts (docs/architecture/aetherd-touchpoints.md totals, rules.json line numbers) will conflict with every other open PR that regenerates them; expect one rebase. The tags.json hunk also re-encodes — as — on the unrelated core/FirmwareCurrency.h row — generator encoding drift, harmless.

Security audit

I ran the required audit (security-audit, CodeGuard rule set) over the flagged files. No confirmed exploitable defect in the new KAT500 code. Specifically cleared, with the bounds checked against the source:

  • Kat500Maintenance.cpp:128-136 decodeBackup — the attacker-controlled file supplies the record address, but addressText is pinned to exactly 4 hex digits and countText to 2, and :131 rejects the record unless data->size() == count and rangeValid(!internal, address, count), which requires address <= (external ? 65536 : 1024) - length with length <= 64. The memory[address + offset] store is always in bounds. :135 rejects overlapping records and :139 demands exact full coverage, so there is no partial or uninitialized restore image. Input capped at 256 KiB, lines at 512 bytes, forced printable ASCII.
  • parseEepromReply (:57-68) and decodeFaultHistory (:157) — both re-validate the reply's own address/length and the exact buffer size before any mid().
  • buildEepromWrite (:48-51) floors at P≥0x20 / S≥0x1000, matching the header's documented restore regions and keeping identity bytes out of reach.
  • No unauthenticated listener: both QTcpSockets are outbound clients; no QTcpServer/bind/listen in the new code. No QProcess/system/exec anywhere in the changed files. File paths all originate from an interactive QFileDialog, writes go through QSaveFile.

All CodeGuard CS-VLN-CMDI-, CS-VLN-PATH-, CS-VLN-SSRF-* and CS-PII-* hits on these files are the known lexical false-positive classes (Markdown-quoted protocol text in comments, docs JSON, CI YAML; the CS-PII-IP hits at Kat500Maintenance.cpp:18 and Kat500Protocol.h:7 are the CRC polynomial and a version string). Dropped.

One item worth routing elsewhere: src/core/Kpa500Connection.cpp:64 emits a rejected reply's argument verbatim into the diagnostics pane and support bundle (report(...).arg(cmd, arg)), where the KPA500 frame parser permits \r, \n, NUL and bytes >0x7F — log/terminal-escape injection from whatever is on the serial line. The same file already does this correctly at :517 via bytes.toPercentEncoding("^; "), and the KAT500 parser discards non-printable frames before any report (Kat500Protocol.cpp:80), so this is a KPA500-only gap. It is not in this PR's 52 changed files — it belongs to #5991. Flagging it so it can be routed there, not as a finding against this PR.

What I tried to break

  • Carrier left keyed. Walked every exit from Kat500TxController: tuner disconnect (:43-47), radio disconnect (:50-53), 30 s Carrier deadline (:25-32), operationFailed (:39-41), authorization/frequency/serial drift via the 100 ms watchdog (:147-151), explicit cancel() (:269), and the destructor (:63-71). All route through stop(), which does std::exchange(m_carrier, {}) then carrier.stop(). I could not construct a path that returns to Idle with the carrier up. The originalIntentValid() fence re-checks serial, frequency, mode, powerOn and carrier.belongsTo(m_radio) on every tick.
  • A new key-on path escaping the coordinator. No — TxController::Input wraps a TxCoordinator::Request captured at the operator boundary (TxController.h:25-48), and the controller carries that captured value through every async step rather than re-capturing at callback time. This is the sanctioned producer path, not a bypass.
  • Settings canon. Kat500Applet.cpp:176/:935 use the flat key "Kat500Applet", but it holds a single JSON document of client-owned, app-global view preferences (Mini/History/FollowTx/Verbose) — exactly the shape and precedent of "Kpa500Applet" (Kpa500Applet.cpp:111). Not per-radio state, so no radio_settings scope is owed. I also confirmed no device configuration (mode, antenna, relay masks) is persisted, matching the body's claim.
  • a11y. No interactive QLabels — the pills are QPushButtons, and there are 24 setAccessibleName/setAccessibleDescription calls in the applet and 16 in the Advanced widget. The one a11y defect I did find is the Space claim in blocker #1.
  • A latched SAVE button. The toggled handler early-returns when KAT500 is selected without restoring the check state, which looked like a stuck-latch bug — but syncAtuIndicators sets setCheckable(false) under a QSignalBlocker when external (TxApplet.cpp:700-706) and restores setCheckable(true) at :722, so toggled never fires on that path. No bug.
  • Raw wire text above the seam. Grepped the new GUI/model files for sendCmd, "transmit , "atu , "slice — nothing. Consistent with check_command_plane not needing a baseline bump and that file not appearing in the diff.
  • Could not check: anything requiring a build or a running GUI, the real .KAT500Config interop claim (whether Elecraft's Utility accepts a file whose KAT500 Utility Version = AetherSDR), and whether decodeMemoryBin's fixed 6-slots-per-bin assumption (Kat500Protocol.cpp:289) holds when the per-bin slot count is configured to fewer than 6. Those need hardware. The body is candid that restore, Memorize, memory erase, factory reset and any RF carrier were never exercised on real hardware in this pass.

Recommendation

Needs maintainer decision, and not mergeable as it stands regardless of the code — the PR targets a temporary branch and the required cross-platform matrix has never run.

Concrete next steps, in order: (1) fix blocker #1 by dropping the "or Space" claim from the doc, tooltip and accessible description; (2) delete the two docs/superpowers/ files; (3) correct the body's % description; (4) get a maintainer ruling on the Use KAT500 for TX Controls default and on whether #4953's maintainer-review label already stands in for an RFC; (5) retarget to main once #5991 lands and let the full matrix run.

On the code itself I have no blocker. Both items above are documentation and repository hygiene, and the TX-path engineering — captured authorization carried through every async step, a fence re-checked on a 100 ms tick, and tests that assert the carrier stops rather than only that it starts — is better than most of what comes through here. Thanks for the unusually honest validation-boundaries section; the explicit list of what was not exercised on hardware made this much faster to review.


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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Tightening one sentence in my review above, so the evidence and the claim match exactly.

I wrote "On the code itself I have no blocker." That is stronger than what I actually verified, and the coverage boundary belongs on the record: I did not read the Kat500Model.cpp (818 lines) transport state machine or Kat500Applet.cpp (1,071 lines) for lifecycle. Those were covered by targeted greps plus the security audit's bounds pass over the parsing surfaces — not by a read of the queue-draining, timer/socket teardown ordering, or reply fencing.

So the body's "reconnect never replays" and "late replies cannot overwrite newer observations" claims are untested by me. tests/kat500_model_test.cpp appears to cover them (the body cites injected-scheduler reconnect and late-reply cases, and commits 307f884 / b594b43 / 2b92dec name exactly that work), but I did not read those assertions to confirm they would fail against an unfixed implementation.

More precisely, then: the two blockers I raised are both documentation and repository hygiene, and I found no blocker in the code I did read — the TX sequence, the maintenance/protocol decoders, the settings path and the TX Controls wiring. That is not the same as a clean bill of health for the model's lifecycle, and a reviewer with a build should spend their time there.

Nothing else in the review changes, and the recommendation stands.


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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

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

  • [CRITICAL] CS-VLN-CMDI-SUBSHELL — Vulnerability: CS-VLN-CMDI-SUBSHELL in .github/workflows/static-checks.yml /tmp/aetherclaude/pr-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.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-6452/.github/workflows/static-checks.yml:534
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in docs/architecture/aetherd-touchpoint-tags.json /tmp/aetherclaude/pr-6452/docs/architecture/aetherd-touchpoint-tags.json:10
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in docs/architecture/aetherd-touchpoint-tags.json /tmp/aetherclaude/pr-6452/docs/architecture/aetherd-touchpoint-tags.json:1157
  • [MEDIUM] CS-VLN-SSRF-HEX — Vulnerability: CS-VLN-SSRF-HEX in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6452/docs/user/src/components/LogAnalyzer/rules.json:89
  • [HIGH] CS-VLN-PATH-UNC — Vulnerability: CS-VLN-PATH-UNC in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6452/docs/user/src/components/LogAnalyzer/rules.json:744
  • [HIGH] CS-VLN-PATH-UNC — Vulnerability: CS-VLN-PATH-UNC in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6452/docs/user/src/components/LogAnalyzer/rules.json:1003
  • [HIGH] CS-PII-DL-1 — PII detected: drivers_license in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6452/docs/user/src/components/LogAnalyzer/rules.json:88
  • [LOW] CS-PII-IP — PII detected: ip_address in src/core/Kat500Maintenance.cpp /tmp/aetherclaude/pr-6452/src/core/Kat500Maintenance.cpp:18
  • [LOW] CS-PII-IP — PII detected: ip_address in src/core/Kat500Protocol.h /tmp/aetherclaude/pr-6452/src/core/Kat500Protocol.h:7
  • [LOW] CS-PII-IP — PII detected: ip_address in src/core/Kpa500FaultHistory.cpp /tmp/aetherclaude/pr-6452/src/core/Kpa500FaultHistory.cpp:70
  • [LOW] CS-PII-IP — PII detected: ip_address in src/core/Kpa500Maintenance.cpp /tmp/aetherclaude/pr-6452/src/core/Kpa500Maintenance.cpp:97
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/LogManager.cpp /tmp/aetherclaude/pr-6452/src/core/LogManager.cpp:156
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/LogManager.cpp /tmp/aetherclaude/pr-6452/src/core/LogManager.cpp:163
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/core/LogManager.cpp /tmp/aetherclaude/pr-6452/src/core/LogManager.cpp:356
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/LogManager.cpp /tmp/aetherclaude/pr-6452/src/core/LogManager.cpp:129
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/LogManager.cpp /tmp/aetherclaude/pr-6452/src/core/LogManager.cpp:178
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:108
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:255
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:390
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:525
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:548
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:611
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:648
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:711
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:788
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:850
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/core/backends/RadioCapabilities.h /tmp/aetherclaude/pr-6452/src/core/backends/RadioCapabilities.h:908

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: $25.6336 · 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 : 16
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 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the actionable review findings at bbbbfdd7 (89ef789b for KAT500, with KPA500 dependency 6a49aeeb).

  • Removed the Space-to-preview instruction from the guide, Settings help, tooltip and accessible description. The mouse hold/release preview remains. The isolated widget-only Space assertion was removed because it did not exercise MainWindow's application filter. The existing window_shortcut_test passes and confirms that global PTT owns Space when shortcuts are enabled. No TX shortcut or admission behavior changed.
  • Removed both internal docs/superpowers/ planning files from the public tree; the implementation documentation and user guide remain.
  • Corrected the PR description: percentage suffixes apply to RF Power/Tune Pwr for all radios, not only while a KPA500 is powered.
  • Renamed the KAT category to aether.kat500 in both the model and LogManager; regenerated the log-category reference.
  • Clarified the carrier comment. TransmitModel::startTune publishes local Tune state synchronously before backend dispatch on every backend; it is not waiting for synchronous radio readback. The socket-free route test now runs through multiple watchdog intervals with a backend that sends no Tune readback and verifies that it does not abort the carrier.
  • Fixed the Tune-button accessible availability description. The applet, Advanced and TX Controls files now report zero accessibility-lint findings. The nine remaining RadioSetupDialog warnings reproduce on the KPA base and are unchanged by this KAT diff.
  • Routed the confirmed diagnostic issue to feat(kpa500): add serial/network applet and Advanced maintenance #5991: non-printable reply bytes are rejected at the KPA parser boundary before decoded diagnostics; raw RX retains escaped byte tracing. That fix is in the updated stack.

Current-head Static Checks, docs and sanitizer configuration are green. The KPA dependency also passed its full cross-platform CI.

Validation: native Mac full app build, all 12 KAT500/KPA500 suites, the keyboard-routing suite, both documentation production builds, generated references and log rules passed. The two new KPA malformed-input regressions were observed failing before the fix. I also checked the KAT model's queue/reset/generation boundaries and the late-EEPROM/canceled-memory/reconnect assertions; the model suite passed. This is bounded offline evidence, not a claim of a comprehensive independent lifecycle audit or physical RF/restore validation. No transmission or destructive hardware operation occurred.

The contributing operator explicitly requested default-on routing. It remains unchanged pending the maintainer's ruling, as does the need to settle RFC approval; #4953 is a feature request, not proof of approval. The operator chose to track completion through #4953 instead of opening a separate RFC: #5991 references the issue, and #6452 closes it after retargeting to main and merging after KPA. No separate RFC issue was created. #6452 still targets the temporary dependency base and must be retargeted to main after #5991 lands so the required cross-platform CI runs. No merge or approval is claimed. Earlier Windows deployment evidence remains explicitly tied to 38718c8c; the follow-up has not replaced those lab binaries.


73, Ozy K6OZY · prepared with Codex

@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 reviewed head addresses the KAT500 half of #4953; KPA500 remains the stacked dependency #5991. Status, SWR, antenna/bypass control, explicit tuning, optional frequency following and connection status are covered. Recommendation: Needs maintainer decision. I found no confirmed code blocker, and all eight focused socket-free tests pass against this stack merged with the main revision listed below.

Scope

File/group Change Claimed? Verdict
Kat500Protocol/Maintenance Command/status parsing, configuration and backup codecs Yes In scope
Kat500Model/Types/TxController Transport, scheduling, maintenance and captured TX sequence Yes In scope
Kat500Applet/AdvancedWidget New operating controls, history, diagnostics and staged maintenance Yes In scope
AppletPanel, MainWindow, RadioSetupDialog Registration, connection preferences and wiring Yes In scope
TxApplet, AtuPreTuneDialog External routing, SAVE, cancellation, sweep/erase and universal percentage suffixes Yes Existing UX/default needs maintainer decision
TxApplet inactive-route ATU stylesheet Restyles the existing radio button even without external routing No Additional visual scope; see inline decision 2
Tests, fixtures, tests.cmake, CMakeLists.txt Socket-free coverage and build/link registration Yes In scope; no new dependency or gate expansion
User docs/screenshots, sidebar, log category, manifests/log references Documentation and generated integration records Yes In scope
tools/docs/gen_reference.py Also recognizes aethersdr.* category rows Not explicit Related generator residue; current category is aether.kat500

The commit author dates form a coherent implementation sequence. KPA dependency integration is disclosed and excluded by the current stacked-base comparison. No CHANGELOG edit, private planning artifacts, new dependency or test-gate weakening remains.

Blockers

None confirmed in code. The maintainer decisions and main-target CI prerequisites below prevent a ready-to-land recommendation.

Maintainer decisions

  1. Default-on external routing: see the inline comment on MainWindow_Wiring.cpp:7528. Jeremy/KK7GWY should explicitly settle the default and the changed ATU/MEM behavior. #4953 contains no maintainer approval of that default; the standalone-applet RFC exception does not settle a takeover of existing TX Controls.
  2. Existing radio ATU appearance: see the inline comment on TxApplet.cpp:720–723. The inactive-route branch installs a different stylesheet for ordinary radio users. Disclose this visual scope and obtain a ruling, or preserve the original radio-button appearance when KAT500 routing is inactive. This finding is from source, without a before/after main-window screenshot.

Nits — non-blocking

  • The guide says numeric C/L Set chooses the closest combination, but it rounds down. The inline documentation suggestion corrects the prose without changing behavior: 29 pF selects 22 pF even though 30 pF is closer, as the passing protocol test explicitly asserts.
  • Refresh generated Log Analyzer locations after retargeting/merging main. All 707 rule checks pass on the synthetic main merge, with 14 moved-line notices from intervening main changes.

Verification and attacks

  • Stacked base: 6a49aeeb19c32ce13693b87b4d6f725c4c2789b2; head: bbbbfdd7513abf39a2eadace2d3db2d057836697.
  • GitHub stacked merge: 9f78c38fcfd0ff34fcb793ee53bffb01fa887787. Separately merged the stack with main 709093e269766cca8f0dacda5ad55708cb490bb7 in a detached scratch worktree: clean, tested tree fa6b24c1f13e1ea390a03526a3f1b351c51e87d9.
  • Prescribed ARM64 toolchain, RADE enabled; focused targets compile. Host/system processors and inspected test executables are arm64; no RNNoise x86 sources in the Ninja graph. This was a focused-target build, not a full AetherSDR.app build.
  • 8/8 CTests pass: kat500_protocol, maintenance, model, applet, advanced_widget, tx_controls, radio_setup_pair_grid and tx_applet_power_reconciliation. Added/modified tests use injected transport/time; no socket-opening synthetic device test was run.
  • Registration, frozen CI gate, touchpoint manifest, generated references and strict engine-boundary checks pass; engine checking has tracked legacy warnings and zero blockers. Log rules pass as noted above.
  • Late EEPROM acknowledgments/readbacks, overdue memory terminators, canceled compound-response drains, reconnect queue clearing, unsafe RF readback, partial backups and single-admission frequency following survived. Disabling active-request expiration makes four model checks fail; restoring it restores the pass.
  • Captured authorization, delayed internal bypass, revocation, competing MOX, disconnect, route change, timeout, controller destruction, SAVE without RF and multi-point sweeps survived. Removing carrier.stop() makes four TX Controls checks fail; restored code passes.
  • Offscreen Qt tests exercise the actual applets/dialogs, selected/disabled readback, history sizing, diagnostics scrolling/pause, confirmation cancellation and file-dialog lifetime. Removing the Debug resize-only followLatest call, then the resize guard/override behavior, did not fail the applet test on this Qt build; these runs do not demonstrate that particular guard is necessary. No claim of complete mutation coverage.
  • Security source review found no confirmed vulnerability in the 26 changed production source files. Parser bounds/checksums, complete backup coverage, device identity fencing and protected EEPROM ranges were checked. Actual Utility interoperability and physical write persistence remain unverified.
  • No main-window bridge session or live hardware was driven: the simulator does not implement a connected KAT500. No RF, physical EEPROM writes or destructive maintenance occurred. Windows/Linux and the docs production build were not rerun by this reviewer. The automated code-review skill was unavailable; a separate lifecycle/failure-path pass was performed directly. The prior review's Space-key instruction and private planning-file blockers are removed in this head.
  • Current head has passing Static checks, Sanitizer option configures and Build docs site; PDF attachment is skipped. The required cross-platform PR build matrix has not run because ci.yml targets PRs to main. The sanitizer-option check is not a sanitizer execution.

After Jeremy/KK7GWY settles the existing-control default and presentation, land #5991, retarget #6452 to main, regenerate moved references and run the required cross-platform checks. Do not merge into the temporary base branch. The focused evidence supports continued review; physical maintenance/RF acceptance remains open.

Comment thread src/gui/MainWindow_Wiring.cpp Outdated
Comment thread src/gui/TxApplet.cpp Outdated
Comment thread docs/user/docs/kat500-tuner-control.md Outdated
@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 : 16
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 : 17
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.

2 similar comments
@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 : 17
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 : 17
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.

@aethersdr-agent

Copy link
Copy Markdown
Contributor

CI triage: touchpoint manifest — already fixed at the live head

Short version: this was a one-cell generated-file drift inherited from the #5991 dependency, it is not your KAT500 code, and you have already fixed it. No action needed. Details below so the record is complete.

What failed

Only one job was red on e636ef18d: Static checks, at the step aetherd touchpoint manifest — .github/workflows/static-checks.yml:200, which runs python tools/gen_touchpoint_manifest.py --check. Every other step in that job passed, and Sanitizer option configures / Build docs site were green.

The error was the generic staleness message:

::error::aetherd-touchpoints.md is stale — run `python tools/gen_touchpoint_manifest.py`

I reproduced it in a worktree at e636ef18d and regenerated. The entire diff is one cell in docs/architecture/aetherd-touchpoints.md:

-| `models/MeterModel.h` | 6 | mixed(flex) — Meter registry+values are core-profile; …
+| `models/MeterModel.h` | 7 | mixed(flex) — Meter registry+values are core-profile; …

Why it drifted

That column counts how many src/gui/ + src/main.cpp files #include each engine header. Walking the merge e636ef18d and both its parents:

commit manifest says actual includers
e66f7af7f (KAT500 side) 6 6 ✅
bc1457fc2 (KPA500 side, #5991) 6 7 ❌
e636ef18d (the merge) 6 7 ❌
4ca5cd34d (live head) 7 7 ✅

The seventh includer is src/gui/Kpa500Applet.cpp:5, added by bc1457fc2 ("Add radio-sourced DRV meter to KPA500 Full mode") for Kpa500Applet::updateRadioDrive(const MeterModel&, bool). That commit added the include but shipped with the manifest still reading 6, so it was already stale on the #5991 branch before it ever reached here. Your KAT500 side was internally consistent at 6/6; the merge simply inherited the upstream gap.

Worth noting this is not the usual failure mode for this gate — normally it's a semantic merge conflict where both branches bump the same count to the same value and git takes the line verbatim. Here both parents genuinely shared TunerApplet.cpp, so it was the simpler case: one side's regen was skipped.

Already resolved

--check reports manifest up to date at both. Static checks is green on this PR's live head 4ca5cd34d (run 38619550591) and on #5991's head 26f42cadc (run 38619537115). The handed e636ef18d is superseded — you'd already pushed both regens by the time this triage ran.

One thing to keep in mind (confirming your own note)

On the temporary base codex/kpa500-5991-base, only Static checks, Sanitizer option configures and the docs jobs run — ci.yml is gated on pull_request: branches: [main], so build, check-windows and check-macos never fire here. Three of the four required contexts are therefore still unexercised on this branch, exactly as your validation section says. By contrast #5991 targets main and has the full matrix in flight on 26f42cadc. Your native Mac and Windows builds are good evidence, but the matrix verdict only lands after the retarget.

Reviewer comments

To close that loop explicitly: none of the open review items relate to this failure. @rfoust's two maintainer-decision requests (default-on UseTxControls, and the radio ATU button restyle when KAT500 routing is inactive) and the Set-rounding docs nit are governance and documentation questions, as is your b5193d2d response. None of them touch MeterModel.h, the GUI include graph, or the generated manifest. The default-on routing ruling remains the open maintainer item.

Thanks for the careful stacked-PR bookkeeping on this one — catching and regenerating both heads yourself, upstream and down, is exactly the right fix and it saved the next person the merge-base walk. Nice work. 73


🤖 aethersdr-agent · cost: $7.3905 · 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 : 17
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 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Published shared RFC #6477 for the KAT500 and KXPA100 TX Controls changes: default-on behavior, AUTO/ATU/SAVE and route indication, optional-tuner coexistence, and shared amplifier-meter precedence. It records that implementation preceded the RFC and requests maintainer approval rather than treating existing code or operator approval as that decision. The KXPA100 precedence findings are explicit open items; this link does not mark them resolved.

@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 : 15
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.

2 similar comments
@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 : 15
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 : 15
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 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

At d0f2dfe8, all three outstanding inline threads have replies and are resolved: the external TX Controls takeover is removed, the original radio ATU styling is restored, and the numeric Set documentation correctly describes rounding down. RFC #6477 is closed as withdrawn following Jeremy's direction relayed by Ozy; it is not a merge approval.

Also addressed the transport parity note from the KXPA100 review in this device's own branch: bounded the TCP read buffer to 4096 bytes and rejected malformed host/port input before connection. New socket-free model regressions failed on the old unbounded buffer and pass with the correction; invalid endpoints leave the socket unconnected and do not start the polling timer. Native Mac application build, 9 focused offline suites, production docs and all applicable stacked-branch CI checks pass. No peer socket or serial port was opened in these tests.

TX Controls remains radio-side. Pre-tune bands stays in applet Settings and Clear all ATU memories stays in Advanced. Full main-target platform CI remains required after eventual retargeting; the PR is ready for Jeremy's code review, not for bypassing that review or the platform gates.


73, Ozy K6OZY · prepared with Codex

@Ozy311 Ozy311 changed the title feat(kat500): add tuner applet, Advanced maintenance and TX Controls routing feat(kat500): add tuner applet and Advanced maintenance Oct 15, 2026
@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 : 15
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.

1 similar comment
@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 : 15
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 added a commit that referenced this pull request Oct 17, 2026
## Summary

Tracking: Refs #4953 (KPA500 portion). #6452 delivers the KAT500 portion
and carries the closing reference, so #4953 remains open until both
device implementations land.

Adds a complete KPA500 peripheral with local serial or raw-TCP network
access, a resizable applet, and **Peripherals → Advanced** maintenance.
The applet displays confirmed amplifier state, keeps stale measurements
out of the UI and main power meter, and distinguishes amplifier RF
output from the radio's TX flag.

This PR delivers the **KPA500 only**. The KAT500 implementation is
tracked separately in #6452.

### Credits

**Bob Holzer / @WA8PAM** contributed the original KPA500 protocol/parser
and command builders, serial connection and polling, first applet,
Peripherals setup, main power-meter integration, initial tests, and
subsequent fixes to the original review findings. His original commits
remain in this branch.

**@Ozy311** extended that foundation with the redesigned full/Mini
applet, history and debug views, the radio-sourced DRV meter, confirmed
power handling, Follow TX band selection, raw-TCP transport, Advanced
maintenance, native-dialog crash fix, additional regression coverage,
and Windows/Mac hardware validation. This is a continuation of WA8PAM's
contribution, with explicit credit to both contributors.

### TX Controls and meter separation

Following Jeremy’s direction recorded in #6477, the KPA500 affects the
VU/PWR meter source and scale, not the radio-side TX Controls gauge. TX
Controls continues to display exciter watts and SWR; RF Power and Tune
Pwr values include **%**. Existing radio-integrated amplifier priority
is retained. The dedicated KPA500 applet keeps amplifier readback and
its Full-mode radio-sourced **DRV** row.

### Applet and connection behavior

- **KP500** appears after a valid amplifier reply and remains available
while that transport connection stays open, including when the amplifier
is off. Full model names remain in titles/settings.
- The power button reads **ON** when confirmed on and **OFF** when
confirmed off. Standby/Operate, manual band selection, fan minimum,
speaker alarm and fault clear follow amplifier readback.
- **Follow TX flag** defaults on and follows the TX-assigned slice's
transmit band. Disable it to park the amplifier on a manually selected
band. It does not key the radio or amplifier.
- **RF ACTIVE** derives from fresh amplifier forward-power readback, not
AetherSDR's TX flag. The serial protocol does not report the RCA KEY
IN/PTT contact. Radio TX separately interlocks power, mode and band
changes.
- Full uses compact 22 px controls, themed meter-readout pills and
major/minor tick marks; SWR stays at 1–5 to match the amplifier face.
Mini hides the lower drawers and mode controls, leaving power,
band/status, power and SWR in a thin strip. Follow TX moves into the
header pill. Full and Mini modes share confirmed state. Expanded history
plots power, SWR, temperature, voltage and current; the popout resizes
without scattering controls and scrolls when expanded content needs more
room.
- **DRV**, Full only, shows the connected radio's measured forward power
on a 0–100 W scale, independently of shared AMP meter selection. It is
before cable loss, not a KPA500 input-sensor measurement or the RF-power
setting. Missing, disconnected or over-two-second-old FWDPWR clears the
bar and shows a dash; a measured zero remains valid. Mini is unchanged.
- Settings provides identity, reply age, transport details, history
explanations, temperature units and an **Advanced…** shortcut. Debug
supports pause/copy/save and opt-in verbose polling output.
- Confirmed power-off stops normal telemetry polling; a five-second
power probe detects power-on. Stale data is invalidated, commands are
guarded, and serial/TCP reconnect does not replay writes.

### Remote access and aether-serial-bridge

Network mode supports remote KPA500 access through a raw TCP serial
bridge. The companion **aether-serial-bridge** project is **coming
soon**: it runs on the computer connected to the equipment's serial port
and makes that port accessible remotely to AetherSDR. Compatible raw-TCP
**ser2net** endpoints also work. Local serial access remains available
without the companion project.

The bridge owns serial baud/framing settings. This PR does not implement
Telnet/RFC2217 negotiation, Elecraft Remote Server framing, or a split
GUI/AetherD peripheral connection. Peripherals labels local serial as
**DIRECT** and TCP as **NETWORK**.

### Advanced maintenance

**Peripherals → Elecraft KPA500 → Advanced** adds configuration
backup/restore, stored fault history with CSV export, and power-on
banner read/edit. Device information also appears in applet Settings.

Maintenance is gated to the observed firmware **01.54**. Restore and
banner writes require explicit confirmation, identity checks, fresh
Standby/zero-RF readback, bounded transfers and matching readback before
success. Polling and ordinary controls pause during maintenance; writes
are not retried or resumed after reconnect. Cancellation, TX, malformed
replies and transport failure abort the operation and report possible
partial completion.

The native file chooser is asynchronous, parent-owned and limited to one
open chooser. This fixes the reproduced Windows COM/Qt crash caused by
duplicate blocking file dialogs.

## Screenshots

Full below shows the current DRV layout using explicitly replayed
telemetry, not a hardware power measurement. Mini, History and Advanced
retain earlier native Mac captures from the real KPA500 with zero RF;
station identifiers are redacted. The History capture predates the added
DRV row and remains a screenshot-refresh follow-up when the bridge is
available. The images are included in the amplifier user guide.

**Full applet**

<img
src="https://raw.githubusercontent.com/WA8PAM/AetherSDR/bc1457fc22a21c00545f33dd0ca9c219dfa9e7a6/docs/user/static/img/kpa500/kpa500-applet-drv.png"
width="360" alt="KPA500 Full with DRV; replayed illustrative values" />

**Mini applet**

<img
src="https://raw.githubusercontent.com/WA8PAM/AetherSDR/453240e91d555f6a6e9dfb93663e093a5014aad4/docs/user/static/img/kpa500/kpa500-applet-mini.png"
width="360" alt="KPA500 Mini applet" />

**Expanded history**

<img
src="https://raw.githubusercontent.com/WA8PAM/AetherSDR/453240e91d555f6a6e9dfb93663e093a5014aad4/docs/user/static/img/kpa500/kpa500-applet-history.png"
width="420" alt="KPA500 telemetry history" />

**Peripherals and Advanced**

<img
src="https://raw.githubusercontent.com/WA8PAM/AetherSDR/453240e91d555f6a6e9dfb93663e093a5014aad4/docs/user/static/img/kpa500/kpa500-advanced-window.png"
width="720" alt="KPA500 NETWORK connection and Advanced maintenance" />

Current radio-side TX Controls, captured on the Mac while disconnected
with no RF:

<img
src="https://raw.githubusercontent.com/aethersdr/AetherSDR/808544493012bfe80861ca71c1fc6b85f67b3999/docs/user/static/img/kxpa100/tx-controls-radio-only.png"
width="300" alt="Radio TX Controls with ATU/MEM, radio scales and
percentage power labels" />

## Constitution principles honored

- **II — Radio-authoritative live state:** confirmed amplifier readback
drives status, controls and power-meter selection; missing/stale values
remain unknown.
- **IV — Clean-room contributions:** standard commands use the public
programmer's reference. Maintenance framing and file format were
independently implemented from observed Utility I/O using an isolated
virtual COM pair and artificial device; no proprietary code was
disassembled or copied. The design note records the observations and
firmware boundary.
- **V — Configuration ownership:** connection/UI preferences use the
existing nested Peripherals/Kpa500 settings; live hardware identity is
not persisted as authoritative state.
- **VI — Transmit on intent / VII — Boundary validation:** no automatic
keying; bounded frame/file parsing, explicit maintenance-write intent
and fail-closed guards.
- **VIII — Evidence over assertion / XI — Fixes are demonstrated:**
tests cover transport, stale-state, maintenance and UI behavior; the
native-dialog regression failed before the fix and passed afterward.

## Validation

Reviewed and rebased onto main `7864ef544`; current head is
`874cf214e19aae344682b57996f8a77a76d1e2b1`.
The rebase preserves the original contributor commits. Its
generated-index conflict was resolved by regeneration, and the rebased
tree matched a clean merge result before the landing fix.

The landing review found and fixed an additional partial-telemetry
failure: expired `^WS` measurements could leave the shared meters
suppressing radio readings while other amplifier replies remained live.
Shared meter routing, suppression and scale now use the same current
power-on/Operate/forward-power predicate. Fresh zero watts remains
valid.

- **Local macOS / Qt 6.12:** all **11/11** selected headless CTests
pass: six KPA500 suites, MeterModel, TX Controls power reconciliation,
both HGauge suites and the Peripherals automatic-connection case. The
connection target compiles without `HAVE_SERIALPORT` and uses only
in-memory transport injection.
- **Mutation:** removing the forward-power freshness guard causes the
two new stale-selection assertions to fail; restoring the guard passes.
- **Static/docs:** base/head engine findings are identical after
ignoring source-line shifts (102 tracked warnings, zero blockers);
capability and command-plane counts do not grow. Test registration,
frozen CI gate, generated touchpoints/references, colour ratchet and
focused accessibility checks pass. Log rules pass 707 checks; their
existing moved-line advisory remains unrelated. `npm ci` and the
user-doc production build pass.
- **Demo bridge:** the clean `874cf214e` native bundle passed 10
assertions in an offscreen, isolated `DEMO-0001` session: unknown
amplifier readings, no TX-band target, Network setup, and disabled
backup/restore/banner writes without hardware. TX/MOX/Tune stayed off;
the owned instance was disconnected and closed. External-amplifier
telemetry remains socket-free injection/source-review evidence, not demo
or hardware proof.
- **Current-head CI:** [Linux, Windows and
macOS](https://github.com/aethersdr/AetherSDR/actions/runs/39044294430),
[Static checks and sanitizer
configuration](https://github.com/aethersdr/AetherSDR/actions/runs/39044294388),
and
[Docs](https://github.com/aethersdr/AetherSDR/actions/runs/39044294336)
all passed. These runs were created at 2026-10-17T15:16:10Z after
current main 7864ef5; post-merge main verification remains separate.

Earlier contributor hardware evidence covers firmware 01.54
identity/telemetry, configuration backup, banner reads and stored faults
on Windows serial and Mac raw TCP. It is separate from this landing
pass. No hardware was contacted or changed in this review.

**Not validated on this final revision:** physical restore/banner-write
persistence, higher-power RF accuracy, or end-to-end transmitted-power
behavior. No transmission, Tune, MOX/PTT, restore or banner writes were
performed for this pass. The demo backend cannot validate external
amplifier firmware.

## Review scope

KPA500 protocol/transport, its applet and Advanced panel, Peripherals
setup, meter integration, source registration, tests and user
documentation are included. KAT500 remains separate in #6452. Unrelated
WSJT-X/a11y edits and the shared ACOM/SPE Standby recolouring from
earlier revisions are absent. Shared clear-fault styling is factored
without changing ACOM behavior. No CHANGELOG entry, dependency, workflow
or gate weakening is included.

The radio-only TX Controls direction and percentage labels follow #6477.
Existing radio-integrated amplifier priority remains first. The operator
requested the review, rebase, blocker repair and guarded merge of this
proposed feature.

Generated with OpenAI Codex (GPT-6 Astra)

---------

Co-authored-by: Ozy311 <Ozy311@users.noreply.github.com>
Co-authored-by: jensenpat <patjensen@gmail.com>
@jensenpat jensenpat self-assigned this Oct 17, 2026
… II.

Rebase the final KAT500-only delta from 0113445 onto current main, excluding the squash-landed KPA500 dependency. Preserve main KPA500 meter freshness admission and regenerate architecture inventories.
@jensenpat
jensenpat force-pushed the codex/kat500-applet branch from 0113445 to e83398b Compare October 17, 2026 21:44
@jensenpat
jensenpat changed the base branch from codex/kpa500-5991-base to main October 17, 2026 21:44
@github-actions

Copy link
Copy Markdown

Accessibility check findings

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

Files scanned : 72
Files with findings: 10
Total findings : 37

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 previously approved these changes Oct 17, 2026

@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.

Reviewed rebased head e83398b against main bccd4b7. No outstanding code blocker.

The dependency-only KPA500 history is excluded. The rebase preserves main’s hasLiveTxMeters() admission in the shared meter selector; existing KPA500 regression assertions reject stale/missing watts and accept a fresh measured zero. The prior TX Controls takeover/restyle findings are retired by the dedicated-app-only implementation documented in #6477; TxApplet remains main’s radio-side implementation. The numeric relay documentation matches round-down behavior.

Native macOS ARM64 app build passed, with 10/10 selected offscreen CTests passing: seven KAT500 targets, KPA500 connection/freshness, Radio Setup pair grid and TX power reconciliation. Reviewed parser bounds, request expiry/reply fencing, reconnect, maintenance confirmation/readback and captured pre-tune ownership. Architecture gates pass on main/head with unchanged normalized legacy findings; manifest/reference/log-rule/test-registration/frozen-gate checks pass. Hosted Docs and Static checks passed. Linux/Windows/macOS CI remains a separate merge prerequisite while those jobs finish.

Drove only an isolated TX-disabled DEMO-0001 instance: one slice/pan, transmitting=false, native ATU/MEM; added the disconnected KAT500 and opened Advanced, where read/restore/erase/reset were disabled with “Connect the KAT500 first.” The owned process exited. No live radio, RF or EEPROM write was performed; physical device convergence and cross-platform runtime are not proved by this pass. The optional automated code-review skill was unavailable; a manual lifecycle/failure-path review was performed. Existing review threads are answered and resolved.

@jensenpat

Copy link
Copy Markdown
Collaborator

Checked the accessibility advisory against the rebased change at e83398b19b80f7fc4fcc2649282ce98b2d79d0c6. The CI comment lists 72 scanned files. The actual KAT500 GUI diff contains 15 files; running tools/check_a11y.py over those files and their existing counterparts on main bccd4b719 yields nine warnings on each side, all in the existing Radio Setup surface. After normalizing shifted line numbers, no new finding appears. The new KAT500 applet/Advanced controls introduce no checker finding. The isolated bridge additionally confirmed that disconnected Advanced operations carry the accessible reason Connect the KAT500 first.

@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.

Re-reviewed 2892e7d. The only change since my e83398b approval adds Kat500AdvancedWidget.cpp to radio_setup_operations_test, a target introduced on current main. Linux and macOS CI reproduced its undefined constructor; the repaired native target compiles and the offscreen CTest passes in 22.8 seconds. Audited all 14 test targets compiling RadioSetupDialog_Peripherals.cpp: each now includes the KAT500 widget source.

Production source is byte-identical to e83398b, whose native app build, 10/10 focused CTests and isolated TX-disabled DEMO-0001 bridge proof are recorded in my prior review. The four architecture gates and local reference/log/registration/frozen-gate checks passed; the new change does not modify production behavior or workflows. Prior review findings remain addressed and all threads are resolved. New-head hosted platform/Docs checks remain a merge prerequisite. No live hardware, RF or EEPROM write was used.

@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 : 15
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 merged commit 450f7b3 into main Oct 17, 2026
10 checks passed
@jensenpat
jensenpat deleted the codex/kat500-applet branch October 17, 2026 22:14
jensenpat added a commit that referenced this pull request Oct 17, 2026
Closes #6512.

Adds the compact Elecraft KX100 applet for the KXPA100 amplifier and
optional KXAT100 tuner, built on the merged KPA500/KAT500 foundations
(#5991, #6452). Supports local serial and raw TCP, confirmed amplifier
telemetry, manual tuner controls, Full/Mini presentation, history,
diagnostics and Advanced maintenance.

- The applet provides Standby/Operate, tuner Auto/Manual/Bypass,
antennas, tuner-only Tune/Cancel, Recall/Memorize, physical
bypass/attenuator and C/L relays. Telemetry includes PA input DRV,
forward/reflected power, SWR, current, voltage, dissipation and
temperature. A missing optional tuner dims only tuner-specific controls.
- Use with current radio binds the amplifier serial to the exact radio
solely for VU/PWR metering and applet frequency context. Association
sends no device commands; refused writes retain the previous durable
association and display/log the failure.
- Fresh associated PA Operate telemetry supplies VU/PWR after
higher-priority radio-integrated amplifiers and KPA500. KAT500 KEY BLOCK
retains the KPA500 radio fallback. Stale/standby/tuning KXPA100
telemetry falls back to the radio. Main’s KPA500 telemetry-freshness
admission is preserved.
- TX Controls remains radio-side, following the direction recorded in
withdrawn RFC #6477. ATU/MEM keeps the radio’s behavior and availability
reasons.
- Advanced provides staged per-band antenna configuration/readback,
validated atomic native `.KXPAConfig` backup/restore, stored faults/CSV,
memory inspection/confirmed erase and separately confirmed reset.
Firmware-dependent maintenance is restricted to the verified 01.39
layout. Connecting and opening Advanced perform no maintenance write.

Transport/parser queues and receive buffers are bounded, endpoints are
validated, and late/uncertain transactions do not replay writes. Basic
SWR polling accepts documented `nn.n` decimal replies, including zero,
alongside captured compact replies. No Telnet/RFC2217 support, remote
power command, firmware updater or raw Command Tester is added. Protocol
knowledge comes from public references and isolated Utility I/O
observations, without copying proprietary implementation.

Validation at rebased head `220f8726e6330ee3b7287cb8a51e76008c2c8a83`:

- Native macOS ARM64 app build passed. All 10 selected headless CTests
passed: six KXPA100 targets plus KAT500 meter-source selection, Radio
Setup pair grid and TX power reconciliation, and the repaired Radio
Setup operations target.
- Disabling decimal SWR support failed both protocol and
production-scheduler model regressions; restoring it passed both. The
model cases include fragmented replies, request completion, advancing
past the old deadline and continued polling without disconnect.
- Isolated TX-disabled DEMO-0001 bridge session: one slice/pan,
transmitting=false, native ATU/MEM; disconnected KXPA100 Advanced
read/restore/erase/reset controls were disabled with accessible reasons.
The owned app exited.
- Four architecture checks passed with unchanged normalized legacy
findings; generated references and Log Analyzer checks passed. The new
Radio Setup operations target includes both peripheral Advanced widget
sources; all 14 peripheral-page test targets were audited. Hosted Docs
and main-target platform CI are recorded in this PR’s checks.
- Peripheral tests use injected transport/time or invalid-endpoint
refusal; no synthetic socket/serial firmware peer was run. Actual
hardware communication, EEPROM effects, RF/TX and cross-platform runtime
operation were not revalidated in this landing pass. The demo does not
establish device convergence.

The Full meter screenshot uses explicitly labeled replay telemetry and
is not a live RF measurement:

![KXPA100 Full applet with replay
telemetry](https://raw.githubusercontent.com/aethersdr/AetherSDR/220f8726e6330ee3b7287cb8a51e76008c2c8a83/docs/user/static/img/kxpa100/kxpa100-full-replay.png)

Generated with OpenAI Codex (GPT-6 Astra)

---------

Co-authored-by: jensenpat <patjensen@gmail.com>
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.

Request to add support for elecraft kat 500 and kpa 500

3 participants