Skip to content

Improve source read efficiency and model compatibility - #867

Merged
anandh8x merged 6 commits into
mainfrom
feat/structural-code-query
Aug 7, 2026
Merged

Improve source read efficiency and model compatibility#867
anandh8x merged 6 commits into
mainfrom
feat/structural-code-query

Conversation

@anandh8x

@anandh8x anandh8x commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • add bounded compact source reads with safe Go fragment parsing and conservative fallback behavior
  • standardize the model-facing read_file contract on path, offset, and limit
  • retain legacy line and byte arguments internally, with mixed legacy calls preferring the line range instead of failing
  • expose one case-sensitivity argument for grep
  • make compact source reading available up front and clarify when exact reads and plans are appropriate
  • add regression coverage for canonical ranges, mixed legacy arguments, schema exposure, and Go fragments

Why

The previous read_file schema exposed overlapping line and byte pagination systems. Some models combined both systems in one request, producing deterministic argument failures and repeated retries until the loop guard stopped the run. The canonical contract removes that ambiguity while preserving compatibility for existing callers.

GPT-5.5 benchmark

Identical read-only inspection prompt against the Zero source tree:

Build Time Tokens Result
Before 40.3s 10,859 stopped after six invalid read_file calls
After 19.4s 13,219 completed with one search, two successful reads, and no plan calls

The pre-change token total is lower only because the task halted without producing the requested answer; the primary measured improvement is successful completion without the invalid-call loop.

Validation

  • make fmt-check
  • go vet ./...
  • go test ./... with an isolated empty user config root
  • go run ./cmd/zero-release build
  • go run ./cmd/zero-release smoke
  • make lint-static
  • make vulncheck
  • git diff HEAD --check

Summary by CodeRabbit

  • New Features
    • Added offset/limit line-range selection for standard and minified source reading.
    • Improved Go minification for standalone and context-aware fragments, including safer handling of partial code.
  • Bug Fixes
    • Updated truncation and out-of-range guidance with clearer range terminology.
    • Refined tool option documentation and behavior for more consistent usage.
  • Documentation
    • Clarified when planning is needed and standardized source-exploration guidance.
  • Tests
    • Expanded coverage for ranged reads, minification edge cases, and validation scenarios.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 381c102b-8892-4219-9e19-1da941b6fee3

📥 Commits

Reviewing files that changed from the base of the PR and between 6a258e1 and 85b1689.

📒 Files selected for processing (2)
  • internal/tools/read_file.go
  • internal/tools/read_minified_file.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/tools/read_file.go
  • internal/tools/read_minified_file.go

Walkthrough

The change adds bounded Go-fragment minification, canonical offset/limit source ranges for file tools, ranged minified reads with recalculated metrics, and updated agent planning and source-exploration guidance.

Changes

Source reading workflow

Layer / File(s) Summary
Go fragment minification
internal/minify/minify.go, internal/minify/minify_test.go
Go files now support bounded fragment parsing and contextual normalization. Tests cover fragment compaction, declaration prefixes, the 512-line limit, and conservative fallback.
Canonical read_file line ranges
internal/tools/read_file.go, internal/tools/file_tools_test.go, internal/tools/file_safety_test.go, internal/tools/file_tracker.go
read_file now uses canonical offset and limit parameters. Legacy parsing remains available when canonical parameters are absent. Messages, truncation hints, and edit authorization use the canonical range model.
Ranged minified reads
internal/tools/read_minified_file.go, internal/tools/read_minified_file_test.go
read_minified_file selects source ranges before contextual minification and recalculates metrics from the selected content. Tests cover lexical preservation, past-end offsets, and large limits.
Tool guidance and wiring
internal/tools/registry.go, internal/tools/registry_test.go, internal/tools/grep.go, internal/tools/update_plan.go, internal/agent/system_prompt.md, internal/agent/system_prompt_models.go, internal/cli/deferred_wiring_test.go, internal/tools/file_tools_test.go
Tool registration and schemas reflect the updated reading behavior. Agent guidance limits update_plan to tasks with at least three meaningful dependent steps and prefers read_minified_file for initial exploration.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant read_minified_file
  participant SourceRangeSelector
  participant ContextualFragment
  Caller->>read_minified_file: Provide path, offset, and limit
  read_minified_file->>SourceRangeSelector: Select source lines
  SourceRangeSelector-->>read_minified_file: Return selected content
  read_minified_file->>ContextualFragment: Minify selected content
  ContextualFragment-->>read_minified_file: Return result and metrics
  read_minified_file-->>Caller: Return ranged output
Loading

Possibly related PRs

  • Gitlawb/zero#838: This PR also changes internal/agent/system_prompt.md planning guidance.

Suggested reviewers: gnanam1990, kevincodex1, vasanthdev2004

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the PR's source-reading efficiency and model-facing compatibility changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/structural-code-query

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/minify/minify.go`:
- Around line 59-61: Update the line-count logic in the minification flow around
strings.Split to remove one trailing empty element when the normalized content
ends with a newline before enforcing the 512-line limit. Preserve rejection
above 512 source lines, and add a regression test covering 512 statements
followed by a final newline that remains eligible for minification.

In `@internal/tools/read_file.go`:
- Around line 34-40: The renderReadFileRange out-of-range error still refers to
the removed start_line field, conflicting with the public schema. Update
renderReadFileRange to name the canonical offset parameter in that user-visible
message while preserving the existing range validation behavior.

In `@internal/tools/read_minified_file.go`:
- Around line 87-88: The ranged minification flow must preserve lexical state
instead of passing context-free fragments to minify.File. Update
selectSourceLines and the surrounding read logic in
internal/tools/read_minified_file.go at lines 87-88 and 131-144 to use only safe
ranges, retain scanner context, or apply whitespace-only normalization for
unsafe ranges; add or update coverage in
internal/tools/read_minified_file_test.go at lines 48-60 for ranges beginning
inside multiline strings, template literals, and block comments.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 794b02e9-666a-47f6-af12-98f2ac92e34f

📥 Commits

Reviewing files that changed from the base of the PR and between 91b413c and a394fd6.

📒 Files selected for processing (14)
  • internal/agent/system_prompt.md
  • internal/agent/system_prompt_models.go
  • internal/cli/deferred_wiring_test.go
  • internal/minify/minify.go
  • internal/minify/minify_test.go
  • internal/tools/file_tools_test.go
  • internal/tools/file_tracker.go
  • internal/tools/grep.go
  • internal/tools/read_file.go
  • internal/tools/read_minified_file.go
  • internal/tools/read_minified_file_test.go
  • internal/tools/registry.go
  • internal/tools/registry_test.go
  • internal/tools/update_plan.go
💤 Files with no reviewable changes (1)
  • internal/tools/grep.go

Comment thread internal/minify/minify.go
Comment thread internal/tools/read_file.go Outdated
Comment thread internal/tools/read_minified_file.go Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 4, 2026
@anandh8x
anandh8x marked this pull request as ready for review August 4, 2026 16:10
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 85b1689a6240
Changed files (15): internal/agent/system_prompt.md, internal/agent/system_prompt_models.go, internal/cli/deferred_wiring_test.go, internal/minify/minify.go, internal/minify/minify_test.go, internal/tools/file_safety_test.go, internal/tools/file_tools_test.go, internal/tools/file_tracker.go, internal/tools/grep.go, internal/tools/read_file.go, internal/tools/read_minified_file.go, internal/tools/read_minified_file_test.go, and 3 more

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requesting changes: the new offset/limit pair cannot be used before an edit.

limit caps the range [offset, EOF] rather than defining the range, so any interior slice comes back flagged truncated. The registry then skips RecordSeenRange and the edit is refused, with a message telling the model to re-read using offset/limit, which is the call that just failed. The start_line/end_line pair this PR deletes from the schema is the only shape that still works:

offset=500 limit=10          truncated=true   reason="limit"   seen=""         edit refused
offset=500 (runs to EOF)     truncated=false                   seen=500-1000   edit ok
start_line=500 end_line=509  truncated=false                   seen=500-509    edit ok

1000 line file, driven through Registry.RunWithOptions.

Three others, all reproducible:

Ranged Go reads corrupt raw strings. A range that starts inside a raw string literal is parsed as code, so string content is deleted and identifiers are rewritten. SECRET-MARKER-ONE comes back as SECRET - MARKER - ONE, a line inside the string vanishes, and the header reports a 49% saving. Fragment's own doc says non-Go takes the conservative path because a range may begin inside a multiline string. Go needs the same guard.

Dropping byte_offset/byte_limit from the schema and from the unseen-file message leaves any file with a line over 128KB unreadable, and so uneditable. The byte path still works, and file_tracker_largefile_test.go still asserts it is what makes those files writable again.

Mixing one canonical and one legacy argument silently reads the wrong lines: {start_line: 5, limit: 2} returns lines 1 and 2.

Minor: read_minified_file with an offset past EOF returns an empty body with status ok, where read_file says the offset is past the end.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

@anandh8x the blocking one is the offset/limit range, the rest are smaller. limit caps [offset, EOF] instead of defining the range, so an interior slice gets flagged truncated, never earns read credit, and the edit after it is refused. A slice that happens to reach EOF passes cleanly, which is why the tests here do not show it.

Two ways out and I would take the first: make limit set endLine so the read is not flagged truncated at all, or stop treating a limit cut as a byte-budget cut at the point the registry commits the observation. The second one reaches further than this PR needs to.

I have the probe that produced the table in the review, driven through Registry.RunWithOptions. Say the word and I will push it as a test on your branch.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tools/file_safety_test.go`:
- Around line 318-323: Update the read_file line-range accounting so an offset
of 500 with limit 10 produces the inclusive range 500-509. In the relevant
read_file range-processing flow, calculate the bounded end as offset + limit - 1
and apply it before rendering, ensuring exact bounded reads receive seen_lines
metadata of 500-509.

In `@internal/tools/read_minified_file.go`:
- Around line 163-164: Update the range-end calculation in the
read-minified-file logic to compare limit against end-start before adding,
preventing integer overflow while preserving the existing limit behavior. Add a
regression test covering a maximum-int limit with a nonzero offset and verify
the resulting slice does not panic.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e278e93d-5cd5-485d-b4fd-949bdb05bbe6

📥 Commits

Reviewing files that changed from the base of the PR and between 00ad4d4 and 3aa190b.

📒 Files selected for processing (7)
  • internal/minify/minify.go
  • internal/tools/file_safety_test.go
  • internal/tools/file_tools_test.go
  • internal/tools/file_tracker.go
  • internal/tools/read_file.go
  • internal/tools/read_minified_file.go
  • internal/tools/read_minified_file_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/tools/file_tracker.go
  • internal/tools/file_tools_test.go
  • internal/tools/read_file.go

Comment thread internal/tools/file_safety_test.go
Comment thread internal/tools/read_minified_file.go Outdated
@anandh8x

anandh8x commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai The latest review found no actionable comments, but the previous changes-requested verdict is still active. Please review the latest commit and clear it if no blockers remain.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR metadata and latest commits ==='
gh pr view 867 --repo Gitlawb/zero --json headRefOid,baseRefOid,commits,reviewDecision \
  --jq '{headRefOid,baseRefOid,reviewDecision,commits:[.commits[]|{oid,messageHeadline,authoredDate}]}'

echo
echo '=== Changed files in the latest commit ==='
git show --stat --oneline --decorate HEAD
git show --format=fuller --find-renames --find-copies -- \
  internal/tools/read_file.go \
  internal/tools/file_safety_test.go \
  internal/tools/file_tools_test.go \
  internal/tools/registry.go \
  internal/tools/read_minified_file.go \
  internal/tools/read_minified_file_test.go

echo
echo '=== Relevant source outlines ==='
ast-grep outline internal/tools/read_file.go --items all --view expanded
ast-grep outline internal/tools/file_safety_test.go --items all --view expanded
ast-grep outline internal/tools/registry.go --items all --view expanded

echo
echo '=== Range, truncation, and observation call sites ==='
rg -n -C 5 -P '\b(offset|limit|endLine|truncated|Observe|observation|RecordRead|read credit)\b' \
  internal/tools/read_file.go \
  internal/tools/file_safety_test.go \
  internal/tools/file_tools_test.go \
  internal/tools/registry.go \
  internal/tools/read_minified_file.go \
  internal/tools/read_minified_file_test.go

Length of output: 54503


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== End-to-end regression test ==='
sed -n '299,333p' internal/tools/file_safety_test.go

echo
echo '=== Registry execution and observation commit ==='
sed -n '129,259p' internal/tools/registry.go

echo
echo '=== Canonical range calculation and observation creation ==='
sed -n '66,177p' internal/tools/read_file.go
sed -n '179,278p' internal/tools/read_file.go

echo
echo '=== Corrective commit for the original blocker ==='
git show --format=fuller --find-renames --find-copies 3aa190bd7f56266325a196b4985c56c413c4d4a5 -- \
  internal/tools/read_file.go \
  internal/tools/file_safety_test.go \
  internal/tools/file_tools_test.go \
  internal/tools/registry.go

Length of output: 24078


@anandh8x I reviewed the latest commit and the prior blocking range issue.

limit now defines the exact end of the canonical line range. An interior range no longer sets Truncated. The regression test uses Registry.RunWithOptions, confirms read credit for lines 500-509, and confirms that an edit in that range succeeds.

The latest commit also prevents overflow for a maximum limit in read_minified_file.

I found no remaining blockers. I did not run tests because the review sandbox does not execute repository code.

[approve]

You are interacting with an AI system.

@anandh8x
anandh8x requested a review from Vasanthdev2004 August 6, 2026 06:30

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict: Approve

Checked out and exercised. The diagnosis is the strong part: two overlapping pagination systems in one schema is an ambiguity the model resolves by combining them, and the old behaviour answered that with a hard error and a retry loop until the guard stopped the run. Six invalid calls then a dead run is a real cost, and the benchmark showing it complete afterwards is the right evidence for it.

Compatibility is genuinely preserved, not just claimed. byte_offset/byte_limit are still in the schema and still work; the canonical offset/limit sit alongside rather than replacing them. Conflicting spellings of the same axis (offset + start_line, limit + end_line/max_lines) still error, which is right — those are the same question asked twice, and picking one would be a guess.

The mixed line+byte case resolves to lines (byteMode := (hasByteOffset || hasByteLimit) && !hasLineRange), which is the correct choice: the failure being fixed is exactly a model that sent both, and answering something beats failing. TestReadFileToolMixedLegacyRangesPreferLines pins it.

go test ./internal/tools/ ./internal/minify/ ./internal/agent/ green on the branch.

One inconsistency worth a follow-up, not blocking

This file already establishes the principle, in its own words at read_file.go:208:

The recovery is surfaced in the output (rangeNote) so it is never silent

The end_line < start_line recovery follows it and emits a note. The new byte-args-ignored recovery does not — a caller that asked for a byte range gets a line range with nothing saying its byte arguments were dropped. Same class of recovery, one discloses and one does not.

I am not blocking on it for one reason: the output is line-numbered (2 | beta), so a byte read and a line read are visually distinguishable, and a model can tell what it got. That makes this a clarity gap rather than a correctness one. Still, a one-line note in the same shape as rangeNote would close it and keep the file consistent with the rule it states about itself.

Unrelated, for the record

TestRunDoctorFormatsRedactedProviderDiagnostics and TestRunDoctorConnectivityProbesProvider fail on this branch — and I verified they fail identically on pristine origin/main, so they are pre-existing and not yours. Worth someone filing separately; they will keep showing up in every reviewer's local run until then.

@anandh8x

anandh8x commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai The latest review found no actionable comments and confirmed the previous blocker is fixed. Please clear the stale changes-requested review and approve the latest commit if no issues remain.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

@anandh8x The prior range blocker is fixed. The latest review found no actionable comments. I approve the latest commit.

✅ Action performed

Comments resolved and changes approved.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving. All four are fixed, and I re-ran the same probes that found them rather than reading the diff.

The blocking one, an interior offset/limit read earning no read-before-edit credit, is gone: on a 1000-line file offset=500 limit=10 now comes back truncated=false with seen_lines=500-509 and the follow-up edit succeeds. It used to be truncated=true, reason="limit", empty seen_lines, edit refused.

The other three as well. Mixing argument families no longer reads the wrong lines: start_line+limit and offset+end_line both return 5-6 now, where they gave 1-2 and 5-8. Byte mode is back in the schema ([offset limit byte_offset byte_limit path]), so a file with a line past the read budget is reachable again. And a ranged Go read starting inside a raw string keeps its content: SECRET-MARKER-ONE survives intact instead of arriving as SECRET - MARKER - ONE, and the line that looked like a comment is no longer deleted.

internal/tools and internal/minify both pass, build and vet clean.

One note for whoever merges rather than for you: this branch carries a merge of main from earlier today, so the diff reads larger than the change.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

@anandh8x approved. All four are fixed and I re-ran the probes that found them rather than reading the diff, so this is verified rather than assumed.

mergeStateStatus is CLEAN, and human approvals are @gnanam1990 and me. If the ruleset wants a third human you will need @jatmn, otherwise it is ready to go.

The one I care most about is the interior range: offset=500 limit=10 now returns seen_lines=500-509 with the edit succeeding, where before it was flagged truncated and the follow-up edit was refused. That was the whole reason I blocked, and it is properly gone rather than worked around.

Thanks for taking the raw-string one seriously too. That was the quietest of the four and the one most likely to have shipped unnoticed, since it corrupted content while reporting a successful compaction.

@anandh8x
anandh8x merged commit 57858a3 into main Aug 7, 2026
9 checks passed
gnanam1990 added a commit to gnanam1990/zero that referenced this pull request Aug 7, 2026
Gitlawb#867 landed on main while this branch was being rebased, reshaping
read_file's schema to the canonical path/offset/limit contract and
rewording its description. The golden hashes the tool DEFINITION bytes,
so a description change on main moves it — the same way Gitlawb#838's rewording
did before.

The new value is what the fixture's tools actually hash to on this base,
and it is the value CI computed independently: the macOS and Ubuntu smoke
jobs both reported got ea7b4e64… against the old constant, which is the
figure recorded here now.

This is main's schema change, not a posture leak from this branch. The
byte-identical guarantee is unaffected: what the guard protects is that a
posture-off run's definitions match a binary built from the same main,
and both sides moved together.
gnanam1990 added a commit to gnanam1990/zero that referenced this pull request Aug 8, 2026
Gitlawb#867 landed on main while this branch was being rebased, reshaping
read_file's schema to the canonical path/offset/limit contract and
rewording its description. The golden hashes the tool DEFINITION bytes,
so a description change on main moves it — the same way Gitlawb#838's rewording
did before.

The new value is what the fixture's tools actually hash to on this base,
and it is the value CI computed independently: the macOS and Ubuntu smoke
jobs both reported got ea7b4e64… against the old constant, which is the
figure recorded here now.

This is main's schema change, not a posture leak from this branch. The
byte-identical guarantee is unaffected: what the guard protects is that a
posture-off run's definitions match a binary built from the same main,
and both sides moved together.
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.

3 participants