Skip to content

fix(discover): count every line of a multi-line call - #5024

Draft
KuSh wants to merge 1 commit into
lex/14-grammar-tablesfrom
fix/report-reads-every-line
Draft

KuSh wants to merge 1 commit into
lex/14-grammar-tablesfrom
fix/report-reads-every-line

Conversation

@KuSh

@KuSh KuSh commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

rtk discover and rtk session read a multi-line call as one command and classified only its first line. git status\ngit log counted one command, and cd x\ngit status offered no saving at all, although the rewrite acts on each line.

The report now reads a block as the rewrite does. Both go through one entry check, read_line, and one block_lines: a line is a command, a trailing operator joins the next line, and a blank or comment-only line is no command. A block the rewrite refuses to read line by line, such as a loop, stays one text as before. Each command of a call is read once, for its share of the output and for its row.

Built on #4401. It uses that stack's lexer.

Behaviour changes

  • total_commands and session adoption now count every line, including lines rtk doesn't handle, so a multi-line setup script lowers a session's adoption.
  • A call has one measured output. It is now shared by the commands that may have written it, in proportion to their category averages, and marked estimated when more than one shares it. A command alone takes it whole, so cargo test\necho done keeps its measurement. Both stages of a pipeline share it. A command that writes next to nothing (echo, cd) takes none, one that sends both its streams elsewhere (cargo test > test.log 2>&1) takes zero, and any other command with no row, as in git status && ./build.sh, takes a share no row shows. This also changes ; and &&: develop gives the number to the last command, and drops it if that is an echo.
  • A line left inside a backquote, or a heredoc with an fd number in front (cat 0<<EOF), now refuses its block in rewrite_command. The hook's answer doesn't change: it already leaves any substitution or heredoc alone.

Known limits

  • A CRLF block stays one text in the report, while the rewrite reads it line by line.
  • A quoted newline beside a real one, such as a multi-line commit message followed by another line, stays one text, because the rewrite refuses that block.
  • A comment-only block still counts as one command.
  • A redirect written on a subshell or a group ((cargo test) > test.log 2>&1) is read as its own part, so the command inside keeps a share of what came back.
  • A line beside a command substitution is listed as reached when the rewrite alone would take it, although the hook defers the whole call; a single-line chain already reads this way.
  • A command on the quiet list can still print a lot (set alone, cp -v); its output then goes to the commands around it. One behind a wrapper (command -v, sudo mkdir) is read as a writer.
  • Redirects are read one command at a time, so an exec > log 2>&1 does not reach the commands after it.
  • Without a hook log row, each supported line re-runs the whole-block permission check, so the estimate is quadratic on very long blocks: about 7 s for 1,000 lines on a debug build.

Test plan

  • cargo fmt --all, cargo clippy --all-targets, cargo test --all, and both with --no-default-features
  • Each guard fails a test when removed
  • 49 multi-line inputs compared before and after: no rewrite moved

🤖 Generated with Claude Code

@KuSh
KuSh marked this pull request as draft November 5, 2026 23:42
@rtk-wshm-sync-bot

Copy link
Copy Markdown

wshm · Automated triage by AI

📊 Automated PR Analysis

🐛 Type bug-fix
🟡 Risk medium

Summary

Fixes rtk discover and rtk session to count every line of a multi-line call instead of only the first line, by sharing a new block_lines helper with the rewrite logic so lines are split the same way the hook rewrites them. Adds a joined_or_as_written lexer helper, updates total_commands/session adoption counting, and documents known limits (CRLF blocks, quoted newlines, comment-only blocks, quadratic cost on very long blocks).

Review Checklist

  • Tests present
  • Breaking change
  • Docs updated

Analyzed automatically by wshm · This is an automated analysis, not a human review.

@KuSh
KuSh force-pushed the fix/report-reads-every-line branch from 126ed0d to 5fda834 Compare November 6, 2026 00:18
`rtk discover` and `rtk session` read a multi-line call as one command, so only its
first line was classified: `git status\ngit log` counted one command, and
`cd x\ngit status` none it could offer a saving on, although the rewrite acts on each
line. A session's adoption now also counts the lines rtk does not handle.

The report now reads a block as the rewrite does, through one entry check, `read_line`,
and one `block_lines`: a line is a command, a trailing operator joins the next line, a
blank or comment-only line is no command. A block the rewrite refuses to read line by
line, such as a loop, stays one text as before, and so does a CRLF block. A heredoc
with an fd number in front (`cat 0<<EOF`) is a heredoc too. Each command of a call is
read once, for its share of the output and for its row.

A call has one measured output, which went to its last command and was lost when that
was an `echo`. Which command wrote what of it cannot be told apart, so the commands that
may have written it now share it by category average, marked estimated, and one alone
takes it whole: `cargo test; echo done` keeps its measurement. Both stages of a pipeline
share it. A command that writes next to nothing, such as `echo` or `cd`, takes no share,
and one that sends both its streams elsewhere (`cargo test > test.log 2>&1`) takes zero.

A line left inside a backquote now refuses its block in `rewrite_command` too. The
hook's answer does not change, as it already leaves any substitution alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KuSh
KuSh force-pushed the fix/report-reads-every-line branch from 5fda834 to dd2e469 Compare November 8, 2026 17:13
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.

1 participant