Guard the specs against platform-specific modifier chords - #233
Merged
wormeyman merged 1 commit intoAug 17, 2026
Merged
Conversation
wormeyman
force-pushed
the
guard-platform-modifier-chords
branch
from
August 17, 2026 05:39
3b8e174 to
5d6604c
Compare
A vitest text scan over tests/*.spec.ts for `Control+A` and its four siblings. On macOS `Control+A` is the emacs "beginning of line" binding, not select-all, so nothing is selected, the typed text lands beside the old text, and the assertion reads "New textOld text". That is #197, fixed in 402fbe3. It reads source rather than driving a browser because the bug **passes on Linux**, and every runner this project has is ubuntu-latest - `vp test` and all four `e2e` shards. #223 and #225 put Playwright in CI, which does not help here: a sharded browser suite gating every PR will go green on this forever. The rule is not "never write Control". A chord reaching the app through actions.ts stays Control, where ModifierKey is Control | Shift | Alt and no Meta binding exists; a chord reaching a focused DOM <input> wants ControlOrMeta. A regex cannot separate them, so it flags both and the ALLOWLIST carries the distinction in writing - one entry today. Mutation-checked against the live instance: dropping PR #222's blueprint-grid-position.spec.ts into tests/ fails the guard naming line 97, and removing it goes green again. The knowledge already existed in prose. After 402fbe3 there is a five-line comment at display-panel-editor.spec.ts:159 explaining the whole trap, one line above its own corrected call, and a contributor then wrote `Control+A` in a different file. A comment at the scene of the last occurrence does not reach the next one. Every figure in the new file's header is measured rather than recalled, which caught two: the display panel comment is five lines and not three, and four specs hold `keyboard.down('Control')` for the ctrl-drag gesture and not five. Both came from #208's own write-up. Part 1 of #208. Deliberately not `Closes`: that issue's part 2, the display panel editor's uncovered surface (the alt-mode checkbox, the icon picker and the connected branch), is untouched here and is real work. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mg2oe7JgL3xEzSoN5emTsd
wormeyman
force-pushed
the
guard-platform-modifier-chords
branch
from
August 17, 2026 05:41
5d6604c to
4b19d31
Compare
This was referenced Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 1 of #208. Not
Closes: that issue's part 2, the display panel editor's uncovered surface, is untouched here.What it is
tests/spec-modifier-keys.test.tsreads every file intests/*.spec.tsand flagsControl+Aand its four siblings (C,V,X,Z) where they appear as an argument tokeyboard.press.On macOS
Control+Ais the emacs "beginning of line" binding, not select-all. So nothing gets selected, the typed text lands beside the old text, and the assertion receives something like"New textOld text". That is #197, fixed in402fbe31.Why a text scan and not a test that drives something
The bug passes on Linux, and every runner this project has is
ubuntu-latest:vp testand all foure2eshards.When #208 was written, the reason this reached the default branch was that CI never ran Playwright at all. #223 and #225 have since closed that half, and it does not help here. A browser suite that gates every PR on four sharded runners will go green on this forever. The only thing that can see it is something reading the spec source.
The rule, which is not "never write Control"
A blanket ban would be wrong, and the measured usage says so. There are two classes:
actions.ts, staysControl.type ModifierKey = 'Control' | 'Shift' | 'Alt'there, so the app has no Meta binding and Control is the only key that works.<input>, handled by the browser or the OS, wantsControlOrMeta, because that binding differs by platform.A regex cannot tell those apart, so it flags both and the
ALLOWLISTcarries the distinction. An entry has to say which class it is and why. One entry today:chest-filters.spec.ts'sControl+KeyZ, which drives the editor's own undo keybind with no DOM input focused.Meta+is flagged for the same five keys even though nothing uses it. It is the same mistake facing the other way.Not flagged:
keyboard.down('Control')/up('Control'), which four specs use to hold the modifier for the ctrl-drag copy gesture. That is a held modifier for a mouse gesture reaching the app's own handler, and it is correct as written in all of them.Mutation-checked against the live instance
Dropping PR #222's
tests/blueprint-grid-position.spec.tsintotests/fails the guard, naming the real line:Removing it goes green again.
Two things the build turned up
It matches the
.press(call form, not the bare text. The first draft matched the characters anywhere and immediately flaggeddisplay-panel-editor.spec.ts:160- the five-line comment explaining this exact trap, sitting directly above its own correctedControlOrMeta+A. Skipping comment lines does not work here, since this codebase writes block comments as bare indented lines with no leading asterisk. Matching the call form removes the whole question: prose can discuss the bug freely, and what gets flagged is the thing that actually runs.The allowlist is checked in both directions. An entry matching nothing is a justification for code that is gone, and the next person reads a stale justification as a live one. Same membership check
tests/entity-accessors.spec.tsuses on its fixture.Why the class needs a guard rather than another comment
After
402fbe31there is a five-line comment atdisplay-panel-editor.spec.ts:159explaining the whole trap, one line above the fix. A contributor then wroteControl+Ain a new spec in a different file (#222,blueprint-grid-position.spec.ts:97). A comment at the scene of the last occurrence does not reach the next one.Cost
Pure Node, so it runs under
vp testinsidechecksin milliseconds rather than behind the browser job.playwright.config.tspins atestMatchof spec files only, so Playwright does not also collect it.vp check0,vp test184 passed.🤖 Generated with Claude Code
https://claude.ai/code/session_01Mg2oe7JgL3xEzSoN5emTsd