bug(discover): a tab between command and subcommand classifies as Supported but never rewrites
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 81k
- Forks
- 5.1k
- Avg merge
- 4d 21h
- Merged PRs (30d)
- 35
Description
Same class as #3995 (absolute-path arm, fixed 2026-09-13): classify_command and the rewrite
disagree about what separates a command from its subcommand.
-
the rule patterns match
\s+—^pnpm\s+(exec|i|install|…),^cargo\s+(build|test|…), … -
strip_word_prefix(src/discover/registry.rs:1930) accepts only a literal ASCII space:} else if cmd.len() > prefix.len() && cmd.starts_with(prefix) && cmd.as_bytes()[prefix.len()] == b' '
So a tab-separated command is classified Supported and then returned unchanged by the hook.
rtk discover and rtk session count it as covered; the command streams raw.
Verified on develop (5e0f92cd) with rtk rewrite, tab written as \t:
| command | rewrite |
|---|---|
git status |
rtk git status |
git\tstatus |
(nothing) |
cargo\tbuild |
(nothing) |
npm\trun build |
(nothing) |
pnpm\tinstall |
(nothing) |
Not tool-specific — it is every rule that goes through strip_word_prefix.
A tab really is a valid separator here, so the classify side is the one that is right:
the shell grammar treats space and tab as blanks when tokenising a command line, independent
of IFS. bash -xc $'git\t--version' traces as + git --version and prints
git version 2.53.0.
And it reaches the hook. Feeding a PreToolUse payload to rtk hook claude — the tab
survives JSON transport as \t:
tool_input.command |
updatedInput.command returned |
|---|---|
git status |
rtk git status |
git\tstatus |
(none — unchanged) |
pnpm\tinstall |
(none — unchanged) |
Frequency: low. An agent writing shell almost always uses a single space, so this is a
correctness gap rather than a material source of lost savings — worth closing for the
consistency of the two sides, not urgent.
Found while reviewing #3275 with a differential fuzz asserting
classify == Supported(rtk pnpm) ⇒ rewrite fires. Over 6528 generated pnpm spellings it trips
64 times, all tab-separated, and the count is identical on develop and on that PR's head —
so this is pre-existing and #3275 neither adds to it nor fixes it.
A fix should make the two sides share one notion of the boundary rather than widening
strip_word_prefix alone: widening only the classify side is what #3275 round 1 had to close,
and widening only the rewrite side would rewrite forms classify still calls Unsupported.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/discover/registry.rs:1930 at strip_word_prefix, then trace classify_command and the rewrite path to understand their command-boundary handling. Run the reported rtk rewrite cases with space and tab separators, and use the differential fuzz scenario if available. Done means supported tab-separated commands are rewritten consistently and classification and rewriting share the same boundary behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100