feat(radio): accept conventional band-name aliases (70cm -> 440) in declared bands#4259
feat(radio): accept conventional band-name aliases (70cm -> 440) in declared bands#4259nigelfenton wants to merge 2 commits into
Conversation
AE's band vocabulary is internally inconsistent — the 70cm band is named "440" — but a gateway (or a ham typing a radio profile) naturally spells it "70cm", and parseDeclaredBands() would silently drop the unrecognized spelling. That mismatch has been patched adapter-by-adapter on the Aether-gate side (PRs aethersdr#14/aethersdr#15/aethersdr#16, each renaming one radio's band); this fixes it once, in AE, so no adapter has to know AE's naming quirks. Add a small alias table resolving conventional spellings to the canonical kBands name before matching (currently just 70cm -> 440, the only mismatch actually observed from a gateway). An alias only ever maps to a name that already exists in kBands, and the resolved name still runs the existing isDeclarable + allow-list, so Principle VII is unchanged: an alias is a second spelling of a known band, never a new band, and junk still drops. Tests (declared_bands_test): 70cm -> [440], case-fold, alias among reals, dedup when both spellings are sent (either order), and the Principle-VII case (70cm,junk -> [440] — alias kept, junk dropped). 17/17 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Clean, tightly-scoped fix. I verified against BandDefs.h: 440 is the canonical kBands entry (there is no 70cm entry), and it's declarable (highMhz 450 ≥ 1.0), so the alias resolves and still passes the isDeclarable + allow-list gate exactly as the description claims. The dedup path is correct in both orders (440,70cm and 70cm,440 both collapse to [440]), and the Principle VII guarantee is genuinely preserved — an alias is only ever a second spelling of an existing band. The comments and test coverage are excellent. Nice work, and thanks for fixing this once in AE rather than per-adapter.
No blocking issues.
Non-blocking notes
kBandAliases: the "alias canonical must already exist in kBands" invariant could be enforced at compile time instead of by review — see inline. Optional but it makes Principle VII hold by construction.- Minor doc nit (no change requested): the
.cppcomment and tests cite Aether-gate PRs #14/#15 while the PR description also mentions #16 for6cm → 5cm; harmless, just noting for future-you when that alias lands.
🤖 aethersdr-agent · cost: $7.8078 · model: claude-opus-4-8
| constexpr BandAlias kBandAliases[] = { | ||
| {"70cm", "440"}, // UHF: every ham + gateway spells it 70cm; AE names it 440 | ||
| }; |
There was a problem hiding this comment.
Optional hardening: since kBands and kBandAliases are both constexpr, the security invariant in the comment above ("an alias may ONLY map to a name that already exists in kBands") can be checked by the compiler rather than trusted to reviewers. Something like:
constexpr bool aliasCanonicalsExist() {
for (const auto& a : kBandAliases) {
bool found = false;
for (const auto& def : kBands)
if (std::string_view(def.name) == a.canonical) { found = true; break; }
if (!found) return false;
}
return true;
}
static_assert(aliasCanonicalsExist(),
"every kBandAliases canonical must name an existing kBands entry");That way a future typo'd or renamed canonical fails the build instead of silently dropping the band. Non-blocking — the current one-entry table is easy to eyeball.
Address the reviewer's optional-hardening suggestion: a constexpr check + static_assert that every kBandAliases canonical names an existing kBands entry, so Principle VII holds by construction rather than by review. A future typo'd or renamed canonical now fails the build instead of silently dropping the band. Also note aethersdr#16 alongside aethersdr#14/aethersdr#15 in the table comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the thorough review! Implemented the compile-time hardening ( |
Accept conventional band spellings (70cm->440) with compile-time invariant. Favorably reviewed by aethersdr-agent, all 7 CI green. Upstream PR aethersdr#4259 still open for maintainer merge.
|
Holding for next week's release. |
Summary
AE's band vocabulary is internally inconsistent — the 70 cm band is named
440, not70cm. But a gateway (or a ham typing a radio profile) naturally spells it70cm, andparseDeclaredBands()matches names exactly againstkBands, so the conventional spelling is silently dropped and the band never appears.That mismatch has so far been patched adapter-by-adapter on the Aether-gate side — one rename per radio (its PRs #14
_70CM→440, #15, #166cm→5cm). This fixes it once, in AE, so no adapter has to know AE's naming quirks: teachparseDeclaredBandsa small alias table that resolves a conventional spelling to the canonicalkBandsname before matching.Follows #4027 (radio-declared
bands=) and its review follow-ups in #4194. Standalone offmain(not stacked).Change
constexpralias table +resolveAlias()helper inDeclaredBands.cpp. Each incoming token is alias-resolved (case-insensitive) before the existingkBandsallow-list loop.70cm → 440, the only mismatch actually observed from a gateway. Easy to extend later with concrete evidence (e.g.6cm → 5cm), but no speculative aliases.Principle VII is unchanged (the bit worth checking)
An alias may only map to a name that already exists in
kBands. The resolved name still runs throughisDeclarable()+ thekBandsallow-list, so:This is enforced by construction:
resolveAlias()returns a plain string that is then validated exactly as before. A non-alias token passes through unchanged.Tests
declared_bands_testgains 6 cases (all green — 17/17):70cm → [440], case-fold70CM → [440]2m,70cm,23cm → [2m,440,23cm]440,70cm → [440]and70cm,440 → [440]70cm,junk → [440]— alias kept, junk droppedBuilt + ran locally on Windows (Qt 6.10.3, current
main=b9735c79).