fix(model): platform-based capability gating from FlexLib ModelInfo (#2177)#3954
Conversation
…2177) Migrate the ad-hoc model-string sniffing for extended DSP and diversity to the FlexLib-sourced ModelCapabilities table (Constitution Principle I — FlexLib is the model authority), and fix the gaps that sniffing left behind. Root of the reported AU-510 bug (extended DSP filters NRL/NRS/RNN/NRF not appearing) is two-fold: - Classification: the old hasExtendedDspFilters() used substring checks (contains("ML-")/"CL-"/"AU-") that silently missed the "S" server variants (MLS-9601 has no "ML-"; CLS-9301 has no "CL-") and was case-sensitive. Now derived from RadioPlatform (BigBend|DragonFire) via the table, which enumerates all 23 current FlexLib models. - Timing: setHasExtendedDsp() was only pushed once at onSliceAdded, so if the `model` status arrived after the slice (GUIClientID session restore) the flag stayed stale. It is now also refreshed on RadioModel::infoChanged alongside SmartSDR+/diversity. Diversity was the same anti-pattern, triplicated across three call sites and wrong in both directions vs FlexLib IsDiversityAllowed: - FLEX-6500 (single-SCU) was wrongly granted diversity. - ML-/MLS-/CL-/CLS- (dual-SCU) were wrongly denied it. All three sites now use RadioModel::isDiversityAllowed(), table-backed. Also: RT-2122 (DragonFire, SliceList {A,B}) now reports 2 slices instead of falling through to the default 4. ModelCapabilities gains a RadioPlatform enum, a platform field, an isDiversityAllowed flag, and a hasExtendedDsp() helper; the model table is corrected (ML-380/CL-200/RT-100 placeholders -> real ML-9600/CL-9300/RT-2122) and completed (MLS-9601, CLS-9301, AU-510). model_capabilities_test asserts platform + 4m/2m/loop + diversity + extended-DSP for all 23 models, with explicit regressions for the MLS/CLS/AU-510/6500 cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Hi @ten9876 — thanks for taking this on. The AU-510 timing-vs-classification split in the writeup is a genuinely nice piece of root-causing, and migrating the sniffing onto the FlexLib What failedTwo checks are red on
What I checked (and ruled out)I want to be straight about tooling: the CI log API I have surfaces only per-step pass/fail, not raw compiler text, so I can't quote the failing
In short, nothing in the diff jumps out as an obvious compile break. Two most likely causes — please grab the real error line
Concrete next step: open the The change itself looks solid; this is very likely one explicit include or a re-run away from green. Thanks again for the careful work. 🙏 🤖 aethersdr-agent · cost: $4.0641 · model: claude-opus-4-8 |
…atform field
Adding the RadioPlatform `platform` field as the first member of
ModelCapabilities broke xvtr_policy_test's positional brace inits
({false,true} / {true,false} assumed the old {has4Meters, has2Meters, ...}
order), which failed to compile in CI (the local incremental build hadn't
rebuilt this target). Switch to designated initializers ({.has2Meters=true}
/ {.has4Meters=true}) so the call sites are order-independent and resilient
to future capability fields.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Nice work — this is a well-scoped fix that turns a recurring class of drift bug (hand-maintained model.contains(...) sniffing) into a single FlexLib-sourced table lookup, which is exactly the right direction under Principle I. The two-fold root cause (classification gap on the S server variants + the one-shot timing bug) is clearly reasoned, and the test coverage is genuinely good: the MLS/CLS/au-510 extended-DSP regressions and the both-directions diversity flips (6500 false-positive, ML/CL false-negative) each have an explicit assertion.
A few things I verified while reviewing:
- All three diversity call sites are covered. Grepping the tree for the old
contains("6500")|...|contains("AU-520")diversity gate finds exactly the three sites this PR replaces (MainWindow.cpp×2,MainWindow_Wiring.cpp×1). The remainingcontains("6500")/contains("AU-520")hits are inmaxSlicesForModelandSmartCatProtocol(CAT ID strings) — correctly out of scope. - Table ordering is right.
MLS-9601beforeML-9600andCLS-9301beforeCL-9300(and the pre-existing suffix-before-base ordering) all hold, so the first-substring-match contract is preserved. - The
xvtr_policy_testswitch to designated initializers ({.has2Meters = true}) is necessary, not cosmetic — sinceplatformis now the first struct member, the old positional{false, true}would no longer compile. Good catch handling that. - All six checks (build / macOS / Windows / CodeQL / analyze / a11y) are green.
Two non-blocking notes:
-
Upstream fidelity is asserted by the table against itself.
model_capabilities_testencodes the same diversity/platform values the table declares, so a green test proves internal consistency, not that the row matches FlexLib's actualIsDiversityAllowed/Platformcolumns. The flips all line up with real SCU counts (6500 single-SCU → false; 6600/6600M/6700(R) dual-SCU → true), so I believe they're correct — but a maintainer eyeball against the currentModelInfo.csbefore merge would fully close the loop, since the whole point is that this table is the authority now. -
RadioModel::maxSlicesForModel(andmaxPanadapters...) still sniff by substring — the same anti-pattern this PR is retiring. Reasonable to leave for a follow-up, but eventually folding slice/panadapter counts intoModelCapabilitiestoo would finish the job.RT-2122was correctly added to the 2-slice branch here in the meantime.
Thanks for the thorough writeup and the honest note that the AU-510 symptom is most likely the timing half — closing the class of bug regardless is the right call. LGTM pending the FlexLib row-check.
🤖 aethersdr-agent · cost: $2.4304 · model: claude-opus-4-8
…orm table
Complete the single-source-of-truth migration started for extended-DSP and
diversity: slice/panadapter capacity and firmware-family routing now derive
from the FlexLib-sourced ModelCapabilities table (Principle I) instead of
parallel model.contains() ladders that had drifted.
- ModelCapabilities gains a maxSlices field (FlexLib SliceList size; also the
max panadapter count, since pan capacity tracks SCU/slice capacity on every
current model). Default 2 mirrors FlexLib's DEFAULT entry.
- maxSlicesForModel() and maxPanadapters() now return capabilitiesFor().maxSlices.
Fixes the dual-SCU ML-9600/MLS-9601/CL-9300/CLS-9301: maxPanadapters() omitted
them from its contains() list, capping them at 2 panadapters instead of 4.
- FirmwareStager::modelToFamily() routes by RadioPlatform (DragonFire -> 9600,
everything else -> 6x00) instead of contains("9600"). The old substring test
misrouted both ways: ML-9600/ML-9600W (BigBend) went to the government 9600
firmware family, while RT-2122 (the actual DragonFire radio) fell to 6x00.
Not migrated (no FlexLib source): maxPanBandwidthMhz/minPanBandwidthMhz come
from packet captures (#1385) and FlexLib has no bandwidth field; hasGpsHardware
isn't in ModelInfo either. Left as-is rather than guessing ML/CL values.
model_capabilities_test asserts maxSlices for all 23 models plus explicit
ML/CL=4 and AU-510M=2 / AU-520M=4 regressions. Full app + test build verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#3961) ## Release documentation prep for **v26.7.1** (2026-07-02) 29 commits since v26.6.5. Docs-only + version bump — no code behavior change. ### Version bump 26.6.5 → 26.7.1 The three canonical locations (per `AGENTS.md`): - `CMakeLists.txt:2` — `project(AetherSDR VERSION 26.7.1)` → `AETHERSDR_VERSION` (the app's version string) - `README.md` — Current version line - `AGENTS.md` — Current version line ### `CHANGELOG.md` Promoted `[Unreleased]` → **`## [v26.7.1] — 2026-07-02`** in house style (v-prefix, em-dash, "N commits since…" opener + headline), authored from all merged PRs and categorized: - **Added:** 3D stacked-trace spectrum (#3899), 3D dBm scale (#3937), in-process NVIDIA BNR + AFX download-on-demand (#3902), TX meter mouse-over readouts (#3936), SWR manual sweep range (#3885), CW sidetone capture (#3895), KiwiSDR metadata scaffolding (#3898), bridge verbs (#3920) - **Changed:** BNR container/NIM backend removed, 60 fps + per-pixel GPU FFT trace (#3958), FlexLib-sourced model capabilities (#3954/#2177), RX speaker-latency cut (#3897), Display pane sections (#3935) - **Fixed:** #3922, #3926, #3941, #3940, #3942, #3921, #3903, #3892, #3924, #3891, #3890, #3900, #3947 - Fresh empty `[Unreleased]` restored above the release block. Internal/CI/docs/self-fix PRs (#3931/#3916/#3934/#3929) omitted per house style. ### `ROADMAP.md` - Cycle header → "post-v26.7.1" - NVIDIA BNR removed from **In flight** (shipped this cycle) - Five v26.7.1 highlights prepended to **Recently shipped** ### `README.md` - Highlights: GPU spectrum bullet now notes the **per-pixel FFT trace at up to 60 fps** and the **3D stacked-trace** spectrum mode ### Reviewer notes - Touches protected paths (`*.md` + `AGENTS.md` Tier-1 + `CMakeLists.txt`) — needs `@aethersdr/infrastructure` sign-off. - Tagging `v26.7.1` and cutting the release build are **not** part of this PR (docs prep only). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Problem
A user with an AU-510 reported that the NRS / RNN / NRF extended-DSP toggles never appear in the VFO DSP menu (NRL, which isn't extended-gated, does show). Investigating surfaced a whole class of model-capability bugs from hand-maintained
model.contains(...)sniffing that had drifted out of sync with FlexLib.Root cause (two-fold for AU-510)
hasExtendedDspFilters()used substring checks (contains("ML-")/"CL-"/"AU-") that silently missed the "S" server variants (MLS-9601has no"ML-";CLS-9301has no"CL-") and was case-sensitive.setHasExtendedDsp()was pushed once atonSliceAdded, so if themodelstatus arrived after the slice (GUIClientID session restore), the flag stayed at itsfalsedefault and never refreshed.Fix
Migrate extended-DSP and diversity gating to the FlexLib-sourced
ModelCapabilitiestable — Constitution Principle I (FlexLib is the model authority) — and close the gaps:ModelCapabilitiesgains aRadioPlatformenum (Microburst / DeepEddy / BigBend / DragonFire), aplatformfield, anisDiversityAllowedflag, and ahasExtendedDsp()helper. The table is corrected (ML-380/CL-200/RT-100placeholders → realML-9600/CL-9300/RT-2122) and completed (MLS-9601,CLS-9301,AU-510) — all 23 current FlexLib models resolve.BigBend | DragonFire), fixing MLS-9601 / CLS-9301 and case-sensitivity.RadioModel::infoChanged(mirroring the SmartSDR+/diversity refresh), so a latemodelstatus corrects the flag.IsDiversityAllowed:FLEX-6500(single-SCU) was wrongly granted diversity → now false.ML-/MLS-/CL-/CLS-(dual-SCU) were wrongly denied it → now true.RadioModel::isDiversityAllowed().RT-2122(DragonFire,SliceList {A,B}) now reports 2 slices instead of defaulting to 4.Verification
model_capabilities_testasserts platform + 4m/2m/loop + diversity + extended-DSP for all 23 models, with explicit regressions for MLS/CLS extended-DSP,au-510(lowercase),FLEX-6500diversity-false, ML/CL diversity-true, RT-2122 diversity-false. Passes locally (ctest -R model_capabilities_test).AetherSDRbuild links clean.Note
The reported AU-510 symptom is most likely the timing half (FlexLib does exact-match uppercase, so the wire string is
AU-510and the oldcontains("AU-")would have matched once the model was known). Both halves are fixed here so the class of bug is closed regardless.🤖 Generated with Claude Code