Skip to content

fix(trace): REQ-PTT-01's statement was a paraphrase; add REQ-PTT-04 (#1411) - #1412

Merged
dc0sk merged 2 commits into
mainfrom
feat/1411-keying-requirement
Sep 19, 2026
Merged

dc0sk merged 2 commits into
mainfrom
feat/1411-keying-requirement

Conversation

@dc0sk

@dc0sk dc0sk commented Sep 19, 2026

Copy link
Copy Markdown
Owner

REQ-PTT-01's yaml statement restored to its ratified prose and re-pointed covered_by: CAP-74 → CAP-59; new REQ-PTT-04 (enforced, CAP-59) for the keying property that had no id; three // VERIFIES: REQ-PTT-04 bindings; the kiss keying test added to CAP-59's tests:; prose added to requirements.md.

The issue half-dissolved, and the reason is a registry defect

#1411 claimed no requirement states the PTT keying property. True for one half, false for the other — my sweep searched the yaml statement: fields, and the ratified prose says something else:

requirements.md:398-402 — Every PTT-keyed transmit scope shall release the transmitter deterministically on scope exit — including on an early return or a panic/unwind — via an RAII guard … (REQ-PTT-01)

The yaml carries PTT assert/release within 50 ms. Provenance by git log -S:

commit what it did
f4c10467 (#872) created REQ-PTT-01 as the RAII release guard
daa1676e (#1098) wrote a traceability-matrix row paraphrasing it as the 50 ms clause, citing the wrong test
1da27abd (#1117) imported that row into requirements.yaml as the statement

The importer was later deleted (#1223), so the yaml became source of truth carrying the paraphrase. The code agrees with the prose, not the yaml — shared_ptt.rs:221,413,869 all cite REQ-PTT-01 for the RAII guard. Nothing checks a yaml statement against its prose.

Consequence: the stuck-key failure mode was registered all along, and several trailers #1402 called "defensible but pointing at a timing requirement" are simply right.

A live #1405 instance, fixed here

REQ-PTT-01 was covered_by: [CAP-74] ("PTT backends"), which does not own shared_ptt.rs — the file its own acceptance test lives in, owned by CAP-59. Its coverage was bound to the paraphrase's evidence rather than to its requirement.

What was genuinely missing → REQ-PTT-04

REQ-PHY-07/08 say which PTT backends must exist; nothing said the configured one is used on every emission. Swept unkeyed|stuck key|keys the transmitter|every emission|dead RF|jammed across requirements.md, regulatory.md, the 1.0 criteria, AGENTS.md and the roadmap: zero hits (positive control: 3 in CLAUDE.md). It shipped broken independently in three front-ends with the same silent symptom, which is why the binding sits in each front-end rather than only at the seam.

Capability: CAP-59, not a new one

A "keying discipline" capability owning bridge.rs would recreate precisely what #1399's maintainer decision measured and rejected — extending CAP-59 into its importers turned two ARDOP/KISS receive mislabels into passes, because file-level overlap cannot separate two concerns in one file — and would rebuild the CAP-68 shape flagged the day before. CAP-59 is the registry's own precedent (these tests were twice added to CAP-59.tests) and mirrors REQ-SEC-13/CAP-77: the capability owns the seam, source scans hold the sites.

Two of my arguments were dropped

  • Atomicity was imported. I proposed splitting on iterative-delivery's "requirements must be atomic". Compound statements are this registry's norm (CTL-02, SEC-14, CTL-04, DISC-04, QRM-01). The split stands instead on provenance, evidence tier and mechanism.
  • "Externally observable" was worthless as a criterion — every defect is observable as silence. What survives is the hole between two existing ids.

Corrections to #1411's text

Ten commits carry Implements: REQ-PTT-01, not eight; "PTT-01 is the only PTT requirement" is false (PTT-02/03, PHY-05/07/08); and CLAUDE.md's 50 ms row names REQ-PHY-05 only, so the "control-path and audio-path halves" pairing was mine, not the repo's.

Verification

GATE: PASS 0e42ea2f9d843dd2ebc5f231f4dee45f18bc767d clean 20260919T095255Z

All eleven steps. Run fresh on this exact commit deliberately: the new enforced binding's evidence should not rest on a verdict from an earlier tree.

Implements: REQ-PTT-04

Review: docs/dev/reviews/review-1411-keying-requirement.md

🤖 Generated with Claude Code

https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6

…1411)

REQ-PTT-01's yaml statement restored to its ratified prose and re-pointed
covered_by CAP-74 -> CAP-59; new REQ-PTT-04 (enforced, CAP-59) for the keying
property that had no id; three `// VERIFIES: REQ-PTT-04` bindings; the kiss
keying test added to CAP-59's tests; prose added to requirements.md.

THE ISSUE HALF-DISSOLVED, AND THE REASON IS A REGISTRY DEFECT. #1411 claimed no
requirement states the PTT keying property. True for one half, FALSE for the
other: my sweep searched the yaml `statement:` fields, and the ratified prose at
requirements.md:398-402 makes REQ-PTT-01 the RAII release-on-scope-exit
requirement. Provenance by `git log -S`: f4c1046 (#872) created it that way;
daa1676 (#1098) wrote a traceability-matrix row paraphrasing it as "PTT
assert/release within 50 ms" and citing the wrong test; 1da27ab (#1117)
imported that row into the yaml as the statement. The importer was later deleted
(#1223), so the yaml became source of truth carrying the paraphrase. The code
agrees with the prose — shared_ptt.rs:221,413,869. Nothing checks a yaml
statement against its prose.

A LIVE #1405 INSTANCE, FIXED HERE: REQ-PTT-01 was covered_by CAP-74 ("PTT
backends"), which does not own shared_ptt.rs, the file its own acceptance test
lives in.

WHAT WAS GENUINELY MISSING is now REQ-PTT-04: REQ-PHY-07/08 say which PTT
backends must EXIST; nothing said the configured one is USED on every emission.
Swept unkeyed|stuck key|keys the transmitter|every emission|dead RF|jammed over
requirements.md, regulatory.md, the 1.0 criteria, AGENTS.md and the roadmap:
zero hits, positive control 3 in CLAUDE.md. It shipped broken independently in
three front-ends with the same silent symptom, which is why the binding sits in
each front-end and not only at the seam.

CAPABILITY: CAP-59, NOT A NEW ONE. A "keying discipline" capability owning
bridge.rs would recreate what #1399's maintainer decision measured and rejected
(file-level overlap cannot separate two concerns in one file) and rebuild the
CAP-68 shape. CAP-59 is the registry's own precedent — these tests were twice
added to CAP-59.tests — and mirrors REQ-SEC-13/CAP-77: capability owns the seam,
source scans hold the sites.

THE ATOMICITY ARGUMENT WAS DROPPED AS IMPORTED. Compound statements are this
registry's norm (CTL-02, SEC-14, CTL-04, DISC-04, QRM-01). The split stands on
provenance, evidence tier and mechanism instead.

Implements: REQ-PTT-04

Review: docs/dev/reviews/review-1411-keying-requirement.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6
Second time today: check-doc-stamps.sh reads COMMITTED content, so running it
while the edit is still uncommitted reports a false pass. It is also not a step
in gate.sh, so a green GATE: PASS does not cover it. Run it after committing.
@dc0sk
dc0sk merged commit 7a3b3ea into main Sep 19, 2026
12 checks passed
@dc0sk
dc0sk deleted the feat/1411-keying-requirement branch September 19, 2026 10:49
dc0sk added a commit that referenced this pull request Sep 19, 2026
…ence (#1413) (#1414)

`trace.py` now compares the stored verdict's `commit` against HEAD, degrading to
the same "unverified" NOTE a toolchain mismatch already produces. Two probes
added to `evidence-self-test`.

`_gate_log`'s own comment states the rule — "A verdict is attributable to (tree,
HEAD, TOOLCHAIN)" — and the code checked TWO of the three: INVALID (tree/HEAD
moved DURING the run) and a toolchain mismatch. The commit was never compared.

FOUND BY RELYING ON IT. #1412 added an enforced requirement with a fresh
`// VERIFIES:` binding, and `scripts/trace.sh check` returned PASS on a verdict
taken at an earlier commit — one that predated the binding.

Sabotage-measured before the fix, with a control proving the machinery fires:

    control  : verdict commit == HEAD          -> TRACE: PASS  rc=0
    sabotage : verdict commit := deadbeef...   -> TRACE: PASS  rc=0   <-- unchecked
    control 2: verdict toolchain := bogus      -> NOTE "...run a full gate"

SCOPE, NARROWLY. Inside gate.sh this was never wrong: gate.sh:203 exports
GATE_LOG, so the live log is used and is attributable by construction. In CI the
traceability job has no target/ and already reports run-status unverified. The
hole was the STANDALONE `trace.sh check` path — the one used while AUTHORING a
binding, which is when the evidence claim is first made. Sharper failure it
permitted: rename a test, bind the old name, and the stale log still records that
name passing, so the binding validates against a test that no longer exists.

DEGRADED, NOT FATAL, deliberately: the toolchain case returns (None, reason) and
the caller reports a NOTE. Matching it gives "not attributable" one behaviour and
keeps an ordinary edit-then-check cycle quiet.

The probes are committed rather than performed once: evidence-self-test gains
"PASS from another commit" and "PASS with no commit recorded", both required to
be refused, alongside the existing PASS control that stops the check being
satisfied by refusing everything.

Verification-objective: a stored gate verdict may only vouch for a cited test's
run-status when it is attributable to the tree being checked, so that a binding
cannot be validated by a run that predates it.

Review: none — mirroring the toolchain branch three lines above it, with the
defect sabotage-measured first and the new behaviour probed in both directions.


Claude-Session: https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
dc0sk added a commit that referenced this pull request Sep 19, 2026
#1415)

One `// VERIFIES: REQ-PTT-04` in openpulse-cli. Reachability 281/363 (0.77) ->
363/363 (1.00).

I INTRODUCED THE DEFECT I HAD JUST BEEN FIXING. REQ-PTT-04 shipped yesterday
(#1412) with three bindings — ardop, kiss, daemon — none of whose test binaries
can link openpulse-cli. So cli/radio.rs and cli/commands/calibrate.rs, 82 of its
363 mutants, were unreachable by construction: a fresh instance of #1405,
created in the same week #1405 was filed. Re-measuring the enforced set after
the merge is what surfaced it, not review.

The binding target was checked for vacuity first: the_cli_never_keys_the_rig_by_
hand is a source scan over include_str!'d CLI sources, and its sibling
the_scan_actually_covers_the_files_that_key validates that scan against a
PLANTED bare `.assert_ptt(` call, so it cannot go vacuous. It is also the
acceptance method REQ-PTT-04's own registered text names.

A LIMIT OF THE METRIC, demonstrated by this very change: the ratio reached 1.00
while the kill-power of those 82 mutants did not meaningfully change. A source
scan makes mutants LINKABLE, not KILLABLE — a mutation of calibrate.rs's logic
does not introduce a bare `.assert_ptt(`. Reachability is necessary for a
mutation verdict to mean anything and not sufficient for it to be strong;
#1405's check reports the necessary condition only and should say so.

Implements: REQ-PTT-04

Review: none — applying #1405's own triage pattern to a requirement added two
commits ago; the binding target was read and its planted-violation control
confirmed before binding.


Claude-Session: https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant