Skip to content

feat(gui): AetherControl is a CanonWindow workspace re-skinned to the canon palette. Principle VIII. - #6429

Merged
jensenpat merged 3 commits into
mainfrom
feat/aethercontrol-canon-window
Oct 14, 2026
Merged

jensenpat merged 3 commits into
mainfrom
feat/aethercontrol-canon-window

Conversation

@ten9876

@ten9876 ten9876 commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Part of #6239 and approved RFC #6226. AetherControl (FlexControlDialog) uses a CanonWindow::Kind::Workspace with the canon header and palette. Detect, Settings… and Compact remain above the scroll area; minimum width reserves the body margins, border, and scrollbar so the device card stays visible. The painted metal knob retains its appearance, while capture and on-state accents use theme tokens and repaint on theme changes.

The workspace is always frameless and opens independently of View → Frameless Window. Its geometry uses the existing FlexControlDialogGeometry key, including import of legacy base64 geometry. Drag empty space to move it and resize from its edges. Escape releases an active knob capture first; subsequent Escape and the platform Close shortcuts close the window. Close shortcuts also close while captured.

User and style documentation describe the migrated window. The AetherControl screenshot has been recaptured through the automation bridge on the built-in demo simulator and visually inspected.

Screenshots

Before:

Previous AetherControl window

After:

Canon AetherControl workspace

Validation

Verified final head efad6319817eb2458a876e291fb94ccb7c23410d, integrated with main fc434510e45fe751e65e9cede63a29205c3c6198:

  • ARM64 macOS / Qt 6.12 desktop build passed using cmake --build build -j22 with selected targets.
  • Six headless CTests passed: aethercontrol_window_test, flex_control_dialog_size_test, canon_window_test, theme_manager_test, theme_seed_test, and ulanzi_mapping_migration_test.
  • The AetherControl fixture reports 12 passed, 0 failed. It covers workspace flags, current geometry persistence, legacy base64 import, all platform Close bindings, Escape from window/knob/sibling button, and captured-ring color under both bundled themes. The geometry assertion derives its requested size from the widget minimum, avoiding dependence on installed font metrics.
  • Before correcting rejection suppression, the new captured-close rows failed for Ctrl+W, Ctrl+F4, and Close. With the Escape-only guard, all three pass and release-first Escape behavior remains intact.
  • An authenticated, settings-isolated, TX-disabled DEMO-0001 bridge session verified opening, capturing, closing/recreating, Dark/Light rendering, Compact shrinking to 700×744, and geometry restoring to 700×1200 across a process restart. All proof processes were stopped.
  • The four architecture gates pass on main and head with identical findings. Test registration, theme seed, generated docs, color ratchet, focused accessibility (0 findings), documentation site build, and log-rule checks pass. The screenshot embedding check reports pre-existing unrelated page drift; the AetherControl page is in sync.

Native macOS Command-W/taskbar behavior, a physical FlexControl, live radio operation, and VoiceOver were not exercised. Offscreen Qt exposes Ctrl+W/Ctrl+F4/Close; this is widget and simulator evidence. The optional automated code-review pass was unavailable. This developer app build has no QtKeychain or DFNR and is not a release-package validation.

Constitution

Principles VIII (Evidence Over Assertion) and XI (Fixes Are Demonstrated): local evidence above; PR CI and the squash commit’s post-merge CI are tracked separately during landing. No new settings key, protocol/capability change, workflow edit, or CHANGELOG entry.

Generated with OpenAI Codex (GPT-6 Astra)

… canon palette. Principle VIII.

Part of #6239. AetherControl (FlexControlDialog) moves from PersistentDialog
to a CanonWindow workspace, following SpotHub (#6401) and AetherGPS (#6364).

- Chrome: no title bar; the ambient ground, the canon header and the corner
  close button. Drag any empty area to move it, resize it from any edge,
  close it with Esc or Ctrl+W. While the knob has the mouse captured, the
  first Esc still only releases it.
- Kind: Workspace, an independent top-level window with its own taskbar
  entry. It no longer follows View -> Frameless Window, so it is created
  directly instead of through showOrRaisePersistent().
- Geometry persists under its old key, FlexControlDialogGeometry.
- Header (maintainer's choice): the canon header replaces the
  "AetherControl / Virtual Tuning Controller" wordmark card; Detect,
  Settings... and Compact sit in a row under it, outside the scroll area.
- Look: the canon/aetherControl scope and one sheet of canon tokens
  replace the window's hex literals. Cards are raised, panels nested,
  buttons and combos on control with cyan text. The "on" states (aux LEDs,
  the selected Aux, a connected FlexControl, checked options, an armed
  capture) keep AetherControl's green through the toggle.success and
  accent.success tokens (maintainer's choice).
- Knob (maintainer's choice): the painted metal knob is unchanged; only its
  capture ring and "Press Esc" badge move from literals to tokens, and it
  repaints on a theme switch.
- The minimum width now counts the body margins, border and vertical
  scrollbar, which used to cover the right edge of the device card.

Tests: aethercontrol_window_test pins the workspace kind, geometry under
the old key, Esc releasing a capture before it closes the window, and the
captured ring in color.accent.success in both themes. Each fails when its
guard is broken (ring literal, Esc release removed, geometry key renamed).

Docs: flexcontrol-tuning-knob.md describes the window; docs/style lists
AetherControl among the canon windows and scopes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ten9876
ten9876 requested a review from a team as a code owner October 13, 2026 03:48

@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. #6239 is a tracker rather than a defect report, so the requirement list comes from the PR's own stated intent plus RFC #6226's canon, and every item maps to a hunk: CanonWindow::Kind::Workspace + frameless flag (FlexControlDialog.cpp:999), the canon/aetherControl scope and the token sheet (:74-254), geometry under the old key (:1006), edge resize (FramelessResizer::install, :1008), the canon header with the control row beneath it outside the scroll area (:1014-1089), direct construction so View → Frameless Window no longer applies (MainWindow_Controllers.cpp:265-278), and the docs rows. Nothing in the diff is unexplained, and nothing claimed is missing.

Scope

File / group What it changes Claimed? Verdict
src/gui/FlexControlDialog.{h,cpp} PersistentDialog → CanonWindow workspace; token sheet; canon header; windowChromeWidth() Yes In scope
src/gui/MainWindow_Controllers.cpp showOrRaisePersistent() → direct construction + WA_DeleteOnClose Yes In scope — matches the established canon pattern verbatim (MainWindow.cpp:3576-3590 RadioSetup, :4681-4685 AGC-T)
tests/aethercontrol_window_test.cpp, tests/tests.cmake New test; flex_control_dialog_size_test sources retargeted to CanonWindow.cpp Yes In scope
docs/style/*.md (3) Add AetherControl to the canon window / scope lists Yes In scope
docs/user/docs/flexcontrol-tuning-knob.md, docs/user/screens.json Section rewrite + alt text Yes In scope

Everything in the diff is explained by the stated intent. No CHANGELOG.md entry (correct). No new settings key — the existing FlexControlDialogGeometry is reused. No new public, protocol or capability surface. The one bundled behaviour change beyond the chrome swap — the minimum width now reserving the scrollbar, which previously overlapped the device card's right edge — is disclosed in the body and is a direct consequence of the new body margins, so it belongs here.

docs/user/versioned_docs/version-stable/flexcontrol-tuning-knob.md:48 still carries the old "Virtual Tuning Controller" wording. That is correct and not a finding: it is the frozen Stable snapshot, re-taken by 34363a381.

Blockers

None.

Nits (non-blocking)

  • docs/user/screens.json:2093 — the alt text now describes the new window:

    "alt": "AetherControl window with Detect, Settings… and Compact buttons under its header. …"

    while docs/user/static/img/screens/aethercontrol-window.png still shows the old wordmark card. You disclose this ("Stale screenshot, to recapture after merge"), so this is a question rather than a complaint: since the entry already carries "grab": {"target": "FlexControlDialog"} and the capture is automated, is there a reason the recapture can't ride in this PR? Until it does, screen-reader users get a description that disagrees with the image they can't see — the one audience for whom the alt text is the whole artifact.

  • tests/aethercontrol_window_test.cpp:188-196 — the released != 0 control is a slack-6 per-channel RGB probe over antialiased vector art, the same test genre 2452cb555 had to repair on main two commits ago. I checked it rather than assuming: all 18 hardcoded stops in the knob's paint (#00040a … #e0e8ef) are a blue-grey ramp, and none lands within 6 on any channel of color.accent.success in either theme (#4dd87a dark, #1a8040 light), so the control is sound today. It is only the future that worries me — any knob restyle toward green flips this red for a reason that has nothing to do with the assertion's subject.

  • src/gui/FlexControlDialog.cpp:238-253 — the new scrollbar rules style :vertical, ::handle:vertical and zero out add-line/sub-line, but leave ::add-page/::sub-page unstyled. With a partially-styled QSS scrollbar Qt falls back to the platform style for the trough segments, which may not read as canon on every platform. Cosmetic.

Bookkeeping, for you as the tracker owner

AetherControl is not on #6239's Picked list, and the sentence this PR edits in aethersdr-style-guide.md:113 still gates canon coverage on "the candidates listed on #6239, once the maintainer picks them". I am not treating that as a governance finding: you are #6239's author and assignee, the body attributes each look choice to the maintainer, and #6273's status comment establishes that picks happen outside the tracker. But the picked list is now lagging by at least three rows — AetherControl, SpotHub (#6401) and Radio Setup — which makes the next reviewer run the same check I just did. Worth a line in #6239.

What I tried to break

  • The headline claim — that the canon palette actually applies. The diff touches no theme resource, and ThemeManager.cpp:296-297 falls back to root, not to the nearest ancestor, when a scope path is unregistered — so an unregistered canon/aetherControl would silently skip the canon re-tint and the PR would be a no-op re-skin. It is registered: theme::setContainer → registerDeclaredContainer → scopeOrCreate (ThemeManager.cpp:1908-1916) walks the segments and creates canon/aetherControl as a child of the seeded canon scope, and the call precedes applyStyleSheet in the constructor. Held.
  • Legacy geometry under the reused key. PersistentDialog wrote base64 saveGeometry(); CanonWindow writes "x,y,w,h". An existing operator's saved value is therefore the wrong format for the new reader, which would silently drop it. CanonWindow::restoreGeometryFromSettings() has an explicit base64 fallback (CanonWindow.cpp:179-181), and base64 contains no comma so it can never take the 4-part branch by accident. The comment's "saved geometry carries over" is true. Held.
  • The ✕ while the knob has the mouse captured. FlexControlDialog::reject() swallows the first Escape to release the capture; if the corner ✕ also routed through reject(), the ✕ would be dead on first click and the new user doc (which scopes the exception to Esc) would be wrong. CanonWindow.cpp:74 connects it to &QDialog::close, and closeEvent releases the capture before delegating. Doc is accurate. Held.
  • What trackPersistentDialog() drops. The new comment claims the only loss is View → Frameless Window. m_persistentDialogs is walked in exactly one place (MainWindow.cpp:10238-10246) and does exactly one thing — dlg->setFramelessMode(on). Nothing else keyed off the tracked set. Claim is complete.
  • Lifetime. WA_DeleteOnClose on a member: MainWindow.h:1697 is QPointer<FlexControlDialog>, and all ~20 call sites null-check, including the two lambdas at :285/:290. Escape routes through reject()→hide() so it never deletes; the ✕ does. Both were already true under showOrRaisePersistent, so this is not a change.
  • windowChromeWidth() double-counting the scrollbar. Checked both states: with the bar hidden width() - m_scrollArea->width() is the margins alone and the bar is deliberately reserved; with it shown the subtraction already removes it, so + sizeHint().width() restores exactly one. The pre-show fallback 2 * (kBodyMargin + kInset) = 30 is exact, not an estimate (14+14 body margins + 2×1 border). No path reaches the isVisible() branch before a layout pass — FlexControlDialog has no showEvent, and the only two call sites are the constructor and the Compact toggle.
  • Stuck maximum height after leaving Compact. applyCompactWindowSize() calls setFixedHeight(), which pins the maximum; updateCompactMode() resets setMaximumHeight(QWIDGETSIZE_MAX) and setMinimumSize(0,0) on entry (:1722-1723). No trap.
  • Contrast on the new pairings, resolved per theme rather than eyeballed. canon.ink on toggle.success.background.checked is 6.86:1 dark (#eaf2fb on #006040) and 10.97:1 light (#1a2a3a on #c8e8d0) — the light ramp inverts (gray.50 = #1a2a3a), so canon surfaces stay legible in both. canon.cyan on canon.control is the tightest at ~4.67:1 light, still over docs/a11y.md's 4.5:1 for 12 px bold. No regression.
  • Tests that pass against unfixed code. They don't. capturedRingIsTheSuccessToken loops both themes, and the pre-PR literal #65d379 is >6 off accent.success in each (24 off dark, 75+ off light), so a revert to any single hex fails at least one theme. The workspace-kind and old-key-geometry slots both assert shapes PersistentDialog cannot produce. Your three mutation runs are author-reported and I can't reproduce them, but the assertions are structurally capable of failing.
  • Link gaps from the retargeted source lists. FramelessMoveHelper.h and Theme.h are header-only, so swapping PersistentDialog.cpp/FramelessWindowTitleBar.cpp for CanonWindow.cpp leaves no undefined symbol; flex_control_dialog_size_test.cpp is unmodified and touches only the public surface plus the still-present "Compact" button text, so it keeps compiling. aethercontrol_window_test is in AETHER_SETTINGS_CONSUMERS (tests.cmake:8712) and uses TestSettingsProfile, per the CMake contract.
  • Security. security-audit (CodeGuard) returned no findings: all 19 leads are refuted — the CMDI hits are C++ || and reference declarators plus a Markdown backtick in a // comment, the SSRF/PII hits are RFC 5737/2606 documentation addresses inside "alt" strings — and none of the flagged lines intersects this diff.

Could not check: anything at runtime. I have no build and no GUI, so every statement above is reasoned from the head checkout at 1601eb3, not reproduced. CI is green on all 10 checks, but ci.yml has no ctest -R filter containing aethercontrol_window_test or flex_control_dialog_size_test — so green proves the new target compiles on Linux, macOS and Windows, and proves nothing about whether its four slots pass. They run post-merge in the full suite. The two gaps you name yourself (no physical knob, no live radio) I also cannot cover.

Recommendation

Approve with nits. This is a clean migration: the scope is exactly what the title says, the two mechanisms most likely to break silently — scope registration and legacy geometry under a reused key — both have real answers in the code rather than hopeful comments, and the new test is a genuine guard rather than a restatement of the implementation. The three nits are all non-blocking; the only one I'd like an answer on before merge is whether the screenshot recapture can ride along, since the alt text in this PR already describes the window the image doesn't show. Next step: a maintainer merge decision, plus the AetherControl/SpotHub/Radio Setup rows on #6239's picked list.


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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

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

  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2579
  • [HIGH] CS-VLN-SSRF-LOCALHOST — Vulnerability: CS-VLN-SSRF-LOCALHOST in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:4219
  • [MEDIUM] CS-PII-EMAIL — PII detected: email in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:3877
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:1122
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2579
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2625
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2659
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2756
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:2796
  • [LOW] CS-PII-IP — PII detected: ip_address in docs/user/screens.json /tmp/aetherclaude/pr-6429/docs/user/screens.json:4219
  • [CRITICAL] CS-VLN-CMDI-PIPE — Vulnerability: CS-VLN-CMDI-PIPE in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:209
  • [CRITICAL] CS-VLN-CMDI-PIPE — Vulnerability: CS-VLN-CMDI-PIPE in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:210
  • [CRITICAL] CS-VLN-CMDI-PIPE — Vulnerability: CS-VLN-CMDI-PIPE in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:3230
  • [CRITICAL] CS-VLN-CMDI-PIPE — Vulnerability: CS-VLN-CMDI-PIPE in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:3231
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:206
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:1934
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:3295
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:628
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow_Controllers.cpp /tmp/aetherclaude/pr-6429/src/gui/MainWindow_Controllers.cpp:1902

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: $19.9856 · model: claude-opus-5

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

Reviewed head 1601eb30d29b53cd1d78185190832b145cd0a1ca. Issue fit: mostly. #6239 is the canon migration tracker, rather than a defect report; RFC #6226 is approved, and the body attributes the surface's look choices to the maintainer. Workspace kind, token scope, header/control placement, old geometry key, scrollbar reservation and direct MainWindow construction map to the stated requirements. The migration works in the checks below, except the newly inherited close shortcut does not close a captured knob's window as documented. Recommendation: Request changes.

Scope

File/group Change Claimed? Verdict
src/gui/FlexControlDialog.{h,cpp} CanonWindow workspace, scoped tokens, header, chrome sizing, capture accents and theme repaint Yes In scope
src/gui/MainWindow_Controllers.cpp Direct construction, WA_DeleteOnClose and show/raise/activate Yes In scope
tests/aethercontrol_window_test.cpp, tests/tests.cmake New socket-free window test and retarget existing size test to CanonWindow Yes In scope
docs/style/aethersdr-style-guide.md, dialog-patterns.md, theme-style-guide.md Register the migrated window and scope in the canon docs Yes In scope
docs/user/docs/flexcontrol-tuning-knob.md, docs/user/screens.json Workspace behavior, close instructions and screenshot alt text Yes In scope; screenshot explicitly disclosed as stale

Everything in the diff is explained by the stated migration. One relevant October 13 authored commit; no unrelated work, new settings key, protocol/capability surface, theme-token value change, or CHANGELOG entry. The minimum-width change and green on-state choices are disclosed. The body checklist's scope/persistence/docs claims hold, subject to the close behavior finding below. #6239's picked list does not yet name this surface, but the maintainer-authored PR explicitly attributes its choices to the maintainer; I am not treating that bookkeeping lag as unauthorized design.

Blockers

  1. Ctrl+W releases capture instead of closing — src/gui/FlexControlDialog.cpp:1889–1894. CanonWindow.cpp:78–79 adds a QKeySequence::Close shortcut that invokes virtual QDialog::reject(). The retained override suppresses every rejection while the wheel is captured, so Ctrl+W reaches it and only releases capture. The body and docs/user/docs/flexcontrol-tuning-knob.md:50 say Ctrl+W closes, with only Escape having the release-first exception. This shortcut is newly exposed by the base-class migration; the corner ✕/close-event path works.

    Reproduced offscreen with the production widget and a real Qt key sequence: show window → double-click the enabled knob → assert armed → QTest::keyClick(knob, Qt::Key_W, Qt::ControlModifier):

    CTRLW visible true armed false
    FAIL! : AetherControlWindowTest::ctrlWClosesWhileCaptured()
      '!window.isVisible()' returned FALSE.
      (Ctrl+W should close the captured workspace)
    

    Restrict rejection suppression to the existing Escape deduplication flag. This drop-in replacement was compiled in scratch and passed all eight checks, including the new Ctrl+W probe, legacy base64 import and the original Escape-release test:

    void FlexControlDialog::reject()
    {
        if (m_ignoreNextReject) {
            m_ignoreNextReject = false;
            releaseWheelCapture();
            return;
        }
        CanonWindow::reject();
    }

    Corrected output: CTRLW visible false armed false, Totals: 8 passed, 0 failed. Add the captured-close-shortcut test to the delivered suite. This is a Linux Ctrl+W reproduction; the same QKeySequence::Close routing is used on macOS, but ⌘W was not executed locally.

Nits — explicitly non-blocking

  • Legacy migration is not pinned by the new test — tests/aethercontrol_window_test.cpp:101–132. It empties the old key and writes a new CanonWindow CSV value, so it never tests the header comment's claim about saved pre-migration base64 geometry. My additional scratch test seeded QDialog::saveGeometry().toBase64() under FlexControlDialogGeometry; head successfully restored 660×700. Add this as a regression case so removal of the CanonWindow base64 fallback cannot silently lose existing geometry.
  • Screenshot/alt mismatch — docs/user/docs/flexcontrol-tuning-knob.md:52, docs/user/screens.json:2093. The alt text describes the new header/control arrangement, while the unchanged PNG still depicts the old wordmark card. The body explicitly identifies this stale shot, as AGENTS.md permits, so it is not a blocker; recapture the image as disclosed.

What I tried to break / verification

  • Test-boundary preflight passed: the new window test and retargeted size test use standalone widgets/slice state, with no serial port, socket or synthetic firmware peer. The settings object-library wiring, settings-consumer registration, and TestSettingsProfile isolation are present.
  • Ran all six named socket-free targets from the clean exact-head build: aethercontrol_window_test, flex_control_dialog_size_test, canon_window_test, theme_manager_test, theme_seed_test, ulanzi_mapping_migration_test all exited 0. Separately compiled scratch Qt probes and alternate dialog objects, reusing unchanged objects from that build; no shared checkout/build was modified. The new production-widget probe found the blocker (7 passed, 1 failed); the focused correction passed all eight.
  • Independently repeated the three claimed mutations: replacing the captured ring with the old literal failed the ring slot; renaming the geometry key failed the save/restore slot; omitting capture release failed the Escape slot. The original test reports dark/light ring pixels released 0, captured 782/864. These tests detect their subjects; I did not adopt the prior review's speculative future-green-knob concern as a current defect.
  • Full desktop bridge: offscreen, fresh isolated settings, NO_TX, identity pr-6429-review, explicit socket aethersdr-pr6429-review; connected only DEMO-0001, confirmed model="AetherSDR Demo" and transmitting=false. Opened via Settings → AetherControl, grabbed and inspected Dark, Light and Compact, toggled Compact both ways, captured the knob and closed/reopened. Reopened capture hint returned to Double-click the knob to capture circular tuning. After resize returned {"actual":{"h":700,"w":640}}, closed, restarted the process, and reopened: dumpTree restored {"h":700,"w":640,"x":449,"y":95}. Review instances were disconnected/closed; no operator session or physical radio was driven. The bridge does not expose arbitrary window-shortcut injection, so Ctrl+W evidence is from the running Qt widget fixture, not a bridge key injection. Physical-knob detection, native taskbar behavior, and macOS/Windows gestures remain unverified locally.
  • Ran all four engine/seam checks on exact source exports of base 34363a38 and head, comparing complete per-file outputs: identical. 102 tracked engine-boundary findings, zero strict blockers; 70 capability booleans; 297 raw commands in 30 files; touchpoint manifests current and unchanged. Lifetime/sizing audit also survived: QPointer member ownership, receiver-bound timers/theme repaint, capture release on hide/destruction, and one scrollbar-width reservation. Prior CodeGuard warnings at MainWindow logical-OR/bit-operation/string/comment lines and unrelated screens.json endpoints are not shell-execution or network changes in this diff; no claimed vulnerability was substantiated.

CI: every required check and the Docs build passed. Earliest head run creation was 2026-10-13 03:48:39 UTC; current main's observed tip is 34363a38 from 2026-10-12 23:18:11 UTC, also the merge base. No stale-main timing gap was found. PR checks do not establish a full-suite run. The optional automated code-review skill was unavailable; this pass used manual audit plus an independent parallel lifetime/sizing review.

Next step: fix the captured close shortcut and add its socket-free regression case; then rerun the focused window tests and required checks. GitHub authentication is the PR author's account, which cannot submit a self REQUEST_CHANGES review, so this single review is posted as COMMENT with the Request changes recommendation preserved.

rfoust
rfoust previously requested changes Oct 13, 2026

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

Reviewed head 1601eb30d29b53cd1d78185190832b145cd0a1ca. Issue fit: mostly. Recommendation: Request changes. The workspace migration matches tracker #6239 and approved RFC #6226, including the stated maintainer choices, but the newly inherited Close shortcut does not close while the knob is captured.

Scope

File/group Change Claimed? Verdict
src/gui/FlexControlDialog.{h,cpp} CanonWindow workspace, scoped tokens, header, chrome sizing and theme repaint Yes In scope
src/gui/MainWindow_Controllers.cpp Direct construction, WA_DeleteOnClose, show/raise/activate Yes In scope
tests/aethercontrol_window_test.cpp, tests/tests.cmake Socket-free window coverage and retargeted size test Yes In scope
docs/style/*.md Document the migrated window and scope Yes In scope
User guide and docs/user/screens.json Workspace behavior and screenshot alt text Yes In scope; stale screenshot disclosed

Everything in the diff is explained by the stated migration. No unrelated changes, new settings keys, public protocol/capability additions, or CHANGELOG entry. The body's scope and persistence checklist holds, subject to the close-behavior blocker.

Blocker

  1. Captured knob swallows Ctrl+W — see the inline comment on FlexControlDialog.cpp:1894. Independently reproduced in the running production widget: Ctrl+W releases capture but leaves the workspace visible, contradicting the documented Escape-only exception. Restrict rejection suppression to the Escape deduplication flag and add a captured-close regression test.

Nits — explicitly non-blocking

  • Legacy geometry import is not pinned — see aethercontrol_window_test.cpp:104. An additional scratch probe confirmed base64 import works; the delivered test exercises only newly saved CanonWindow geometry.
  • Screenshot/alt mismatch — see flexcontrol-tuning-knob.md:52. The unchanged PNG shows the old window. This is disclosed in the body and is non-blocking; recapture it as planned.

Verification and attacks

  • Constructed a clean scratch merge of head 1601eb30 with observed current main 47aa4098. GitHub merge ref a06044e5 still uses base 34363a38; the green required checks predate that main advance and do not run the new window test.
  • Test-boundary preflight passed: the changed targets do not open sockets or serial ports or emulate firmware. ARM64/Qt 6.12 focused builds succeeded, with RADE left enabled; ARM64 processors and absence of RNNoise x86 sources were checked. aethercontrol_window_test, flex_control_dialog_size_test, and canon_window_test all passed.
  • Added a scratch-only production-widget Ctrl+W probe. Uncorrected routing returned CAPTURED CLOSE "Ctrl+W" visible true armed false and failed. Limiting suppression to m_ignoreNextReject returned visible false armed false; all eight checks passed, including the original Escape-release test and an added legacy-base64 import case.
  • Replacing the captured ring token with its old literal failed the ring slot in both themes. Restored production code produced released/captured token-colored pixel counts of 0/782 dark and 0/864 light. The test detects that regression.
  • Test registration, generated reference pages, and focused accessibility checks passed. Manual lifecycle/scope review found QPointer ownership, receiver-bound theme repaint, capture release on hide/destruction, and legacy geometry fallback intact. Prior CodeGuard leads were not substantiated as vulnerabilities in this diff.
  • Full desktop build was started but not completed; no demo bridge session was run. Runtime reproduction uses the offscreen production-widget fixture. Native macOS Command-W, physical-knob detection, and taskbar behavior remain unverified. No operator session or live radio was driven. The optional automated review pass was unavailable.

Next step: fix the captured Close shortcut, deliver its socket-free regression case, and rerun the focused tests and required checks. Scratch changes were restored; the operator's checkout was preserved.

Comment thread src/gui/FlexControlDialog.cpp
Comment thread tests/aethercontrol_window_test.cpp
Comment thread docs/user/docs/flexcontrol-tuning-knob.md
NF0T
NF0T previously requested changes Oct 13, 2026

@NF0T NF0T 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 head 1601eb30d29b53cd1d78185190832b145cd0a1ca. Recommendation: Request changes, one blocker.

The migration itself is clean. Every hunk maps to the stated intent, and the two mechanisms most likely to fail silently both hold up. canon/aetherControl is registered before applyStyleSheet, and the pre-migration base64 geometry still restores through CanonWindow::restoreGeometryFromSettings() (CanonWindow.cpp:179-181). The captured-ring test is a real guard: its released control reads 0 and the captured knob reads 782 (dark) and 864 (light) token-colored pixels. The one thing I found is the same one @rfoust and the earlier maintainer-account pass reported, and I reproduced it on a third toolchain.

Scope

File / group Claimed? Verdict
FlexControlDialog.{h,cpp}: PersistentDialog to CanonWindow workspace, token sheet, canon header, windowChromeWidth() Yes In scope
MainWindow_Controllers.cpp: direct construction + WA_DeleteOnClose Yes In scope; same shape as Radio Setup and AGC-T
tests/aethercontrol_window_test.cpp, tests.cmake Yes In scope
docs/style/*.md (3), docs/user/docs/flexcontrol-tuning-knob.md, screens.json Yes In scope; stale screenshot disclosed

One commit, authored 2026-10-13. No new settings key, no protocol or capability surface, no CHANGELOG entry. Preference-vs-fix: this is a deliberate look change, and the body attributes each choice to the maintainer under RFC #6226 / #6239. The PR is the maintainer's own, so I am not treating it as an unauthorised preference change.

Main is now one commit ahead of the merge base (47aa4098, CTR2) and touches MainWindow_Controllers.cpp. A trial merge of this head onto current main is clean.

Blocker

Ctrl+W (and Ctrl+F4 on Windows) release the knob's capture but never close the window. FlexControlDialog.cpp:1889 (reject()).

CanonWindow.cpp:78-79 wires QKeySequence::Close to QDialog::reject. That shortcut is new to this window, since PersistentDialog had none. FlexControlDialog::reject() swallows every rejection while m_wheel->captured(), so the shortcut only releases the capture. The body and flexcontrol-tuning-knob.md:50 both promise that Ctrl+W (⌘W) closes, with only Esc releasing first. The ✕ is unaffected because it connects to QDialog::close.

I reproduced it on Windows 11, MinGW 13.1 / Qt 6.12.0, offscreen, building the PR's own aethercontrol_window_test and adding a slot that double-clicks the knob and then sends each binding Qt reports for QKeySequence::Close:

CLOSEKEY Ctrl+F4 visible true armed false
CLOSEKEY Ctrl+W  visible true armed false
FAIL! probeCloseShortcutWhileCaptured(): did not close: Ctrl+F4, Ctrl+W, Close

Restricting the suppression to the Escape-dedup flag fixes it. This is the same change @rfoust and @ten9876's pass proposed:

void FlexControlDialog::reject()
{
    if (m_ignoreNextReject) {
        m_ignoreNextReject = false;
        releaseWheelCapture();
        return;
    }
    CanonWindow::reject();
}

With that applied, the same probe gives visible false armed false for all three bindings.

I wanted to check what the || m_wheel->captured() clause was protecting before agreeing to drop it. Every Escape route sets m_ignoreNextReject first (handleEscapeRelease() from event(), eventFilter() and keyPressEvent()), so I probed Escape sent to the window, to the knob, and to another focused child (an option button). With the fix, each one releases the capture, leaves the window open, and closes on the next Esc. Full run: 8 passed, 0 failed.

Please add a captured-close regression to the delivered test. Looping over QKeySequence::keyBindings(QKeySequence::Close) also covers the Windows binding without hard-coding Ctrl+W.

Sibling migrations (#6372, #6340) put "every close path" in their subject lines. This one is the close path that got missed.

Non-blocking

  • Legacy-geometry import is unpinned (aethercontrol_window_test.cpp:104). Agree with @rfoust. The fallback exists and I read it, but the delivered test only exercises the new CSV format. Seeding QDialog::saveGeometry().toBase64() under the old key would pin the "geometry carries over" claim.
  • geometryPersistsUnderTheOldKeyAndRestores depends on font metrics. It asserts window.minimumWidth() < 640 as a precondition. On my machine, offscreen with no Qt font directory, minimumWidth() was 764 and the slot failed, and the Ctrl+W failure above is unrelated to it. With QT_QPA_FONTDIR=C:/Windows/Fonts it passes. Choosing the target size relative to minimumWidth() (say minimum + 40) would remove the dependency. I did not check which CI lanes run this test.
  • Screenshot / alt text. aethercontrol-window.png is stale, and the alt text already describes the new window. It is disclosed, and AGENTS.md permits it. I'd lean toward recapturing in this PR since capture_screenshots.py --only is automated, but I am not asking for it.

Other reviews

  • @rfoust and the maintainer-account pass: agree on the blocker and on the fix. I reproduced it myself, rather than relying on their output.
  • aethersdr-agent ("Approve with nits"): I disagree with the verdict. Its ✕ check was right, since closeEvent releases the capture. It stopped there and did not follow the QKeySequence::Close shortcut into reject(), so it vouched for a doc sentence that is false for Ctrl+W. Its slack-6 probe concern is not a current defect. All 18 hardcoded knob stops are blue-grey, and the ring slot measured 0 released against 782 and 864 captured.
  • CodeGuard's 19 leads sit on lines outside this diff, and I found nothing to substantiate them.

What I tried to break

  • Test-boundary preflight: the added test and the retargeted size test construct bare widgets and a standalone SliceModel. There are no sockets, serial ports or fake-firmware peers.
  • Reproduction: built aethercontrol_window_test from the PR head in an isolated worktree and build dir. Unmodified: the PR's slots pass with fonts available, and my close-shortcut probe fails as shown. With the fix: all pass. flex_control_dialog_size_test also passes (6/6).
  • Escape release-first, from window, knob and a sibling child, before and after the fix.
  • reject() vs close(): the corner ✕ goes through close(), so it is unaffected.
  • Governance: Principle VIII matches the citation on #6401 and #6413. CODEOWNERS is Tier 3 only (src/ falls to *, docs/ and tests/ to @aethersdr/reviewers). .github/ci-test-gate.txt is unchanged. CI runs no ctest -R for either window test, so green proves the target compiles, not that its slots pass.
  • Not tested: I did not drive the demo bridge. This is a key-routing defect reproduced at the widget level, and the maintainer-account pass already drove the bridge. macOS ⌘W, a physical knob, and native taskbar behaviour are unverified by me. One unverified side note: the captured() clause also backstopped any Escape-equivalent that reaches QDialog::keyPressEvent without passing handleEscapeRelease(), such as macOS Ctrl+. as I recall the Qt source. I did not check it. Worth a look on a Mac after the change.

Next step: apply the reject() change, add the captured-close regression, and re-run aethercontrol_window_test and flex_control_dialog_size_test. I'll approve on the next push if nothing else turns up. The squash subject would be the current title plus (#6429): feat(gui): AetherControl is a CanonWindow workspace re-skinned to the canon palette. Principle VIII. (#6429).

Thanks for another careful canon migration. The scope discipline, the controls in the ring test, and the disclosure of the stale screenshot made this easy to review.

73, Ryan NF0T & Claude (AI dev partner)


👨🏼‍💻 Co-authored by Claude Sonnet 5.5

@jensenpat jensenpat self-assigned this Oct 14, 2026
@jensenpat
jensenpat dismissed stale reviews from rfoust and NF0T October 14, 2026 14:01

Retired by efad631: the captured Close shortcut now closes via the Escape-only reject guard at FlexControlDialog.cpp:1889. Delivered platform-binding regression failed on the old guard (Ctrl+W/Ctrl+F4/Close) and passes now; Escape window/knob/sibling routing, legacy base64 geometry, and font-independent geometry sizing pass. Final aethercontrol_window_test: 12 passed, 0 failed; six selected CTests pass, full desktop build passes, and a private TX-disabled DEMO-0001 bridge demonstrates capture-close/recreate, both themes, Compact, and geometry across restart. Stale screenshot recaptured and inspected; evidence posted in the review threads and PR body. Hosted CI is still running; no claim of post-merge validation.

@jensenpat

jensenpat commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Remediation is now on verified head efad6319817eb2458a876e291fb94ccb7c23410d. The captured-Close bug, legacy geometry coverage, font-dependent geometry precondition, and stale screenshot are addressed, with evidence in all three resolved threads and the rewritten PR body. Two blocking reviews have been dismissed with that evidence.

I independently inspected the CodeGuard leads on the original head. The C++ lines are boolean ||, reference declarators, a comment, and a QString display template (MainWindow_Controllers.cpp:206,209–210,628,1902,1934,3230–3231,3295), with no shell execution. The JSON hits are documentation/loopback addresses and an example.com placeholder in passive screenshot descriptions (screens.json:1122,2579,2625,2659,2756,2796,3877,4219). They do not substantiate command injection, SSRF, or private-address disclosure in this change.

The ring-test concern is hypothetical: on the final production widget, the released control has 0 success-colored pixels and the captured knob has 782 (Dark) / 864 (Light). The test’s current control holds, and both themes pass. No knob restyle is part of this PR. The bot’s potential scrollbar trough difference is an optional cosmetic suggestion rather than a reproduced defect; the maintainer-approved stylesheet is retained as explicitly directed by the operator ("Leave current scrollbar styling"). This does not broaden the accepted migration’s palette. Tracker #6239 bookkeeping is outside this PR’s implementation and is not a correctness finding, as the existing reviews explicitly note.

Final local evidence: desktop build passed, 6/6 selected CTests passed, AetherControl fixture 12 passed / 0 failed, before-fix captured-close rows failed, documentation build passed, and the architecture gates have identical findings on main and head. The private TX-disabled DEMO-0001 bridge proved capture/close/recreation, Dark/Light/Compact rendering and 700×1200 geometry restoration across restart. All proof processes have stopped. Native Cocoa Command-W, taskbar behavior, a physical knob, VoiceOver, and live hardware remain unverified. PR CI is running; post-merge CI is still outstanding.

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

Verified head efad6319817eb2458a876e291fb94ccb7c23410d after the final push, integrated with main fc434510e45fe751e65e9cede63a29205c3c6198.

  • FlexControlDialog.cpp:1889: the Escape-only rejection guard fixes captured platform Close shortcuts. The delivered regression fails on the prior guard (Ctrl+W, Ctrl+F4, Close) and passes on this head. Escape from window, knob, and sibling control still releases first and closes on the next press.
  • aethercontrol_window_test.cpp:105–156: legacy base64 geometry import is now exercised, and the CSV size assertion derives from the widget minimum rather than a font-dependent width limit.
  • The AetherControl screenshot is recaptured, visually inspected, and matches its alt text; before/after images are in the PR body.

Empirical proof: final ARM64/macOS Qt 6.12 desktop build passed; six headless CTests passed; AetherControl reports 12 passed, 0 failed. Authenticated, isolated-settings, TX-disabled DEMO-0001 bridge verification covered capture/close/recreation, Dark/Light, Compact (700×744), and geometry restoration (700×1200) across a process boundary. Both proof processes were stopped. Docs site and static checks pass locally; all four architecture gates produce identical main/head findings. All three review threads have evidence replies and are resolved; both blocking reviews were dismissed only after their requests were demonstrated.

CodeGuard leads are refuted by their actual source content (C++ expressions/declarations and passive example-address descriptions). The current ring control reads 0 released / 782 Dark / 864 Light captured pixels; its suggested future-restyle risk is not a current defect. The original approved scrollbar palette is retained; an optional cosmetic change was put to the operator, with no extra styling applied without direction. No new design or scope choice was needed for the fixes.

Manual adversarial pass checked capture cleanup on hide/destruction, receiver-bound repaint, QPointer recreation, legacy geometry fallback, scope registration and unchanged engine touchpoints. Automated code review was unavailable. Native Cocoa Command-W/taskbar behavior, physical hardware, live radio and VoiceOver remain unverified; widget and simulator evidence do not establish hardware behavior. This developer build has no QtKeychain/DFNR and is not a release-package proof.

CI freshness checked: earliest run on this head was created 2026-10-14T13:59:08Z; current main was committed 2026-10-14T06:55:52Z, so its tree precedes the fresh runs. Platform jobs are still running; this review does not claim they or post-merge main CI have passed. Landing remains contingent on all required checks and a final exact-head/main/thread/signature/merge-tree recheck.

@jensenpat
jensenpat merged commit 86f592a into main Oct 14, 2026
10 checks passed
@jensenpat
jensenpat deleted the feat/aethercontrol-canon-window branch October 14, 2026 14:12
@jensenpat

Copy link
Copy Markdown
Collaborator

Post-merge verification for squash commit 86f592a9f5303e3581d514d9ceb8a7dead9a3235:

  • Main CI passed: Linux build, check-macos and check-windows.
  • Full Suite passed: 793 passed, 7 skipped, 0 failed out of 800 selected. The delivered aethercontrol_window_test passed in 0.23 s and flex_control_dialog_size_test in 0.04 s. This is the independent re-run on the squash commit required by Principle XI.
  • Docs and Code Quality also passed. Static Checks is PR-only; its successful pre-merge verdict remains separate from these main runs.
  • The squash has a verified GitHub signature, preserves the original author/co-author attribution, and its tree c60a2376d0d17003fba5f9351356b644864e95ac exactly matches the verified merge result.

CodeQL and System Libraries Canary are still running; no success is claimed for either yet. The operator explicitly chose to retain the existing scrollbar styling. No live hardware or native Cocoa Command-W proof was performed.

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.

4 participants