Skip to content

fix: Reject non-name key filters in record-input#2021

Merged
hatayama merged 2 commits into
feature/cli-discoverability-integrationfrom
fix/record-input-key-filter-name-whitelist
Jul 27, 2026
Merged

fix: Reject non-name key filters in record-input#2021
hatayama merged 2 commits into
feature/cli-discoverability-integrationfrom
fix/record-input-key-filter-name-whitelist

Conversation

@hatayama

@hatayama hatayama commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • record-input --keys now accepts only real key names, so a filter never silently records different keys than the ones asked for.
  • A name that matches no key is reported back in the response instead of being dropped.

User Impact

Before: --keys was parsed with Enum.TryParse<Key>, which also accepts enum ordinals. uloop record-input --action Start --keys 3 started a recording filtered to Key.Tab and reported success, with only an Editor Console warning that an agent driving the CLI never sees. If every entry was rejected, the filter collapsed to "no filter" and the recording captured all keys — the opposite of what was asked — and the response looked identical to a run with no --keys at all.

After: --keys 3 fails immediately with

Invalid key name(s) in the keys filter: 3. Use Input System Key enum names (e.g. "W", "Space", "LeftShift", "Digit3").

Valid names keep working exactly as before, case-insensitively, and Return is accepted as Enter just as simulate-keyboard accepts it.

Changes

  • Key-name resolution moves into KeyNameResolver in the shared Common/InputSystem assembly that both simulate-keyboard and the input-recording assembly already reference. SimulateKeyboardUseCase now uses it instead of its own private copy, so both tools apply one rule.
  • ParseKeyFilter returns a result carrying the parsed keys plus every entry that named no key, and record-input rejects the request when that list is non-empty.
  • Rejecting the whole request rather than filtering with the entries that did parse: a recording is taken once, and a partially applied filter produces a file that looks like the requested one. The all-rejected case is worse still, silently recording everything.
  • The Console warning is gone; the same information now reaches the caller in the response.
  • A filter made only of empty entries (, or ) is rejected too: it would otherwise record every key with a response indistinguishable from omitting --keys. A trailing comma beside a named key stays harmless.
  • Skill parameter table for --keys documents the name rule; the generated tool catalog, the .claude/.agents copies, and the shared release-input stamps are regenerated from it.

Verification

  • TDD: the new tests were written first and failed to compile against the missing API (error CS0103: The name 'KeyNameResolver' does not exist in the current context).
  • uloop compile: 0 errors, 0 warnings.
  • uloop run-tests (EditMode, KeyNameResolverTests|InputRecordingKeyFilterTests): 14/14 passed. Covers ordinals (3), signed ordinals (-1), undefined ordinals (300), comma-OR-ed names (Space,Enter), None, casing, padding, the Return alias, and the filter's mixed valid/invalid case.
  • uloop run-tests (PlayMode, RecordInputKeyFilterRejectionTests|SimulateKeyboardTests|KeyboardKeyNameSuggesterTests): 48/48 passed — the shared resolver does not change simulate-keyboard behavior, and the new PlayMode test pins the rejection itself.
  • Mutation check: deleting the rejection branch fails the PlayMode test, and dropping the empty-entry guard fails the EditMode test; both restored.
  • go run ./cmd/check-release-triggers --base HEAD~2: Release trigger guard passed. after running scripts/stamp-release-inputs.sh.

--keys went through Enum.TryParse<Key>, which also accepts enum ordinals, so
"--keys 3" silently became a filter for Key.Tab. The same hole was closed for
simulate-keyboard's --key by matching defined Key enum names; this applies that
rule to the filter as well.

The name-to-Key whitelist moves to the shared Common/InputSystem assembly both
tools already reference, so the rule lives in one place instead of being copied.

Entries that name no key are now reported rather than skipped. Skipping them
records a different set of keys than the caller asked for, and skipping all of
them falls back to recording every key - the opposite of the request - with
nothing in the response to distinguish it from omitting --keys entirely.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c524224-a2db-46b7-b957-1a6657619cb3

📥 Commits

Reviewing files that changed from the base of the PR and between fe05dbd and e4babfb.

⛔ Files ignored due to path filters (5)
  • Assets/Tests/Editor/InputRecordingKeyFilterTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/KeyNameResolverTests.cs.meta is excluded by none and included by none
  • Assets/Tests/PlayMode/RecordInputKeyFilterRejectionTests.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/Common/InputRecording/KeyFilterParseResult.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/Common/InputSystem/KeyNameResolver.cs.meta is excluded by none and included by none
📒 Files selected for processing (14)
  • .agents/skills/uloop-record-input/SKILL.md
  • .claude/skills/uloop-record-input/SKILL.md
  • Assets/Tests/Editor/InputRecordingKeyFilterTests.cs
  • Assets/Tests/Editor/KeyNameResolverTests.cs
  • Assets/Tests/PlayMode/RecordInputKeyFilterRejectionTests.cs
  • Packages/src/Editor/FirstPartyTools/Common/InputRecording/InputRecordingFileHelper.cs
  • Packages/src/Editor/FirstPartyTools/Common/InputRecording/KeyFilterParseResult.cs
  • Packages/src/Editor/FirstPartyTools/Common/InputSystem/KeyNameResolver.cs
  • Packages/src/Editor/FirstPartyTools/RecordInput/RecordInputUseCase.cs
  • Packages/src/Editor/FirstPartyTools/RecordInput/Skill/SKILL.md
  • Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs
  • cli/common/tools/default-tools.json
  • cli/dispatcher/shared-inputs-stamp.json
  • cli/project-runner/shared-inputs-stamp.json

📝 Walkthrough

Walkthrough

Key-name resolution is centralized and rejects ordinals, undefined names, and malformed entries. Record-input parsing reports invalid names before recording starts, with tests and CLI/skill documentation updated for the accepted key formats.

Changes

Input key validation

Layer / File(s) Summary
Centralized key-name resolution
Packages/src/Editor/FirstPartyTools/Common/InputSystem/KeyNameResolver.cs, Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs, Assets/Tests/Editor/KeyNameResolverTests.cs
Adds normalized, case-insensitive key resolution with the Return alias and routes simulated keyboard input through the shared resolver.
Structured filter parsing
Packages/src/Editor/FirstPartyTools/Common/InputRecording/*, Assets/Tests/Editor/InputRecordingKeyFilterTests.cs
Returns resolved keys alongside invalid names, handles empty entries explicitly, and tests valid, invalid, mixed, and omitted filters.
Recording rejection and command contract
Packages/src/Editor/FirstPartyTools/RecordInput/RecordInputUseCase.cs, Assets/Tests/PlayMode/RecordInputKeyFilterRejectionTests.cs, */SKILL.md, cli/common/tools/default-tools.json, cli/*/shared-inputs-stamp.json
Rejects invalid filters before recording, verifies the failure path, and documents case-insensitive names, digit-key names, and empty-filter behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant RecordInputUseCase
  participant InputRecordingFileHelper
  participant KeyNameResolver
  participant InputRecorder
  CLI->>RecordInputUseCase: Start recording with Keys
  RecordInputUseCase->>InputRecordingFileHelper: ParseKeyFilter(Keys)
  InputRecordingFileHelper->>KeyNameResolver: Resolve each key name
  KeyNameResolver-->>InputRecordingFileHelper: Resolved keys and invalid names
  InputRecordingFileHelper-->>RecordInputUseCase: KeyFilterParseResult
  alt Invalid key names
    RecordInputUseCase-->>CLI: Failure response
  else Valid filter
    RecordInputUseCase->>InputRecorder: Start recording with filter
    InputRecorder-->>CLI: Success response
  end
Loading

Possibly related PRs

  • hatayama/unity-cli-loop#2013: Refactors simulated keyboard key-name parsing to use KeyNameResolver, matching this PR’s resolver behavior and rejection tests.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/record-input-key-filter-name-whitelist

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…tract

- Run scripts/stamp-release-inputs.sh: the regenerated tool catalog is a shared
  release input, so both stamp files must move with it or the release trigger
  guard fails.
- Say "fails the command" rather than "is rejected" in the --keys documentation:
  rejected reads as if only that name is dropped while the rest still records.
- A filter made only of empty entries ("," or " ") no longer falls through to
  recording every key with a response indistinguishable from no filter at all.
  A trailing comma beside a named key stays harmless.
- Add the PlayMode test for the rejection itself: without it, deleting the check
  in RecordInputUseCase left every test green.
- Move normalizedKey into the failure branch that is now its only user.
@hatayama
hatayama merged commit b87c5f9 into feature/cli-discoverability-integration Jul 27, 2026
1 of 2 checks passed
@hatayama
hatayama deleted the fix/record-input-key-filter-name-whitelist branch July 27, 2026 02:46
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