rtk-ai / rtk-ai/rtk

rtk diff - raw fallback is not byte-exact: a newline is appended when the input has none

Open
#3,924 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:cli bug good first issue priority:medium
Dominant language
Rust
Stars
81.1k
Forks
5.1k
Avg merge
4d 21h
Merged PRs (30d)
35

Description

rtk diff - falls back to raw passthrough whenever the parser cannot agree with the
stream's structure, and that fallback is documented as emitting the input bytes exactly —
condense_unified_diff_strict's contract is "None means the caller must emit its exact
input bytes".

It does not, when the input has no trailing newline. Verified on develop (665b2720):

$ printf 'not a diff at all' > in.txt
$ wc -c < in.txt
17
$ rtk diff - < in.txt | wc -c
18

The extra byte is a \n appended by run_stdin:

out.write_all(&bytes)?;
if !bytes.is_empty() && !bytes.ends_with(b"\n") {
    writeln!(out)?;
}

Input that already ends with a newline round-trips byte-exact, so this is specific to a
stream whose last line is unterminated — a truncated capture, printf without \n, a
producer killed mid-write. Those are exactly the streams most likely to hit the raw
fallback in the first place.

Two ways to close it, and the choice is a real one:

  • make the fallback byte-exact and drop the writeln!, which matches the documented
    contract but can leave a shell prompt mid-line;
  • keep the newline and narrow the contract wording to "the input bytes, newline-terminated",
    so the guarantee stated in the parser doc and in #3788 matches what ships.

Either way it needs a test. Nothing currently covers it: mutation testing over
diff_cmd.rs left three mutants alive on this exact condition (!bytes.is_empty(),
the &&, and the !), all in run_stdin. A unit test cannot reach it because the
behaviour is in the write path, so it belongs in tests/ as a real-process test asserting
the output bytes for both a newline-terminated and an unterminated input.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in diff_cmd.rs at run_stdin and review the parser contract described for condense_unified_diff_strict. Add a real-process test under tests/ covering both newline-terminated and unterminated input, asserting the output bytes. The remaining decision is whether the fallback must preserve bytes exactly or guarantee a trailing newline.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.