Linear: MOR-1628
Parent GitHub: #2541
Parent: MOR-1500
Source authority: origin/main f016380
Outcome
Close the Web handler path that calls set_tuner_status directly and bypasses both the command queue and RadioPoller._execute, while preserving intentional direct CW exemptions.
Owned paths
src/rigplane/web/handlers/control.py
tests/test_web_tuner_tx_interlock.py (new focused test)
Red-first witness
A direct-handler test shows set_tuner_status values 1 and 2 reach the radio during known TX without consulting the interlock.
Acceptance criteria
Dependencies
Blocked by MOR-1500 A0, A1, and A3. It does not require the deferred lane because tuner enable/start is BLOCK, not DEFER.
Scope guardrails
- Anchor: origin/main f016380.
- Maximum 3 owned files and 400 changed LOC.
- Red-first focused tests; foreground timeout 600000 ms; never run the full suite for this child.
- No refactor, new layer, model-name branch, unrelated cleanup, or scope expansion.
- Public API/CLI/config/rigctld compatibility changes must be called out explicitly.
Project fields
Priority=P1; Risk=high; Size=S; Phase=stable; Owner=codex; WorkType=bug.
Linear: MOR-1628
Parent GitHub: #2541
Parent: MOR-1500
Source authority: origin/main f016380
Outcome
Close the Web handler path that calls set_tuner_status directly and bypasses both the command queue and RadioPoller._execute, while preserving intentional direct CW exemptions.
Owned paths
src/rigplane/web/handlers/control.pytests/test_web_tuner_tx_interlock.py(new focused test)Red-first witness
A direct-handler test shows set_tuner_status values 1 and 2 reach the radio during known TX without consulting the interlock.
Acceptance criteria
Dependencies
Blocked by MOR-1500 A0, A1, and A3. It does not require the deferred lane because tuner enable/start is BLOCK, not DEFER.
Scope guardrails
Project fields
Priority=P1; Risk=high; Size=S; Phase=stable; Owner=codex; WorkType=bug.