You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Surfaced while adjudicating #1402's 29 flagged commits. Not a mislabel — a missing requirement that makes correct trailers look wrong.
The observation
Eight production commits carry Implements: REQ-PTT-01:
d8dfedc9 fix(kiss): the TNC built a SharedPtt and never started its watchdog
63ca1803 fix(repeater): the cross-band relay cannot leave rig_b keyed
68887bd5 fix(daemon): the OTA send stops on a PTT fault without …
fb169538 feat(radio): refuse a second key, defer the ID when …
5d444be2 feat(radio): a PTT guard releases only the key it took
d838d3e9 fix(kiss): key the transmitter for every emission
635010f9 fix(daemon): key the transmitter for every emission
88a0485d fix(ardop): key the transmitter for every emission
REQ-PTT-01's registered statement is, in full:
PTT assert/release within 50 ms
Keying-at-all and keying-within-50 ms are different properties. Not one of those eight is about latency; they are about whether a transmission is keyed, whether the key is released on every error path, and whether a watchdog bounds a hang. They carry PTT-01 because it is the only PTT requirement — there is nowhere better to point.
Why this is a gap rather than sloppiness
The property is real, load-bearing, and already pinned by tests. CLAUDE.md's acceptance table gives it three separate rows:
"Every ARDOP emission keys the transmitter — data, ARQ, IRS ACK/NACK and relay, not just the station ID"
"Every DAEMON emission keys the transmitter — handshake (CONREQ/CONACK), both QSY lines, relay forward and the non-OTA send, which all transmitted unkeyed while five guards sat in server.rs"
"No relay-path error leaves rig_b keyed while the daemon is alive"
So the repo treats it as an acceptance criterion in prose, with tests, while the registry carries only the timing clause. That is the asymmetry: the requirement that actually governs eight merged commits and three acceptance rows does not exist as an id.
It also has regulatory weight — an unkeyed emission is dead RF, and a stuck key is an unattended transmitter (§97.221 territory), which is why openpulse-mesh had its audio route removed rather than guarded.
A new requirement, roughly: "Every transmission keys the PTT for its duration and releases it on every exit path, including errors and unwinds; no path may leave the transmitter keyed while the process is alive." Then re-point the eight (the ledger is the only place a merged trailer can be corrected — see #1410) and give it the three acceptance rows and their tests.
Open questions, which is why this is an issue and not a PR:
One requirement or two? "Every emission keys" and "no error path leaves it keyed" are arguably separate — the second is the safety-critical half and the one with the watchdog.
enforced or baseline? It has real tests today (ptt_keys_every_transmit, ptt_keys_every_daemon_transmit, abnormal_exit_release, shared_ptt), several of which run in the gate, so enforced looks reachable — but that needs the binding checked rather than assumed.
Surfaced while adjudicating #1402's 29 flagged commits. Not a mislabel — a missing requirement that makes correct trailers look wrong.
The observation
Eight production commits carry
Implements: REQ-PTT-01:REQ-PTT-01's registered statement is, in full:
Keying-at-all and keying-within-50 ms are different properties. Not one of those eight is about latency; they are about whether a transmission is keyed, whether the key is released on every error path, and whether a watchdog bounds a hang. They carry PTT-01 because it is the only PTT requirement — there is nowhere better to point.
Why this is a gap rather than sloppiness
The property is real, load-bearing, and already pinned by tests. CLAUDE.md's acceptance table gives it three separate rows:
server.rs"So the repo treats it as an acceptance criterion in prose, with tests, while the registry carries only the timing clause. That is the asymmetry: the requirement that actually governs eight merged commits and three acceptance rows does not exist as an id.
It also has regulatory weight — an unkeyed emission is dead RF, and a stuck key is an unattended transmitter (§97.221 territory), which is why
openpulse-meshhad its audio route removed rather than guarded.Why it matters beyond tidiness
rigctld_ptt_round_trip_under_50msis PTT-01's real evidence, and CLAUDE.md is explicit that it covers the control-path half only — REQ-PHY-05's audio half is deferred to REQ-PHY-05 (PTT drop within 50 ms of the last transmitted sample) has no test covering the audio half #1112. Loading a second, unrelated property onto the same id makes that already-careful distinction harder to keep straight.What would close it
A new requirement, roughly: "Every transmission keys the PTT for its duration and releases it on every exit path, including errors and unwinds; no path may leave the transmitter keyed while the process is alive." Then re-point the eight (the ledger is the only place a merged trailer can be corrected — see #1410) and give it the three acceptance rows and their tests.
Open questions, which is why this is an issue and not a PR:
enforcedorbaseline? It has real tests today (ptt_keys_every_transmit,ptt_keys_every_daemon_transmit,abnormal_exit_release,shared_ptt), several of which run in the gate, soenforcedlooks reachable — but that needs the binding checked rather than assumed.shared_ptt.rs→ CAP-59 was a judgement call. The emission paths live in ardop/kiss/daemon/repeater, none of which those capabilities own.Related: #1402 (where this surfaced), #1410 (the nine corrected trailers), #1405 (reachability), #1112 (REQ-PHY-05's deferred audio half).
🤖 Generated with Claude Code
https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6