Skip to content

test(tx-safe): repair the emergency-stop wiring guard, which checked only its own text - #200

Merged
dc0sk merged 1 commit into
mainfrom
fix/structural-guards-self-match
Sep 22, 2026
Merged

dc0sk merged 1 commit into
mainfrom
fix/structural-guards-self-match

Conversation

@dc0sk

@dc0sk dc0sk commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Summary

fr_tx_safe_05_estop_is_dispatched_before_all_other_key_handling has checked nothing since 2026-07-21. The emergency-stop code itself is correct — the check is the first statement of the KeyPressed arm. What was lost is the alarm that would catch a future regression.

What was wrong (confirmed before changing anything)

Deleting the real self.send(WorkerCmd::EmergencyStop) left the guard green.

The guard include_str!s all of main.rs and searched for Message::KeyPressed(key, mods) => {. Commit c11b377 gave the arm a third argument, so that text occurred exactly once — inside the guard itself — and every assertion was satisfied by the guard's own literals. Its .expect("the KeyPressed handler must exist"), written to fail loudly on rot, never fired.

A second guard had the same shape: fr_ui_hold_01_tap_hold_wraps_a_non_interactive_visual counted its own match_indices("tap_hold(") line as a seventh call (production has exactly six), so one real popup chip could be deleted and "at least six" would still pass.

The fix

  • source_guard::production() returns only the code above the test modules (its marker is built with concat! so it does not contain itself).
  • The checks are pure functions of a source string, tested on synthetic sources: three arities × three indentations, every kind of code before the check, missing dispatch, dispatch belonging to the next arm, an arm with no check beside a neighbour that has one, dispatch after the block, no return, a multi-line condition with nested calls, arm renamed / only constructed / present twice.
  • The arm is found by shape (Message::KeyPressed() => {), so another argument cannot rot it; finding none is an error, not a pass.
  • Only comments may precede the check. (This replaces a list of named barriers, which would have masked the stricter rule under mutation.)
  • The dispatch must be inside the block the check opens, and that block must return.

Verified by sabotaging the real code

Dispatch deleted · dispatch kept but return deleted · a modal check moved before it · an unrelated statement before it · the check disabled · the arm renamed — all six caught (the first is the one the old guard missed). The tap/hold count is exactly six. 23 mutations of the guards themselves are all killed.

My first version of this fix had a bug of its own, which the real-code sabotage found: it read the arm's indentation from the pattern's position (always empty), so the "next arm" was never found, the arm ran to the end of the file, and deleting the dispatch was still missed. The synthetic test that should have caught it only ran at zero indentation; every negative case now runs at every indentation.

fmt, clippy --all-features, 403 workspace tests, cargo xtask OK.

Merge note

The ledger header is 4.14.1 because the open stack #196#199 uses 4.15+ (and the SRS 0.64+). Whichever merges second gets a trivial conflict in the docs/test/test-strategy.md header and the row above 4.14.

Not covered

The guards on the other branches (TLS, redraw pacing, afterglow) each already slice off their own test modules, and each has its own sabotage evidence. A repo-wide "no test may scan its own file unsliced" check was considered and not added, because it would fail those PRs at merge; say if you want it as a follow-up.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ma4bQKqGNFTYyVSEKPcXRk

…only its own text (FR-TX-SAFE-05)

fr_tx_safe_05_estop_is_dispatched_before_all_other_key_handling read the whole
of main.rs and searched for `Message::KeyPressed(key, mods) => {`. When the arm
gained a third argument (c11b377, 2026-07-21) that text occurred once, inside the
guard itself, and every assertion was satisfied by the guard's own literals. It
had not checked anything since: deleting the real
`self.send(WorkerCmd::EmergencyStop)` left it green (confirmed before changing
anything). The real code is correct.

fr_ui_hold_01_tap_hold_wraps_a_non_interactive_visual had the same shape: it
counted its own `tap_hold(` line as a seventh call, so one of the six real popup
chips could be removed and "at least six" still passed.

- source_guard::production() returns only the code above the test modules.
- The checks are pure functions of a source string, tested on synthetic sources
  (three arities x three indentations, missing/renamed/duplicated arm, code
  before the check, dispatch outside the check's block, no return, ...).
- The arm is found by shape, so another argument cannot rot it; none found is an
  error, not a pass. Only comments may precede the check.
- Verified by sabotaging the real code: dispatch deleted, return deleted, a modal
  check moved before it, an unrelated statement before it, the check disabled,
  the arm renamed - all caught. The first version of this fix read the arm's
  indentation wrongly and still missed the deleted dispatch; the real-code
  sabotage found it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ma4bQKqGNFTYyVSEKPcXRk
@dc0sk
dc0sk force-pushed the fix/structural-guards-self-match branch from be15673 to 37e79d3 Compare September 22, 2026 07:12
@dc0sk
dc0sk merged commit 0623020 into main Sep 22, 2026
5 checks passed
@dc0sk
dc0sk deleted the fix/structural-guards-self-match branch September 22, 2026 08:22
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