[codex] Consolidate profile load hold timing#3573
Conversation
0e603f3 to
c4263b3
Compare
c4263b3 to
b731615
Compare
There was a problem hiding this comment.
Pull request overview
This PR centralizes profile-load “radio-state write hold” timing into the shared profile-load command helper so that dependent recovery timers (deferred pan-dimension flush and post-hold recovery) stay derived from the same source of truth, reducing duplicated magic delays across model/UI code.
Changes:
- Hoists
kProfileLoadStateWriteHoldMs(and derived recovery delays) intoProfileLoadCommand.hand updates call sites to use the shared constants. - Replaces the hard-coded suppressed-write callback code with a named sentinel constant.
- Extends
profile_load_command_testto assert the derived recovery delays are ordered after the hold window.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/profile_load_command_test.cpp | Adds assertions ensuring recovery delays remain ordered relative to the shared hold duration. |
| src/models/RadioModel.cpp | Uses the named suppressed-write sentinel (and removes the local duplicated hold constant). |
| src/models/ProfileLoadCommand.h | Introduces shared profile-load timing constants and a named suppressed-command sentinel. |
| src/gui/MainWindow_Wiring.cpp | Removes duplicated hold constants and derives delayed recovery singleShot timings from shared constants. |
| if (cb) { | ||
| cb(0x50000061, QStringLiteral("suppressed during profile load")); | ||
| cb(kProfileLoadSuppressedCommandCode, | ||
| QStringLiteral("suppressed during profile load")); | ||
| } |
There was a problem hiding this comment.
Reviewed the diff against the branch — this is a clean, well-scoped consolidation. Thanks @rfoust. 🙏
What's good
- The hold window is now a single source of truth.
kProfileLoadStateWriteHoldMsmoves intoProfileLoadCommand.h, and the local copies in bothRadioModel.cppandMainWindow_Wiring.cpp(two functions) are removed. Both consumers already#include "ProfileLoadCommand.h", so the shared constant resolves cleanly. - Behavior is preserved exactly: the derived timers reproduce the old magic delays (
10000 + 1000 = 11000,10000 + 1250 = 11250), so the twoQTimer::singleShotcalls are unchanged at runtime while no longer being free-floating literals. - The
static_cast<int>on theqint64base is safe at these magnitudes (~11k, far underINT_MAX), andQTimer::singleShottakesint, so the narrowing is correct. - Naming
kProfileLoadSuppressedCommandCodeand documenting that it is not a SmartSDR protocol code is a genuine readability win at the suppression site. - The two new test invariants (
deferred pan flush > hold,post-hold recovery > deferred flush) lock in the ordering relationship, so a future edit to the base hold can't silently invert the sequence. Nice touch.
On the Copilot finding (RadioModel.cpp:3654) — the concern that the suppressed-write path invokes cb(...) with a non-zero code while returning 0, which callbacks may misread as a real radio error, is a legitimate observation. But it's pre-existing behavior: this PR only renames the literal and adds a clarifying comment; it doesn't alter the callback contract. So it's not a blocker for this consolidation. If you agree it's worth addressing, it'd be cleaner as a focused follow-up — either report suppression as a benign completion (cb(0, ...)) or skip the callback entirely — after confirming what the registered callbacks actually do with code != 0.
No scope creep, no AppSettings/RAII concerns, includes are correct. Looks good to me.
🤖 aethersdr-agent · cost: $2.4616 · model: claude-opus-4-8
Summary
Fixes #3572. This follow-up consolidates the profile-load radio-state write hold into the shared profile-load command helper, derives the delayed pan-dimension flush and post-hold recovery timers from that same hold window, and names the internal suppressed-write sentinel so it is clear the callback is not reporting a SmartSDR protocol response. The goal is to keep AetherSDR from sending profile-owned slice/panadapter state back to the radio while the radio is still restoring its saved profile/session layout.
Constitution principle honored
Principle I - FlexLib Is The Protocol Authority. The change keeps profile recall radio-state timing centralized around the radio-authoritative profile-load path instead of scattering independent magic delays through the client.
Test plan
cmake --build build --target profile_load_command_test AetherSDR aprs_packet_test aprs_messenger_test -j4)Local validation run:
ctest --test-dir build --output-on-failure -R 'profile_load_command_test|profile_transfer_test|radio_status_ownership_test|slice_recreate_policy_test|transmit_model_test'ctest --test-dir build --output-on-failure -E '^theme_manager_test$'git diff --checkChecklist
docs/COMMIT-SIGNING.md)AppSettingscalls - use nested-JSON-under-one-key (Principle V)MeterSmoother(Principle II)