Skip to content

feat(gui): radio tab shows an AT chip for adaptive throttle and colours its dot by network quality. Principle VIII. - #6787

Merged
rfoust merged 7 commits into
aethersdr:mainfrom
chibondking:feat/radio-tab-throttle-chip
Nov 3, 2026
Merged

rfoust merged 7 commits into
aethersdr:mainfrom
chibondking:feat/radio-tab-throttle-chip

Conversation

@chibondking

@chibondking chibondking commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #6790.

Behavior

The connected radio's tab shows an AT chip when Enable adaptive frame-rate throttle is enabled. It is outlined while armed and filled in the cap's quality color while capping. Unticking the checkbox does not lift an existing cap; the filled chip remains until disconnect, matching the existing throttle policy.

While the chip shows and the link is healthy, the dot shows network quality: green for Excellent/Very Good, blue for Good, amber for Fair and red for Poor. With AT off, it uses the normal connected green. Discovery amber and link-lost red take priority. Heartbeat glow follows the dot unless a cap supplies its tint. Tooltips and accessible descriptions spell out the grade and throttle state.

The tab's actual width follows chip and status-text changes, including disconnect/reconnect and the “Link lost” alarm. Narrow title bars scroll the tabs rather than squeezing away the chip.

This adds the chip and live-grade cue to the unified title bar. The old standalone lamp displayed the cap tier only; it did not display live network quality. Quality thresholds, throttle policy, defaults and settings ownership remain unchanged.

Approved palette

Implements @ten9876's RFC ruling. One networkQualityColor() mapping reads color.networkQuality.* tokens for the status label, dot and adaptiveFpsCapColor(). Theme switches refresh them immediately, including an engaged cap's glow tint. Both bundled themes and the generated fallback seed define the five tokens.

Grade/token suffix Dark (preserved exactly) Light Light status-label contrast
Excellent / Very Good (excellent) #00cc66 color.green.500 / #1a8040 4.59:1
Good (good) #00b4d8 color.blue.500 / #0088b0 3.75:1
Fair (fair) #cc9900 #a85a00 4.68:1
Poor (poor) #cc3333 color.red.500 / #c02020 5.56:1
Off / unknown (off) #8aa8c0 #8aa8c0 2.29:1

Status-label ratios use WCAG relative luminance against the actual Default Light status-block background sampled from the full app (#f5f5f8). Fair is calculated from the approved token, not a live Fair simulator grade. Good remains below 4.5:1; Off retains the neutral value, as the ruling permits. The grade dots and cap outlines meet 3:1 against the active-tab background in both bundled themes. Filled-chip letters use color.text.primary and meet 4.5:1 against their 22% tinted fill.

Documentation and bridge

Updates the menu and low-bandwidth user guides, window-chrome architecture, canonical tokens and automation-bridge reference. Bridge titlebar.radios exposes linkQuality, resolved linkQualityColor, adaptiveThrottle, adaptiveFpsCap and tabs[].throttleChip. Existing screenshots of the normal AT-off title bar remain representative; the new armed/capped state is described in the guides.

Verification

  • Apple Silicon ARM64 full app built with RADE enabled; processor, executable and RNNoise source checks passed.
  • Socket-free unified_title_bar_test and theme_manager_test: both pass. Coverage checks actual tab/host geometry on AT on/off, reconnect, link-loss text and narrow strips; dot/override/session behavior; chip paint and words; both themes' contrast.
  • Mutation proof: removing the geometry fix causes 11 assertion failures; restoring the old light Excellent hex causes the contrast assertion to fail. Restored builds pass.
  • Final changes also built and tested merged locally with fresh main (base and integration tree recorded in the approving review).
  • Full app driven offscreen with isolated settings and explicit automation socket, connected only to DEMO-0001. Verified checkbox toggles, light/dark theme changes, tooltip/bridge state, disconnect/reconnect, simulator disconnect fault, and settings persistence across a process restart. All owned instances closed normally; TX explicitly disabled throughout.
  • Architecture ratchets, generated theme seed and docs references, log-rule checks, and Docusaurus production build pass. No new GUI-to-engine include or ratchet growth; no CI workflow or CHANGELOG changes.

unified_title_bar_test is compiled but is outside the per-PR CTest filter; the local executed result above is required evidence. The simulator remains Excellent and does not engage an adaptive cap, so final live cap convergence and RF behavior were not tested. Cap rendering/state are covered socket-free; the contributor's earlier FLEX-6600 bridge proof is historical evidence, not a claim about this final build.

…rs its dot by network quality. Principle VIII.

The unified title bar folded the heartbeat lamp into the active radio tab's
dot, which lost the lamp's quality cue and left adaptive throttle visible
only as a glow tint. The connected tab's dot now takes the status bar's
network-quality colour (and names the grade in its tooltip/accessible
description), and an "AT" chip follows the radio's name while the adaptive
frame-rate throttle is enabled: outlined when armed, filled in the cap's
quality colour while a cap is in force.

Bridge: radios.linkQuality, linkQualityColor, adaptiveThrottle,
adaptiveFpsCap and tabs[].throttleChip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chibondking
chibondking requested a review from a team as a code owner October 26, 2026 02:07

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this — the AT chip is a genuinely useful cue, the ours/session gating is carefully reasoned, and the WCAG 1.4.1 work (grade and throttle state spelled out in the tooltip and accessible description, not colour-only) is the right instinct. The code itself is clean; I tried several ways to break it and it survived all of them. My one blocker is about authority for a visual change, not about the implementation.

1. Issue fit

No linked issue and no RFC — search_issues for the adaptive-throttle indicator and for the heartbeat-lamp/tab-dot quality cue returns nothing but this PR. So I reviewed against the body's own stated intent. The body frames the change as restoring two cues lost when the unified title bar landed (#6198). One of those two premises does not hold — see Blocker 1. The AT chip half is sound: m_throttleFlashColor did exist pre-#6198 and the throttle really was visible only as a glow tint, so the chip addresses a real gap.

2. Scope

Everything in the diff is explained by the body; no unrelated files, no vendored or CI churn, no removed guards. One row is in scope but undisclosed as a visible change.

File(s) What it changes Claimed? Verdict
RadioTabBar.cpp/.h AT chip, quality-coloured dot, 5 new bridge fields Yes In scope; the dot recolour is Blocker 1, the bridge surface is Decision 2
MainWindow.cpp/.h refreshAdaptiveThrottleChip(), quality push, fpsCapColor lambda → helper Yes In scope
MainWindowHelpers.cpp/.h adaptiveFpsCapColor() extracted Yes In scope; thresholds byte-identical to the removed lambda, and it removes 3 hex literals
ConnectionPanel.cpp/.h adaptiveThrottleEnabledChanged signal Yes In scope; correctly under signals:
TitleBar.cpp currentBeatColor() returns invalid instead of accent.success Partly In scope, but changes the discovery pulse too — undisclosed (Nit 7)
tests/unified_title_bar_test.cpp 1 new block Yes In scope (Nit 1 on what it pins)
4 doc files chip/quality/bridge Yes In scope

No socket test is added, modified, or removed by this PR — no QTcpServer/QUdpSocket/bind/listen/connectToHost and no fake peer in the changed test. Nothing to surface under the socket-test reporting rule.

3. Blockers

1. src/gui/RadioTabBar.cpp:317-319 — the quality-coloured dot is a new visual-design decision, not a restoration. The premise it rests on is not true, and GOVERNANCE.md requires an RFC for it.

The body's justification:

When the unified title bar landed (#6198), the standalone heartbeat lamp was folded into the active radio tab's status dot. That dropped … the lamp's network-quality colour

I checked the tree immediately before #6198 (5f09371e2^). The lamp never had a network-quality colour:

  • src/gui/TitleBar.cpp at 5f09371e2^ contains zero occurrences of "quality" (57 KB file, so it is the real pre-change file).
  • The lamp was a 10×10 QLabel (TitleBar.h:166, TitleBar.cpp:133-138) whose own accessible description read: "Flashes green when radio discovery packets are received". Its colour states were grey/green/amber/red plus m_throttleFlashColor — no quality tier.
  • networkQualityColor() at 5f09371e2^ had exactly the two consumers it has on main today: the status-bar label (MainWindow.cpp:2248) and the diagnostics tooltip (MainWindowHelpers.cpp:182). The lamp was never one of them.

So #6198 dropped the throttle-tint prominence (real — the chip fixes it) but did not drop a quality cue. Moving the status bar's five-tier palette onto the tab dot is a new design choice: on main that dot means radio status, and after this PR a healthy connected radio on a Fair link shows amber and on a Poor link shows red — the same red family as the link-lost alarm.

GOVERNANCE.md, "What requires an RFC":

  • Any change to visual design — colors, fonts, spacing, theme, icons

and the "does NOT require an RFC" list covers only "New applets or dialogs that don't change existing UX". This changes the meaning of an existing indicator. Sibling PRs in flight (#6753, #6757, #6759, #6762) all cite RFC #6226 for comparable work, so the project clearly gates this.

I'm not saying the idea is wrong — it may well be an improvement. It needs its own issue and a maintainer ruling rather than riding in under a restoration framing. Concretely: either land the AT chip alone (additive, fixes a cue that measurably did regress) and split the dot recolour into an RFC, or get an explicit ruling on the recolour before merge. Either way the body's #6198 sentence should be corrected.

4. Nits (all non-blocking)

  • tests/unified_title_bar_test.cpp:971-1020 — neither visual claim is actually pinned. The block asserts tooltip strings and bridge ints only. Delete the quality branch from dotColor() (RadioTabBar.cpp:317-319) and every new check still passes; likewise setAdaptiveThrottle(true, 8, QColor("#cc9900")) asserts the tooltip and adaptiveFpsCap but never that the chip tints. The dot is a solid-filled ellipse, so a centre-pixel probe of grab() is deterministic (unlike the glyph probes elsewhere in this suite, it isn't font-dependent).
  • tests/unified_title_bar_test.cpp:985 — the session half of the gate is untested. "another radio's tab does not claim this session's quality" passes on isCarrier alone; dropping && !m_activeId.isEmpty() from RadioTabBar.cpp:861 leaves it green. A bar->setActiveRadio({}) followed by check(!sessionTab->isThrottleChipShown(), …) would pin the disconnect-clears-chip path cheaply.
  • src/gui/MainWindow.cpp:731-732 — the comment is wrong. It says:
        // A cap can still be in force just after the box is unticked (it lifts at
        // the next quality update), so the chip stays until the cap is gone too.
    RadioModel::applyAdaptiveFrameRate() returns early at src/models/RadioModel.cpp:8991 when AdaptiveThrottleEnabled != "True", so the lift at :9024 is never reached — an already-applied cap lifts only on disconnect (:8639). That matches low-bandwidth-connections.md ("reconnect to lift an already-applied cap") and the checkbox tooltip at ConnectionPanel.cpp:1044. The enabled || m_adaptiveFpsCap > 0 behaviour is right; only the stated reason is wrong, and "just after" understates it — the chip stays filled for the rest of the session.
  • src/gui/RadioTabBar.cpp:317-319 — first hard-coded hex on the tab dot. Every other dot colour routes through ThemeManager: TitleBar::linkOverrideColor() uses color.accent.danger/color.accent.warning, and the fallback uses statusToken(). networkQualityColor() returns literals (#00cc66, #00b4d8, #cc9900, #cc3333) calibrated against the status bar's background, now painted on color.titlebar.tab.active.background. A user theme can't restyle the dot any more. docs/a11y.md wants 3:1 for non-text UI — worth stating the five colours' contrast against the tab background in both bundled themes rather than assuming the status bar's calibration carries over.
  • src/gui/RadioTabBar.cpp:877-879 — non-session tabs are pushed live chip state. setThrottleChip(ours && m_throttleEnabled, m_throttleCapColor, chipText) hands every tab the current tint and text even when shown is false, so a cap change (8→4) misses the equality guard on every such tab and costs a refreshAccessibility() (three setters) plus a full update() for no visible change. Also, chipText is built with tr(...).arg(...) at :862-864 on every applyLinkVisuals() call, and that runs once per pulse tick (:666) for the whole glow decay. Both go away with:
            tab->setThrottleChip(ours && m_throttleEnabled,
                                 ours ? m_throttleCapColor : QColor(),
                                 ours ? chipText : QString());
  • docs/automation-bridge.md:3243-3247 — radios.adaptiveThrottle is documented as "(enabled)" but refreshAdaptiveThrottleChip() passes enabled || m_adaptiveFpsCap > 0, so after unticking the box with a cap in force the field reads true while the setting is false. Given the nit above that is the rest of the session. Worth wording it as "the chip is showing" rather than "enabled".
  • src/gui/TitleBar.cpp:1669-1671 — an undisclosed behaviour change. The removed line was:
        return m_throttleFlashColor.isEmpty()
            ? ThemeManager::instance().color(this, QStringLiteral("color.accent.success"))
    The consumer handles invalid correctly (RadioTabBar.cpp:429, m_beatColor.isValid() ? m_beatColor : dot), so this is safe — but it also changes the discovery pulse, which previously glowed green over an amber override and now glows amber. Probably an improvement; it's explained only in a code comment, not the body.
  • src/gui/RadioTabBar.cpp:223 — pre-existing, out of scope, credit security-audit (CodeGuard). setToolTip(descriptionLine()) passes m_entry.name (:194-195) unescaped, and Qt auto-detects rich text in tooltips, so a radio nickname containing markup renders as HTML. The repo already escapes one layer up (MainWindowHelpers.cpp:192 calls .toHtmlEscaped() on the quality string). Fix is .toHtmlEscaped() on the name. This PR's additions to that tooltip are tr() constants and a fixed-table label, so it does not widen the surface — flagging only because you're in the function. I did not verify the agent's further claim that this could trigger a remote resource fetch, so please don't take that part as established.

5. What I tried to break (no finding)

Everything below is reasoned from reading the head checkout at /tmp/aetherclaude/pr-6787; I am headless, so nothing here was reproduced at runtime.

  • Constructor ordering. The new connect(m_connPanel, …) and seed refreshAdaptiveThrottleChip() sit around MainWindow.cpp:2205-2207, but m_titleBar/m_connPanel are assigned at :5467/:5525 — which looked like a null-sender connect() that would silently never fire. Refuted: those lines are in buildUI(), called at :1421, and the constructor spans :1085–<2618. Both pointers are live. (The diff's @@ … MainWindow::MainWindow header is git's context heuristic, not the enclosing scope.)
  • The new signal's access specifier. The hunk header reads public slots:; a signal declared under slots: would never be emittable. Refuted — ConnectionPanel.h:132-145 puts it under signals: with its siblings.
  • Stale quality/chip across a radio swap or disconnect. Two independent defences: RadioModel emits both adaptiveThrottleChanged(false, 0) (:8639) and networkQualityChanged("Off", 0) (:8740) on teardown, and setActiveRadio("") → applyActiveState() → applyLinkVisuals() re-pushes to every tab, so ours == false clears both. A second radio can't inherit the first's grade.
  • Another writer of AdaptiveThrottleEnabled bypassing the new signal. ConnectionPanel.cpp:1048 is the only writer in the tree; the three other sites are reads. The signal covers every path.
  • currentBeatColor() returning an invalid QColor. Only caller is TitleBar.cpp:1683; the sink at RadioTabBar.cpp:429 already branches on isValid(). No null-colour paint.
  • adaptiveFpsCapColor() drifting from the lambda it replaced. Identical: ≤4 → #cc3333, ≤8 → #cc9900, else #00b4d8.
  • Accessibility churn from the per-tick applyLinkVisuals(). The early-return guards in RadioTab::setLinkQuality/setThrottleChip mean refreshAccessibility() fires only on a real change — correct for the carrier tab (the waste is on the other tabs, Nit 5).
  • radioTabBar() null deref. Unconditionally constructed at TitleBar.cpp:227; the existing site at MainWindow.cpp:4837 dereferences identically.
  • The security triage. CodeGuard's 97 findings are all false positives on this change — the CMDI-BACKTICK/AMP/PIPE and XSS-OBJECT hits are C++ comment prose (neither RadioTabBar.cpp nor ConnectionPanel.cpp contains any shell invocation), the SSRF-PRIV/PII-IP hits are setPlaceholderText examples and a test fixture, PATH-PROC is the fixed /proc/self/status, and PATH-UNC is JSON-escaped regex. Nothing real is introduced by this diff.

What I could not check: any runtime or visual behaviour (no build, no GUI); the actual contrast ratios in Nit 4; and unified_title_bar_test is not in ci.yml's per-PR ctest -R list, so the green checks prove it compiles, not that the new block passes — the body's local Windows run is the only evidence for it, and the body doesn't disclose that gap.

6. Recommendation

Needs maintainer decision. The implementation is solid and I found no correctness defect, but two calls aren't mine to make: (a) the quality-coloured dot is a visual-design change to an existing indicator whose stated justification is contradicted by the pre-#6198 source, and GOVERNANCE.md names exactly this category as RFC-gated; (b) five new bridge keys are public surface third parties will bind to, arriving without an issue.

Concrete next step: correct the #6198 sentence in the body, then either split the dot recolour into its own RFC and land the AT chip on its own — which I'd recommend, since the chip stands on a gap that genuinely did regress — or get @ten9876 to rule on the recolour directly. The nits are all cheap and worth folding in either way; Nits 1 and 3 are the two I'd most want fixed before merge.


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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

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

  • [MEDIUM] CS-VLN-SSRF-HEX — Vulnerability: CS-VLN-SSRF-HEX in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6787/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-6787/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-6787/docs/user/src/components/LogAnalyzer/rules.json:1071
  • [HIGH] CS-PII-DL-1 — PII detected: drivers_license in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6787/docs/user/src/components/LogAnalyzer/rules.json:88
  • [LOW] CS-PII-IP — PII detected: ip_address in packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml /tmp/aetherclaude/pr-6787/packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml:83
  • [LOW] CS-PII-IP — PII detected: ip_address in packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml /tmp/aetherclaude/pr-6787/packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml:92
  • [HIGH] CS-VLN-SSRF-PRIV-10 — Vulnerability: CS-VLN-SSRF-PRIV-10 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:797
  • [HIGH] CS-VLN-SSRF-PRIV-10 — Vulnerability: CS-VLN-SSRF-PRIV-10 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2557
  • [HIGH] CS-VLN-SSRF-PRIV-172 — Vulnerability: CS-VLN-SSRF-PRIV-172 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2556
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:175
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:176
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2554
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2555
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:1193
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:1304
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2356
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2384
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2758
  • [MEDIUM] CS-VLN-XSS-OBJECT — Vulnerability: CS-VLN-XSS-OBJECT in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:3509
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:175
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:176
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:797
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2039
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2554
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2555
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2556
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2557
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.h /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.h:192
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9803
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9804
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9805
  • [HIGH] CS-VLN-PATH-PROC — Vulnerability: CS-VLN-PATH-PROC in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:6245
  • [HIGH] CS-VLN-PATH-PROC — Vulnerability: CS-VLN-PATH-PROC in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:6324
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:520
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:3601
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:518
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1239
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1722
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1810
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1887

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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

Antares Detector — candidate vulnerable file(s)

  • src/core/NetworkDiagnostics.cpp
  • src/core/NetworkDiagnostics.h

The NetworkDiagnostics implementation likely reads network packets and deserializes them; if it uses unsafe deserialization or untrusted network packet reads, it can lead to memory corruption or unsafe memory access.

Localized by Cisco Foundation AI Antares-1B running locally in the AetherClaude sandbox, seeded by the Cartographer security map. Advisory only — please verify before acting.


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

@chibondking

Copy link
Copy Markdown
Collaborator Author

Live proof via the automation bridge

Build: fork Windows Installer run 40263712412 on b5c0d1af (portable zip). The full app compiles with the MainWindow.cpp / ConnectionPanel.cpp changes.
Radio: FLEX-6600 "NW8S-Barn", firmware 4.2.20, LAN. Windows 10. Receive only; nothing was keyed.

State was read from the bridge's titlebar model (radios), tooltips with tooltip, and the tab captured with grab_widget radioTab_<serial>.

Toggle sequence (one connected session)

Step Checkbox adaptiveThrottle adaptiveFpsCap tabs[].throttleChip Dot (linkQualityColor) Tab tooltip
1. Original state unticked false 0 false Poor #cc3333 … · WT2P · Network Poor
2. Ticked ticked true 0 true (outlined AT) Poor #cc3333 … · Network Poor · Adaptive throttle on
3. Unticked unticked false 0 false Poor #cc3333 … · WT2P · Network Poor (same as step 1)

The chip follows the checkbox immediately, through the new ConnectionPanel::adaptiveThrottleEnabledChanged signal, with no wait for a quality update.

Cap in force (earlier session, throttle enabled, reconnected)

linkQuality adaptiveFpsCap Chip Tab tooltip Status bar label
Fair #cc9900 8 filled amber AT … · Network Fair · Adaptive throttle: 8 fps cap [Fair · 8 fps cap] in #cc9900
  • Unticking with a cap in force: the chip stayed while the 8 fps cap was still in force, as designed. The cap lifts at the next quality update or on reconnect.
  • Disconnect: linkQuality and linkQualityColor cleared and the tab showed no chip, while adaptiveThrottle stayed true (the setting itself).
  • Status bar match: in every reading the dot colour matched the status bar's network label colour (networkQualityColor()), for both Poor and Fair.

Notes

  • The Poor grading on this LAN is real, not an artifact of this change. The status bar showed the same grade, from about 13–15% FFT sequence gaps at a 50 ms RTT. That's worth a separate look.
  • Not covered: a Good or Excellent link, and a 4 fps (Poor) cap.

73, CJ (WT2P)


👨🏼‍💻 Co-authored by Claude Opus 5.5

…. Principle VIII.

Operator feedback on aethersdr#6787: with adaptive throttle off the connection dot
should stay the plain connected green, and any colour change should come
with the AT chip that explains it. RadioTabBar now passes the quality to
the session's tab only while the throttle is enabled; the bridge still
publishes radios.linkQuality as the model's grade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chibondking

Copy link
Copy Markdown
Collaborator Author

Bridge re-proof for d36fe274: the quality colour only appears beside the AT chip

Build: fork installer run 40274923048 (head d36fe274), portable, AETHER_AUTOMATION=1.
Radio: FLEX-6600 "NW8S-Barn" (4.2.20), LAN. The link was grading Poor, so a quality-coloured dot would show red and can't be mistaken for the plain green.

Each row shows the checkbox state set through the bridge, then what titlebar → radios and the tooltip verb returned:

Step linkQuality adaptiveThrottle throttleChip Dot Tooltip
Connected, box unticked Very Good false false green NW8S-Barn · FLEX-6600 · Connected · WT2P
Box ticked Poor (#cc3333) true true red, outlined AT chip … · WT2P · Network Poor · Adaptive throttle on
Box unticked, link still Poor Poor (#cc3333) false false green … · WT2P (no network grade)
  • Last row: this is the change in d36fe274. The bridge still publishes the quality (linkQuality: Poor), but with the throttle off the tab doesn't colour its dot by it or mention it.
  • Whenever the dot is recoloured: the AT chip and the words "Network Poor" are there too.
  • Tab width: the tab's on-screen width stayed at 195 px in all three states, and the grab shows the chip with no truncation of "NW8S-Barn".
  • Cleanup: after the test the box was unticked, which is how this build found it. The test build was then disconnected and closed.

Not re-run here: an fps cap in force (filled chip). That code path is unchanged since the first proof above, which showed it at 8 fps / Fair.

…nd correct the throttle-cap comment. Principle VIII.

Review follow-ups for the AT chip:
- unified_title_bar_test probes the dot's centre pixel: plain connected
  colour without AT, the quality colour with it, plain again once the
  throttle is off. It also checks that no tab keeps the chip or quality
  with no session. Each check fails if its gate is removed (verified by
  mutation).
- MainWindow: an applied cap lifts on disconnect, not at the next
  quality update (RadioModel::applyAdaptiveFrameRate returns early when
  the box is unticked).
- RadioTabBar: tabs that can't show the chip get empty tint/text, and
  the chip text is built only when a tab can show it.
- automation-bridge.md: radios.adaptiveThrottle means the chip is
  showing, not that the setting is on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chibondking

Copy link
Copy Markdown
Collaborator Author

@AetherClaude please re-review. Your review was of b5c0d1af; the head is now af06e03b.

No issue → #6790. It's filed now and the description says Closes #6790. The issue asks for a maintainer ruling on the dot recolour.

Blocker 1 (premise and visual design): You're right that the old lamp never showed the live network grade, and the description now says so in a correction. It wasn't colour-free either: at 5f09371e2^, MainWindow.cpp:2272 called setThrottleFlashColor(fpsCapColor(fpsCap)). So while a cap was in force, the lamp flashed in the cap's tier (red / amber / blue), the same palette as the status bar. You may have missed this because the colour came from MainWindow, not TitleBar.cpp.

The scope of the recolour has also narrowed since you looked. In d36fe274, after operator testing, the dot takes the quality colour only while the AT chip shows. With the throttle off it stays the plain connected green, so a healthy radio on a Fair link is no longer amber unless the throttle is armed. The visual-design call is still a maintainer's, and #6790 asks for it.

Nits:

  1. Visual claims not pinned: fixed. A centre-pixel probe checks the dot in three states: off, AT on, AT off again. Removing && m_throttleEnabled fails four checks (mutation-tested locally).
  2. Session gate untested: fixed. setActiveRadio({}) must clear the chip and the quality. Removing && !m_activeId.isEmpty() fails two checks.
  3. Wrong comment: fixed. A cap lifts on disconnect, because applyAdaptiveFrameRate returns early once the box is unticked.
  4. Hard-coded colours / contrast: not changed. The contrast isn't measured, and the description now says so. These are the existing networkQualityColor() values; turning them into theme tokens would change the status bar too, which is out of scope here.
  5. Live state pushed to other tabs: fixed. Other tabs get empty tint and text, and the chip text is built only when some tab can show it.
  6. radios.adaptiveThrottle docs: fixed. It now reads "the chip is showing", including the cap-after-untick case.
  7. Discovery pulse change undisclosed: now disclosed in the description.
  8. Unescaped radio name in the tooltip: pre-existing and out of scope; left for its own PR.

CI gap: the description now says unified_title_bar_test isn't in the per-PR ctest -R list.

Live proof on a FLEX-6600 through the bridge is in the two comments above. The second one covers d36fe274: a Poor link with AT off shows a green dot.

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

Re-review at af06e03b (previous pass was b5c0d1af). Thanks for the correction in the description, the mutation-tested checks and the two bridge proofs — the live tables made several of my attacks cheap to aim.

1. Issue fit

Closes #6790, which is this PR's own spec: it was filed 2026-10-26 06:56Z, 4h49m after the PR opened (02:07Z), by the same author, with no comments and no maintainer input. Against what it asks: item 1 (AT chip, outlined when armed / filled in the cap's colour) and item 3 (grade and throttle state in words) are implemented and restore what #6198 dropped — RadioTabBar.cpp:302-316, RadioTabBar.cpp:477-493, RadioTabBar.cpp:191-201. Item 2 (dot takes the quality colour, only while the chip shows) is implemented at RadioTabBar.cpp:314-316 + RadioTabBar.cpp:864-879, and both the issue and the description say it needs a maintainer ruling. That ruling is the one thing missing, and it's the recommendation below — the code is otherwise the cleanest part of this review.

The premise now checks out: RadioModel::applyAdaptiveFrameRate emits the cap, MainWindow maps it through what is now adaptiveFpsCapColor(), and the pre-#6198 lamp took that same tier colour. Your correction that the lamp never showed the live grade is in the description, so item 2 is correctly labelled as new rather than restored.

2. Scope

File(s) What it changes Claimed in body? Verdict
src/gui/RadioTabBar.{h,cpp} AT chip paint/size/state, quality-coloured dot, session gate, 4 new bridge fields + tabs[].throttleChip Yes In scope; new public surface (bridge fields)
src/gui/MainWindow.{h,cpp} refreshAdaptiveThrottleChip(), quality push, lambda → adaptiveFpsCapColor() Yes In scope
src/gui/MainWindowHelpers.{h,cpp} adaptiveFpsCapColor() extracted from the inline lambda Yes In scope; new exported helper
src/gui/ConnectionPanel.{h,cpp} adaptiveThrottleEnabledChanged(bool) signal + emit Yes In scope; new signal (internal API)
src/gui/TitleBar.cpp currentBeatColor() returns invalid instead of fixed green Yes (incl. the amber discovery pulse consequence) In scope
tests/unified_title_bar_test.cpp 19 checks: dot pixel, session gate, chip, bridge fields, width Yes In scope
docs/{architecture/window-chrome,automation-bridge,user/docs/menu-reference,user/docs/low-bandwidth-connections}.md Documents the above Yes In scope

No unrelated files, no formatting churn, no deleted guard, no CHANGELOG.md entry, and the - lines are confined to the lambda removal and the currentBeatColor() body. The checklist's "No new flat-key AppSettings calls" is accurate: MainWindow.cpp:729-730 reads the existing AdaptiveThrottleEnabled key and writes nothing.

Socket tests: none added, removed or modified. unified_title_bar_test opens no socket; the only network-looking token is the string fixture connected.transport = QStringLiteral("192.168.1.21") at tests/unified_title_bar_test.cpp:466, which is display text.

Security audit (required by the harness, 97 CodeGuard findings): ran, no findings. Every flagged ID is a lexical match with no security meaning — CS-VLN-CMDI-BACKTICK on the backticked identifiers in your new header comments (src/gui/RadioTabBar.h:186), CS-VLN-CMDI-AMP on & as address-of in connect() (src/gui/MainWindow.cpp:2173), CS-VLN-SSRF-PRIV-*/CS-PII-IP on the setPlaceholderText example addresses at src/gui/ConnectionPanel.cpp:2554-2557 (present verbatim on main, never dialled), CS-VLN-PATH-PROC on the pre-existing /proc/self/status RSS read. The new surface is bool/int/QColor moved between widgets: no parser, no sink, no stylesheet, no path. Credit: security-audit (CodeGuard).

3. Blockers

1. GOVERNANCE.md — the quality-coloured dot is a visual-design change with no approved RFC. Not a code defect; a process gate, and you flagged it yourself, so this is mostly me putting the citation on the record for the maintainer.

GOVERNANCE.md:97:

  • Any change to visual design — colors, fonts, spacing, theme, icons

and GOVERNANCE.md:122,131:

Open a GitHub issue with the label rfc and the title prefix [RFC]. […] Do not open a PR until the RFC issue is approved.

plus the normative agent limit at GOVERNANCE.md:221-223:

May not autonomously change: visual design (colours, fonts, layout, theme) […] The Project Maintainer is the sole authority on visual design and UX direction.

#6790 is labelled enhancement/GUI, has no [RFC] prefix, no rfc label, no maintainer comment, and postdates the PR, so it is not the approval that sentence asks for. The GOVERNANCE.md:110-118 exemption for "bug fixes with a clear root cause" plausibly covers items 1 and 3 — the AT chip restores a cue #6198 dropped, and that's a regression with a named root cause. It does not cover item 2: the live-grade palette on the tab dot is new, as your own correction says. Three distinct palette decisions need the ruling, not one: the dot recolour, the chip's filled tint, and the glow now following the dot (amber discovery pulse). What a fix looks like: either relabel #6790 as [RFC] and wait for @ten9876, or split item 2 (RadioTabBar.cpp:314-316, the showQuality gate at RadioTabBar.cpp:874-878, and the TitleBar.cpp:1669-1671 glow change) into a follow-up PR and merge the chip + words now, which stand on the regression exemption alone.

4. Nits (non-blocking)

  • src/gui/MainWindowHelpers.cpp:153-158 / src/gui/RadioTabBar.cpp:314-316 — I measured the contrast you left unmeasured, and the light theme is the problem. Compositing color.titlebar.tab.active.background (#1a0088b0) over color.titlebar.background (#ebf5f5f8) gives an effective #ddebf2; dark resolves to #0c2636. Ratios for the dot:

    Grade light #ddebf2 dark #0c2636
    Excellent/Very Good #00cc66 1.75:1 7.30:1
    Good #00b4d8 2.02:1 6.33:1
    Fair #cc9900 2.12:1 6.03:1
    Poor #cc3333 4.22:1 3.04:1
    replaced color.titlebar.status.connected 4.10:1 (#1a8040) 8.48:1 (#4dd87a)

    Dark is fine everywhere. In the light theme three of four grades land below docs/a11y.md:144-146's 3:1 for non-text, and the token they displace passes at 4.10:1 — precisely because the token is theme-switchable and these literals are not. I agree with your nit-4 answer that retokenising networkQualityColor() would drag the status bar in and is out of scope; docs/a11y.md:155 explicitly allows that ("concrete hex is a valid intermediate state — file a follow-up issue to add the token"), so the ask is just the follow-up issue, with these numbers in it. The spelled-out grade in the tooltip already covers WCAG 1.4.1; this is 1.4.11.

  • docs/automation-bridge.md:3243-3249 vs src/gui/RadioTabBar.cpp:1359 — nit 6 isn't fixed; the doc now states something the code doesn't do. The doc says radios.adaptiveThrottle means "the chip is showing", but state() publishes the ungated flag:

            {QStringLiteral("adaptiveThrottle"), m_throttleEnabled},

    m_throttleEnabled is the setting (OR'd with an in-force cap), with no session gate, while the chip additionally requires ours && session at RadioTabBar.cpp:874-884. Your own first bridge proof records the divergence: "Disconnect: … the tab showed no chip, while adaptiveThrottle stayed true (the setting itself)." That's the common state — box ticked, nothing connected: field true, every tabs[].throttleChip false. Cheapest fix is the doc, since tabs[].throttleChip already carries the per-tab truth: reword to "the throttle is armed for this client (ticked, or a cap still in force after unticking); tabs[].throttleChip says whether a tab is actually showing the chip."

  • src/gui/MainWindow.cpp:7174-7175 — the disconnect path clears the cap locally but never pushes it to the bar.

            m_adaptiveThrottleActive = false;
            m_adaptiveFpsCap = 0;  // clear cap alongside throttle flag — see #2829 review

    RadioModel::stopNetworkMonitor() emits only networkQualityChanged (src/models/RadioModel.cpp:8740); the compensating adaptiveThrottleChanged(false, 0) lives in startNetworkMonitor() (src/models/RadioModel.cpp:8639), i.e. the next connect. So between disconnect and next connect RadioTabBar::m_throttleFpsCap/m_throttleCapColor keep the dead cap and radios.adaptiveFpsCap publishes it. Reasoned from code, not reproduced: the chip itself stays correctly hidden by the session gate, so this is bridge state only. Drop-in:

            m_adaptiveThrottleActive = false;
            m_adaptiveFpsCap = 0;  // clear cap alongside throttle flag — see #2829 review
            refreshAdaptiveThrottleChip();
  • src/gui/TitleBar.h:249 — comment invalidated by this PR's own change.

        QString      m_throttleFlashColor; // empty = default green; set while adaptive throttle is active

    After TitleBar.cpp:1669-1671, empty means "glow in the dot's own colour", not green. Suggest: // empty = glow in the dot's own colour; set while adaptive throttle is active.

  • src/gui/MainWindowHelpers.cpp:153 — adaptiveFpsCapColor(0) returns Poor red. Unreachable today (both call sites guard cap > 0, same shape as the lambda it replaced), but it's now an exported helper in a header rather than a lambda two lines from its only caller, so the precondition is worth stating in the MainWindowHelpers.h:66-68 comment.

5. What I tried to break (no finding)

  • Chip overflowing a narrow tab. nameW floors at 0.0 (RadioTabBar.cpp:467), so I went looking for a squeeze that would push the chip past kTabPadX. There isn't one: RadioTabBar.cpp:919 pins m_tabHost to m_tabsLayout->sizeHint().width() and the strip scrolls instead of shrinking, and sizeHint() already budgets chipSize().width() + kChipGap (RadioTabBar.cpp:344-347). The floor is unreachable and the chip can't overlap the name or the tab edge. Your 195 px grab agrees.
  • Per-tick churn on the a11y surface. applyLinkVisuals() runs on every 80 ms pulse tick, and it now calls setLinkQuality/setThrottleChip on every tab. Both no-change-guard before refreshAccessibility() (RadioTabBar.cpp:290-316), and chipText is built only when a tab can show it, so the steady state is zero tooltip/accessible-name writes and zero repaints. docs/a11y.md's throttled-update rule is satisfied.
  • A black glow from the currentBeatColor() change. Returning an invalid QColor could have painted an invalid gradient; RadioTabBar.cpp:429 falls back to dot (m_beatColor.isValid() ? m_beatColor : dot), which is the whole point of the change. The amber discovery pulse follows from the same line and is disclosed.
  • A stale grade surviving a disconnect or following the next radio. stopNetworkMonitor() emits networkQualityChanged(networkQuality(), 0) with m_netState already Off (src/models/RadioModel.cpp:8718-8740), which maps to an invalid QColor at MainWindow.cpp:2151-2153; dotColor() additionally requires RadioTabStatus::Connected, and applyLinkVisuals() requires a non-empty m_activeId. Three independent gates — I couldn't get a grade onto a tab that isn't the live session's.
  • Construction order hiding the initial push. refreshAdaptiveThrottleChip() at MainWindow.cpp:2210 is guarded by if (!m_titleBar) return;, which would silently no-op if it ran first. It doesn't: buildUI() runs at MainWindow.cpp:1422 and creates m_titleBar (:5469) and m_connPanel (:5527), both before the ctor's connect block. So a ticked box shows the chip from launch, and the m_connPanel connect at :2208 isn't dereferencing a null.
  • Unticking mid-cap. applyAdaptiveFrameRate() returns early when the setting is off (src/models/RadioModel.cpp:8991-8992), so no adaptiveThrottleChanged(false, 0) ever arrives and m_adaptiveFpsCap legitimately stays > 0. The corrected comment at MainWindow.cpp:731-733 now matches the code; the earlier "next quality update" wording did not.
  • The "one shared mapping" claim. NetworkDiagnosticsDialog connects adaptiveThrottleChanged (:2363) and was the obvious place for a second cap→colour table. grep finds only chart-series colours there (:3455, :3473, :3501, :3612) — no sibling tier mapping left behind, so extracting the lambda really did unify every consumer.
  • The pixel probe. The usual "exact-RGB probes are font-dependent" objection doesn't apply here: the dot is an opaque filled 7 px ellipse at a fixed kTabPadX, the glow and the active-tab tint both paint under it, and the probe samples the centre. The three-state sequence (plain → quality → plain) plus your mutation counts (4 and 2) is real evidence, and it matches the gates I read at RadioTabBar.cpp:874-884.
  • CI, honestly. At af06e03b, build, check-windows and check-macos were still in_progress; Static checks and Sanitizer option configures passed. I confirmed your CI-gap disclosure independently: unified_title_bar_test appears in no ctest -R list in any workflow, so green proves compilation only. Your local run and the bridge proofs are the only evidence these 19 checks pass, and I can't re-run them — everything above is reasoned from the source, not observed at runtime.

6. Recommendation

Needs maintainer decision. The engineering is in good shape: the session gate, the no-change guards, the sizeHint budget and the glow fallback all survived the attacks above, the extracted helper leaves no sibling mapping behind, and the nits are a doc sentence, a stale comment, one missing refresh call and a follow-up issue. What's unresolved is the ruling GOVERNANCE.md requires before the dot recolour, chip tint and glow change can merge — and that's @ten9876's call, not mine. Concrete next step: relabel #6790 as [RFC] with the rfc label and the four RFC headings, including the light-theme contrast numbers above; or, if you'd rather land something now, split item 2 out and merge the chip and the spelled-out words, which the regression exemption covers on their own.


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

@aethersdr-agent

Copy link
Copy Markdown
Contributor

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

  • [MEDIUM] CS-VLN-SSRF-HEX — Vulnerability: CS-VLN-SSRF-HEX in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6787/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-6787/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-6787/docs/user/src/components/LogAnalyzer/rules.json:1071
  • [HIGH] CS-PII-DL-1 — PII detected: drivers_license in docs/user/src/components/LogAnalyzer/rules.json /tmp/aetherclaude/pr-6787/docs/user/src/components/LogAnalyzer/rules.json:88
  • [LOW] CS-PII-IP — PII detected: ip_address in packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml /tmp/aetherclaude/pr-6787/packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml:83
  • [LOW] CS-PII-IP — PII detected: ip_address in packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml /tmp/aetherclaude/pr-6787/packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml:92
  • [HIGH] CS-VLN-SSRF-PRIV-10 — Vulnerability: CS-VLN-SSRF-PRIV-10 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:797
  • [HIGH] CS-VLN-SSRF-PRIV-10 — Vulnerability: CS-VLN-SSRF-PRIV-10 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2557
  • [HIGH] CS-VLN-SSRF-PRIV-172 — Vulnerability: CS-VLN-SSRF-PRIV-172 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2556
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:175
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:176
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2554
  • [HIGH] CS-VLN-SSRF-PRIV-192 — Vulnerability: CS-VLN-SSRF-PRIV-192 in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2555
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:1193
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:1304
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2356
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2384
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2758
  • [MEDIUM] CS-VLN-XSS-OBJECT — Vulnerability: CS-VLN-XSS-OBJECT in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:3509
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:175
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:176
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:797
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2039
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2554
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2555
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2556
  • [LOW] CS-PII-IP — PII detected: ip_address in src/gui/ConnectionPanel.cpp /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.cpp:2557
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/ConnectionPanel.h /tmp/aetherclaude/pr-6787/src/gui/ConnectionPanel.h:192
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9805
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9806
  • [MEDIUM] CG-PATH-001 — Potential path traversal in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:9807
  • [HIGH] CS-VLN-PATH-PROC — Vulnerability: CS-VLN-PATH-PROC in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:6247
  • [HIGH] CS-VLN-PATH-PROC — Vulnerability: CS-VLN-PATH-PROC in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:6326
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:520
  • [CRITICAL] CS-VLN-CMDI-AMP — Vulnerability: CS-VLN-CMDI-AMP in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:3603
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:518
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1240
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1723
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1811
  • [CRITICAL] CS-VLN-CMDI-BACKTICK — Vulnerability: CS-VLN-CMDI-BACKTICK in src/gui/MainWindow.cpp /tmp/aetherclaude/pr-6787/src/gui/MainWindow.cpp:1888

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


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

…t, and correct three comments and docs. Principle VIII.

From the PR review:
- MainWindow: the disconnect path cleared m_adaptiveFpsCap but never
  pushed it to the bar, so radios.adaptiveFpsCap kept the dead cap until
  the next connect. Call refreshAdaptiveThrottleChip() there.
- automation-bridge.md: radios.adaptiveThrottle is the armed flag, true
  with nothing connected; tabs[].throttleChip is the per-tab truth.
- TitleBar.h: an empty flash colour now glows in the dot's own colour,
  not green.
- MainWindowHelpers.h: adaptiveFpsCapColor() expects a cap in force; 0
  maps to Poor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chibondking

Copy link
Copy Markdown
Collaborator Author

Thanks for the re-review.

Blocker (RFC): #6790 is now an RFC: retitled [RFC] …, labelled rfc, and rewritten under the four GOVERNANCE.md headings. It sets out the three palette decisions as (a), (b) and (c), includes your light-theme contrast table, and proposes the tokenisation follow-up. This PR waits on @ten9876's ruling there. If (a) is declined, I'll take out the dot recolour and the glow change and keep the chip and the words.

Nits, in 11c57b80:

  • radios.adaptiveThrottle doc: reworded as you suggested. It is the armed flag, true with nothing connected, and tabs[].throttleChip says whether a tab is actually showing the chip.
  • Disconnect: refreshAdaptiveThrottleChip() is now called right after the cap is cleared, so radios.adaptiveFpsCap drops to 0 on disconnect. This is reasoned from the code, as you noted; I didn't add a test for it.
  • TitleBar.h:249: comment fixed ("empty = glow in the dot's own colour").
  • MainWindowHelpers.h: the precondition is stated: callers pass a cap in force, and 0 maps to Poor.
  • Contrast follow-up issue: held until the RFC is ruled on, since it only applies if (a) is approved. The numbers are in the RFC.

Local test run: unified_title_bar_test passes every check except one: "four radios fit whole in an 1800 px bar". That check comes from main, runs before any chip checks, and fails the same way here when built from main's versions of every file this PR changes. So it's an environment issue on this machine, not this PR. I'll file it separately if it reproduces elsewhere.

@nigelfenton nigelfenton 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 at 11c57b80. The code is sound. The visual design is @ten9876's to rule on in RFC #6790, so this is a COMMENT, not an approval. I've put the contrast numbers on the RFC, where the ruling happens. One suggestion here: three checks that pin the "link state speaks first" ordering, which nothing currently tests.

Issue fit. The PR implements RFC #6790 items 1–3 as written. That covers the chip (outlined when armed, filled when capped), the dot taking the quality colour only beside the chip, and the words in the tooltip and accessible name. It also includes palette decisions (a), (b) and (c). The stale-chip defect from the triage is fixed in 11c57b80.

File / group What it changes Claimed? Verdict
RadioTabBar.cpp/.h Chip painting and size, quality branch in dotColor(), words in descriptionLine(), session gate, bridge keys Yes In scope; the visual surface is on RFC #6790
MainWindow.cpp/.h, MainWindowHelpers.* refreshAdaptiveThrottleChip(), quality push, adaptiveFpsCapColor() replaces the inline lambda Yes In scope
ConnectionPanel.* adaptiveThrottleEnabledChanged signal Yes In scope
TitleBar.cpp/.h currentBeatColor() returns invalid when unthrottled Yes (disclosed) In scope; part of ruling (c)
tests/unified_title_bar_test.cpp Dot pixel, session gate, chip, bridge checks Yes In scope
docs/* Window chrome, bridge, menu reference, low-bandwidth Yes In scope

Everything in the diff is explained by #6790. No settings keys and no CHANGELOG entry. The new titlebar.radios bridge keys are documented in automation-bridge.md.

What I ran. unified_title_bar_test isn't in ci.yml's per-PR list, so your local run was the only evidence it passes:

  • Built the merge base (1076c60e), your head, and your head merged with current main (a904cc79, merges clean) on Linux/GCC and macOS/Apple Silicon. The head was also built on Windows/MSVC. All Qt 6.12, app target included for head and merged.
  • Linux and macOS: unified_title_bar_test: all checks passed on all three trees.
  • Windows: every check passes except "four radios fit whole in an 1800 px bar", which fails on the merge base too. That's a second Windows machine reproducing what you saw, while Linux and macOS pass it, so it is Windows-specific and pre-existing, not this PR. It does look worth the separate issue you mentioned.

Suggestion: pin the ordering in dotColor() and descriptionLine(). The PR relies on "discovery amber and link-lost red still take priority", and the comment in dotColor() says so. No check covers it with AT on. I made both mutations on Windows, and all of your new checks still passed under each:

  • quality branch moved above the override branch in dotColor();
  • && !m_alarm dropped from descriptionLine(), so a lost link keeps saying "Network Fair".

These three checks, after "with AT the dot takes the quality colour", catch both. Each fails only under its own mutation, and all pass on your head:

                // Link state still speaks first (dotColor()): an override such
                // as the amber discovery pulse wins over the quality colour,
                // and a lost link stops announcing the old grade.
                tabs->setLinkIndicator(QColor(QStringLiteral("#e0a020")), /*alarm=*/false);
                check(dotPixel(sessionTab) == QColor(QStringLiteral("#e0a020")).rgb(),
                      "a link override still speaks over the quality colour");
                tabs->setLinkIndicator(QColor(QStringLiteral("#cc3333")), /*alarm=*/true);
                check(!sessionTab->toolTip().contains(QLatin1String("Network Fair")),
                      "a lost link does not keep announcing the old quality");
                tabs->setLinkIndicator(QColor(), /*alarm=*/false);
                check(dotPixel(sessionTab) == fair, "the quality colour returns once the link state clears");

Nit: MainWindow.h:2076 declares refreshAdaptiveThrottleChip() in the middle of the data members. It would sit better with the other private methods.

What I tried to break that held:

  • The stale chip from the triage. refreshAdaptiveThrottleChip() now runs right after m_adaptiveFpsCap = 0 on disconnect, so an untick-with-cap followed by a reconnect no longer repaints a dead 8 fps chip. That path is in MainWindow, so I verified it by reading, not by test.
  • The glow change with AT off. currentBeatColor() now hands back no colour, so the glow takes color.titlebar.status.connected instead of color.accent.success. Both bundled themes resolve those to the same value (#1a8040 light, #4dd87a dark), so with AT off nothing visibly changes. A user theme that sets them differently would see its glow change. That's worth a line under ruling (c), not a defect.
  • Excellent never reaches a filled chip. adaptiveFpsCapColor() maps the caps to Poor, Fair or Good only. That matters for the contrast numbers on the RFC.
  • I did not drive the GUI. The demo backend never grades the link below Excellent, so the throttle can't engage there. Your two bridge sessions on the 6600 are the live evidence.

73, Nigel G0JKN/W3

… pin that link state speaks before the quality dot. Principle VIII.

The capped chip drew "AT" in the cap's colour over a 22% fill of the same
colour, 1.70-4.34:1 in both bundled themes against the 4.5:1 that text
needs (Nigel G0JKN's numbers on RFC aethersdr#6790). The outline and fill keep the
cap colour, so the tier still shows; the letters now use
color.text.primary (7.3-10.2:1).

Adds Nigel's three checks to unified_title_bar_test: a link override wins
over the quality colour, a lost link stops announcing the old grade, and
the quality colour returns once the link state clears. Moves the
refreshAdaptiveThrottleChip() declaration in with the private methods.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chibondking

Copy link
Copy Markdown
Collaborator Author

Thanks, @nigelfenton. Both suggestions are in 803ade43.

Changes

  • Chip letters. A capped chip now draws "AT" in color.text.primary. The outline and the 22 % fill keep the cap's colour, so the tier still shows. The armed chip is unchanged.
  • Ordering checks. Your three checks are in unified_title_bar_test, after "with AT the dot takes the quality colour".
  • Nit. refreshAdaptiveThrottleChip() is now declared with the private methods.

Live proof via the automation bridge

Build: fork Windows Installer run 41199940878 on 803ade43 (portable zip).
Radio: FLEX-6600 "NW8S-Barn", firmware 4.2.20, LAN, Windows 10. Receive only.

State was read from get titlebar (radios), the tooltip with tooltip, and the tab with grab_widget. Contrast is computed from pixels sampled in the captures.

Step adaptiveFpsCap linkQuality Chip Tooltip
Ticked, no cap yet 0 Poor outlined, grey letters —
Reconnected, cap engaged 4, then 8 Poor, then Fair filled, primary-text letters … · Network Fair · Adaptive throttle: 8 fps cap
Disconnected 0 (cleared) none (throttleChip: false) —

The cap goes on at the next grade change, so it engaged after a reconnect. On this LAN the link moved between Poor and Fair by itself, so the 4 fps / Poor cap is now covered live as well.

Capped chip (Fair, 8 fps) in each theme:

Theme Letters Fill under them ≈ contrast
Default Dark near-white #373a23 8:1
Default Light #1a2a3a #d9d9bc 10:1
A user theme with amber color.text.primary (#e79a00) amber #373a23 5:1

Both bundled themes fall in your predicted 7.3–10.2:1. The third row is my own theme. It still passes 4.5:1, but amber letters on an amber chip show what happens when the letters follow the theme's text colour.

Not driven live: the link-override and lost-link ordering. This LAN never produced a discovery pulse or a lost link during the run. Your three checks cover that order. unified_title_bar_test isn't in ci.yml, so I haven't seen them run at 803ade43.

The dot recolour and palette decisions (a)–(c) still wait on @ten9876's ruling in #6790.

73, CJ (WT2P)


👨🏼‍💻 Co-authored by Claude Opus 5.5

Resolves the overlap with aethersdr#6793 (merged): MainWindow keeps both
restorePreCapPanRates() and refreshAdaptiveThrottleChip(), the throttle
handler keeps aethersdr#6793's episode sets and restore and calls the chip refresh,
and it uses adaptiveFpsCapColor() in place of the removed fpsCapColor
lambda. low-bandwidth-connections.md keeps the AT chip bullet and aethersdr#6793's
restore bullets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rfoust rfoust self-assigned this Nov 3, 2026
@ten9876

ten9876 commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

The design is approved in #6790 (ruling): (a), (b) and (c), plus the chip and the tooltip text. One condition before merge: networkQualityColor() reads theme tokens, with today's hex kept in dark and passing (≥ 3:1) values in light, instead of landing the failing light-theme hex with a follow-up. Details and measured candidate values are in the ruling.

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

Implements RFC #6790, including the written maintainer ruling. The earlier design-authority blocker is settled. The required shared tokenization is now in e6cc5e74457de3bd6968fba439b69aefd8c31d6d; the dark palette is unchanged and the approved light values are used by the status label, tab dot and cap tint.

Scope

File/group Change In final PR body? Verdict
src/gui/RadioTabBar.{cpp,h} Session-only quality/chip, words, bridge fields, actual-width refresh Yes In scope
src/gui/ConnectionPanel.{cpp,h} Signal after saving the existing throttle checkbox Yes In scope; no new settings key
src/gui/MainWindow.{cpp,h}, MainWindowHelpers.{cpp,h}, MainWindow_Session.cpp Shared quality mapping and immediate chip/theme refresh; clear on disconnect Yes In scope
src/gui/TitleBar.{cpp,h} Uncapped heartbeat glow follows the dot Yes Approved RFC item (c)
Both bundled theme JSON files; src/core/ThemeSeedGenerated.cpp Five quality tokens, generated fallback seed Yes Required by the ruling
tests/unified_title_bar_test.cpp, theme_manager_test.cpp Widget/state/pixel/geometry and contrast regressions Yes Socket-free, in scope
Five changed docs pages/references User behavior, architecture, tokens and bridge fields Yes In scope

No unrelated changes, CI edits, CHANGELOG entry, throttle-policy/default change, new radio command, or new GUI-to-engine include. The new bridge fields are documented read-only observations of this UI.

Findings disposition

No outstanding blockers or nits. Fixes in e6cc5e74457de3bd6968fba439b69aefd8c31d6d:

  1. P2, tab geometry: src/gui/RadioTabBar.cpp:902 refreshes the fixed-width scroll host when chip/status changes alter its preferred width; :1084 sizes after the link visuals update. The unmodified full app kept a 224 px tab while requesting 226 px, eliding its name. The fixed app gives it 226 px; the strip's actual widths plus spacing match its 423 px content width. This also fixes the “Link lost” status path. Removing the geometry fix makes 11 assertions fail; restoring it passes.
  2. RFC condition / light contrast: src/gui/MainWindowHelpers.cpp:135 resolves one color.networkQuality.* mapping. Dark remains exactly #00cc66/#00b4d8/#cc9900/#cc3333; Light uses #1a8040/#0088b0/#a85a00/#c02020; Off/unknown retains #8aa8c0. MainWindow_Session.cpp:120 refreshes label, dot, chip and cap tint on a theme change. The contrast regression at tests/theme_manager_test.cpp:1786 passes both themes and fails if the old light Excellent hex returns. The PR body records Fair status text at 4.68:1, Good at 3.75:1, and the unchanged neutral Off at 2.29:1 against the sampled #f5f5f8 status background, within the maintainer's explicit ruling.
  3. Documentation accuracy: corrected the old-lamp and accessible-description comments, documented the shared tokens and actual tab resizing, and kept the new MainWindow work in its Session translation unit.

Nigel's chip-letter and override/alarm-priority requests were already implemented in 803ade43; I retained and executed those checks. The disconnect cap reset from 11c57b80 is retained. The old bot governance objection is retired by the written RFC ruling. The advisory CodeGuard entries are lexical candidates, not demonstrated source-to-sink vulnerabilities; the cited literal/documentation patterns do not establish an exploit in this diff. Antares' suggested NetworkDiagnostics.{cpp,h} files are unchanged by this PR. No additional security defect was validated from those reports.

There are no inline review threads to resolve and no CHANGES_REQUESTED reviews to dismiss.

Verification and limits

  • Reviewed head: e6cc5e74457de3bd6968fba439b69aefd8c31d6d.
  • Fresh-main local integration: base 57efaf8836a9c5d0ea140eebe09386893e041656, tree 3a6dd4bf49b416548cde78fff1292fea0b9a2eb8. GitHub merge ref 58e1f52b69da87e401ed86b76bf7e40aa9cdfea7 has that same base/head and exact tree. No merge-from-main commit was pushed.
  • ARM64 RelWithDebInfo app built with the required toolchain and RADE enabled. Host/system/executable are ARM64; no RNNoise x86 sources. Socket-free unified_title_bar_test and theme_manager_test pass on both the final head and integration result, including after both mutation restorations.
  • Architecture/manifest/capability/command ratchets pass without baseline growth; generated theme seed and docs references pass; 767 log-rule checks pass. Docusaurus production build passes. Pre-existing log-source line hints concern unchanged files and were not bundled here.
  • Full-app integration instance PID 20810 used offscreen UI, isolated settings, explicit socket and AETHER_AUTOMATION_NO_TX=1; whoami reported txAllowed:false. Connected only to DEMO-0001. Verified armed chip, full tab width, dark-to-light live color refresh, tooltip words, disconnect/reconnect and session-only state. Head instance PID 10071 additionally proved throttle/theme persistence across process restart and simulator-disconnect recovery. Every owned instance closed normally.
  • All seven PR commits are GitHub-verified signatures. Required build, check-windows, check-macos and Static checks are green on this head; Docs and sanitizer configuration checks also pass. CI run 41564215543 checkout logs confirm merge 58e1f52b69da87e401ed86b76bf7e40aa9cdfea7, matching the locally tested integration tree. Current main is still the tested base. The independent post-squash main run is checked after landing.

The demo never degrades below Excellent or engages a cap. Final live cap convergence/RF behavior is therefore unverified; cap state, paint, words and contrast are covered by socket-free tests. unified_title_bar_test is compiled but not executed by the per-PR CTest filter, so its local pass is explicit evidence. A separate code-review tool was unavailable; the second adversarial pass was manual.

What I tried to break

  • AT on/off/on, disconnect/reconnect, no-session and other-radio gates, active-tab overflow, short names dominated by alarm text, and actual widget width rather than only sizeHint().
  • Discovery/alarm overrides against a quality-colored dot, suppression of stale quality words during link loss, armed versus capped paint, and the retained cap when its checkbox is unticked.
  • Both bundled themes' dot/border and chip-letter contrast, live theme refresh, settings across a process boundary, and simulator fault recovery. Both intentional mutations failed as expected and restored builds passed.

Approving the pinned head with the recorded demo/hardware limits.

@rfoust
rfoust merged commit 89f7357 into aethersdr:main Nov 3, 2026
11 checks passed
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.

[RFC] Radio tab: AT chip and quality-coloured status dot while adaptive frame-rate throttle is on

4 participants