Skip to content

fix(ledger): read the line budget per command, not per reply - #752

Merged
fajarhide merged 1 commit into
mainfrom
fix/750-751-command-position-per-segment
Sep 2, 2026
Merged

fix(ledger): read the line budget per command, not per reply#752
fajarhide merged 1 commit into
mainfrom
fix/750-751-command-position-per-segment

Conversation

@fajarhide

@fajarhide fajarhide commented Sep 2, 2026

Copy link
Copy Markdown
Owner

rations_its_output was narrowed to command position by #742, and read that position
off the previous token. split_whitespace has already eaten the newline by then, so a
two-line command is one command and nothing on the second line can open one. That put
the #741 shape back for the way an agent actually writes a command:

cd /path/to/repo
sed -n '58,95p' src/app.tsx

The reply is now split at its separators and the question is asked per command. A
newline separates, the sed scan cannot reach a later command's 5p, a separator glued
to the following token works, sudo / env VAR=1 / time / nohup step aside, and a
wrapper such as docker exec app tail -5 app.log keeps the lines it named, since its
argument list is somebody else's command line and no position in it is ours to read.

Measured by replaying the predicate over the 4,193 commands recorded in ~/.omni/omni.db:

predicate commands it rations
before #742, name anywhere 2,697
shipped in #742, command position 2,529
this PR, per command 2,730

168 of the 201 recovered are the regression, 136 of them to a newline. The other 33 are
sed -n '255,300p;403,497p' f and friends, where the old version read the whole
multi-address as one token and rejected it. The 18 commands the anywhere-match caught
and this does not are #738's own case: the word inside a heredoc body or a path.

Verification: make ci green. rations_its_output_reads_a_line_budget_and_nothing_else
was driven red five times, once per direction the fix can be wrong (newline not a
separator, wrapper not opaque, no prefix words, ; not a separator, and the sed
boundary on its own with the positives that shadow it removed).

Closes #750
Closes #751

Greptile Summary

The PR changes ledger line-budget detection to evaluate newline- and operator-separated command segments, recognizes several command introducers, and reuses wrapper detection from the pipeline registry.

  • Splits compound replies before identifying head, tail, and numeric sed budgets.
  • Adds support for bare sudo, env, time, and nohup prefixes.
  • Makes wrapper detection available to the ledger and expands regression tests.

Confidence Score: 3/5

The PR should not merge until option-bearing prefixes and prefixed opaque wrappers reliably preserve explicitly requested lines.

The new command-position logic misses bounded readers after common prefix options, and wrapper detection misses wrappers preceded by introducers, allowing project folds to hide the requested output; raw separator splitting also causes a non-blocking regression for literal command text.

Files Needing Attention: src/ledger/mod.rs and src/pipeline/registry.rs

Important Files Changed

Filename Overview
src/ledger/mod.rs Adds per-segment budget detection, but raw separator parsing and incomplete prefix handling leave both false-positive and missed-budget paths.
src/pipeline/registry.rs Exposes wrapper detection to the ledger, but the helper still assumes the wrapper is the first token.
changelog.d/750.fixed.md Documents the intended newline, prefix, and wrapper behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Raw command] --> B[Split into segments]
  B --> C{Opaque wrapper?}
  C -->|Yes| D[Scan bounded reader anywhere]
  C -->|No| E[Find command after introducers]
  D --> F{Line budget found?}
  E --> F
  F -->|Yes| G[Preserve project-origin lines]
  F -->|No| H[Allow normal ledger folding]
Loading

Fix all with Greploop Fix All in Claude Code Fix All in Codex Fix All in Cursor Fix All in Conductor

Prompt To Fix All With AI
### Issue 1
src/ledger/mod.rs:988-990
**Prefix options hide bounded commands**

When a bounded reader uses an option-bearing prefix such as `sudo -u root tail -5 app.log`, `opens_a_command` rejects the reader because `-u` and `root` are not introducers, causing project-origin folds to replace explicitly requested lines with a retrieval marker.

### Issue 2
src/ledger/mod.rs:954-955
**Literal separators become command boundaries**

The unconditional split treats separators inside heredoc bodies, comments, and quoted arguments as command boundaries, so literal `head`, `tail`, or numeric `sed` text disables project folding for replies that did not request bounded output, increasing delivered context unnecessarily.

### Issue 3
src/ledger/mod.rs:994-1000
**Introducer options bypass line protection**

When a bounded reader uses an ordinary option-bearing prefix such as `env -i head -20 file` or `time -p sed -n 5p file`, the option token fails `introduces_a_command`, causing project-origin folds to replace the requested lines with a retrieval marker.

### Issue 4
src/ledger/mod.rs:968-972
**Prefixed wrappers lose opacity**

When an opaque wrapper is preceded by an introducer, as in `sudo docker exec app tail -5 app.log`, wrapper detection sees `sudo` instead of `docker` and command-position checking rejects the nested reader, causing project folding to replace the wrapper’s requested output with a retrieval marker.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(ledger): read the line budget per co..." | Re-trigger Greptile

Greptile also left 4 inline comments on this PR.

Context used (3)

rations_its_output was narrowed to command position by #742, and read that
position off the previous token. split_whitespace has already eaten the
newline by then, so a two-line command is one command and nothing on the
second line can open one. That is the #741 shape back for the way an agent
actually writes a command:

    cd /path/to/repo
    sed -n '58,95p' src/app.tsx

Replaying both versions of the predicate over the 4,193 commands recorded in
~/.omni/omni.db, the narrowing gave up the guard on 168 of them, and 136 of
those to a newline. 3.2% of the corpus, folding lines the caller had just
named.

Split the reply at its separators and ask the question per segment. A newline
is one of them, the sed scan can no longer reach a later command's 5p, and a
separator glued to the following token works too. sudo, env, time, nohup and
VAR=value introduce a command without being one, and a wrapper's argument
list is somebody else's command line, so the name counts anywhere inside it.

Closes #750
Closes #751
Comment thread src/ledger/mod.rs
Comment on lines 988 to +990
fn opens_a_command(tokens: &[&str], i: usize) -> bool {
match i.checked_sub(1).map(|p| tokens[p]) {
None => true,
Some(prev) => prev.ends_with([';', '|', '&']),
}
tokens[..i].iter().all(|t| introduces_a_command(t))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Prefix options hide bounded commands

When a bounded reader uses an option-bearing prefix such as sudo -u root tail -5 app.log, opens_a_command rejects the reader because -u and root are not introducers, causing project-origin folds to replace explicitly requested lines with a retrieval marker.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ledger/mod.rs
Line: 988-990

Comment:
**Prefix options hide bounded commands**

When a bounded reader uses an option-bearing prefix such as `sudo -u root tail -5 app.log`, `opens_a_command` rejects the reader because `-u` and `root` are not introducers, causing project-origin folds to replace explicitly requested lines with a retrieval marker.

**Knowledge Base Used:**
- [Restore command-aware ledger folding](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/incident-mitigation_737-20260830-command-budgeted-output-cdc73f6.md)
- [Restore accurate ledger handling for bounded command output](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/rollback_742-20260901-ledger-line-budget-detection-f1fc2a4.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex Fix in Cursor Fix in Conductor

@fajarhide fajarhide Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and fixed in 09570e0. Same root as the other two P1s: the walk asked that every earlier token be an introducer, so an introducer's own option and its argument put the reader out of position. sudo, env, time, nohup and a VAR=value assignment now make the segment opaque, on the same reasoning wraps_another_command already applies to docker exec, so the name counts anywhere inside it and their flag grammars never have to be parsed.

Comment thread src/ledger/mod.rs
Comment on lines +954 to +955
command
.split(['\n', ';', '|', '&'])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Literal separators become command boundaries

The unconditional split treats separators inside heredoc bodies, comments, and quoted arguments as command boundaries, so literal head, tail, or numeric sed text disables project folding for replies that did not request bounded output, increasing delivered context unnecessarily.

Knowledge Base Used: Restore accurate ledger handling for bounded command output

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ledger/mod.rs
Line: 954-955

Comment:
**Literal separators become command boundaries**

The unconditional split treats separators inside heredoc bodies, comments, and quoted arguments as command boundaries, so literal `head`, `tail`, or numeric `sed` text disables project folding for replies that did not request bounded output, increasing delivered context unnecessarily.

**Knowledge Base Used:** [Restore accurate ledger handling for bounded command output](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/rollback_742-20260901-ledger-line-budget-detection-f1fc2a4.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex Fix in Cursor Fix in Conductor

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid in principle, and measured at zero instances, so it is not fixed here.

Replaying the predicate over the 4,193 commands recorded in ~/.omni/omni.db, 51 of them
are rationed by this version and were not by the anywhere-match that preceded #742. Every
one of the 51 is a real bounded reader that the token walk could not see: a separator
glued to the next token (2>&1|tail -1, --json x|head), or a multi-address sed -n '1,20p;70,110p' that the old version read as one token and rejected. None came from a
heredoc body or a quoted argument.

The direction also matters. A boundary invented inside a quote costs context and cannot
delete a line, which is the cheap half of this predicate's two failure modes. A
quote-aware splitter is the parser this predicate keeps refusing to be, and it gets
written when a payload demands it rather than before.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Given the replay found zero instances of this failure mode, while the current splitter recovers real bounded-reader commands and only risks over-preserving context when it encounters a quoted or literal separator, this is not actionable for this PR. A quote-aware shell splitter can be a separate improvement if future payloads demonstrate the need.

Comment thread src/ledger/mod.rs
Comment on lines +994 to 1000
matches!(
token.rsplit('/').next().unwrap_or(token),
"sudo" | "env" | "time" | "nohup"
) || token.split_once('=').is_some_and(|(name, _)| {
!name.is_empty() && name.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_')
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Introducer options bypass line protection

When a bounded reader uses an ordinary option-bearing prefix such as env -i head -20 file or time -p sed -n 5p file, the option token fails introduces_a_command, causing project-origin folds to replace the requested lines with a retrieval marker.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ledger/mod.rs
Line: 994-1000

Comment:
**Introducer options bypass line protection**

When a bounded reader uses an ordinary option-bearing prefix such as `env -i head -20 file` or `time -p sed -n 5p file`, the option token fails `introduces_a_command`, causing project-origin folds to replace the requested lines with a retrieval marker.

**Knowledge Base Used:**
- [Restore command-aware ledger folding](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/incident-mitigation_737-20260830-command-budgeted-output-cdc73f6.md)
- [Restore accurate ledger handling for bounded command output](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/rollback_742-20260901-ledger-line-budget-detection-f1fc2a4.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex Fix in Cursor Fix in Conductor

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and fixed by the same change. env -i and time -p are the introducer's own flags, and the segment is now opaque rather than walked.

Comment thread src/ledger/mod.rs
Comment on lines +968 to 972
let opaque = registry::wraps_another_command(segment);
tokens.iter().enumerate().any(|(i, tok)| {
if !opens_a_command(&tokens, i) {
if !opaque && !opens_a_command(&tokens, i) {
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Prefixed wrappers lose opacity

When an opaque wrapper is preceded by an introducer, as in sudo docker exec app tail -5 app.log, wrapper detection sees sudo instead of docker and command-position checking rejects the nested reader, causing project folding to replace the wrapper’s requested output with a retrieval marker.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ledger/mod.rs
Line: 968-972

Comment:
**Prefixed wrappers lose opacity**

When an opaque wrapper is preceded by an introducer, as in `sudo docker exec app tail -5 app.log`, wrapper detection sees `sudo` instead of `docker` and command-position checking rejects the nested reader, causing project folding to replace the wrapper’s requested output with a retrieval marker.

**Knowledge Base Used:**
- [Pipeline stages and quality controls](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/docs/pipeline-stages-and-quality.md)
- [Restore command-aware ledger folding](https://app.greptile.com/weekndlabs/-/custom-context/knowledge-base/fajarhide/omni/-/reverts/incident-mitigation_737-20260830-command-budgeted-output-cdc73f6.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex Fix in Cursor Fix in Conductor

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and fixed by the same change. sudo docker exec app tail -5 x is opaque on the sudo, so the wrapper behind it no longer has to be found.

@fajarhide
fajarhide merged commit feb4802 into main Sep 2, 2026
14 checks passed
@fajarhide
fajarhide deleted the fix/750-751-command-position-per-segment branch September 2, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant