aethersdr / aethersdr/AetherSDR
check_capability_records.py: an accessor in RadioCapabilities silently deletes the next bool from the count, and the tool then asks you to lower the freeze
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 302
Description
tools/check_capability_records.py counts direct bool members of RadioCapabilities and freezes the population at 71, shrink-only. The parser's field scan runs to the next ;, so a member function declared inside the struct swallows whatever follows it — and a bool declared immediately after an accessor disappears from the count.
The ratchet then reports a drop, exits 0, and tells the reader to make the loss permanent.
Reproduction, on main's own header
Insert one accessor immediately before an existing bool — canCreateSlices happens to be the first one in the struct:
struct RadioCapabilities {
...
+ [[nodiscard]] bool someAccessor() const { return true; }
bool canCreateSlices = false;
$ python3 tools/check_capability_records.py --strict
capability-records: 70 boolean(s), below the frozen 71 — the migration is working.
Lower FROZEN_BOOL_COUNT in tools/check_capability_records.py to 70 so the gain
cannot be given back.
EXIT=0
canCreateSlices is still declared, still read, still load-bearing. Nothing was migrated. CI is green, and the tool's own advice — followed in good faith, in the same commit, exactly as the docstring asks — gives the bool away permanently.
The same thing happens in isolation. direct_bool_fields() on
struct RadioCapabilities {
bool alpha = false;
std::optional<PanAmplitudeModel> panAmplitude;
[[nodiscard]] bool dbmAxisIsCalibrated() const
{ return !panAmplitude || panAmplitude->calibratedDbm; }
bool beta = false;
double gap = 0.0;
bool delta = false;
};
returns ['alpha', 'delta']. beta is gone.
Why the existing guards do not catch it
MAX_PLAUSIBLE_DROP = 15 bounds a drop that is implausibly large. This arrives one bool at a time, which is the most plausible size there is. The docstring's own anti-vacuity worry — "the parser falling over" — is exactly this failure, and the guard is sized for the wrong end of the range.
txPowerMaxWattsAt is unaffected today only by luck: a QStringList follows it rather than a bool.
Where we met it
On #5725 and #5726, adding accessors alongside std::optional records — which is the shape the ratchet asks for. We placed panAmplitude and its two accessors in the panadapter block rather than beside radioOwnsDbmScale where the field they replace lived, because persistsMemories follows that slot and would have vanished. That placement is a workaround for this bug, not a design choice, and we would rather it did not have to be.
We verified the conversion by dumping direct_bool_fields() on both branches and diffing the name set against main rather than trusting the count — identical, 71 names, nothing swallowed. That check is what a reader should not have to invent.
Shape of a fix, not a patch
Skipping a member function's body would do it — the declaration's ( before the ; is the signal, and = default / = delete need the same treatment. A name-set comparison rather than a count would make the swallow visible whatever the cause, at the price of churn on renames, which the docstring says is deliberately tolerated today.
Not proposing one here: which trade this project wants is yours, and #5262 is where that was decided.
What we did not check
Whether any bool has already been lost this way on main — the frozen 71 is itself a count taken by this parser, so if the shape existed at the freeze the number was wrong from the start. The name set today is 71 and internally consistent; we have not compared it against a hand count of the header.
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with tools/check_capability_records.py, especially direct_bool_fields() and the --strict path, then inspect RadioCapabilities in the main header. Reproduce the missing bool after an accessor and compare the reported name set with the header. Done means member functions no longer hide following bools and the ratchet cannot recommend lowering the frozen count for an unverified drop; review the tradeoff noted in #5262.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100