Repository navigation
Conversation
…inciple VIII. The Hermes-Lite 2 transmit path now has exactly one modulator, a WDSP TXA channel, selectable neither at run time nor at build time. No CI job sets AETHER_HL2_TX_TXA in either direction -- `git grep AETHER_HL2_TX_TXA -- .github/` returns nothing -- so the CMake default is the only configuration anything compiles. While the default was OFF the fallback was compiled for free; since aethersdr#5779 flipped it ON, the phasing translation unit has not been syntax-checked by anything and two guarded blocks in hl2_txdsp_test have compiled nowhere. CMakeLists.txt disclosed this in its own words rather than hiding it, after aethersdr-agent raised it on aethersdr#5779. A way back that nothing keeps open is not a way back. Removed: the option() and its comment block, the PUBLIC macro definition, the phasing implementation in Hl2TxDsp.cpp and its members in Hl2TxDsp.h, both Hl2Backend.cpp expressions, and every guard in hl2_txdsp_test, hl2_dsp_readback_test and wdsp_channel_test. The `modulator` bridge field stays and still reads wdsp-txa. Two costs, both stated in the PR body rather than absorbed: the receive-only modes evidence block goes with it, so hl2_family_transition_test's comment and message are corrected to claim the declaration rather than the modulator; and Hl2TxDsp.cpp's "LOWER BOUND" wording, which aethersdr#5810 retracted in the test file and never here, is corrected to floor-limited and UNRESOLVED. Refs aethersdr#5678, aethersdr#5779, aethersdr#5796. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Issue fit
No Fixes/Closes — the commit refs #5678, #5779, #5796. I read #5796: it documents "no CI job builds the optional-dependency-OFF configuration" and explicitly says "Whether this is worth a CI job, and what shape it takes … is a maintainer call." This PR takes the other branch of that decision for one flag — delete the configuration rather than build it — which is a defensible answer and, for AETHER_HL2_TX_TXA specifically, the one the removed CMake comment itself argued toward. It does what its title says, and the central factual claim checks out: git grep AETHER_HL2_TX_TXA over .github/ returns nothing on this tree, so the OFF arm has not been compiled by anything since #5779 flipped the default.
Verdict: Yes, with one governance question for the maintainer (below) and a documentation-accuracy finding the PR half-did.
Scope
| File(s) | What it changes | Claimed by title/body | Verdict |
|---|---|---|---|
CMakeLists.txt |
removes option(AETHER_HL2_TX_TXA) + the PUBLIC target_compile_definitions pair |
yes | in scope |
src/core/backends/hl2/Hl2TxDsp.{h,cpp} |
deletes the phasing implementation, its members, and the #if/#else guards |
yes | in scope |
src/core/backends/hl2/Hl2Backend.cpp |
total = actualNumRx + 1; unconditional TX-step announcement; readback comments |
yes | in scope |
src/core/AutomationServer.cpp, src/core/backends/IRadioBackend.h |
comment-only | yes | in scope |
docs/HERMES.md, docs/automation-bridge.md, docs/hl2-txa-configuration-diff.md |
readback/status prose | yes | in scope |
tests/hl2_txdsp_test.cpp, hl2_dsp_readback_test.cpp, wdsp_channel_test.cpp |
unguard the TXA arms, delete the #if !AETHER_HL2_TX_TXA blocks |
yes | in scope |
tests/hl2_family_transition_test.cpp |
assertion message + comment; the assertion itself is unchanged | disclosed in the commit message | in scope, but see finding 1 |
Nothing in the diff is unexplained by the stated change. No new public surface: the modulator bridge field is retained and still emits wdsp-txa, so no client contract moves. No CHANGELOG.md edit — correct per AGENTS.md. No socket test is added, modified or removed by this PR.
Deleted behavior audit. I read the - lines for removed guards whose symptom could recur. The deleted CMake comment and the deleted #else arm both carried the conjugation warning ("every transmission went out on the wrong sideband … caught on the air, not on the bench"). That rule survives in Hl2TxDsp.h:40-52 and at Hl2TxDsp.cpp:252, with the falsifying mutation still recorded (167.31 dB → -175.64 dB). Nothing user-facing was gated on the flag, so nothing user-facing is deleted with it.
Blockers
None. Nothing here breaks a default build, and every test-threshold change is a no-op for the configuration CI actually compiles (see "What I tried to break").
Findings
-
The production rationale for
receiveOnlyModesstill asserts the premise this PR deletes.src/core/backends/hl2/Hl2Backend.cpp:1928-1937reads: "The transmit chain is not WDSP. Hl2TxDsp is a hand-written phasing SSB modulator: setMode() stores the mode and the only reader is isLowerSideband() … So AM, SAM, DSB, FM, NFM, WBFM and DRM all take the upper-sideband branch and go on the air as SSB." Every clause of that is now false —setMode()also reachesapplyModeAndFilter()→WdspChannel::setMode()→SetTXAMode. This PR writes the correction intohl2_family_transition_test.cpp:93-105("the bit-identity premise no longer holds") and leaves the source of truth uncorrected, so the one test that readscapabilities()now points at a rationale that contradicts it. The declaration itself stays conservative and safe, so there is no user-visible defect — but this is the exact drift class the PR invokes Principle VIII against, and it is one paragraph. Inline comment on the test hunk. -
~22 sibling comments in the same files still describe a two-build world. Not cosmetic in aggregate — several are load-bearing explanations a future editor will act on:
Hl2TxDsp.h:129("In the PHASING build there is no WDSP channel behind this"),:153("or -1 when this build has none"),:162-165("ALWAYS 0 in the phasing build … the stated reason this is a build flag at all"),:238("THE TXA BUILD IS NOT RATE-FREE, and the phasing build is"),:295("A no-op in the phasing build"),Hl2TxDsp.cpp:358("per build"),Hl2Backend.cpp:5217("this build flag exists for"), and in the file this PR rewrote most heavily,hl2_txdsp_test.cpp:126, 255, 442, 452, 1799("Applied in BOTH builds", "this whole build flag exists to avoid", "runs on the whole run in BOTH builds"). Inline comment on the header hunk with the full list. -
Nothing in the tree now records that WDSP TX has no WBFM mode, and the runtime path is unguarded. The deleted block was the only place that said TXA "refuses WBFM outright". That refusal is enforced only in
create()-time config validation (WdspChannel.cpp:876);WdspChannel::setMode()(:589-605) does no direction/mode check and returnstrue, soSetTXAMode(id, wdspMode(Wbfm))is issued on a live channel. It is reachable:Hl2Backend.cpp:3114and:3324push the TX slice's mode straight through on any TX-slice mode change or TX-slice move. WBFM is onreceiveOnlyModes, so no emission can follow, and a return to USB re-pushes the mode — but an undefined TXA mode index does reach WDSP. Pre-existing since #5779, not introduced here; I raise it because this PR removes the only note of it. Reasoned from source; I have not run it. -
The
dsp-configfallback ingatherDspChainsis now dead, and the doc states categorically what the code still hedges.Hl2Backend.cpp:5209-5212keepschannel ? "channel-config" : "dsp-config"and thetxChannelId >= 0guard.configure()setsm_configuredonly afterbuildModulator()succeeds, andbuildModulator()returnsfalsewhenWdspChannel::create()yields null — soisConfigured()impliesm_channel != nullptr, and the early-return on!isConfigured()means theelsearms are unreachable. Harmless defensively, but the docs now assert the dead branch away; if they are going to, the code can say so too. -
Minor, and explicitly not a request to edit a release file:
CHANGELOG.md:61still reads "the in-tree phasing modulator remains one flag away", which this PR makes false. Flagging it for whoever does release prep rather than asking for a change here. -
Governance — maintainer decision, not a violation.
GOVERNANCE.md§"What requires an RFC" lists "Architecture changes"; it also exempts "Build / CI fixes". This sits on the seam: mechanically it deletes an uncompiled build arm, but substantively it retires the fallback that #5678 was approved on ("keep the phasing modulator behind a switch until the TXA path passes the extended suite AND has had hardware time"). Both halves of that condition are now met and named — ON8ST's 2026-09-17 dummy-load and antenna runs, with the SWR corroboration — so the condition has expired on its own terms. I do not think this needs an RFC; I do think it needs a maintainer saying "yes, the way back is closed", because after this the only way back is a revert and the PR says so plainly.
Nits
docs/automation-bridge.md:1502— "Onhl2-txentries,levelischannel-config" is unconditional, but the code emits"not-configured"and returns early when!isConfigured(). The very next bullet already says "on a configuredhl2-txentry"; matching that word here would make the two agree.docs/hl2-txa-configuration-diff.md:463-464keeps both build rows in the suite table with "(since removed)" — correct as history, and I am not asking for it to change; noting I read it as deliberate rather than stale.tests/hl2_family_transition_test.cpp:129's new message, "HL2 declares exactly these modes receive-only", is honest about the weakened claim. The assertion still catches list drift; it no longer carries modulator evidence. Disclosed in the commit message, which is the right handling.
What I tried to break
- "No CI job sets the flag." Grepped the whole head checkout:
AETHER_HL2_TX_TXAsurvives only inCHANGELOG.md:61and two historical lines ofdocs/hl2-txa-configuration-diff.md. Nothing in.github/, no CMake preset, no source, no test. The claim holds. - Dangling references after the deletion. Grepped for every removed symbol —
kTaps,blackman,m_bandpass,m_hilbert,m_hist,m_histPos,Band::settledFloorDb, thesettledFloor()lambda. Zero live references; the only survivors are twokTaps 255 -> 127lines inside a mutation-table comment inhl2_txdsp_test.cpp:1001-1009, which are historical prose, not code. - Did any assertion get loosened? This was the attack I expected to land and it did not. Every threshold the diff touches was already at the value it now hardcodes in the configuration CI compiles:
kMinSuppDb/kMinLowEdgeSuppDbwere bothkFloorLimitedSuppDb(140.0) in the TXA arm; thesettledFloor(b)lambda already returnedkMinSuppDb, so droppingBand::settledFloorDbchanges nothing;feed()'s pacing sleep andcrest(settledTail(slam))were already the TXA arms. The#if !AETHER_HL2_TX_TXAbit-identity block genuinely compiled nowhere. Net coverage loss for the built configuration: none. - Can the newly-unconditional readback assertions go red?
hl2_dsp_readback_testnow assertslevel == "channel-config"andwdspChannelId >= 0without a guard. Walked the refusal path:WdspChannel::create()returns null →buildModulator()returns false →configure()leavesm_configuredfalse →gatherDspChainsemitslevel: "not-configured"and returns before either assertion's field exists. So a refused channel produces a different-shaped entry, not a failing one. The assertions are safe. - Does the progress denominator stall at "N of N+1"?
total = actualNumRx + 1is now unconditional and the TX announcement fires onif (self)alone, while the work itself is stillif (txDsp). Tracedm_txDsp: constructed unconditionally atHl2Backend.cpp:361, deleted only in the destructor, never nulled — so the counted step always runs and theif (txDsp)is defensive. No regression, and no change frommain, where the flag was already ON. - Removed-guard-whose-symptom-recurs check. The wrong-sideband bug the deleted phasing comment describes is a property of the deleted code; the TXA no-conjugation rule and its falsifying mutation are both retained. Nothing gated on the macro outside the two files that implement the modulator.
- CI. 5/5 green on
98d49fd8(Static checks, build, check-macos, check-windows, Sanitizer option configures). Worth noting what that proves here: since no job ever set the flag, green on this PR is the same green the flag's presence always produced — it is not evidence the removal was safe, which is why I walked the deletions by hand instead.
Could not check: anything at runtime. No build, no ctest, no radio. Every finding above is reasoned from the source in /tmp/aetherclaude/pr-5906, with file:line given so each can be checked independently. In particular, finding 3's WBFM path is read from the call graph, not observed on hardware.
Recommendation
Approve with nits (review event stays COMMENT; the merge call is yours). The deletion is clean, the arithmetic of what CI actually compiled is correct, and the tests survive it without a single assertion being weakened for the built configuration — I looked hard for a loosened threshold and there isn't one. Finding 1 is the one I would fix before merge: the PR corrected the test comment and left the production comment asserting the dead premise, three files away from the change that killed it. Findings 2-5 are follow-up-sized. The one thing a maintainer should actively say yes to is finding 6 — this closes the way back that #5678's approval was conditioned on, and the condition expiring on its own terms is an argument, not a ratification.
Nice work, @on8st — the honesty about what the migration is not worth (the 1 kHz row against EP2's 16-bit wire) and the retraction of the ">= 180.6 dB" bound wording are the parts of this diff that will still be paying off in a year.
🤖 aethersdr-agent · cost: $11.0770 · model: claude-opus-5
…. Principle VIII. Review follow-up on aethersdr#5906. The removal was clean; what it left behind was a tree that still describes two transmit builds in about thirty-six places, one of them the production rationale the removal's own test correction contradicts. Hl2Backend::capabilities()'s receiveOnlyModes block still argued the list from a premise this PR deleted -- "The transmit chain is not WDSP ... setMode() stores the mode and the only reader is isLowerSideband()". Every clause of that is now false: setMode() reaches applyModeAndFilter() -> WdspChannel::setMode() -> SetTXAMode. The list itself was already conservative and does not move; the argument for it is rewritten to the one that actually holds, which is that nothing has measured this chain in AM, SAM, DSB, FM or DRM (docs/hl2-txa-configuration-diff.md section 7: "No AM, DSB, SAM, FM or CW channel was opened"). docs/architecture/radio-capabilities-map.md carried the same dead premise and is corrected with it. WDSP TX HAS NO WBFM MODE, and after this PR nothing in the tree said so -- the deleted evidence block was the only note of it. The note is restored beside the check that enforces it, WdspChannel::validateConfig(), rather than in a file that no longer exists, and it records what the check does NOT cover: WdspChannel::setMode() makes no direction/mode test and returns true, so SetTXAMode(id, wdspMode(Wbfm)) reaches WDSP on a live channel. Reachable from three sites in Hl2Backend -- a TX-slice mode change, a TX-slice move, and the connect-time push -- with modeFromString mapping both "WBFM" and "WFM" onto Mode::Wbfm. No emission follows, because both spellings are on receiveOnlyModes. Pre-existing since aethersdr#5779 and NOT fixed here: the note explains why mirroring create()'s two lines into setMode() would make it worse, since the caller pushes mode and passband as a pair and the passband's sign is derived from the new mode. gatherDspChains' hl2-tx fallback is removed rather than documented. isConfigured() implies a live channel -- configure() clears m_configured on entry and sets it only after buildModulator() returns true, which returns false whenever WdspChannel::create() yields null, the one place m_channel is assigned -- so the "dsp-config" level, the omitted wdspChannelId and the requested-figure fallbacks could not be reached. docs/automation-bridge.md already told clients the channel is always there; now both say it. The channel null-check folds into the existing !isConfigured() early return, so no state produces a half-shaped entry. Comment sweep: 42 sites across hl2_txdsp_test.cpp (17), Hl2TxDsp.h (10), wdsp_channel_test.cpp (8), Hl2TxDsp.cpp (5), Hl2Backend.cpp (1) and radio-capabilities-map.md (1). Fixed are the ones that describe a second build as live -- "In the PHASING build there is no WDSP channel", "A no-op in the phasing build", "THE WINDOW DIFFERS BY BUILD", "Applied in BOTH builds". Kept unchanged are the ones that record what the predecessor MEASURED: its 22.06 / 87.15 dB figures, the sweep's baseline table and wdsp_channel_test's 100 dB floor, which is derived from that chain's best point and is the line that says the migration has lost its argument. docs/automation-bridge.md's "On hl2-tx entries, level is channel-config" now says "On a configured hl2-tx entry", matching both the code and the next bullet. CHANGELOG.md is a released file and is not touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…. Principle VIII. Review follow-up on aethersdr#5906. The removal was clean; what it left behind was a tree that still describes two transmit builds in about thirty-six places, one of them the production rationale the removal's own test correction contradicts. Hl2Backend::capabilities()'s receiveOnlyModes block still argued the list from a premise this PR deleted -- "The transmit chain is not WDSP ... setMode() stores the mode and the only reader is isLowerSideband()". Every clause of that is now false: setMode() reaches applyModeAndFilter() -> WdspChannel::setMode() -> SetTXAMode. The list itself was already conservative and does not move; the argument for it is rewritten to the one that actually holds, which is that nothing has measured this chain in AM, SAM, DSB, FM or DRM (docs/hl2-txa-configuration-diff.md section 7: "No AM, DSB, SAM, FM or CW channel was opened"). docs/architecture/radio-capabilities-map.md carried the same dead premise and is corrected with it. WDSP TX HAS NO WBFM MODE, and after this PR nothing in the tree said so -- the deleted evidence block was the only note of it. The note is restored beside the check that enforces it, WdspChannel::validateConfig(), rather than in a file that no longer exists, and it records what the check does NOT cover: WdspChannel::setMode() makes no direction/mode test and returns true, so SetTXAMode(id, wdspMode(Wbfm)) reaches WDSP on a live channel. Reachable from three sites in Hl2Backend -- a TX-slice mode change, a TX-slice move, and the connect-time push -- with modeFromString mapping both "WBFM" and "WFM" onto Mode::Wbfm. No emission follows, because both spellings are on receiveOnlyModes. Pre-existing since aethersdr#5779 and NOT fixed here: the note explains why mirroring create()'s two lines into setMode() would make it worse, since the caller pushes mode and passband as a pair and the passband's sign is derived from the new mode. gatherDspChains' hl2-tx fallback is removed rather than documented. isConfigured() implies a live channel -- configure() clears m_configured on entry and sets it only after buildModulator() returns true, which returns false whenever WdspChannel::create() yields null, the one place m_channel is assigned -- so the "dsp-config" level, the omitted wdspChannelId and the requested-figure fallbacks could not be reached. docs/automation-bridge.md already told clients the channel is always there; now both say it. The channel null-check folds into the existing !isConfigured() early return, so no state produces a half-shaped entry. Comment sweep: 42 sites across hl2_txdsp_test.cpp (17), Hl2TxDsp.h (10), wdsp_channel_test.cpp (8), Hl2TxDsp.cpp (5), Hl2Backend.cpp (1) and radio-capabilities-map.md (1). Fixed are the ones that describe a second build as live -- "In the PHASING build there is no WDSP channel", "A no-op in the phasing build", "THE WINDOW DIFFERS BY BUILD", "Applied in BOTH builds". Kept unchanged are the ones that record what the predecessor MEASURED: its 22.06 / 87.15 dB figures, the sweep's baseline table and wdsp_channel_test's 100 dB floor, which is derived from that chain's best point and is the line that says the migration has lost its argument. docs/automation-bridge.md's "On hl2-tx entries, level is channel-config" now says "On a configured hl2-tx entry", matching both the code and the next bullet. CHANGELOG.md is a released file and is not touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014TtnKQu6QGrSeBirGeAsAs
|
Four of the six are ours and all four are done, in Your finding 6 quotes a sentence that is not @ten9876's, and this PR's own lead section is where I said so. The condition you cite — "keep the phasing modulator behind a switch until the TXA path passes the extended suite AND has had hardware time" — is I have carried that sentence myself and it is worth naming why it is sticky: it reads like a ruling, it was quoted in Which makes your conclusion stronger, not weaker, and I am adopting your framing over my own. I wrote this PR as "it asks the maintainer to revisit a ruling already made." Yours is better: this does not need an RFC, and it does need a maintainer saying "yes, the way back is closed." The correction only sharpens it — because the ruling carried no condition, nothing expires on its own terms, and a maintainer's yes is the only thing that can close it. There is no reading in which it closes itself. The three answers in the body stand unchanged. And your finding 3 is reachable from three sites, not two. Alongside 1 — the production rationale. Fixed.Correct, and worse than you wrote it: the closing paragraph of the same block said "the WDSP TXA chain carries all of these", which is false for WBFM specifically, by your own finding 3. Rewritten. The declaration does not move. What moves is the argument for it, from the dead premise to the one that actually holds: nothing has measured this chain in any of those modes.
2 — the sibling comments. 42, not ~22.I worked from my own grep rather than your list. All twelve sites you named are real — I checked each against
The second pass is worth reporting because of what it caught. My first sweep keyed on the obvious phrasings — "phasing build", "TXA build", "BOTH builds". Re-reading the same files afterwards turned up five more that say the same thing without any of those words: The two you did not sweep are where the load-bearing ones were.
What I did not change, deliberately: every comment that records what the removed modulator measured. Its 22.06 dB at DIGU 150 Hz and 87.15 dB at USB 1 kHz, the sweep's baseline table, and 3 — the WBFM note. Restored, in
|
| # | tree | ctest |
result |
|---|---|---|---|
| 1 | 73d31cca |
-j4, all 524 |
523 / 524 — vkamp_connection_test failed |
| 2 | dc6581c9 (this push) |
-j4, all 524 |
523 / 524 — hl2_txdsp_test failed |
| 3 | dc6581c9 |
-j2, the five HL2/DSP tests + vkamp |
5 / 5 pass, 0 underruns |
Run 1's tree differs from the pushed commit by zero code lines — all 23 differing lines are // comments, checked mechanically rather than eyeballed. Run 2 is the pushed commit: configure and build clean, and no compiler warning in any file this commit touches.
Why both failures are the machine, and what would have changed my mind. They are different tests in the two runs, which is already the signature of load rather than a defect. Run 2's is the sharper case and it is worth quoting, because it names its own cause:
HL2 TXA modulator: block not placed on the wire (underrun), 1 of 82 blocks so far.
The caller is feeding faster than the channel can drain, or the channel has stalled.
FAIL: reset regression has no underruns
One block of 82. In the same run, the characterisation sweep hit the same starvation at 500 Hz and at 150 Hz, printed retrying (attempt 2 of 3) and recovered — hl2_txdsp_test's sweep has the retry wrapper this file's own comment argues for, and the reset-regression leg does not. Every substantive assertion in that run passed with the usual figures: USB 320.71 dB, LSB 320.51 dB, DIGU 150 Hz 180.62 dB. The machine was at load average 130–140 with the build at nice 5, which is the condition hl2_txdsp_test documents beside modulate(): "measured under a load average of 252, this file and wdsp_channel_test both starved, and the sideband assertions then failed saying the chain had regressed."
At -j2: zero underruns anywhere, hl2_txdsp_test green in 164.71 s, and vkamp_connection_test — run 1's failure — green too.
The check that actually rules my diff out, because "it's a known flake" is the answer I would distrust in someone else's comment: this commit changes zero code lines in hl2_txdsp_test.cpp, wdsp_channel_test.cpp, Hl2TxDsp.h and Hl2TxDsp.cpp — every edit in those four files is inside a // comment. The only executable change in the whole commit is in Hl2Backend::gatherDspChains, and the test that covers it, hl2_dsp_readback_test, passed in all three runs.
CI on dc6581c9: Static checks and Sanitizer option configures green; build, check-macos and check-windows still running at the time of writing. Worth saying plainly that CI green proves less here than usual, for the reason your review already gave about this PR: no job ever set the removed flag, so nothing in CI exercises what changed. hl2_dsp_readback_test is the job that does.
Not run, and stated rather than implied: no radio was keyed, no antenna port was touched, no hpsdrsim, no socket, no bench cell. Nothing in this follow-up is measurable on a radio — it is comments, one readback branch and one restored note. The WBFM path in finding 3 remains reasoned from source and not observed, exactly as you flagged it.
🤖 Generated with Claude Code
|
One dependency worth stating, having considered holding this PR and decided not to. #5911 reports that v26.9.4's TXA default changed the character of transmitted audio — a sharper skirt and symmetric pre-ringing around the onset, from We are not asking for a hold. The comparison point is not a reason to keep dead code, the history carries it, and the TXA path measures cleanly on every distortion metric we could resolve. But a reviewer should decide that with the dependency in view rather than discover it afterwards, and if #5911's question — whether the 300–2700 passband is the intended shipped voice bandwidth now that the modulator actually enforces it — is one anyone wants measured both ways, that measurement gets harder the moment this lands. 🤖 Generated with Claude Code |
One textual conflict, in docs/architecture/radio-capabilities-map.md's receiveOnlyModes row: this branch had re-premised the HL2 rationale (the phasing modulator is gone; the list stays because nothing has measured TXA in those modes and WDSP TX has no WBFM mode), and main (ca29208, aethersdr#5879) had rewritten the alias sentence after setSliceMode and applyRestoredState began canonicalising. Both kept: this branch's premise, main's alias wording. Three places main added that still argued from AETHER_HL2_TX_TXA's two builds, all from ca29208, adapted to the single TXA path rather than reintroducing the option: - Hl2Backend::capabilities(), the fmTonePresentation comment - tests/hl2_fm_controls_declaration_test.cpp, the file header - radio-capabilities-map.md, the fmTonePresentation row The argument itself is unchanged: FM/NFM are refused by receiveOnlyModes, not by the modulator, and TXA's chain does carry fmmod. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged The conflict. There was one textual conflict: the Stale references from main.
The argument is unchanged. FM and NFM are refused by What was checked.
Verification was run on macOS / arm64 at
No radio was keyed and no bench run was taken; nothing in this merge can be measured on a radio. |
b785440 to
3d89544
Compare
|
Force-pushed |
|
Re-verified on repaired hardware. The keyed runs cited in #5779 and here came from my HL2 while it had a hardware fault: a bad joint at AD9866 pin 1 that corrupted TX DAC bits 11 and 5 (see the correction comments on #5354 and #5943). After the repair on 2026-09-27 I keyed TXA again, using v26.9.4, where TXA is the default, into a dummy load:
So TXA stands on healthy hardware, and nothing in this PR relied on the phasing modulator's figures from the faulty unit. |
…nciple VIII. main() skipped under `#if !AETHER_HL2_TX_TXA`. aethersdr#5906 removes that build option and with it every definition of the macro, and an undefined macro reads as 0 in #if -- so after aethersdr#5906 this test would skip itself, report Passed, and run none of its checks. Found by a local integration build of the open HL2 PRs: on aethersdr#5906 + this branch it printed the phasing- modulator skip line. Skip only when the macro is DEFINED and 0, i.e. an explicit phasing build. Verified on aethersdr#5906 + this branch: the test runs and passes.
|
I ran the TX-path tests this PR touches under the sanitizers locally, at
So this branch will show that test red in a sanitizer lane until it takes main. I have not merged main into it here, and I have not run the merged result; main alone passes, as shown above. Three limits on everything below:
Flags, from
Configured with Results, five runs each:
The TSan reports (132 to 136 per run, 28 distinct signatures):
Positive control for the ASan + UBSan lane: a small program with a signed overflow and a heap use-after-free, built and run with the same flags and options, reports both. Still not run: the weekly lane itself (Linux, instrumented Qt, leak detection on, whole suite). 73, ON8ST |
jensenpat
left a comment
There was a problem hiding this comment.
Issue fit and purpose
Reviewed head 3d895446ac0f77161a0a15b46f9ce467a53113c4. This is a proposal to retire HL2's compile-time phasing-modulator fallback, not a fix for a presently broken fallback. #5779 made TXA the default, and no workflow explicitly builds AETHER_HL2_TX_TXA=OFF. The author reports that the OFF baseline still builds and passes. Deletion removes this one unexercised configuration; it does not solve #5796's general optional-dependency coverage problem.
The actual maintainer ruling on #5678 explicitly endorses a build option as the way back. The PR now correctly acknowledges that it asks Jeremy (@ten9876) to revisit that ruling. I found no subsequent maintainer approval of removal in this PR. #5911 remains open and describes changed TX audio after the TXA default flip; its comparison used the very OFF configuration removed here. This makes fallback retirement a substantive maintainer decision, not an inevitable cleanup. My proposal is to retain the fallback and add an explicit OFF configure/build lane in a suitable existing periodic workflow unless Jeremy deliberately chooses retirement. This is not a claim that the default TXA path is defective.
Scope
| File/group | Change | Claimed? | Verdict |
|---|---|---|---|
CMakeLists.txt |
Removes option and exported macro | Yes | Central retirement decision |
Hl2TxDsp.{h,cpp} |
Deletes phasing implementation and selects TXA unconditionally | Yes | In scope |
Hl2Backend.cpp |
Unconditional TX setup step; simpler configured readback; rationale updates | Yes, including follow-up | In scope |
AutomationServer.cpp, IRadioBackend.h, WdspChannel.cpp |
Comment corrections and WBFM limitation documentation | Body/commit/follow-up | In scope; comment nit below |
Four HL2 test files and wdsp_channel_test.cpp |
Removes OFF-only branches; retains TXA assertions; updates declaration wording | Yes | In scope; no new regression test |
HERMES.md, capabilities map, bridge documentation, TXA configuration document |
Documents sole remaining path; preserves historical measurements | Yes | In scope |
No unrelated feature, UI preference, new dependency, new keying verb, capability expansion, enforcement-baseline growth, or CHANGELOG edit found. The default-path assertions retain their existing thresholds. The deleted receive-only-mode identity block was already disabled in the default build; deleting it removes fallback-specific evidence rather than coverage running in today's default.
Blocker
- Current-main integration fails.
src/core/AutomationServer.cpp:5183,src/core/backends/IRadioBackend.h:1008,src/core/backends/hl2/Hl2Backend.cpp:5773,src/core/backends/hl2/Hl2TxDsp.cpp:21, andsrc/core/backends/hl2/Hl2TxDsp.h:29:git merge-tree --write-tree 3d895446 68cdf661exits 1 with content conflicts in all five files. GitHub also reportsCONFLICTING. Preserve the intervening main changes when updating the branch, then rerun the appropriate checks. All five displayed check contexts succeeded, but their pull-request runs were created 2026-09-26 16:20:27 UTC; current main68cdf661was committed 2026-10-01 23:59:33 UTC. Those runs do not validate the current integration.
Non-blocking nits and decision
- Retirement needs a maintainer decision (
CMakeLists.txt:146,Hl2TxDsp.cpp:23). GOVERNANCE reserves architecture and feature scope to the project maintainer. The prior explicit compile-time fallback decision is still the relevant authority. Either obtain Jeremy's ruling to retire it, or keep it and exercise OFF builds. I am not manufacturing a new RFC violation for deletion of an optional build branch. - Closing-issue linkage contradicts intent (PR body, “What this does not cover”; deletion at
CMakeLists.txt:146).closingIssuesReferencescurrently lists #5796, despite the body saying it should remain open. GitHub recognizes the closing phrase even in a negated sentence. Rewrite it as “#5796 remains open; this addresses only its HL2 example” and verify that the closing linkage disappears before merge. - Keep rationale concise and current (
Hl2TxDsp.cpp:21-82,Hl2Backend.cpp:5776-5793,WdspChannel.cpp:1091-1122). The new prose repeatedly retells earlier failures/reviews and the readback paragraph cites a Constitution principle in code. AGENTS' Comments guidance says “History does not go in code” and “don't cite Constitution principles in code.” Retain short invariants and link the existing document; move the narrative to the PR. Also qualifyHl2TxDsp.cpp:80's “at every asserted point”: the body itself acknowledges a resolvable TXA skirt in the asserted widest-passband rows. “At the two comparison points above” is the precise scope of that table.
Verification and attacks
- Empirically preprocessed merge base
33c0032cand head with Clang, removing include directives only, withAETHER_HL2_TX_TXA=1, then compared C++ tokens.Hl2TxDsp.cpp,Hl2TxDsp.h,WdspChannel.cpp,hl2_fm_controls_declaration_test.cpp, andwdsp_channel_test.cppare token-identical. This supports unchanged default implementation; it is not a compile or runtime test. The family-transition test differs in assertion text, as disclosed. - Ran engine-boundary, touchpoint-manifest, capability-record, and command-plane gates on base and head. Both pass; engine findings are byte-identical (102 tracked findings, zero strict blockers), 71 capability booleans and 413 raw commands are unchanged, and the manifest is current. No new #5554 seam violations found in the diff.
- Inspected configured/unconfigured readback, refused channel creation, signed passband routing, retained no-conjugation rule, TX progress counting, removed symbols, and test thresholds. The configured-channel invariant supports removing the phasing readback alternatives. WBFM validation behavior is unchanged and was not represented as a new fix.
- Test-boundary notification: modified
tests/hl2_family_transition_test.cpp:63,79reaches real TCP/UDP connection paths via RadioModel against TEST-NET addresses. It is registered in CTest, outside the ordinary per-PR filters. Notified the operator before continuing; did not build or execute this target. Other changed tests were inspected for socket ownership; no new fake firmware peer was introduced. - Local build/tests not run; no test mutation run. The author's 524/524 and later 546/546 reports were read, not independently reproduced. No app or bridge instance launched: the demo backend cannot exercise the removed HL2 compile-time path or HL2-specific readback, and default-path equivalence does not establish on-air TXA quality. No live hardware contacted or keyed. A separate automated code-review skill was unavailable; existing bot findings were checked against the updated source.
Recommendation
Request changes for current-main conflicts. Independently, needs maintainer decision on retiring the fallback. The diff appears mechanically coherent for the default TXA configuration, but that does not answer whether the working escape hatch should be removed. Resolve that decision first, correct the #5796 linkage, and validate a conflict-free updated head.
|
Closing this proposal: we are keeping the compile-time phasing-modulator fallback per Jeremy's guidance on #5678. His ruling explicitly endorsed a build option as the way back, with no runtime switch: #5678 (comment) The lack of an OFF build lane does not supersede that decision. #5796 remains open as the separate optional-configuration CI coverage question. Closed at @jensenpat's direction. |
…iple VIII. Merge of origin/main (2d57129) into hl2/tx-am-fm. This branch was stacked on aethersdr#5906, which removed the AETHER_HL2_TX_TXA build option and the phasing modulator. aethersdr#5906 was closed unmerged: the build option stays as the way back. So this merge reverts, in effect, the three aethersdr#5906 commits the branch carried (98d49fd, 0ab048b and the merge 3d89544): the option, the phasing modulator and its tests are back exactly as on main. The PR's own change (806affb, AM, DSB and FM through TXA) is re-applied on main with the option kept: - AETHER_HL2_TX_TXA=ON (default): AM, DSB, FM and NFM come off receiveOnlyModes and transmit through TXA, as 806affb proposed. - AETHER_HL2_TX_TXA=OFF: unchanged from main. Those modes stay on receiveOnlyModes and key-on is refused, because the phasing modulator only distinguishes sidebands and would send them as USB. - Hl2TxDsp::txaPassband() feeds the TXA arm; isLowerSideband() stays, in the phasing arm only. - The declaration tests assert the list for the build they are compiled in; hl2_txdsp_test measures AM, DSB and FM under #if AETHER_HL2_TX_TXA and keeps the phasing build's bit-identical-to-USB block. - Comments this PR adds are brought to five lines or fewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebase the effective change from PR aethersdr#5977 onto current main, consolidating the obsolete aethersdr#5906 stack and subsequent merge resolutions. Keep AETHER_HL2_TX_TXA and its phasing fallback intact. Preserve mode-specific TXA filtering, explicit AM/FM parameters, CTCSS-off policy, offline DSP coverage and user documentation. Refs aethersdr#5678. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Rebase the effective change from PR aethersdr#5977 onto current main, consolidating the obsolete aethersdr#5906 stack and subsequent merge resolutions. Keep AETHER_HL2_TX_TXA and its phasing fallback intact. Preserve mode-specific TXA filtering, explicit AM/FM parameters, CTCSS-off policy, offline DSP coverage and user documentation. Refs aethersdr#5678. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Enables Hermes-Lite 2 AM, DSB and simplex FM/NFM transmit in the default WDSP TXA build, addressing row 1.2 of #5678. The TXA build uses a symmetric audio passband, explicitly sets the AM carrier level to 0.5 and FM deviation to 5000 Hz, and disables TXA's default-on CTCSS encoder on every transmit-channel open. No tone or repeater-offset control is added. `AETHER_HL2_TX_TXA=OFF` retains the phasing modulator and its existing receive-only restriction for AM, DSB, FM and NFM. SAM, WBFM/WFM and DRM remain receive-only in both builds. Existing TX intent gates and TUNE generation remain intact. #5678 stays open. The branch is rebased onto main `5813556e0709e31d5535281b3eda02da3b2338d8`, with the obsolete #5906 stack and intervening merge commits consolidated into the effective change. on8st retains authorship and the existing AI co-author credit. ## Validation - macOS arm64 / Qt 6.12.0 at `c310a5aa27be0d355a69514f632e74c922f20770` (before the final clean rebase): seven selected socket-free CTests passed with `QT_QPA_PLATFORM=offscreen` (`hl2_txdsp_test`, `wdsp_channel_test`, `hl2_family_transition_test`, `hl2_fm_controls_declaration_test`, `hl2_mode_vocabulary_test`, `hl2_dsp_readback_test`, `control_receive_test`). - The TXA IQ test measures AM carrier/sidebands, suppressed-carrier DSB, FM envelope and deviation, and absence of the default 100 Hz CTCSS tone. It also checks USB→AM→USB mode/filter changes. - `AETHER_HL2_TX_TXA=OFF`: all six flag-sensitive CTests passed again at final head `980e5d219d5d7c4f35cb4b11f7003de34c5a34a4`, including the phasing modulator's bit-identity evidence and the longer receive-only list. - Mutation: reversing the build-option condition in the live backend made `hl2_fm_controls_declaration_test` fail its FM/NFM capability assertion. The mutation was restored and is absent from this head. - The initial default test run found an older staged QtKeychain loading Qt 6.11 alongside 6.12. The default TXA IQ test and mutation were repeated with the matching Qt 6.12 Keychain library, and the OFF suite used that library; all expected outcomes held without the duplicate-framework warning. No repository code change was needed. - Measured offline IQ: AM carrier 0.50000 and equal sidebands 0.12500 (−12.04 dBc); DSB sidebands 0.25000 with carrier suppression above the test's 60 dB threshold; FM deviation 1676.4 Hz at the test's 2 kHz/0.5 tone, halved by halving either level or deviation setting, envelope spread 0.0021, and 100 Hz component 0.00 Hz. - The final rebase changes only the inherited KPA500 integration. HL2/WDSP production code and all seven selected test sources are byte-identical to the default-build validation head; that default DSP evidence is reused, and fresh platform CI validates the new integration. - Both the default focused build and `npm ci && npm run build` passed. Build-option, test-registration, WDSP-link, generated-reference and log-analyzer checks passed. - Engine boundary, touchpoint manifest, capability-record and command-plane gates passed with identical findings against current main and the rebased head. No workflow or ratchet baseline was changed. The tests exercise real WDSP DSP channels offline and do not open a radio connection. The automation bridge's demo backend cannot exercise HL2 transmit modulation; no live hardware was contacted or keyed during this review. RF measurements from the earlier `806affbd` head remain historical evidence only and are not proof of this rebased head. Sanitizers and a local full-suite run were not run in this pass. No CI lane builds the option-OFF configuration (#5796). The user guide and capability map describe the current mode policy. The log analyzer's moved HL2 source citation is refreshed. The AM carrier and FM deviation remain fixed internal parameters; no operator control reaches them. Speech-level FM deviation can be below 5 kHz because pre-emphasis precedes modulation. AM carrier power is one quarter of PEP. Generated with OpenAI Codex (GPT-6 Astra) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The correction this PR has to lead with
#5678's go/no-go was answered, and the answer endorsed the build option this PR removes.
@ten9876 ruled on 2026-09-16, item 2 of that comment:
That condition was met:
Hl2TxDspselects one modulator at compile time and there hasnever been a runtime switch. So this is not a PR that finishes an unanswered question.
It asks the maintainer to revisit a ruling already made, on the strength of something that
changed two days after it — see the next section.
A second attribution needs fixing while I am here, because the
CMakeLists.txtcomment thisPR removes gets it wrong. That comment says "The approval on #5678 was conditional" and
quotes "until the TXA path passes the extended suite AND HAS HAD HARDWARE TIME". That
sentence is aethersdr-agent's triage recommendation of 2026-09-13, not the maintainer
response. @jensenpat already said so on #5779:
Removing the option removes the mis-attributed paragraph with it, but the correction is
worth stating rather than deleting quietly.
The fact that changed
#5779 flipped the default to ON on 2026-09-18, and no CI job compiles the other side.
git grep -n 'AETHER_HL2_TX_TXA' -- .github/on currentmainreturns nothing at all —not just no workflow, no file, and there is no
CMakePresets.jsoneither. Every workflowjob that configures this tree takes the CMake default:
ci.yml's build, check-windows andcheck-macos;
full-suite;sanitizersandappimageandmacos-dmg(two matrix legseach);
codeql;windows-installer;system-libs-canary; andstatic-checks'ssanitizer-option, which configures three times into/tmpand never builds.So the default is the only configuration CI compiles —
CMakeLists.txt's own wording.While the default was OFF, the fallback was the compiled path for free. Since the flip:
tests/hl2_txdsp_test.cpp's#if !AETHER_HL2_TX_TXAblock compiles in no CI build;#elsecrest-factor assertion in the slider-top leg of the same file;Hl2TxDsp.cpp— a preprocessor region, not a wholetranslation unit — is no longer preprocessed into any CI build, so nothing syntax-checks
it there.
A fallback that no job compiles is not a fallback. The first thing an operator flipping
the flag after a bad TXA report would discover is whether the branch still builds.
And the honest counterweight, measured rather than assumed: it still does. Before
deleting anything I configured this branch's base with
-DAETHER_HL2_TX_TXA=OFFand builtand tested it — 524/524 pass, zero failures (see Verification). The way back is intact
today. So this PR is not rescuing a path that has already rotted; it is arguing that a
path nothing guards will rot without anyone finding out, and that a way back which has to
be re-verified by hand before it can be trusted is not the reassurance the option was kept
for. A maintainer who weighs that differently has a real fact on their side, and it is
this paragraph.
This is disclosed, not discovered.
aethersdr-agentraised it as finding 3 on #5779and named the remedy — "Either add an
OFFconfigure+build lane in this PR, or amend155-156 to say plainly that the fallback is no longer built by any configuration" — and
the second option is what landed.
CMakeLists.txt's comment block says it in its ownwords today, including "THE WAY BACK EXISTS ONLY WHILE IT STILL COMPILES, AND NOTHING
WOULD NOTICE WHEN IT STOPPED." This PR takes the third option that comment does not
list: stop shipping a way back that nothing keeps open.
What the source shows
Derived at
main7c8fdf84, not quoted from notes. 42 references to the macro acrossseven build/source/test files, plus 9 across three documents and 1 in
CHANGELOG.md.Those eleven files are the only ones on
mainthat contain it.CMakeLists.txtoption(), its ~65-line comment block, and theif/elsethat defines the macroPUBLIConaethercoresrc/core/backends/hl2/Hl2TxDsp.cpp#if !AETHER_HL2_TX_TXAblackman()anonymous namespace; the#elsephasing implementation (buildModulator,applyModeAndFilter,resetModulatorState,modulate,modulatorName,wdspChannelId,channelConfig, both counters) — 137 lines; the guard insetFilter(); two comment blockssrc/core/backends/hl2/Hl2TxDsp.h#elsemember block (kTaps,m_bandpass,m_hilbert,m_hist,m_histPos)src/core/backends/hl2/Hl2Backend.cppbeginDspSetup'sactualNumRx + (AETHER_HL2_TX_TXA ? 1 : 0); the guarded "Preparing the transmit chain…" stage emit; a readback commenttests/hl2_txdsp_test.cppfeed()and in the reset regression; thekMinSuppDb/kMinLowEdgeSuppDb/kModulator#if; the plumbing-check block; the#if !AETHER_HL2_TX_TXAreceive-only-modes block; thesettledFloorternary; the crest#if/#elsetests/hl2_dsp_readback_test.cppif/else, a bareifand a comment, all over thehl2-txreadback shapetests/wdsp_channel_test.cppdocs/HERMES.md,docs/automation-bridge.md,docs/hl2-txa-configuration-diff.mdmodulatorreadback vocabulary and the configure-line guidanceCHANGELOG.mdv26.9.4section and is a historical record of what shippedTwo comments elsewhere still describe the HL2 as running "a hand-written phasing
modulator on transmit" —
src/core/AutomationServer.cpp(gatherDspChainsdoc) andsrc/core/backends/IRadioBackend.h(thedspChainscontract). They are already wrong onmaintoday and are corrected here.backend.chains[].modulatorstays in the readback and still readswdsp-txa. Thefield is a bridge contract and its purpose — making a transmit report name the chain that
produced the signal — does not depend on there being two answers.
The instrument this rests on
hl2_txdsp_test'sbinPowersideband gate is the instrument TXA's correctness is checkedagainst, and its history matters: #5810 fixed it after it was found measuring its own
epsilon guard rather than the modulator. It now discards the same 12288-sample settling
prefix in the sweep as in the asserted blocks, uses
1e-30in place of an epsilon thatdominated small image bins, raises the TXA regression threshold from 100 to 140 dB, and
labels floor-limited figures
UNRESOLVED, neither bound nor measurement.It is now a sound regression gate, which is not the same as right. #5810 says so
itself — "This is a regression gate, not a guarantee of true suppression", and "Neither
the test nor these changes establish actual floor-limited TXA suppression" — and the file
repeats it beside the constant. It is also not the only instrument:
wdsp_channel_testruns the same fourteen tones against a raw TXA channel at the live geometry, sharing no
code with
hl2_txdsp_testbut the arithmetic, and the two agree at DIGU 150 Hz. Thatagreement is worth more than either figure, and it survives this PR untouched.
What was NOT measured
Nothing in this PR ran on a radio, and removing a fallback is not measurable on one.
The argument is build-time plus the record that already exists:
transmitter, no dummy load, no antenna, no
hpsdrsim, no socket. It ranhl2_txdsp_testin both configurations off one tree at57b80ed4. At each of its fourasserted DIGU points TXA's opposite-sideband image sat at or below the instrument's
numerical floor and the incumbent's did not; the incumbent read 22.06 dB at DIGU
150 Hz on {150, 3000}, reproducing test(hl2): characterise TX opposite-sideband suppression across the passband — 22 dB at 150 Hz, measured #5741's measured figure exactly. The TXA figures
are floor-limited and are not suppression values — 180 dB / 292 dB must not be quoted
as TXA's suppression. One run per configuration, no spread.
57b80ed4the TXA thresholds were
kMinSuppDb = kMinLowEdgeSuppDb = 100.0;kFloorLimitedSuppDb,floorMark(), the 12288-sample sweep prefix and the1e-30epsilon did not exist.d109's TXA numbers therefore came off the instrument test(hl2): the TX sideband gate was measuring itself, not the modulator #5810 corrected, and have not
been re-derived on the corrected one. The incumbent's side is unaffected — the
phasing thresholds were 30.0 / 20.0 before and after, and test(hl2): the TX sideband gate was measuring itself, not the modulator #5810's own validation
records DIGU 150 Hz still reading 22.06 dB — so the positive control survives and the
TXA figures are the ones to treat as provisional.
hl2_txdsp_testnames the exception itself: at the{0, 4000}low edge "a TXA skirtis still resolvable and this sweep measures it" — 59.37 dB at 100 Hz on a wanted bin of
4.995e-01 against an image of 5.372e-04, and 142.26 dB at 150 Hz. That row is asserted,
against a 5.0 dB passband floor. It is the widest passband
Hl2Backend::setTxFilteradmits and it is where an operator who widens all the way would live. Removing the
fallback does not change it, but a body that said "at every asserted point" without it
would be claiming the universality the file spends a paragraph denying.
CMakeLists.txt(2026-09-17, board id 6, gateware 74) are a 1 kHz dummy-load tone andvoice SSB on an antenna; the same comment says TXA's advantage at 1 kHz is below the
EP2 wire and unusable. @jensenpat's approval of build(hl2): default AETHER_HL2_TX_TXA to ON — the volunteer keyed it, into a load and onto an antenna #5779 records the remaining gap in its
own words — the CHANGES_REQUESTED review of 2026-09-18, not the approval that followed
it 19 minutes later: the later handedness evidence at 150 Hz with the digital passband
geometry is "not a DIGU/DIGL end-to-end run or a measured suppression floor." That limitation
is unchanged by this PR and is not claimed closed — if anything, removing the fallback
makes it matter more, which is a reason for a maintainer to weigh it rather than a
reason to hide it.
What this costs, stated rather than lost
1. The crest-factor assertion keeps an equivalent. The
#elsearm asserts whole-runcrest < 1.05; the#ifarm assertscrest(settledTail(...)) < 1.05. The window differsfor a documented reason — a TXA channel's
create_slewsmute ramp is deliberate T/Rshaping that raises whole-run crest legitimately (measured in the file: whole run 1.0684,
settled tail 1.0000) — and the fault the whole-run window guards, a key-on window of
flat-topped modulator input, is pinned in both builds by the whole-run clamp check
check(mx < 0.999, ...)beside it. Deleting the#elseremoves an assertion noconfiguration compiles today and loses no coverage that runs.
2. The receive-only-modes evidence block is a real loss, and it is the one worth
reading.
tests/hl2_txdsp_test.cpp's#if !AETHER_HL2_TX_TXAblock is the evidencebehind
Hl2Backend::capabilities()'sreceiveOnlyModes: it proved AM, SAM, DSB, FM, WBFMand DRM are bit-identical to USB through the modulator, which is stronger than
asserting that a list contains strings. It was written with a deliberate tripwire — "If
someone later teaches this chain a real AM or FM modulator, this block FAILS, which is the
point: the failure is the reminder to take that mode back off the receive-only list" —
and TXA is that modulator:
Hl2TxDsp::applyModeAndFiltercallsWdspChannel::setMode(m_config.mode), so AM/SAM/FM/DSB take real WDSP transmit modes. Theblock was guarded out rather than resolved when TXA landed — its own comment says "in the
TXA build every assertion here fails -- seven of them -- while nothing is wrong" and
"That reminder is hereby taken, and it is NOT this PR's to act on." So the tripwire has
already fired; what this PR deletes is the record of it having fired and been deferred.
That is a smaller loss than an armed trap and a real one: the record was in the one place
a future editor of the modulator would trip over it.
The concrete consequence is in a second file.
tests/hl2_family_transition_test.cppasserts
caps.receiveOnlyModes.size() == declared.size()under the message "HL2 declaresexactly the modes hl2_txdsp_test carries evidence for", and its comment above says "hl2_txdsp_test
proves the modulator half … What that test cannot see is the DECLARATION." After this PR
no test carries that evidence in any configuration, so the assertion cites something that
no longer exists. Both are corrected here to say what they now actually check — the
declaration, not the modulator — with the reason written in. That is a downgrade in
coverage, stated rather than papered over. The question it defers is a capability
decision belonging with #5678 rows 1.2 / 6.2 / 6.3, and it is not this PR's to make.
3. One stale claim fixed on the way past.
Hl2TxDsp.cpp's rationale comment stillsays "Every TXA figure above is a LOWER BOUND, not a value" and prints
>= 180.6 dB.#5810 retracted exactly that phrasing in
hl2_txdsp_test.cpp— "AN EARLIER VERSION OFTHIS COMMENT CALLED THEM LOWER BOUNDS. That was wrong" — because the correlation error is
a complex vector and can oppose the image as easily as add to it. The correction never
reached
Hl2TxDsp.cpp. This PR rewrites that comment anyway, so it is fixed here: thefigures are floor-limited and
UNRESOLVED, neither bound nor measurement.What this does not cover
This removes one instance of the class #5796 names, not the class. #5796 —
"No CI job builds the optional-dependency-OFF configuration — three build breaks on main
in one week", opened by @ten9876 — lists the phasing modulator third, after #5706
(
ENABLE_DFNR=OFF) and #5767 (noHAVE_HIDAPI). Deleting one optional path closesnothing about the other two or about the next one. This PR does not close #5796 and
should not be read as an answer to it.
This is a proposal, and it is one revert away
@ten9876 ruled for a compile-time fallback on #5678 and this removes it, so the decision
is not mine and not ON8ST's to take by merging. What I am asking for is a ruling on one
narrow question: is a way back that no configuration builds worth keeping, given that
nobody would learn it had stopped working until they needed it? There are three
defensible answers and only the first is this PR:
exercise. This diff.
AETHER_HL2_TX_TXA=OFFconfigure+build lane toci.ymlorfull-suite.yml, which is whataethersdr-agentasked for on build(hl2): default AETHER_HL2_TX_TXA to ON — the volunteer keyed it, into a load and onto an antenna #5779 andwhat ON8ST declined to do unilaterally because a workflow change is a maintainer's
call. Close this PR and I will send that one instead.
is documentation of a decision rather than a working escape hatch. That is roughly
where
mainstands today, and it is a coherent position; it just deserves to bechosen rather than arrived at.
While this PR is open nothing is lost: the phasing modulator is one
git revertaway andthe base it is cut from is recorded below. If it merges and TXA then disappoints on the
air, the revert is still the remedy — the difference is that it becomes a deliberate act
with a review rather than a flag somebody flips alone.
Verification
Branched from
origin/mainat7c8fdf84. macOS 15 / arm64, RelWithDebInfo, theconfigure line
AGENTS.mdmandates:Three full builds and three full
ctestruns, in this order. The first two are thebaselines, taken before anything was deleted, because "the fallback no longer builds"
would have been a different PR and had to be ruled out rather than assumed:
ctest(524 tests)hl2_txdsp_test7c8fdf84, untouched-DAETHER_HL2_TX_TXA=OFF7c8fdf84, untouched-DAETHER_HL2_TX_TXA=ONRun 1 is the one that matters to the argument, and it argues against me. The fallback
compiles today and passes the whole suite today. Nothing here is a rescue.
The
hl2_txdsp_testdurations are the pacing difference, not a regression: the TXAmodulator is driven at the configured audio rate because a
blockForOutput = falsechannel starves under an unpaced feed, which the file documents beside
feed().Run 3 was configured fresh —
rm -rf build, no cache carried over — so the removed optioncannot be sitting in a cache entry: CMake prints no "HL2 transmit modulator" line and no
unused-variable warning, and the
Build SHA:stamp was taken after the commit rather thanbefore it.
vkamp_connection_testandwdsp_channel_testare known to flake under-j4on thismachine; neither did in any of the three runs, so no re-run at
-j2was needed.Not run, and stated rather than implied: no radio was keyed, no antenna port was
touched, no
hpsdrsim, no socket, and no bench cell was taken for this PR. The d109 runcited above is quoted, not re-taken, and is flagged as predating #5810.
🤖 Generated with Claude Code