Pin filter-before-merge invariant on license-class-aware contiguousRegionsForBand (#3060). Principle IV.#3089
Merged
Merged
Conversation
…gionsForBand (#3060). Principle IV. PR #3050 (closing #2649) added a license-class-aware overload of BandPlanManager::contiguousRegionsForBand that filters segments by the operator's class before merging contiguous regions. The filter-BEFORE-merge ordering is load-bearing: if an allowed segment is adjacent to a disallowed one, they must NOT merge — otherwise the merged region's center could fall on a disallowed frequency. The implementation comment calls this out, but no test pinned the invariant. A future refactor (STL-algorithm consolidation, parallelisation of the segment loop) could silently re-introduce the bug. This commit adds tests/band_plan_license_filter_test.cpp covering the five scenarios enumerated in the issue: 1. Empty class → no filter (three-arg with "" == two-arg). 2. Empty-license segments (BCN markers) always pass. 3. Class filter drops non-matching segments [E]/[G]/[E,G] under T/G/E. 4. Adjacent allowed/disallowed segments stay separate (THE invariant). 5. Trailing-whitespace allowedClass is trimmed; "GE" doesn't match "G,E" substring-style; lowercase doesn't match uppercase. To make scenario 5 pass and to keep the comparison symmetric, the allowedClass argument is now .trimmed() at the top of the filter — the segment-side code was already trimmed per element. This is a one-line forgiveness fix; existing callers that pass already-trimmed strings (MainWindow::startSwrSweep, AtuPreTuneDialog::populateBands) are unaffected. A small public test hook BandPlanManager::setSegmentsForTest is added so the test can inject synthetic segments without going through resource loading or AppSettings. Matches the *ForTest naming convention already used in PerfTelemetry::resetForTest and AetherAx25LibmodemShim::processRecoveredBitsForTest. Honors Principle IV (region-aware data comes from BandPlanManager, not BandDefs.h) by hardening the regression-guard around the manager's license-class filter — exactly the surface a refactor cleanup pass would be tempted to consolidate. Blast radius: risk_score=0.198, 4 high-risk affected (top: MainWindow::MainWindow, MainWindow::buildMenuBar, MainWindow::buildUI). Header change is purely additive (new public inline setSegmentsForTest) — no existing API touched; the high-risk callers don't reference the new symbol and aren't behaviorally affected, only a recompile cascade. The .cpp change adds .trimmed() to one argument — forgiveness-only (strings that previously failed strict comparison may now match); no caller currently passes whitespace. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
BandPlanManager.h:4 includes <QColor> for the Segment struct's color field. The test target was only linking Qt6::Core, so the test build failed with `fatal error: QColor: No such file or directory`. Fix: add Qt6::Gui to target_link_libraries. Local build clean, all 13 test scenarios pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
There was a problem hiding this comment.
Looks good — focused regression pin for the filter-before-merge invariant.
Strengths
- Scenario 4 directly captures the bug class the comment in
BandPlanManager.cpp:84warns about, so a future STL-algorithm refactor that hoists the filter past the merge will trip a deterministic test. - Test hook follows the existing
…ForTestconvention used byPerfTelemetry::resetForTestandAetherAx25LibmodemShim::processRecoveredBitsForTest. - Tests bypass
loadPlans()/AppSettingscleanly — no global state leaked between scenarios.
Small notes (non-blocking)
- The
needle = allowedClass.trimmed()change inBandPlanManager.cpp:88is a behavior change beyond the stated "pin invariant" scope (previously trailing whitespace onallowedClasswould not match; now it does). Worth a one-line mention in the PR body since the title only advertises the tests. Scenario 5 covers the new behavior, so functionally fine. setSegmentsForTestlives in the public header. Naming is clear enough, but if you want to harden it later, wrapping in#ifdef AETHER_TESTINGor adding afrienddeclaration would prevent accidental call from production code. Not required given the codebase's existing convention.
Thanks for the careful comments — especially the inline derivation of why E-class A and C stay separate in scenario 3. Makes the test self-documenting.
🤖 aethersdr-agent · cost: $2.3574 · model: claude-opus-4-7
G6PWY-Chris
pushed a commit
to G6PWY-Chris/AetherSDR
that referenced
this pull request
Jun 22, 2026
…gionsForBand (aethersdr#3060). Principle IV. (aethersdr#3089) ## Summary Fixes aethersdr#3060 ### What was changed Pin filter-before-merge invariant on license-class-aware contiguousRegionsForBand (aethersdr#3060). Principle IV. ### Files modified - `CMakeLists.txt` - `src/models/BandPlanManager.cpp` - `src/models/BandPlanManager.h` - `tests/band_plan_license_filter_test.cpp` ``` CMakeLists.txt | 11 ++ src/models/BandPlanManager.cpp | 3 +- src/models/BandPlanManager.h | 5 + tests/band_plan_license_filter_test.cpp | 212 ++++++++++++++++++++++++++++++++ 4 files changed, 230 insertions(+), 1 deletion(-) ``` --- Generated by AetherClaude (automated agent for AetherSDR) --- <sub>🤖 aethersdr-agent · cost: $10.0004 · model: claude-opus-4-7</sub> --------- Co-authored-by: aethersdr-agent[bot] <273844287+aethersdr-agent[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Jeremy Fielder <kk7gwy@aethersdr.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #3060
What was changed
Pin filter-before-merge invariant on license-class-aware contiguousRegionsForBand (#3060). Principle IV.
Files modified
CMakeLists.txtsrc/models/BandPlanManager.cppsrc/models/BandPlanManager.htests/band_plan_license_filter_test.cppGenerated by AetherClaude (automated agent for AetherSDR)
🤖 aethersdr-agent · cost: $10.0004 · model: claude-opus-4-7