Skip to content

fix(wc): preserve filenames containing spaces in wc filter - #8

Merged
ryanmurf merged 1 commit into
masterfrom
fix/wc-filenames-with-spaces
May 30, 2026
Merged

ryanmurf merged 1 commit into
masterfrom
fix/wc-filenames-with-spaces

Conversation

@ryanmurf

Copy link
Copy Markdown

Problem

The wc output filter (src/cmds/system/wc_cmd.rs) parsed each line with split_whitespace() and assumed the filename was a single trailing token (parts.last() / parts[3]). GNU wc prints the filename verbatim, so wc -l "my file.txt" emits 3 my file.txt — and the filter silently corrupted the name the model then reads.

Verified against real GNU wc:

$ wc -l "my file.txt"
3 my file.txt
$ wc "my file.txt"
3 3 6 my file.txt

Corruption observed (proven failing pre-fix)

Mode Input Buggy output Correct
Lines multi-file 30 my file.txt 30 file.txt 30 my file.txt
Full multi-file 30 96 978 my file.txt 30L 96W 978B my 30L 96W 978B my file.txt
Full + common prefix 30 96 978 src/my file.txt 30L 96W 978B src/my 30L 96W 978B my file.txt
Mixed single-file 30 96 my file.txt 30 96 my 30 96

This is the same defect class as the grep BRE-pipe bug (#6): a filter that mangles output the model reasons over. A truncated/renamed file can send the model to act on the wrong path.

Fix

Added split_counts_and_name(line, max_counts) — peels off exactly the known number of leading numeric count columns (1 for -l/-w/-c/-m, 3 for Full, up to 4 for Mixed -lwcm) and treats the remainder as one opaque, verbatim filename with internal spaces preserved. All single/multi formatters and the common-prefix scan now route through it. No change to the compact output format for ordinary (space-free) filenames.

Tests

  • Regression tests for every affected mode — confirmed to fail pre-fix (5 panics) and pass post-fix.
  • Direct contract tests for the helper: single/full columns, stdin (no name), the count-column cap (numeric-looking filename tokens stay in the name), total line, and tabs/extra spacing.
  • 28/28 wc_cmd tests pass; full cargo test --all green.

CI gates run locally

  • cargo fmt --all -- --check ✅
  • cargo clippy --all-targets -- -D unsafe_code ✅ (exit 0; only pre-existing warnings, no new ones)
  • cargo test --all ✅ (0 failures)
  • cargo build --release ✅

🤖 Generated with Claude Code

The wc output filter parsed each line with split_whitespace() and assumed
the filename was a single trailing token (parts.last() / parts[3]). GNU wc
prints the filename verbatim, so `wc -l "my file.txt"` emits `3 my file.txt`
and the filter silently corrupted the name the model then reads:

  - Lines/Words/Bytes/Chars multi-file: "my file.txt" -> "file.txt"
    (only the last path segment survived)
  - Full multi-file: "30 96 978 my file.txt" -> took parts[3] = "my",
    dropping "file.txt" entirely
  - Mixed single-file: leaked a filename fragment into the counts
    ("30 96 my" instead of "30 96")

This is the same class of defect as the grep BRE-pipe bug (#6): a filter
that mangles output the model reasons over.

Fix: add split_counts_and_name(line, max_counts) which peels off exactly the
known number of leading numeric count columns and treats the remainder as one
opaque, verbatim filename (spaces preserved). All multi/single formatters and
the common-prefix scan now use it.

Adds regression tests for every affected mode (proven to fail pre-fix) plus
direct contract tests for the helper, including the count-column cap and
trailing-name edge cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 Thanks for the PR! It looks like this targets master, but all PRs should target the develop branch.

Please update the base branch:

  1. Click Edit at the top right of this PR
  2. Change the base branch from master to develop

See CONTRIBUTING.md for details.

@ryanmurf
ryanmurf enabled auto-merge (squash) May 30, 2026 01:17
@ryanmurf
ryanmurf merged commit 54b1216 into master May 30, 2026
17 checks passed
@ryanmurf
ryanmurf deleted the fix/wc-filenames-with-spaces branch May 30, 2026 01:23
ryanmurf added a commit that referenced this pull request May 30, 2026
#9)

The tree filter stripped any line matching the loose substring heuristic
`line.contains("director") && line.contains("file")`, intended to drop
tree's trailing summary line (e.g. "5 directories, 23 files"). But this
silently dropped legitimate entries whose filenames contain both words,
e.g. `director-files.txt`, `file_directory.json`, or a path segment like
`my directory with files` — the model never saw those files existed.

Same bug class as the grep BRE-pipe over-match (#6) and the wc
space-filename drop (#8): an output transform that over-matches and
silently strips real content the model reasons over.

Fix: anchor the summary detector to tree's exact summary shape with a
whole-line regex (`^\d+ director(y|ies)(, N files)?(, N links)?$`)
instead of a substring contains-check. Regression tests prove the dropped
filenames now survive and the real summary line is still stripped,
including the `, N links` platform variation.

Co-authored-by: rtk-sweep-agent <agent@herodevs.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants