Skip to content

Answer a reader that went away, rather than panicking at it - #38

Merged
HackingGate merged 1 commit into
mainfrom
fix/a-reader-that-went-away
Aug 15, 2026
Merged

Answer a reader that went away, rather than panicking at it#38
HackingGate merged 1 commit into
mainfrom
fix/a-reader-that-went-away

Conversation

@HackingGate

Copy link
Copy Markdown
Owner

Closes #37.

uphold rules --effective | head -2 exited 101, and so did every other subcommand piped into anything that stops reading. println! unwraps its write and panics, and Rust ignores SIGPIPE at startup, so a closed pipe arrives at the macro as an ordinary EPIPE rather than killing the process the way a shell expects. 114 print sites across 18 files reached it.

101 is not one of the three codes this tool promises, out of a binary installed in front of git, gh and npm -- and the run had already decided its verdict by the time the write failed.

before after
uphold rules --effective | head -2 101 0
uphold scan | head -1, tree with a violation 101 1
uphold rules --effective > /dev/full 101 2

Two answers, because the two failures are not the same thing:

  • The reader went away. Nothing is wrong with the run and nothing more will be read, so the rest of the output is dropped and the exit code stays the verdict. Asked once per stream and remembered, so a report with thousands of findings does not make thousands of failed syscalls.
  • The write failed for any other reason -- a full disk under a redirected report. There the output really did not arrive, and that is exit 2 by the rule that governs every other could-not-look here. A caller holding half a file must not read 0 as a clean tree.

Why a shadowed macro rather than a helper function. A helper is a rule that 114 call sites have to remember and that the next line of code can silently break -- the same shape as a hand-copied rule, and invisible in the same way. What cannot be forgotten is the spelling everybody already types, so println!, print! and eprintln! are shadowed in main.rs ahead of the module list, where a macro_rules! is in scope for everything that follows it. eprint! is shadowed too though nothing spells it yet, under an #[expect(unused_macros)] that turns the first use into a build error pointing at the line to delete. src/out.rs is now the only place in the crate that touches either stream.

Checks

Both cases are tested at the CLI, where the only evidence is the process's exit status, and both were driven the other way first: with the macros removed they fail with Some(101). The /dev/full case is skipped out loud where that device is not there.

prek run --all-files --hook-stage manual passes, coverage floor included. cargo mutants --file src/out.rs: 10 mutants, 0 missed.

https://claude.ai/code/session_01Dm334jAm9MP19Yzqq6Cua8

Closes #37. `uphold rules --effective | head -2` exited 101, and so did every
other subcommand piped into anything that stops reading: `println!` unwraps its
write and panics, and Rust ignores SIGPIPE at startup, so a closed pipe arrives
at the macro as an ordinary EPIPE rather than killing the process the way a
shell expects. 114 print sites across 18 files reached it.

101 is not one of the three codes this tool promises, out of a binary installed
in front of `git`, `gh` and `npm` -- and the run had already decided its verdict
by the time the write failed. A crash loses that verdict and names `stdio.rs` at
a reader who can act on neither. `report.rs` carries the same sentence about an
earlier version of this, where a panic replaced the report the run existed to
produce.

Two answers, because the two failures are not the same thing:

* **The reader went away.** Nothing is wrong with the run and nothing more will
  be read, so the rest of the output is dropped and the exit code stays the
  verdict. `head` closing a pipe is a reader's decision, not a check that could
  not be made. Asked once per stream and remembered, so a report with thousands
  of findings does not make thousands of failed syscalls.
* **The write failed for any other reason** -- a full disk under a redirected
  report, a file this process may no longer write. There the output really did
  not arrive, and that is exit 2 by the rule that governs every other
  could-not-look here. `main` reads the first such error on the way out, because
  a caller holding half a file must not read 0 as a clean tree.

Reached by shadowing `println!`, `print!` and `eprintln!` in `main.rs` rather
than by a helper function beside them. A helper is a rule that 114 call sites
have to remember and that the next line of code can silently break -- the same
shape as a hand-copied rule, and invisible in exactly the same way. What cannot
be forgotten is the spelling everybody already types. `eprint!` is shadowed too
though nothing spells it yet, under an `#[expect(unused_macros)]` that turns the
first use into a build error pointing at the line to delete.

Both cases are tested at the CLI, where the only evidence is the process's exit
status, and both were driven the other way first: with the macros removed they
fail with `Some(101)` -- the pipe case on `rules --sets --json` and on `scan`,
the unwritable-report case through `/dev/full`, which is skipped out loud where
that device is not there.

Claude-Session: https://claude.ai/code/session_01Dm334jAm9MP19Yzqq6Cua8
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@HackingGate, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5c4e8250-d0ef-4c88-975b-0f9fc1ed758a

📥 Commits

Reviewing files that changed from the base of the PR and between 659c51b and b7c68c5.

📒 Files selected for processing (4)
  • docs/REFERENCE.md
  • src/main.rs
  • src/out.rs
  • tests/root_cli.rs

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.

@HackingGate
HackingGate merged commit 4a262ae into main Aug 15, 2026
12 checks passed
@HackingGate
HackingGate deleted the fix/a-reader-that-went-away branch August 15, 2026 01:02
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.77419% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.44%. Comparing base (659c51b) to head (b7c68c5).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/out.rs 96.55% 2 Missing ⚠️

❌ Your patch status has failed because the patch coverage (96.77%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #38      +/-   ##
==========================================
+ Coverage   89.40%   89.44%   +0.04%     
==========================================
  Files          30       31       +1     
  Lines        9670     9732      +62     
==========================================
+ Hits         8645     8705      +60     
- Misses       1025     1027       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

A reader that goes away panics the binary at exit 101

2 participants