Skip to content

Radio connection workspace with Locations, operator profiles and SmartLink accounts - #6885

Open
jensenpat wants to merge 2 commits into
aethersdr:mainfrom
jensenpat:aether/station-workspace-connect
Open

jensenpat wants to merge 2 commits into
aethersdr:mainfrom
jensenpat:aether/station-workspace-connect

Conversation

@jensenpat

@jensenpat jensenpat commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #6561 #6223 and #6539.

Connection workflow

Choose a Location, select a saved or discovered radio, and press Connect. Locations organize radio connections; the window is titled Connect to a radio, and its blue list heading identifies the selected Location, such as Radios at Home.

  • Start with Home, POTA, Club and RV. Create custom Locations such as Cabin. The selected Location is bold and the saved order can be changed by dragging or using Move.
  • Use Edit, Move, Rename and Remove on Locations and saved radio entries. Remove asks for confirmation. Moving a radio carries its saved connection paths to the chosen Location.
  • Show saved radio names prominently, with model or address and availability on the second line. Group access paths that share the same saved family and serial.
  • Use Nearby radios for discovery and + Add radio by IP for manual setup. Existing family-specific setup controls remain available. Put Connection name first and Save connection beside Connect by IP.
  • Select an operator through Operating as or Profiles…. Create, edit, duplicate and remove profiles containing microphone, audio-output and pan-arrangement choices. The initial profile is Radio operator. Create and use profile saves and selects the new profile.
  • Save multiple named SmartLink accounts with separate credential references and session credentials. A saved remote connection selects its owning account. Switching accounts clears the previous listing and fences callbacks from the previous authentication attempt. A dependent WAN session locks account switching and removal.
  • Save Icom credentials by connection identity, and restore each saved connection's source path, Icom port selection, CI-V choice and low-bandwidth choice.
  • Support Return and keypad Enter in profile entry dialogs. Expanding Startup and connection preferences exposes all its checkboxes.

Persistence and integration

  • Store Locations, connections, operator preferences, account metadata and selected IDs in the versioned ConnectionWorkspace feature document through AppSettings. The internal stations collection name is retained for saved-document compatibility.
  • Migrate existing routed paths, address history, last-radio identity, SmartLink metadata/token references and client audio/layout preferences. Retain the legacy settings snapshot and the existing startup preference.
  • Keep credential values in the existing credential store or session vault. Reserve scoped credential keys at the settings boundary and keep credential values out of workspace documents and settings exports.
  • Apply operator preferences when connecting. Browsing Locations or operator profiles preserves the active session and its audio choices. An unavailable saved audio device is shown as a choice needing replacement.
  • Build the connection surface and entry dialogs with CanonWindow and existing Canon theme tokens. Update connection documentation and its screenshot catalog.
  • Add connect profiles for redacted workspace inspection and connect profile stations|operators <id> for selection. Creation and editing use the normal widgets through the existing invoke bridge command.

Tests and exercised flows

Test or exercise Covered behavior
connection_workspace_test Migration and schema guards; credential-field rejection; mixed-family Location memberships; operator and account metadata; account reset/locking; profile forms and Enter; named radio grouping; Move/Remove; saved order; Icom port restoration; preference sizing; empty-email account rename.
connection_panel_source_pick_test A chosen IPv6 source survives address editing and family changes, using fixed interface snapshots; an explicit Auto choice remains selected.
network_path_resolver_test Address-family selection and saved-interface/address matching, including IPv6 GUA/ULA choices.
icom_credentials_singleflight_test Credential read coordination and connection-scoped credential isolation.
connection_panel_size_test, startup_autoconnect_lockout_test, app_settings_safety_* Connection-window geometry, startup lockout behavior and settings persistence/safety cases.
Automation bridge and native keyboard exercises Simulator connect/disconnect; Location browsing during a session; saved paths; Location/operator/account creation; connection and account rename; Move and confirmed/cancelled Remove; saved Icom port restoration; preference expansion; Return and keypad Enter.
Documentation and static checks User-guide build; screenshot embeds; bridge/touchpoint generation; test registration; settings-use, engine-boundary and command-plane checks.

Recorded results: 35 focused CTest cases passed. The app build, user-guide build and listed static checks completed successfully.

Screenshots

Home:

Home

POTA:

POTA

Cabin:

Cabin

Operator selection:

Operator selection

Operator creation:

Operator creation

jensenpat added a commit to jensenpat/AetherSDR that referenced this pull request Oct 31, 2026
Preserve the selected-radio hierarchy from aethersdr#6885 while retaining active-path disabling and confirmed single-session switching.
@jensenpat

Copy link
Copy Markdown
Collaborator Author

Heads up to reviewers, I have approval from @ten9876 for use of a new gradient theme color. Noted in the event that color audit fails.

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

Review of #6885, reviewed together with the stacked #6889

What I ran: this head (136dba0b1), plus #6889 (d878d7e3c) merged with current main (155850f50). Built on Linux with Qt 6.12.0, the same Qt CI uses.

  • Focused tests: 37 CTest registrations.
  • A bridge session against the built-in demo radio (DEMO-0001): offscreen, isolated settings store, TX disabled. No hardware was involved.
  • Findings that come only from #6889's delta are in my review on #6889.

Issue fit. #6561 is the RFC, approved by @ten9876 on 2026-10-18. #6223 and #6539 are the multi-account SmartLink requests.

  • The workspace model and its versioning, one-shot migration, credential isolation and multi-account SmartLink with an auth-generation fence all address those asks. Most of it held up under attack (see the end).
  • Two things don't hold yet: the Return/Enter claim, and the operator-profile behavior on connect. Both are below.

CI. Green, but the runs were created at 06:14Z, before main moved (tip 14:09Z), and the PR is now CONFLICTING.

  • The only conflict is the generated docs/architecture/aetherd-touchpoints.md. Regenerating it with tools/gen_touchpoint_manifest.py resolves it.
  • Neither connection_workspace_test nor connection_panel_size_test is in ci.yml's -R filter, so green never ran them.

Scope

File / group Claimed in body? Verdict
models/ConnectionWorkspace.{h,cpp} and the ConnectionPanel workspace UI Yes In scope
SmartLinkClient multi-account and auth fence Yes (#6223, #6539) In scope
IcomCredentials per-connection scoping, SettingsCredentialPolicy.h, AppSettings.cpp Yes In scope
AutomationServer / IConnectionAutomation: connect profiles, connect profile … Yes New public bridge surface. Maintainer accepts it.
docs/user/**, screenshots, screens.json, sidebars.js Yes In scope
aetherd-touchpoint-tags.json: new models/ConnectionWorkspace.h tagged universal No Nit 4
connection_panel_source_pick_test rewrite: new m_manualSourceCandidates seam, SKIP_RETURN_CODE 77 dropped No A good change, but please mention it in the body
docs/BUILDING.md +5, CMakeLists.txt +1 No Please explain these in the body

Blockers

1. Return / keypad Enter does nothing in the Move and Copy dialogs on Linux, and this PR's own test fails 3/3 there.

  • connection_workspace_test fails deterministically on this head, unmerged, with 3 failures in each of 3 runs:
    [FAIL] Move carries all paths to the destination location
    [FAIL] confirmed Remove deletes this location's paths only
    [FAIL] keypad Enter copies the connection to the chosen location
    
  • Cause: the focused widget in the Move dialog (src/gui/ConnectionPanel.cpp:4863) and the Copy dialog (:4391) is a non-editable QComboBox. On Qt 6.12 on Linux, Return and Enter on that combo open its popup; they do not reach the dialog's default button.
    • I confirmed it with a 20-line standalone Qt 6.12 probe: a QDialog holding a combo and a default Ok, then QTest::keyClick(combo, Key_Return) gives accepted=0 popupVisible=1.
    • Instrumenting the test shows connectionMoveRadio is still visible after the keypress.
    • The "Remove" failure is a knock-on effect: the Move never happened.
  • So "Support Return and keypad Enter in profile entry dialogs" doesn't hold in these two dialogs, and "35 focused CTest cases passed" can't have been a Linux run.
  • Fix: handle Return/Enter on the combo explicitly, for example by accepting from QComboBox::activated or with a small key filter that clicks the default button when the popup is closed.
  • Separately, connection_panel_size_test fails identically on main (horizontal overflow is reachable, not clipped), so that one is pre-existing and not this PR's.

2. Operator profiles override the operator's own audio and layout choices on every connect, and a missing saved device blocks connect. The maintainer ruled that both parts need fixing.

  • The selected profile is captured once, at migration (src/models/ConnectionWorkspace.cpp:157-159). It is re-applied on every connect: applyWorkspaceOperator() at ConnectionPanel.cpp:2177/2214/2770, then MainWindow_Session.cpp:468-488 writes PanadapterLayout and calls applyAudioDeviceSelection.
    • Nothing updates the profile when the operator changes devices or layout in Settings. The next connect silently reverts them.
    • Please make Settings changes update the active profile, or apply a profile only when the operator explicitly picks one.
  • A saved device that is now missing makes applyWorkspaceOperator() refuse the connect (MainWindow_Session.cpp:873). That includes unattended startup auto-connect, which previously fell back to the default device. An unplugged USB headset now leaves a kiosk sitting on a status line.
    • The test pins this as intended ("missing saved microphone blocks connect").
    • Please fall back to the default device with a visible warning instead.

3. If this lands without #6889, a failed SmartLink reconnect leaves the account locked until restart.

  • MainWindow.cpp:833 locks the account on WAN connect.
  • The authFailed reconnect handler (MainWindow_Session.cpp:702-720) closes the reconnect dialog and opens the connection dialog. It never calls setAccountLocked(false) or clears m_pendingWanRadio.
  • Sign-in, account switching and account removal are then all refused, and the Disconnect button is hidden while disconnected.
  • #6889's beginExplicitRadioChoice unlocks it (MainWindow_Session.cpp:333-336 at d878d7e3c), so in the stack the user can recover by clicking a tab. On its own this PR has no way out.
  • Fix: in that handler, add m_smartLink.setAccountLocked(false); m_pendingWanRadio = {}; beside m_wanReconnectTimer.stop();.
  • This was reasoned from the code. I did not reproduce it: the demo has no SmartLink path.

Nits (non-blocking)

  1. The legacy flat keys are still live co-owners. This is a maintainer call; I am not citing it as a canon violation.
    • setConnected still writes IcomCredentials::save(), saveManualProfile and IcomSettings::setLastHost (ConnectionPanel.cpp:1513-1525), and login() still writes SmartLinkEmail.
    • So routes live in both RoutedProfilesJson and the workspace. Two Locations with the same host and different routes overwrite each other's legacy entry.
    • The body calls this "retain the legacy settings snapshot", but it isn't a snapshot. Constitution V asks for one owner. Either freeze the legacy keys or explain why they stay live.
  2. ConnectionWorkspace::load() carries fixups for document shapes that never shipped (ConnectionWorkspace.cpp:196-228): the "Existing preferences" and "Existing setup" renames. They run on every load. A user profile literally named "Existing preferences" gets renamed to "Radio operator". Drop them before merge.
  3. connect profiles is described as redacted, but nothing is redacted.
    • ConnectionPanel.h:139 returns workspaceSnapshot() unchanged: emails, hosts, Icom usernames and device IDs.
    • No secrets leak, because validate rejects credential-shaped keys. Either redact, or change the doc and body wording.
  4. The touchpoint tag for models/ConnectionWorkspace.h is universal.
    • Its content is client UI preference (audio devices, layout, Locations). The precedent is CwDecodeSettings.h → ui-support.
    • Also, SmartLinkClient.cpp, an engine file, now includes models/ConnectionWorkspace.h only to get a key string.
  5. Per-connection Icom keychain entries (icom/<hash>/password) are never deleted. They are shared across Locations by hash, so deleting one needs a reference check. Please at least say so in the Remove confirmation. SmartLink removal does delete its key correctly.
  6. The scoped-key formats are hand-written in three places: SettingsCredentialPolicy.h, ConnectionWorkspace::credentialKey, and IcomCredentials.cpp (twice). Build them from the policy table so they can't drift.
  7. Migration always creates an "Existing account" SmartLink entry, even with no prior SmartLink use (seen on a clean store: {"id":"legacy","name":"Existing account","email":""}). Also, RecentConnectByIpAddresses hosts are all tagged flex.
  8. Weak tests. "switching fences pending asynchronous authentication" only checks that m_authGeneration incremented, so deleting every generation != m_authGeneration guard would still pass. Deliver a stale reply instead. "legacy source is retained" checks contains(), not that the value is unchanged.
  9. Small items.
    • Operator-dialog button labels are not wrapped in tr() (ConnectionPanel.cpp:4944).
    • The friend struct name ConnectionPanelSmartLinkTestAccess is misleading.
    • A 129–254-character email can't sign in, because the name is capped at 128 by validate.
  10. Main moved. Whichever of #6885 / #6889 lands second needs tools/gen_touchpoint_manifest.py re-run.

What I tried to break that held

  • Newer schema, corrupt or unavailable store: load() returns {} and save() refuses, so a newer document is never overwritten.
  • Migration is one-shot: the document's existence is the marker, and a failed save retries next launch.
  • Credentials in the document or exports: hasSecrets rejects them at save. Scoped keys are reserved at the setValue, import and export seam. The test proves setValue(scopedKey) lands in the session vault.
  • The SmartLink fence covers the login and refresh replies and the keychain read. logout, setAccountId and login are refused while locked.
  • Removing the last or the selected Location or operator is refused, and empty or duplicate names are refused. Removing the Location that holds the connected radio leaves the session alone. Dialogs follow the CanonWindow exception and new widgets carry accessible names.
  • Engine-boundary and command-plane gates, run on merge base and head and compared per file: identical except for line shifts. The theme seed check passes. color.brand.gradient is an existing token, not a new one.
  • Bridge, on the demo:
    • A clean store migrates to Home/POTA/Club/RV plus "Radio operator".
    • Connecting the demo saves it to Home: connect profiles shows {"family":"sim","serial":"DEMO-0001","kind":"local"} under Home.
    • A saved TEST-NET manual connection (192.0.2.10) persists.
    • The workspace survives a process restart.

ten9876 added a commit that referenced this pull request Nov 1, 2026
… Remote Access, taskbar and metainfo claims. Principle VIII.

- AetherLab saves a JSON session (no CSV export) and does not inhibit
  radio TX (#6481).
- README and ROADMAP qualify FLEX-6000 Remote Access as not yet run end
  to end from AetherSDR, as the CHANGELOG entry does (#6945).
- The canon workspaces are windows of their own; the taskbar claim is
  dropped, since Memory Channels is an owned window (#6931).
- #6897's entry states that an old non-straddling CW/CWL preset is
  dropped on load; #6950's agent is 63 KB packaged, about 110 KB on the
  radio.
- The metainfo description says seven NR engines and a TCI server,
  matching the README.
- ROADMAP and README carry approved RFC #6561 as in flight (#6885 open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ten9876 added a commit that referenced this pull request Nov 1, 2026
…6961)

## Intent

Prepare v26.11.1 at cutoff `ab47610d3`: the six release files, a
CHANGELOG section mapped from every PR in `v26.10.4..ab47610`, the
README/ROADMAP refresh, and the Stable docs snapshot. Tag the resulting
`main` commit afterwards with `/tag-release`.

## Summary

Six-file release prep for **v26.11.1**, plus the Stable docs snapshot.
Metadata and docs only: no source, test or CI changes.

Cutoff: `origin/main` at `ab47610d3` (#6848, merged 2026-11-01).
Anything that merges after it is folded in before the tag.

**44 merged changes** from **11 human contributors**, AetherClaude (0)
and Dependabot (0). First-time contributors: **@oz457** and **@vu2cpl**.
Both were confirmed by searching for a prior merged PR per login before
the v26.10.4 timestamp, not from `author_association`.

## Changelog

Built from `v26.10.4..ab47610` mapped through the commit-to-PR API
(`repos/…/commits/<sha>/pulls`), not from commit subjects: 44 PRs and 0
direct commits, every one cited in the section. `v26.10.4` is an
ancestor of `main`, so nothing is excluded. The notes lead with Install
update on Windows, macOS and Linux (#6777, #6927/#6930,
#6810/#6891/#6925). Next come Remote Access QR sign-in and FLEX-6000
support (#6932, #6945, #6951), container environments and radio health
tools (#6949, #6950), AetherLab (#6481), eight canon windows, and the
TCI 2.1 changes.

Numbers in the section come from the PR bodies. Bodies that disagree
with themselves were kept out of the section: #6810 says 333 files plus
4 links where #6891 says 333 entries (329 + 4), #6858 says "four gaps"
but lists five, and #6886 gives a 1–8 frame lookback against "at most 9
frames" lost. None of those numbers is quoted.

## Docs refresh, not just version strings

- **README**: the Highlights in-app updates line now says the Updates
window installs on all three platforms. The CGNAT/TCI line adds
FLEX-6000, QR sign-in and TCI protocol 2.1, replacing "TCI v2.0". A new
AetherLab highlight is added. In the Roadmap section, In-app updates
leaves the list and the canon line names this cycle's windows. Tree
checks: six backend directories, seven NR methods. Both unchanged.
- **ROADMAP**:
- **In flight:** In-app updates is removed as shipped. The canon item
gains the v26.11.1 windows, and Hermes-Lite 2 gains the DSB/CW/CWL/FM
receive filter (#6897).
  - **Queued:** nothing shipped from it.
- **Open RFCs:** checked against `label:rfc`. #6799 (FFT FPS sets every
pan), #6790 (radio-tab AT chip) and #6816 (amber TGXL STANDBY) join.
None leaves. Approved RFC #6561, which was in neither list, joins In
flight (above).
- **Recently shipped:** this is the month rollover. The intro names
v26.11.x, the list is trimmed to the cycle, and it holds five new
`(v26.11.1)` entries.

## Judgment calls flagged for the maintainer

- **In-app updates (RFC #5304) counts as shipped.** All six phases have
merged and the RFC is closed, so the item leaves In flight in both
ROADMAP and README and becomes a Recently shipped entry. The CHANGELOG
still says the first real in-place Windows update runs from this release
to the next.
- **The Recently shipped rollover trim.** The 31 v26.10.x entries (8
from v26.10.1, 9 from v26.10.2, 8 from v26.10.3, 6 from v26.10.4) leave
ROADMAP.md. They remain in CHANGELOG.md.
- **Approved RFC #6561 goes in flight.** The radio connection workspace
has been approved since 2026-10-18 and its implementation is open in
#6885, so ROADMAP In flight and the README Roadmap list carry it, with
nothing shipped yet.
- **The checker's zero-bot intro shape is fixed in a separate PR**, not
here, so this prep stays at its six files plus the snapshot.
- **Proceed with main's Full Suite red at the cutoff.** See the heading
below.
- **Opened ready for review.**

## main CI at the cutoff

- **Full Suite on `ab47610d3`: the first attempt failed because the
runner's disk filled, not because a test failed.** The link of
`aetherd_pan_decode_test` failed with `ld: final link failed: No space
left on device`, and `/__w` was at 100% ([run
41351482051](https://github.com/aethersdr/AetherSDR/actions/runs/41351482051)).
Attempt 2 is in progress. The parent `9fb0ece95` finished green.
- **The weekly sanitizer lane was red on its last three runs.** It runs
TSan failures that #6952 fixes and a TSan build that #6948 repairs. Only
the next scheduled run on `main` shows whether those fixes hold, and
this prep does not wait for it.

## Release-pipeline firsts at this tag (for `/tag-release`)

- This is the first tag with the Linux release tarballs (#6891) and the
macOS `.app.tar.zst` tarballs (#6930). The asset set becomes **25**
(#6930's count). Signing and the Update Manifest run with tarballs
present for the first time.
- Not a hotfix: the Store `.msixupload` is expected.

## Scope

| file | change |
|---|---|
| `CMakeLists.txt` | `project(AetherSDR VERSION 26.11.1)` |
| `README.md` | Current version line, plus the prose refresh above |
| `AGENTS.md` | Current version line |
| `CHANGELOG.md` | new `[v26.11.1] — 2026-11-01` section; `[Unreleased]`
stays and stays empty; history below byte-identical |
| `packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml` |
`<release version="26.11.1" date="2026-11-01"/>` first in `<releases>`;
the description says seven NR engines and a TCI server, matching the
README |
| `ROADMAP.md` | cycle heading → post-v26.11.1, plus the prose refresh
above |
| `docs/user/versioned_docs/version-stable/**`,
`docs/user/versioned_sidebars/version-stable-sidebars.json`,
`docs/user/stable-version.json` | docs snapshot
(`tools/docs/snapshot_stable.py 26.11.1`, 103 pages, its own commit). It
adds the new `aetherlab`, `radio-health-tools` and
`waveform-environment` pages. |

## Validation

Output of `check_release_prep.py --mapping mapping.json`: **30 checks, 2
FAIL, 1 WARN**. All three are explained below.

```
release-prep check: v26.11.1  previous v26.10.4  base origin/main  tree /home/jeremy/agent-worktrees/46dbb397/wt-release-v26.11.1
PASS v26.10.4 is an ancestor of origin/main
PASS all six version spots say 26.11.1
     CMakeLists.txt, README.md, AGENTS.md, ROADMAP.md (cycle heading), CHANGELOG.md (newest section), packaging/linux/io.github.aethersdr.aethersdr.metainfo.xml (first <release>)
PASS CHANGELOG heading date equals metainfo release date
     2026-11-01
PASS appstreamcli validate
     ✔ Validation was successful.
PASS metainfo <release> list is date-descending with unique versions
     26 entries, newest ('26.11.1', '2026-11-01')
PASS `## [Unreleased]` stays and stays empty
PASS `## [v26.11.1]` sits directly under `[Unreleased]`
PASS the previous section is `[v26.10.4]`
PASS CHANGELOG diff is exactly the inserted section
     73 lines inserted, history below byte-identical to origin/main
PASS new section opens with a `### <headline>`
     Install update on Windows, macOS and Linux · Remote Access on FLEX-6000 radios with QR sign-in · AetherLab, an experimen
FAIL intro sentence has the house shape
     `N merged changes from M human contributors, AetherClaude and K Dependabot updates within that total.`
PASS new section has a `### Contributors` block
PASS release_contents.py --check (citations, intro and Contributors counts)
     section: [v26.11.1]  PRs in range: 44  cited: 44
     PASS every PR in the range is cited
     INFO citations outside the range (3) — each must be an issue, an RFC or a deliberate prior-PR reference:
       #5304  RFC  closed  RFC: AetherSDR In-App Update Design
       #6226  RFC  closed  [RFC] Adopt the AetherSDR style guide as the visual canon (About window as the first implementation)
       #6471  RFC  closed  [RFC] AetherLab: RigExpert antenna analysis in a station workspace tab
     PASS intro counts: section says 44/11, mapping says 44/11
     PASS Contributors paragraph matches the mapping (11 entries)
     PASS first-time contributors: ['oz457', 'vu2cpl']
PASS code fences balance in README.md
PASS no duplicated table headers or doubled `---` in README.md
PASS code fences balance in ROADMAP.md
PASS no duplicated table headers or doubled `---` in ROADMAP.md
PASS code fences balance in CHANGELOG.md (new section)
PASS no duplicated table headers or doubled `---` in CHANGELOG.md (new section)
PASS every local link in README.md resolves
PASS every local link in ROADMAP.md resolves
PASS no heading removed from README/ROADMAP is still linked elsewhere
PASS Recently shipped `(vX)` markers run newest-first and lead with the new version
     5 entries marked (v26.11.1); versions present: v26.11.1
PASS Recently shipped intro names the current cycle (v26.11.x)
FAIL only the four current-version lines lose the `26.10.4` string outside CHANGELOG
     historical mentions must stay:
     - **In-app updates** ([RFC #5304](#5304)) — v26.10.4 shipped the
       RFC #5304 (v26.10.4).
       unsigned amplifier/tuner meter handles (v26.10.4).
       (v26.10.4).
       recentering, and the G2's filter bank and speaker mute (v26.10.4).
       scrolling for touch screens. RFC #6775 (v26.10.4).
       Qt TLS plugin that disabled SmartLink, update checks and downloads (v26.10.4).
       "label": "26.10.4"
PASS diff touches no src/, tests/, third_party/ or .github/workflows/ path
PASS all six release files are in the diff
WARN files beyond the six (each needs a reason in the PR body's scope table)
     docs/user/stable-version.json
     docs/user/versioned_docs/version-stable/aetherlab.md
     docs/user/versioned_docs/version-stable/automation-bridge-and-mcp.md
     docs/user/versioned_docs/version-stable/callsign-lookup.md
     docs/user/versioned_docs/version-stable/cw-decoder.md
     docs/user/versioned_docs/version-stable/dvk-panel.md
     docs/user/versioned_docs/version-stable/generated/tci-commands.md
     docs/user/versioned_docs/version-stable/hermes-lite-2.md
     docs/user/versioned_docs/version-stable/kat500-tuner-control.md
     docs/user/versioned_docs/version-stable/keyboard-shortcuts.md
     docs/user/versioned_docs/version-stable/low-bandwidth-connections.md
     docs/user/versioned_docs/version-stable/memory-channels.md
     docs/user/versioned_docs/version-stable/menu-reference.md
     docs/user/versioned_docs/version-stable/midi-controller-mapping.md
     docs/user/versioned_docs/version-stable/mqtt-station-automation.md
     docs/user/versioned_docs/version-stable/net-scheduler.md
     docs/user/versioned_docs/version-stable/panadapter-controls.md
     docs/user/versioned_docs/version-stable/radio-health-tools.md
     docs/user/versioned_docs/version-stable/support-and-logging.md
     docs/user/versioned_docs/version-stable/tailscale-remote-access.md
     docs/user/versioned_docs/version-stable/tci-server.md
     docs/user/versioned_docs/version-stable/troubleshooting.md
     docs/user/versioned_docs/version-stable/ulanzi-dial.md
     docs/user/versioned_docs/version-stable/updates.md
     docs/user/versioned_docs/version-stable/waveform-environment.md
     docs/user/versioned_docs/version-stable/windows.md
     docs/user/versioned_docs/version-stable/workspace-canvas.md
     docs/user/versioned_sidebars/version-stable-sidebars.json
PASS git diff --check
INFO maturity wording per family across README / ROADMAP / new CHANGELOG section — read these against each other
     Hermes-Lite 2  README    early, experimental
     Hermes-Lite 2  ROADMAP   experimental, supported
     Hermes-Lite 2  CHANGELOG -
     Icom           README    early, experimental, supported
     Icom           ROADMAP   early, supported, transmit confirmation
     Icom           CHANGELOG -
     ANAN           README    experimental, receive-only, supported
     ANAN           ROADMAP   experimental, receive-only
     ANAN           CHANGELOG -
     RTL-SDR        README    experimental, receive-only, supported
     RTL-SDR        ROADMAP   experimental, receive-only
     RTL-SDR        CHANGELOG -
30 checks: 2 FAIL, 1 WARN
```

- **FAIL "intro sentence has the house shape"**: a false positive. The
check requires the literal `…human contributors, AetherClaude and…`, but
AetherClaude and Dependabot have no commits in this range, so the
sentence says `44 merged changes from 11 human contributors.`.
v26.10.4's intro still named its one Dependabot update; this range has
no bot commits at all, so neither name appears. The counts check
(`release_contents.py --check`) passes: 44/11, 11 Contributors entries,
first-timers match.
- **FAIL "only the four current-version lines lose `26.10.4`"**: the
removed lines are the In-app updates In flight entry and the v26.10.x
Recently shipped entries, both removed by maintainer decision (above).
No version string was replaced. The mentions inside the kept entries are
untouched.
- **WARN extra files**: the docs snapshot, listed in the scope table.
- Docs: `npm ci && npm run build` in `docs/user` succeeded, and `node
tools/docs/test_log_rules.mjs` passed 767 checks for 49 rules.
- AetherLab's entry follows #6481 and its user guide: each acquisition,
cancellation or error *attempts* the analyzer stop and closes USB,
physical RF silence is unverified, radio TX is not inhibited, sessions
save to JSON (there is no CSV export), and the feature is an
experimental proof of concept with hardware sweeps qualified on one
Stick Pro 108 on macOS (README, ROADMAP and the CHANGELOG headline,
intro and entry).
- FLEX-6000 Remote Access is qualified as not yet run end to end from
AetherSDR in the README and ROADMAP, as it is in the CHANGELOG (#6945).
- No configure, build or test run. This is metadata, and CI builds it.

After merge: tag the resulting **main** commit, not this branch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants