Skip to content

perf: improve harness context efficiency - #838

Merged
anandh8x merged 14 commits into
mainfrom
feat/harness-efficiency-foundation
Jul 31, 2026
Merged

perf: improve harness context efficiency#838
anandh8x merged 14 commits into
mainfrom
feat/harness-efficiency-foundation

Conversation

@anandh8x

@anandh8x anandh8x commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • defer optional built-in tools behind a stable searchable catalog while keeping core read, search, edit, execution, and planning tools eager
  • report the actual initially exposed, available, and deferred tool surface in zero context
  • compact repetitive successful go test package output while retaining exact raw output as an artifact and surfacing that state in the TUI
  • track file versions and exact seen line ranges so edits reject stale or unseen source content
  • prune superseded identical read results only when compaction pressure already requires a context rewrite
  • normalize provider-expanded empty or already-covered permission requests to avoid wasteful failed tool retries
  • make planning and specialist guidance milestone-based and evidence-driven instead of encouraging unnecessary model/tool turns
  • replace per-turn recap requests with a cancellable idle orientation note that appears after four minutes of inactivity and uses the active goal, current task, and recent conversation to suggest the next action

Why

Zero previously exposed full schemas for optional tools on every request, retained repeated recoverable context, relied on weaker read-before-edit state, and issued an extra recap request after every successful TUI turn. This increased fixed context and could cause avoidable model retries and tool calls. The changes keep capabilities discoverable while reducing model-visible noise, strengthening edit safety, and moving recap work off the critical path.

Measured impact

Frozen 10-task comparison using the same ChatGPT provider, GPT-5.5 model, balanced execution profile, task wording, and one iteration per task:

Metric Before After Change
Correctness-checked tasks 6/6 6/6 unchanged
Initial fixed context 10,964 8,201 tokens -25.2%
Initial tool schemas 5,977 3,271 tokens -45.3%
Total input tokens 838,494 493,714 -41.1%
Uncached input tokens 237,918 177,810 -25.3%
Output tokens 8,724 5,470 -37.3%
Model requests 79 47 -40.5%
Tool calls 84 50 -40.5%
Generation span time 249.7s 129.7s -48.1%

Generated benchmark reports remain outside the repository.

Recap measurement scope

The benchmark runs tasks back-to-back and does not wait for the four-minute idle window, so the figures above do not measure the recap redesign. No token, cost, or latency improvement is claimed for that path. Its behavior is verified separately: scheduling performs no provider work, user activity and disabling recaps cancel in-flight generation, stale results are discarded, and the TUI no longer makes an immediate duplicate recap request after a completed turn. A generated idle recap may use up to 4,800 characters of bounded goal, plan, and recent-conversation context, compared with the previous 1,600-character final-answer input.

Verification

  • make fmt-check
  • go vet ./...
  • go test ./...
  • focused go test -race coverage for file tracking, output reduction, tool partitioning, pruning, permission normalization, and recap cancellation
  • go run ./cmd/zero-release build
  • go run ./cmd/zero-release smoke
  • make lint-static
  • make vulncheck
  • git diff HEAD --check
  • manual Terminal Control TUI check against the freshly built branch binary: a normal answer completed without the previous immediate duplicate recap request

Summary by CodeRabbit

  • New Features

    • Optional tools can now be discovered on demand, reducing initial context usage.
    • Added exact byte-range file reads with UTF-8-safe continuation details.
    • Added idle recaps after periods of inactivity.
    • Repetitive command output is summarized while preserving complete raw output.
  • Bug Fixes

    • Strengthened file safety by requiring observed content before edits.
    • Improved permission normalization and output metadata preservation.
  • Improvements

    • Reduced unnecessary context compaction.
    • Tool cards now display output-budget and saved-artifact indicators.
    • Refined tool discovery and delegation guidance.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: cf1de4b6-dbe4-4123-8130-cc9158a99000

📥 Commits

Reviewing files that changed from the base of the PR and between 7d16bda and 73e07cd.

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

Walkthrough

Changes

The pull request adds deferred tool discovery, exact file-observation enforcement, context pruning, command-output reduction, TUI budget indicators, permission normalization, idle recaps, and updated agent guidance.

Deferred tool discovery

Layer / File(s) Summary
Deferred tool registration and catalog
internal/tools/*, internal/agent/loop.go, internal/agent/deferred_loop_test.go
Optional tools are marked deferred. The tool catalog remains stable as deferred tools load.
Deferred context reporting
internal/contextreport/*, internal/cli/context.go, internal/cli/deferred_wiring_test.go
Reports include available and deferred tool counts and apply DeferThreshold.

Exact file observation safety

Layer / File(s) Summary
Observation tracking and range reads
internal/tools/file_tracker.go, internal/tools/read_file.go
FileTracker records version-scoped line and byte ranges. read_file supports exact UTF-8-safe byte ranges.
Edit and patch enforcement
internal/tools/edit_file.go, internal/tools/write_file.go, internal/tools/apply_patch.go, internal/tools/registry.go, internal/agent/loop.go
Edits, overwrites, and patches validate observed content. Tracker commits occur after final output processing.
Safety regression coverage
internal/tools/*test.go, internal/agent/output_budget_propagation_test.go, internal/agent/loop_test.go
Tests cover partial reads, exact reads, UTF-8 ranges, formatting, patch creation, truncation, retries, and follow-up edits.

Output compaction and presentation

Layer / File(s) Summary
Context pruning
internal/agent/prune.go, internal/agent/compaction.go, internal/agent/*test.go
Older identical read results are pruned before stale-output cleanup and summarization.
Command output reduction
internal/tools/shell_output_reducer.go, internal/tools/registry.go, internal/tools/output_boundary.go, internal/tools/*test.go
Supported simple Go test output is compacted while raw output and metadata are retained.
TUI status propagation
internal/tui/transcript.go, internal/tui/session.go, internal/tui/model.go, internal/tui/rendering.go, internal/tui/tool_display_test.go
Tool-result metadata renders compact-token and raw-artifact indicators.

Permission normalization

Layer / File(s) Summary
Permission normalization
internal/agent/loop.go, internal/agent/additional_permissions_validation_test.go
Redundant additional permissions are removed before shell permission handling. Real or broadening requests remain unchanged.

Idle recaps

Layer / File(s) Summary
Idle recap lifecycle
internal/tui/model.go, internal/tui/recap.go, internal/config/*
Recaps run after inactivity, use bounded session context, reject stale work, and render as ephemeral orientation text.
Idle recap validation
internal/tui/recap_test.go
Tests cover scheduling, context selection, cancellation, stale messages, rendering, and configuration changes.

Agent guidance

Layer / File(s) Summary
Delegation, planning, and editing guidance
internal/agent/system_prompt.go, internal/agent/system_prompt.md, internal/agent/specialist_delegation_test.go
Delegation, plan updates, and focused multi-file editing instructions are revised and tested.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TUI
  participant RecapProvider
  User->>TUI: Stop interacting
  TUI->>TUI: Start four-minute idle timer
  TUI->>RecapProvider: Request bounded session recap
  RecapProvider-->>TUI: Return recap text
  TUI-->>User: Display ephemeral idle recap
Loading

Possibly related PRs

  • Gitlawb/zero#172: Directly related FileTracker, read_file, and edit-safety changes.
  • Gitlawb/zero#842: Directly related FileTracker range-coverage changes and tests.

Suggested reviewers: jatmn, vasanthdev2004, gnanam1990

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.26% 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 summarizes the primary objective of improving harness context efficiency across the changeset.
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/harness-efficiency-foundation

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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tools/output_boundary.go (1)

60-70: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Retain the upstream raw spill when both layers truncate.

If command reduction already set result.Truncated and budgetSemanticOutput also truncates, Line 60 is skipped. Line 69 then spills the already-reduced output and replaces spill_path, so the exact raw artifact is no longer reachable.

Capture the upstream spill before deciding whether to create a new one:

+ if result.Truncated && budgeted.spillPath == "" {
+   budgeted.spillPath = result.Meta["spill_path"]
+ }
  if result.Truncated && !budgeted.truncated {
    budgeted.truncated = true
    ...
-   budgeted.spillPath = result.Meta["spill_path"]
  }

Add a regression test with reducer output large enough to trigger the self-managed budget too.

🤖 Prompt for 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.

In `@internal/tools/output_boundary.go` around lines 60 - 70, Update the
truncation handling around budgetSemanticOutput to preserve
result.Meta["spill_path"] before the budgeted truncation check, including when
both result.Truncated and budgeted.truncated are true. Prevent
attachExistingSpill from replacing an existing upstream raw spill path, and add
a regression test where reducer output also exceeds the self-managed budget
while verifying the raw upstream artifact remains reachable.
🧹 Nitpick comments (1)
internal/agent/prune.go (1)

154-165: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Track all newer bodies for each read key.

Line 165 overwrites the prior body. For A → B → A results from the same call, the oldest A remains even though the newest A supersedes it, reducing the intended context savings.

Suggested fix
- type seenResult struct {
-   content string
- }
- seen := map[string]seenResult{}
+ type seenResultKey struct {
+   call    string
+   content string
+ }
+ seen := map[seenResultKey]struct{}{}
...
- key := call.Name + "\x00" + strings.TrimSpace(call.Arguments)
- if newer, exists := seen[key]; exists && newer.content == message.Content {
+ key := call.Name + "\x00" + strings.TrimSpace(call.Arguments)
+ resultKey := seenResultKey{call: key, content: message.Content}
+ if _, exists := seen[resultKey]; exists {
...
- seen[key] = seenResult{content: message.Content}
+ seen[resultKey] = struct{}{}
🤖 Prompt for 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.

In `@internal/agent/prune.go` around lines 154 - 165, Update the deduplication
state around the seen map and its assignment in the pruning loop to retain every
newer result body for each read key instead of overwriting the prior body. For
each message, treat it as superseded when any later body for the same key
matches its content, so an A → B → A sequence replaces both older A results
while preserving the newest result.
🤖 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/agent/additional_permissions_validation_test.go`:
- Around line 199-228: Update the test around normalizeNoopAdditionalPermissions
to start with SandboxPermissionsWithAdditionalPermissions instead of
SandboxPermissionsUseDefault, while keeping the engine-covered
additional_permissions setup. After normalization, assert sandbox_permissions is
reset to SandboxPermissionsUseDefault and retain the existing assertion that
additional_permissions is removed.

In `@internal/agent/compaction.go`:
- Around line 416-423: Add a regression test covering the
pruneSupersededReadResults path in the compaction flow: configure superseded
reads so pruning reduces calibrated usage at or below state.threshold, assert
the returned messages and lowWaterMark, and verify the summarizer is not
invoked.

In `@internal/tools/edit_file.go`:
- Around line 168-173: Preserve the pre-format content around the edit-file flow
and only record ranges as seen when formatting leaves the content unchanged or
the formatted result is explicitly returned/read. Apply this guard to
internal/tools/edit_file.go at lines 168-173 and internal/tools/write_file.go at
line 121, while retaining existing range behavior for unchanged content.

In `@internal/tools/file_safety_test.go`:
- Around line 147-152: Update the successful edit test around
registry.RunWithOptions to read the resulting f.txt contents and assert they
contain “bravo,” while retaining the existing StatusOK assertion so a no-op
success cannot pass.

In `@internal/tools/file_tracker.go`:
- Around line 89-104: Update RecordSeenRange to treat total == 0 as a whole-file
observation before rejecting end < start, so empty files set observation.whole
and clear ranges. In internal/tools/write_file.go lines 121-121, retain the
existing full-observation call for empty writes; add a regression test covering
a subsequent overwrite of a newly created empty file.

In `@internal/tools/registry_test.go`:
- Around line 527-537: The BuiltinCatalog test does not fail when an unlisted
tool is unexpectedly deferred. Update the loop around wantDeferred and
IsDeferred to reject any deferred tool whose name is absent from wantDeferred,
while preserving the expected deferred-tool checks and removal logic.

In `@internal/tools/shell_output_reducer.go`:
- Around line 18-25: Update the reduction guard in the command-output flow
around commandTextForReducer and reduceGoTestPassingPackages to return the
original result whenever result.Status indicates failure, before compacting
output. Preserve reduction only for successful commands, and extend the failure
test with enough passing-package lines to cover the reduction branch.

---

Outside diff comments:
In `@internal/tools/output_boundary.go`:
- Around line 60-70: Update the truncation handling around budgetSemanticOutput
to preserve result.Meta["spill_path"] before the budgeted truncation check,
including when both result.Truncated and budgeted.truncated are true. Prevent
attachExistingSpill from replacing an existing upstream raw spill path, and add
a regression test where reducer output also exceeds the self-managed budget
while verifying the raw upstream artifact remains reachable.

---

Nitpick comments:
In `@internal/agent/prune.go`:
- Around line 154-165: Update the deduplication state around the seen map and
its assignment in the pruning loop to retain every newer result body for each
read key instead of overwriting the prior body. For each message, treat it as
superseded when any later body for the same key matches its content, so an A → B
→ A sequence replaces both older A results while preserving the newest result.
🪄 Autofix (Beta)

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: 7efe8b89-3963-4edf-8285-64c1417c2802

📥 Commits

Reviewing files that changed from the base of the PR and between d37de92 and 68a60f1.

📒 Files selected for processing (38)
  • internal/agent/additional_permissions_validation_test.go
  • internal/agent/compaction.go
  • internal/agent/deferred_loop_test.go
  • internal/agent/loop.go
  • internal/agent/prune.go
  • internal/agent/prune_test.go
  • internal/agent/specialist_delegation_test.go
  • internal/agent/system_prompt.go
  • internal/agent/system_prompt.md
  • internal/cli/context.go
  • internal/cli/deferred_wiring_test.go
  • internal/contextreport/contextreport.go
  • internal/contextreport/contextreport_test.go
  • internal/tools/bash.go
  • internal/tools/edit_file.go
  • internal/tools/file_safety_test.go
  • internal/tools/file_tracker.go
  • internal/tools/local_browser.go
  • internal/tools/local_capture.go
  • internal/tools/local_desktop.go
  • internal/tools/local_terminal.go
  • internal/tools/lsp_navigate.go
  • internal/tools/output_boundary.go
  • internal/tools/read_file.go
  • internal/tools/read_minified_file.go
  • internal/tools/registry.go
  • internal/tools/registry_test.go
  • internal/tools/shell_output_reducer.go
  • internal/tools/shell_output_reducer_test.go
  • internal/tools/types.go
  • internal/tools/web_fetch.go
  • internal/tools/web_search.go
  • internal/tools/write_file.go
  • internal/tui/model.go
  • internal/tui/rendering.go
  • internal/tui/session.go
  • internal/tui/tool_display_test.go
  • internal/tui/transcript.go

Comment thread internal/agent/additional_permissions_validation_test.go
Comment thread internal/agent/compaction.go
Comment thread internal/tools/edit_file.go Outdated
Comment thread internal/tools/file_safety_test.go
Comment thread internal/tools/file_tracker.go
Comment thread internal/tools/registry_test.go
Comment thread internal/tools/shell_output_reducer.go

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tools/edit_file.go (1)

144-144: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Record every span changed by replace_all.

replace_all updates every occurrence, but editStart uses strings.Index and the tracker records only one new span. After a partial read, a follow-up edit to a later replacement can be rejected as unseen even though the model supplied that replacement. Record the post-edit span for every occurrence, including line shifts caused by earlier replacements. Add a regression test with two occurrences on different lines.

Also applies to: 169-175

🤖 Prompt for 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.

In `@internal/tools/edit_file.go` at line 144, Update the replace_all handling
around editStart and the tracker updates to iterate over every occurrence of
oldString, recording each replacement’s post-edit span while accounting for
cumulative line shifts from earlier replacements. Preserve single-replacement
behavior, and add a regression test covering two occurrences on different lines
followed by a later edit to the second replacement.
🤖 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/format_on_write_test.go`:
- Around line 64-86: Extend the formatter-modified edit test around
NewScopedEditFileTool to perform a second edit without an intervening exact
read, using an intentionally unformatted replacement so the formatted output
differs from the model-known content. Assert that this edit returns StatusError
with the “has not been read exactly” message, then retain the existing
exact-read and successful follow-up edit assertions.

---

Outside diff comments:
In `@internal/tools/edit_file.go`:
- Line 144: Update the replace_all handling around editStart and the tracker
updates to iterate over every occurrence of oldString, recording each
replacement’s post-edit span while accounting for cumulative line shifts from
earlier replacements. Preserve single-replacement behavior, and add a regression
test covering two occurrences on different lines followed by a later edit to the
second replacement.
🪄 Autofix (Beta)

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: 07be597b-b10c-439d-b118-22bfc5d14c83

📥 Commits

Reviewing files that changed from the base of the PR and between 68a60f1 and 6ce0931.

📒 Files selected for processing (12)
  • internal/agent/additional_permissions_validation_test.go
  • internal/agent/compaction_test.go
  • internal/agent/prune.go
  • internal/agent/prune_test.go
  • internal/tools/edit_file.go
  • internal/tools/file_safety_test.go
  • internal/tools/file_tracker.go
  • internal/tools/format_on_write_test.go
  • internal/tools/output_boundary.go
  • internal/tools/registry_test.go
  • internal/tools/shell_output_reducer_test.go
  • internal/tools/write_file.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • internal/tools/write_file.go
  • internal/tools/registry_test.go
  • internal/agent/additional_permissions_validation_test.go
  • internal/tools/shell_output_reducer_test.go
  • internal/tools/output_boundary.go
  • internal/tools/file_safety_test.go
  • internal/tools/file_tracker.go
  • internal/agent/prune.go

Comment thread internal/tools/format_on_write_test.go
anandh8x added 2 commits July 31, 2026 12:10
Delay recap generation until the session has been inactive, orient it around the active goal and next task, cancel stale work on activity, and render the result ephemerally above the composer.

Also strengthen the formatter safety regression to exercise formatter-modified edit output.
Translate each replacement into its post-edit line range, including cumulative shifts from earlier replacements, so follow-up edits remain authorized for every model-supplied change.

@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.

🧹 Nitpick comments (1)
internal/tui/recap_test.go (1)

165-178: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for disabling recaps while generation is in-flight.

TestHandleConfigCommandTogglesRecaps only checks toggling on a static model. It does not exercise the path where recapCancel is set to a real cancel function and recapRunning is true when the user runs "recaps off". handleConfigCommand relies on cancelIdleRecap to cancel that context, mirroring TestUserActivityCancelsAndClearsIdleRecap. Add a similar case here to confirm the context actually cancels when recaps are disabled mid-generation, not just that idleRecap clears.

As per path instructions, "add a regression test for behavior changes."

✅ Suggested additional case
func TestHandleConfigCommandCancelsInFlightRecap(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	m := model{recapsEnabled: true, recapRunning: true, recapCancel: cancel, idleRecap: "old recap"}
	m, _ = m.handleConfigCommand("recaps off")
	if m.recapRunning || m.recapCancel != nil || m.idleRecap != "" {
		t.Fatalf("disabling recaps did not clear in-flight state: running=%v cancel=%v recap=%q", m.recapRunning, m.recapCancel != nil, m.idleRecap)
	}
	select {
	case <-ctx.Done():
	default:
		t.Fatal("disabling recaps did not cancel in-flight generation context")
	}
}
🤖 Prompt for 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.

In `@internal/tui/recap_test.go` around lines 165 - 178, Add a regression test
alongside TestHandleConfigCommandTogglesRecaps that creates a cancellable
context, initializes model with recapRunning true and recapCancel set, then
invokes handleConfigCommand("recaps off"). Assert the in-flight state and
idleRecap are cleared and verify the context is canceled, covering cancellation
through cancelIdleRecap.

Source: Path instructions

🤖 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.

Nitpick comments:
In `@internal/tui/recap_test.go`:
- Around line 165-178: Add a regression test alongside
TestHandleConfigCommandTogglesRecaps that creates a cancellable context,
initializes model with recapRunning true and recapCancel set, then invokes
handleConfigCommand("recaps off"). Assert the in-flight state and idleRecap are
cleared and verify the context is canceled, covering cancellation through
cancelIdleRecap.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d6d9a4e-f10f-49bb-87d3-7c3245bad8c4

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce0931 and 400e285.

📒 Files selected for processing (6)
  • internal/config/types.go
  • internal/config/writer.go
  • internal/tools/format_on_write_test.go
  • internal/tui/model.go
  • internal/tui/recap.go
  • internal/tui/recap_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/tools/format_on_write_test.go

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Had a look at 689591d4 while it's still a draft — early scope feedback rather than a line-by-line, since that's the useful thing to say now and not after another round of polish.

The numbers are good. -41% input tokens and -40% model requests with correctness held at 6/6 is a real result, and I like that the comparison is frozen on provider, model, profile and wording.

Seven independent changes in 44 files is my main concern. Tool deferral, context reporting, test-output compaction, file version tracking, read pruning, permission normalization and planning guidance don't depend on each other, and they fail in completely different ways: deferral is a provider-cache and discoverability question, file versioning is edit correctness, permission normalization is security-adjacent, compaction is output fidelity. If a context-efficiency regression shows up three weeks from now, a bisect lands on one commit that did all seven. Each is independently reviewable and independently revertable if they go in separately.

The recap rewrite isn't in the description at all, and it's the largest single change in the diff. recap.go +118-38 and recap_test.go +125-65 — more than any other file. It's not a refactor either; it changes user-visible behaviour:

  • per-turn summary → idle-triggered orientation note after recapIdleDelay = 4 * time.Minute
  • system prompt goes from "summarize what the assistant just did" to "state the goal, then the next actionable step"
  • context budget triples, recapMaxAnswerChars = 1600recapMaxContextChars = 4800

That's a reasonable change on its own merits. It just isn't one of the seven bullets, and someone reading the summary would not know it happened.

Related: I don't think the measured impact covers it. The recap only fires after four minutes of inactivity in the TUI, and a frozen 10-task benchmark with one iteration per task run back-to-back never idles that long — so recapIdleDelay never elapses and the recap path isn't exercised. The direction is plausibly still good (far fewer recap calls, each 3× larger), but as it stands the headline numbers can't be evidence for it either way. Worth either measuring it separately or saying it's unmeasured.

One thing I checked properly because it's the security-adjacent bit, and it's fine. normalizeNoopAdditionalPermissions fails closed on every path — unmarshal error, normalize error, and anything that isn't Empty() or CoversRequestPermissions all return with the args untouched. And stripping can only ever reduce what a command gets, so the failure direction is a command that errors rather than one that over-reaches. The comment claims "requests that broaden access and malformed payloads are left untouched so validation stays closed" and that's accurate.

Housekeeping: all three CodeRabbit reviews are on older commits (68a60f14, 6ce0931a, 400e2852) and the head is 689591d4, so the CHANGES_REQUESTED on the PR doesn't reflect what's there now.

Happy to do a proper review of any of these once they're split, or of the whole thing if you'd rather keep it together — say which and I'll go through it in depth. Not blocking anything while it's a draft.

Verify replace-all tracking through the canonical edit tool path instead of a platform-sensitive temp path, and cover cancellation when recaps are disabled during generation.
@anandh8x

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review Please review the latest commit (6474b14) and update the review status if the requested changes are addressed.

@anandh8x

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Built and ran this locally against main (d37de921) on Windows, 689591d4. Good news first: the headline numbers reproduce, on a different workspace and provider config than your benchmark.

main   : usage 11.4k   tools: 28                              Tools 6.4k
#838   : usage  8.4k   tools: 14 exposed, 28 available, 15 deferred   Tools 3.4k

Tool schemas −46.9% (you claimed −45.3%), total fixed context −26.3% (you claimed −25.2%). Independent corroboration on both.

go test ./... is green apart from two failures that fail identically on clean main on my box (TestBuildServeScopeKeepsLexicalPaths needs symlink privilege, TestAltScreenTranscriptScrollKeepsFooterFixed is the long-path footer one). -race on internal/tools, internal/agent, internal/contextreport is clean.

Deferral is safe. All five deferred tools — bash, lsp_navigate, read_minified_file, web_fetch, web_search — appear in the 452-char catalog, so nothing becomes unreachable. And exec_command stays eager, so shell work doesn't need a discovery round-trip first. That split looks right to me.

The elision guard is correct, and I checked it specifically because it's the dangerous direction. A 2.6MB file read returns 131KB with truncation_reason=byte_budget, and RecordSeenRange is skipped, so SeenWhole stays false. The model is never credited with content it didn't see. RecordSeenRange's "exact, non-elided" contract holds.


One real bug, though, and it falls out of exactly that guard.

A file past the read byte budget can never satisfy SeenWhole, so write_file with overwrite: true is permanently rejected on it:

full read: status=ok reason="byte_budget" seenWhole=false
write_file(overwrite): status=error
   Error writing big.go: the intended change depends on content that has not
   been read exactly in this session. Read the affected lines with read_file,
   then retry the edit.

There is no sequence of reads that clears it. Two things combine:

  1. A full read is byte-truncated, so RecordSeenRange is skipped entirely — nothing is recorded at all.
  2. RecordSeenRange only sets whole when a single call satisfies start == 1 && end >= total. Chunked reads accumulate ranges but never promote whole.

So the advice in the error can't work for this tool, which is the part I'd fix regardless of the rest — a model will loop on it.

Related and probably the same root: SeenWhole and SeenRange disagree about accumulated coverage. After reading 1–50 and 51–100 of a 100-line file, SeenRange(40,60) is true but SeenWhole is false. One merges adjacent ranges, the other doesn't.

edit_file is fine — it gates on SeenRange, and it succeeded on the same 2.6MB file after a scoped 5-line read. So the model isn't stuck, it just can't wholesale-rewrite a large file. That limits the blast radius but the misleading error still stands.

Suggestion: compute whole from the accumulated ranges rather than tracking it as a separate flag, which fixes both at once. If the byte-budget case is meant to be unrecoverable by design, the error should say so instead of pointing at read_file.

Happy to send this as a patch if it's useful — say the word. Everything above is on top of the scope and recap points from my earlier comment, which still stand.

SeenWhole was a flag set only by a SINGLE read covering the file, while
SeenRange judged coverage from the accumulated ranges. The two then
disagreed about identical reads: after reading lines 1-50 and 51-100 of a
100-line file, SeenRange(1,100) was true and SeenWhole was false.

That matters because write_file gates overwrites on SeenWhole. A file past
the read byte budget cannot be read whole in one call — the read is
truncated and RecordSeenRange is correctly skipped, since the model did not
see those lines — so no sequence of reads could ever set the flag, and the
overwrite was refused permanently with:

    the intended change depends on content that has not been read exactly
    in this session. Read the affected lines with read_file, then retry.

Advice that could not change the answer. edit_file was unaffected because it
gates on SeenRange, so the escape was to edit rather than rewrite, but a
model following the error text would loop.

SeenWhole is now computed from the ranges against the file's recorded line
count, so scoped reads that together cover a file make it writable and the
error text becomes actionable. The observation carries that line count, and
a read reporting a different one clears the accumulated ranges: they
describe a shape the file no longer has.

Coverage is judged by merging sorted ranges rather than walking every line
against every range, which the previous SeenRange did — same answer, and it
no longer scans line-by-line over a large file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Patch is up as #842, targeting feat/harness-efficiency-foundation rather than main so it lands inside this PR. Merge it, cherry-pick it, or close it and write it your way — no attachment to the implementation.

The SeenWhole derivation is the substance. Two things in there I'd particularly want a second opinion on: resetting the accumulated ranges when a read reports a different line count (otherwise a file read whole at 100 lines then appended to still reports seen-whole at 200), and switching coverage to merged-sorted-ranges — that path is now hit by SeenWhole too, so the old line-by-line scan would have been paid on every overwrite check of a large file.

Your existing file-tracking tests pass untouched.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Requested commit =='
git show --no-ext-diff --format=fuller --stat 6474b14
echo
echo '== Requested commit diff =='
git diff --no-ext-diff --find-renames 6474b14^ 6474b14 -- \
  internal/tools/file_tracker.go \
  internal/tools/file_safety_test.go \
  internal/tools/read_file.go \
  internal/tools/write_file.go \
  internal/tools/edit_file.go \
  internal/tools/format_on_write_test.go \
  internal/tui/recap.go \
  internal/tui/recap_test.go

echo
echo '== Relevant file outlines =='
ast-grep outline internal/tools/file_tracker.go --items all --type function,method
ast-grep outline internal/tools/file_safety_test.go --items all --type function
ast-grep outline internal/tools/read_file.go --items all --type function,method
ast-grep outline internal/tools/write_file.go --items all --type function,method

echo
echo '== File-tracker call sites and tests =='
rg -n -C 4 '\b(RecordSeenRange|SeenWhole|SeenRange|RecordHash)\s*\(' \
  internal/tools/file_tracker.go \
  internal/tools/file_safety_test.go \
  internal/tools/format_on_write_test.go \
  internal/tools/read_file.go \
  internal/tools/write_file.go \
  internal/tools/edit_file.go

Length of output: 14601


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Commits that changed file tracking since the earlier reviewed head =='
git log --no-ext-diff --oneline 689591d4..6474b14 -- \
  internal/tools/file_tracker.go \
  internal/tools/file_safety_test.go \
  internal/tools/read_file.go \
  internal/tools/write_file.go \
  internal/tools/edit_file.go

echo
echo '== FileTracker implementation =='
sed -n '1,260p' internal/tools/file_tracker.go

echo
echo '== File-safety regression test =='
sed -n '100,205p' internal/tools/file_safety_test.go

echo
echo '== Read/write/edit tracking paths =='
sed -n '62,130p' internal/tools/read_file.go
sed -n '60,132p' internal/tools/write_file.go
sed -n '128,245p' internal/tools/edit_file.go

echo
echo '== Recap cancellation implementation and test context =='
ast-grep outline internal/tui/model.go internal/tui/recap.go --items all --type function,method
rg -n -C 8 '\b(handleConfigCommand|recapCancel|recapRunning|cancel.*[Rr]ecap|recaps off)\b' \
  internal/tui/model.go internal/tui/recap.go internal/tui/recap_test.go

Length of output: 50222


@anandh8x I reviewed commit 6474b14.

The recap cancellation regression is addressed. handleConfigCommand("recaps off") calls cancelIdleRecap, and the new test verifies cancellation of the active context.

The file-tracker issue is not addressed. internal/tools/file_tracker.go still marks whole only when one RecordSeenRange call covers line 1 through the final line. It does not derive whole-file coverage from accumulated ranges. SeenWhole still reads only that flag.

As a result, a model cannot overwrite a large byte-truncated file after it reads every line in exact chunks. write_file continues to reject the overwrite because SeenWhole remains false. The test change in internal/tools/file_safety_test.go correctly tests shifted replace_all spans through the canonical tool path, but it does not test accumulated whole-file coverage or line-count changes.

I cannot mark the requested file-tracker change as addressed.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Vasanthdev2004 and others added 3 commits July 31, 2026 13:22
read_file resolves the workspace root through EvalSymlinks before recording
anything, so the tracker is keyed on the resolved path. The test asserted
against the raw t.TempDir() path, which is the same string on Windows and a
different one on macOS, where the temp dir sits under /var — a symlink to
/private/var. The SeenWhole assertions would have looked up a key that never
existed: passing here, failing on macOS CI.

Also switches the line generator to fmt.Fprintf (staticcheck QF1012).

Both from CodeRabbit on #842.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit's message claimed this was done. It was not: the edit
silently did not apply and I reported it fixed without re-reading the file,
so builder.WriteString(fmt.Sprintf(...)) survived at the head — caught by
@anandh8x, not by me.

Verified this time by running the linter rather than by reading the diff:
golangci-lint --enable-only unused,ineffassign,staticcheck ./internal/tools/
reports 0 issues.
fix(tools): derive SeenWhole from the recorded ranges
@anandh8x
anandh8x marked this pull request as ready for review July 31, 2026 14:13
@anandh8x

Copy link
Copy Markdown
Collaborator Author

@Vasanthdev2004 please review the latest head (b4bea8c6), which now includes #842. All CI checks are green. If your concerns are addressed, please approve and clear the requested-changes state.\n\n@coderabbitai review Please review the latest head and update the review status if all requested changes are addressed.

@anandh8x

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review\n\nPlease review the latest head (b4bea8c6) and update the review status if the requested changes are addressed.

@coderabbitai

coderabbitai Bot commented Jul 31, 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 '== Checked-out commit and PR head =='
git rev-parse HEAD
git show --no-ext-diff --format=fuller --no-patch HEAD
echo
echo '== Commits since prior review target =='
git log --no-ext-diff --oneline 6474b14..HEAD
echo
echo '== Changed files since prior review target =='
git diff --no-ext-diff --name-status 6474b14..HEAD
echo
echo '== File-tracker implementation map =='
ast-grep outline internal/tools/file_tracker.go --items all --type function,method
echo
echo '== File-tracker and tool-path source =='
sed -n '1,300p' internal/tools/file_tracker.go
sed -n '55,155p' internal/tools/read_file.go
sed -n '55,145p' internal/tools/write_file.go
sed -n '115,280p' internal/tools/edit_file.go
echo
echo '== File-tracker regression tests =='
fd -t f 'file_tracker.*test\.go|file_safety_test\.go|format_on_write_test\.go' internal/tools \
  -x sh -c 'echo "--- $1"; ast-grep outline "$1" --items all --type function' sh {}
echo
echo '== New commit diffs =='
git diff --no-ext-diff --find-renames 6474b14..HEAD -- \
  internal/tools/file_tracker.go \
  internal/tools/file_tracker_coverage_test.go \
  internal/tools/file_tracker_largefile_test.go \
  internal/tools/file_safety_test.go \
  internal/tools/read_file.go \
  internal/tools/write_file.go \
  internal/tools/edit_file.go \
  internal/tools/format_on_write_test.go

Length of output: 38994


@anandh8x I reviewed commit b4bea8c6.

The prior FileTracker.SeenWhole finding is addressed.

SeenWhole now derives complete coverage from accumulated ranges. coversFully handles adjacent, overlapping, and out-of-order ranges. RecordSeenRange clears prior coverage when the line count changes.

The new tests cover the previous large-file failure path. They also cover range gaps and changed line counts.

I found no new correctness, safety, CLI UX, or test-coverage issue in the incremental changes. I did not execute tests in this environment. CI is reported green.

I resolved my review comments. An approval requires an explicit @coderabbitai approve command.

[resolve]

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Jul 31, 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 '== Current HEAD and requested commit =='
git rev-parse HEAD
git show --no-ext-diff --format=fuller --stat b4bea8c6

echo
echo '== Commits after the previously reviewed commit =='
git log --no-ext-diff --oneline 6474b14..b4bea8c6

echo
echo '== File-tracker changes since the previous review =='
git diff --no-ext-diff --find-renames 6474b14..b4bea8c6 -- \
  internal/tools/file_tracker.go \
  internal/tools/file_tracker_coverage_test.go \
  internal/tools/file_tracker_largefile_test.go \
  internal/tools/file_safety_test.go \
  internal/tools/read_file.go \
  internal/tools/write_file.go

echo
echo '== FileTracker implementation outline =='
ast-grep outline internal/tools/file_tracker.go --items all --type function,method

echo
echo '== FileTracker implementation =='
sed -n '1,300p' internal/tools/file_tracker.go

echo
echo '== File-tracker coverage and large-file regression tests =='
sed -n '1,260p' internal/tools/file_tracker_coverage_test.go
sed -n '1,220p' internal/tools/file_tracker_largefile_test.go

echo
echo '== Relevant tracker call sites =='
rg -n -C 5 '\b(RecordSeenRange|SeenWhole|SeenRange|RecordHash)\s*\(' \
  internal/tools/read_file.go \
  internal/tools/write_file.go \
  internal/tools/edit_file.go \
  internal/tools/file_tracker.go \
  internal/tools/file_tracker_coverage_test.go \
  internal/tools/file_tracker_largefile_test.go

echo
echo '== Pull request review metadata =='
gh pr view 838 --repo Gitlawb/zero --json headRefOid,reviews,reviewDecision,statusCheckRollup \
  --jq '{headRefOid, reviewDecision, reviews: [.reviews[] | {author: .author.login, state, commit: .commit.oid}], checks: [.statusCheckRollup[] | {name: .name, conclusion: .conclusion, status: .status}]}'

Length of output: 45674


@anandh8x I reviewed b4bea8c6.

The requested file-tracker change is addressed.

SeenWhole now derives whole-file coverage from accumulated exact read ranges. coversFully merges sorted adjacent and overlapping ranges. RecordSeenRange resets recorded coverage when the reported line count changes.

The new tests cover cumulative scoped reads, coverage gaps, range ordering, changed file length, byte-truncated reads, and overwrite success after complete scoped reads of a large file.

I found no new blocking issue in this focused review. The completed CI checks report success.

[resolve]

You are interacting with an AI system.

@anandh8x

Copy link
Copy Markdown
Collaborator Author

@coderabbitai approve

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@github-actions

github-actions Bot commented Jul 31, 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: 73e07cd3eaef
Changed files (49): internal/agent/additional_permissions_validation_test.go, internal/agent/compaction.go, internal/agent/compaction_test.go, internal/agent/deferred_loop_test.go, internal/agent/loop.go, internal/agent/loop_test.go, internal/agent/output_budget_propagation_test.go, internal/agent/prune.go, internal/agent/prune_test.go, internal/agent/specialist_delegation_test.go, internal/agent/system_prompt.go, internal/agent/system_prompt.md, and 37 more

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

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

@anandh8x flagging the rename/copy one from my review as the priority — it's the only finding that's a regression against your own previous head, so it's cheap to confirm.

apply_patch.go:130:

wasWhole := wholeBefore[absolute] || createdBefore[absolute]

createdBefore comes from missingPatchTargets, and patchHeaderPaths feeds it both sides of diff --git a/X b/Y. So the destination of a rename or copy is "missing before the apply" and gets treated as a file the model supplied in full. It didn't — git took those bytes from the source, which the patch never quotes.

Smallest repro, no read_file anywhere in the session:

diff --git a/secret.txt b/exposed.txt
similarity index 100%
rename from secret.txt
rename to exposed.txt

On 1c1cb942: SeenWhole(exposed.txt)=true, and write_file with overwrite: true then rewrites it — a file whose contents were never shown to the model. On b4bea8c6 the same sequence gives SeenWhole=false and the write is refused. Copy patches behave the same way. Worth running a write_file control on an unread file first so you can see the gate is live in the harness before you measure.

The fix is in what createdBefore is allowed to mean: "the patch body contained every line of this file" (a /dev/null creation hunk) rather than "this path didn't exist before". Rename and copy headers should fall through to Forget like everything else.

The byte-mode over-credit in the same review has a different root cause — recording happens before Registry.RunWithOptions applies its budget — so they'll need separate fixes. No rush on my end, ping me when it's pushed and I'll re-check both.

@anandh8x anandh8x changed the title Improve harness context efficiency perf: improve harness context efficiency Jul 31, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 31, 2026

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tools/registry.go (1)

139-155: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Commit file observation after the final model output in the retry and ask_user paths.

When DeferFileObservationCommit is true, registry.RunWithOptions defers until the caller calls CommitFileObservation. executeToolCall takes that path and commits after dispatchAfterTool, but runToolForNetworkRetry, runToolForUnsandboxedRetry, and askUserFallbackResult do not pass the flag or commit. If these paths run file-tracking tools, they can leave later edits refused despite a successful successful read, or commit too early before caller output transformations. Add the final-commit handling for these direct Registry outputs and cover it with a race-detector test.

🤖 Prompt for 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.

In `@internal/tools/registry.go` around lines 139 - 155, Update
runToolForNetworkRetry, runToolForUnsandboxedRetry, and askUserFallbackResult to
preserve DeferFileObservationCommit and commit file observations only after all
final output transformations complete, matching executeToolCall behavior. Ensure
each direct Registry output propagates the defer state and performs the final
CommitFileObservation when required, preventing premature or missing commits.
Add a race-detector test covering file-tracking tools through these retry and
ask_user paths.
🧹 Nitpick comments (1)
internal/tools/apply_patch.go (1)

163-216: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the shared hunk-walking logic to avoid duplicated diff parsing.

completeCreatedPatchTargets (Lines 163-216) and patchHeaderPaths (Lines 293-329) both implement the same unified-diff line-walking state machine: tracking inHunk, oldRemaining, newRemaining, and consuming hunk-body lines identically. A future fix to hunk-counting or line-classification logic in one function can be missed in the other, which is risky for patch-parsing code that gates file-observation safety.

Extract a shared line-walker that yields classified lines (diff header, ---/+++ header, @@ header, hunk body) to both callers, keeping each function's per-line handling in its own callback.

🤖 Prompt for 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.

In `@internal/tools/apply_patch.go` around lines 163 - 216, Extract the duplicated
unified-diff hunk state machine from completeCreatedPatchTargets and
patchHeaderPaths into a shared line-walker that classifies diff headers, file
headers, hunk headers, and hunk-body lines. Update both callers to consume the
walker while retaining their existing per-line handling and results.
🤖 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/agent/loop.go`:
- Around line 1360-1361: Update both retry helpers, runToolForNetworkRetry and
runToolForUnsandboxedRetry, to copy DeferFileObservationCommit into their
RunOptions alongside FileTracker. Preserve the flag’s existing value so retry
results continue through the loop-level CommitFileObservation step.

In `@internal/agent/output_budget_propagation_test.go`:
- Around line 76-130: Update both tests,
TestExecuteToolCallCommitsReadObservationAfterFinalBoundary and
TestExecuteToolCallDoesNotCommitReadObservationBeforeHookBudget, to create a
separate target file plus a symlink, invoke read_file with the symlink path, and
retain the resolved target path for tracker assertions. Ensure the first test
expects the target to be observed and the second confirms it is not committed
before hook output budgeting.

In `@internal/tools/file_safety_test.go`:
- Around line 205-214: Extend the follow-up edit assertion in the test around
registry.RunWithOptions to read new.txt after the successful edit and verify its
content is exactly "updated content". Keep the existing status assertion, and
fail the test if reading the file fails or the replacement did not change the
supplied content.

---

Outside diff comments:
In `@internal/tools/registry.go`:
- Around line 139-155: Update runToolForNetworkRetry,
runToolForUnsandboxedRetry, and askUserFallbackResult to preserve
DeferFileObservationCommit and commit file observations only after all final
output transformations complete, matching executeToolCall behavior. Ensure each
direct Registry output propagates the defer state and performs the final
CommitFileObservation when required, preventing premature or missing commits.
Add a race-detector test covering file-tracking tools through these retry and
ask_user paths.

---

Nitpick comments:
In `@internal/tools/apply_patch.go`:
- Around line 163-216: Extract the duplicated unified-diff hunk state machine
from completeCreatedPatchTargets and patchHeaderPaths into a shared line-walker
that classifies diff headers, file headers, hunk headers, and hunk-body lines.
Update both callers to consume the walker while retaining their existing
per-line handling and results.
🪄 Autofix (Beta)

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: 5b731c93-30e3-4876-9567-54a9997a2eaf

📥 Commits

Reviewing files that changed from the base of the PR and between 2ddb134 and 74c06a1.

📒 Files selected for processing (9)
  • internal/agent/loop.go
  • internal/agent/output_budget_propagation_test.go
  • internal/tools/apply_patch.go
  • internal/tools/file_safety_test.go
  • internal/tools/file_tracker.go
  • internal/tools/file_tracker_largefile_test.go
  • internal/tools/read_file.go
  • internal/tools/registry.go
  • internal/tools/types.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/tools/types.go
  • internal/tools/file_tracker.go

Comment thread internal/agent/loop.go
Comment thread internal/agent/output_budget_propagation_test.go
Comment thread internal/tools/file_safety_test.go
gnanam1990
gnanam1990 previously approved these changes Jul 31, 2026

@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. My blocker is closed, and so are both of the soundness holes @Vasanthdev2004 found after my last review — I verified all three independently rather than reading the commit messages.

Re-reviewed at 74c06a13, base d37de921. Previously reviewed at 1c1cb942; the delta is 2ddb1340 "test: cover permission normalization wiring" and 74c06a13 "fix: commit file observations after output budgeting".

Withdrawn — my blocker

The permission normalization was reachable only through tests that called the helper directly, so deleting the call site left internal/agent green. 2ddb1340 adds the wiring test. Re-running the same mutation now fails TestExecuteToolCallNormalizesProviderExpandedEmptyAdditionalPermissions. Closed.

Verified — both of Vasanth's findings

Credit where it is due: these were the two real defects in this PR and I did not find either. I had probed the "can the model edit content it never saw" direction on an older head and cleared it; his probes were better aimed.

Rename and copy destinations no longer gain whole-file credit. apply_patch.go:132 now derives wasWhole from completeCreatedPatchTargets — only files whose full contents come from a /dev/null creation hunk — instead of missingPatchTargets, which counted any header path that did not previously exist and therefore swept in rename/copy destinations whose bytes come from an unread source. Reproduced his probe end to end, with a control first to prove the gate was live:

control: write_file on never-read src.txt -> error      (gate live)
apply_patch(rename)                       -> ok
   SeenWhole(dst, NEVER read)             = false       (was true)
   write_file on never-read dst           -> error
   disk = "ORIGINAL SECRET CONTENT"                     (unchanged)

Byte credit is no longer granted for content the registry strips. The recording moved out of the tool and behind pendingFileObservation, committed by Registry.CommitFileObservation only when result.Status == StatusOK && !result.Truncated && strings.HasPrefix(result.Output, observation.output) — i.e. only when the tool's complete output survived every later layer intact. That is the right shape: a trimming layer breaks the prefix and silently forfeits credit rather than over-claiming it.

Load-bearing, confirmed by mutation. Reducing the guard to observation == nil || tracker == nil fails three tests across two packages:

--- FAIL: TestRegistryTruncationDoesNotCreditUndeliveredByteRanges
--- FAIL: TestRegistryTruncationDoesNotCreditWholeLineRead
--- FAIL: TestExecuteToolCallDoesNotCommitReadObservationBeforeHookBudget

The third is the one I would have asked for: it pins the agent-side hook budget as a layer that must also run before credit is committed, not just the registry's own budget.

Also fixed since my review

  • The title is now a conventional commitperf: improve harness context efficiency. With ten-plus commits the squash subject comes from the PR title, so this will now produce a changelog entry rather than being silently dropped.
  • go test -cover keeps its numbers. reduceGoTestPassingPackages now excludes lines containing coverage: or [no test files]. I confirmed all 20 coverage lines survive in a synthetic go test -cover ./... output and the reduction correctly declines to fire. This also subsumes the narrower t.Logf("ok …") case I raised.

What I verified overall

Across three passes I have now tried to break seven mechanisms in this PR. Six were pinned by tests that failed for the right reason; the seventh (permission wiring) is fixed above.

Mutation Result
SeenWhole ignores accumulated line ranges caught
SeenWhole ignores byte coverage caught (incl. a UTF-8 boundary case)
apply_patch drops whole-seen propagation caught
Output reducer disabled caught
Deferred tool catalog emptied caught (6 tests)
Observation committed despite a trimmed output caught (3 tests)
Permission normalization call site deleted caught, as of 2ddb1340

Gauntlet at this head, darwin/arm64, non-/tmp checkout: go build ./..., make fmt-check, go vet ./..., git diff HEAD --check all clean; internal/tools, internal/agent, internal/tui, internal/contextreport all pass. The two internal/cli doctor failures are pre-existing and environmental on my machine — they read the real ~/.config/zero/config.json and fail identically at base.

Non-blocking

  • The headline measurements are stale in the one direction that matters. read_file has gained byte_offset and byte_limit since the benchmark was run, and it is eager (no Deferred() method), so both properties and their descriptions now sit in the fixed context on every request. The "-45.3% initial tool schemas" and "-25.2% initial fixed context" figures were measured at 68a60f14. Still very likely a large net win, but since the case for this PR rests on those numbers, re-running them at the final head before merge would make the claim true again rather than approximately true.
  • Scope: eight changes, no linked issue. All eight are now disclosed in the description, which was my substantive objection, so I am not holding the PR for it. The cost is on record though: across this PR's life, three separate defects — the SeenWhole lockout, the rename credit and the byte over-credit — each needed its own follow-up commit, and every one of them lived in the read-before-edit change. That piece would have been much easier to reason about, bisect and revert on its own.
  • One edit still clears the seen ranges for the whole file, not just the touched region: RecordRecordHash drops the entire seen entry on any hash change, after which only the edited spans are re-recorded. That is the conservative direction and I am not asking for a change, but it is the same wasted-re-read cost that motivated the apply_patch work, so it is worth knowing it is still there for edit_file.

Not verified

  • The prune-on-pressure change and the context-report change, beyond confirming their packages pass.
  • The prompt/guidance rewrite, which is behavioural in a way tests cannot settle.
  • The recap rework beyond confirming internal/tui passes; Vasanth checked its four guarantees by breaking each in turn and I did not repeat that.
  • The full go test ./...; I ran the five affected packages.
  • Any platform other than darwin/arm64.

The testing discipline here ended up genuinely strong — every defect found in review came back with a regression test that fails for the right reason.

Vasanthdev2004
Vasanthdev2004 previously approved these changes Jul 31, 2026

@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.

Re-reviewed at 74c06a13. Both blockers are fixed, and the way you fixed them is better than what I suggested — staging a pendingFileObservation and committing it at the boundary that actually decides what the model receives is the right shape, and the HasPrefix(result.Output, observation.output) check is a nice touch because it verifies survival rather than trusting a flag.

Re-ran every probe from my last review:

[rename] SeenWhole(dst)=false  write_file=error
[copy]   SeenWhole(dst)=false  write_file=error
byte-mode CJK: credit=""  SeenWhole=false  edit on never-delivered marker=error
line-mode 102KB CJK: seen_lines=""  SeenWhole=false

And checked you didn't over-correct, which was the real risk here:

  • a genuine /dev/null creation patch still gets whole-file credit and the follow-up edit passes — completeCreatedPatchTargets draws the line where it should
  • read → patch → edit still needs no re-read
  • the ASCII single-line recovery still works, 7 chunks, write succeeds
  • a hunk body containing literal --- /dev/null and +++ b/secret.txt lines does not fool the parser — the hunk-count skip holds, credit stays false and the write is refused

The executeToolCall wiring is right too: defer set at 1361, commit at 1413 after RebudgetAfterHook, exactly once, and every early return simply loses credit rather than granting it.

Clearing my requested-changes. Two things I'd like handled, neither blocking.

The recovery path doesn't converge at its own default on multibyte content. byte_limit defaults to 65536 and that's also the maximum, and on CJK text a 65536-byte request delivers ~290 bytes, gets correctly denied credit, and says nothing about why:

byte_limit=65536  truncated=true  delivered=287    credit=NONE
byte_limit=16384  truncated=false delivered=16459  credit=0-16383
byte_limit=4096   truncated=false delivered=4169   credit=0-4095

At 16384 a 252KB CJK file covers in 16 calls, so the path works fine — but only if the model happens to pick a smaller limit. At the default it gets a spill-path notice, and an identical retry returns identically, so it has no reason to try anything different and no signal telling it to. The refusal text names byte_offset/byte_limit but not "smaller". Either mention the limit that would fit when the budget denies a byte-mode read, or have the tool shrink the chunk itself — it knows the content is multibyte before it renders.

The new defer flag has no enforcement, and two of its first callers already diverge. CodeRabbit caught this one and it's worth acting on: runToolForNetworkRetry and runToolForUnsandboxedRetry both build a fresh tools.RunOptions that sets FileTracker but not DeferFileObservationCommit, so the registry commits inline — and their results then return into executeToolCall and pass through RebudgetAfterHook before reaching the model. Credit lands before that layer can trim. (askUserFallbackResult sets no tracker, so it's moot there.) I traced this rather than reproducing it — it needs a file-tracking tool to hit a sandbox retry, which is narrow — so treat it as unconfirmed, but the shape is the same one this commit exists to fix. The general problem is that "any caller with an extra output layer must set this flag" is an invariant nothing checks, and it was already missed twice in the same file the day it was introduced. Worth a comment on the field at minimum.

gofmt, go vet and the internal/tools, internal/agent and recap suites are all clean for me.

@anandh8x
anandh8x dismissed stale reviews from Vasanthdev2004 and gnanam1990 via 7d16bda July 31, 2026 17:19

@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: 1

🤖 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/agent/loop_test.go`:
- Around line 493-495: Update both retry fixture assertions in the test to
require the complete defer flag sequence [false, true], not merely a true second
entry. Verify that the initial call does not defer file observation commits and
only the retry does, preserving the existing failure diagnostics for each
fixture.
🪄 Autofix (Beta)

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: 877c8511-2464-4ae7-957e-17f74ceb852d

📥 Commits

Reviewing files that changed from the base of the PR and between 74c06a1 and 7d16bda.

📒 Files selected for processing (4)
  • internal/agent/loop.go
  • internal/agent/loop_test.go
  • internal/agent/output_budget_propagation_test.go
  • internal/tools/file_safety_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/agent/output_budget_propagation_test.go
  • internal/agent/loop.go
  • internal/tools/file_safety_test.go

Comment thread internal/agent/loop_test.go
Vasanthdev2004
Vasanthdev2004 previously approved these changes Jul 31, 2026

@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.

Re-checked at 7d16bda4. The retry fix is right — both helpers now pass DeferFileObservationCommit: true, and since CommitFileObservation at loop.go:1413 sits outside the if toolFound block, the retry branch reaches it. I mutation-tested your new assertion by stripping the flag from both helpers (leaving executeToolCall's in place) and both tests failed with retry defer flags = []bool{true, false}, so it's load-bearing rather than incidental.

Re-ran the earlier probes on this head and nothing regressed: rename and copy still give SeenWhole=false with the write refused, a 64K CJK chunk still earns no credit and the edit is refused, and the ASCII single-line recovery is still 7 chunks to a successful write.

One thing to fix before you merge — TestApplyPatchCompleteCreationCreditsSuppliedFile fails on Windows:

file_safety_test.go:219: follow-up edit content = "updated content\r\n", want "updated content\n"

It's the test, not the code. git apply runs in the tool's temp workspace, which picks up core.autocrlf=true from Git for Windows' system gitconfig — my repo has core.autocrlf=false locally and it still reproduces, so a local override won't save it. Git for Windows installs that system default, so windows-latest will very likely hit the same thing. ubuntu-latest and macos-latest are already green here, which fits — they never see CRLF.

Cheapest fix is to stop asserting on exact bytes for something git apply is allowed to rewrite: compare with line endings normalized, or pass -c core.autocrlf=false on the git apply invocation the tool makes. Same family as the CRLF traps we've hit before on this repo.

Approving on the substance so my earlier review isn't what's holding this up — everything I asked for across the three rounds is in. @anandh8x once the Windows check is sorted, go ahead and merge.

@anandh8x

Copy link
Copy Markdown
Collaborator Author

@gnanam1990 @Vasanthdev2004 GitHub automatically marked the prior reviews stale after the required Windows CI fix was pushed. The latest commit only normalizes CRLF/LF in the cross-platform test assertion; the production changes are unchanged. Please re-review the latest head when available. @coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 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

repo="Gitlawb/zero"
pr="838"

echo '== PR head and review status =='
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,reviewDecision,statusCheckRollup \
  --jq '{
    headRefOid,
    reviewDecision,
    checks: [.statusCheckRollup[] | {name, status, conclusion}]
  }'

head="$(gh pr view "$pr" --repo "$repo" --json headRefOid --jq .headRefOid)"
echo
echo "== Commits after 1c1cb942 through ${head} =="
git log --no-ext-diff --oneline 1c1cb942.."$head"

echo
echo '== Changed files after 1c1cb942 =='
git diff --no-ext-diff --name-status 1c1cb942.."$head"

echo
echo '== Incremental diff after 1c1cb942 =='
git diff --no-ext-diff --find-renames 1c1cb942.."$head"

echo
echo '== Relevant implementation map =='
ast-grep outline internal/tools/apply_patch.go internal/tools/registry.go internal/tools/read_file.go internal/tools/file_tracker.go --items all --type function,method

echo
echo '== Patch visibility and observation-commit paths =='
rg -n -C 10 '\b(createdBefore|missingPatchTargets|patchHeaderPaths|fullySupplied|/dev/null|rename from|rename to|copy from|copy to|CommitFileObservation|pendingFileObservation|DeferFileObservationCommit|RecordSeenBytes|RecordSeenRange)\b' \
  internal/tools/apply_patch.go \
  internal/tools/registry.go \
  internal/tools/read_file.go \
  internal/tools/file_tracker.go \
  internal/tools/*_test.go

echo
echo '== Focused diffs since b4bea8c6 for the unresolved concerns =='
git diff --no-ext-diff --find-renames b4bea8c6.."$head" -- \
  internal/tools/apply_patch.go \
  internal/tools/registry.go \
  internal/tools/read_file.go \
  internal/tools/file_tracker.go \
  internal/tools/file_safety_test.go \
  internal/tools/file_tracker_largefile_test.go \
  internal/agent/loop.go \
  internal/agent/output_budget_propagation_test.go

Length of output: 126398


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Latest commit metadata and diff =='
git show --no-ext-diff --format=fuller --stat 73e07cd
git show --no-ext-diff --find-renames --format= 73e07cd

echo
echo '== Affected test context =='
git show --no-ext-diff --format= --name-only 73e07cd |
while IFS= read -r file; do
  [ -n "$file" ] || continue
  echo "--- $file"
  ast-grep outline "$file" --items all --type function,method
  sed -n '1,260p' "$file"
done

echo
echo '== Current PR review and check status =='
gh pr view 838 --repo Gitlawb/zero \
  --json headRefOid,reviewDecision,statusCheckRollup \
  --jq '{
    headRefOid,
    reviewDecision,
    checks: [.statusCheckRollup[] | {name, status, conclusion}]
  }'

Length of output: 13075


@anandh8x I reviewed the latest head, 73e07cd3.

The latest commit changes only the CRLF/LF comparison in TestApplyPatchCompleteCreationCreditsSuppliedFile. It does not change production code.

The prior requested changes remain addressed:

  • Rename and copy destinations do not receive whole-file visibility without an exact read.
  • /dev/null creation patches retain whole-file visibility when the patch supplies the file content.
  • Read observations commit only after final output budgeting and after-tool processing.
  • Registry and hook truncation do not grant visibility for omitted output.

I found no new blocking issue in this incremental review. I did not execute tests in this environment. Analyze (actions), Performance Smoke, and CodeQL have succeeded. Other checks are still running.

[resolve]

You are interacting with an AI system.

@anandh8x

Copy link
Copy Markdown
Collaborator Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ 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.

Re-checked at 73e07cd3. The line-ending fix is right, and Smoke (windows-latest) is green now — that test passes on my Windows box too, where it was failing before. Good that you normalized rather than loosening the assertion to a substring; it still proves the edit landed.

Confirmed the change is test-only (one line in file_safety_test.go, nothing in production), and re-ran the gate checks on this head:

[rename] SeenWhole=false write=error
[copy]   SeenWhole=false write=error
CJK 64K chunk: credit="" edit=error
/dev/null create: patch=ok edit=ok

So both bypasses stay closed and the legitimate creation path still gets its credit. internal/tools and internal/agent suites are clean here. The one internal/tui failure I see locally is TestAltScreenTranscriptScrollKeepsFooterFixed, which also fails on origin/main for me and passes in your CI — my machine, not this PR.

Re-approving; my previous one was dismissed by the push. Everything I raised across the four rounds is in, and the two follow-ups from my earlier review still stand as non-blocking: the multibyte byte_limit default that earns no credit with nothing telling the model to shrink it, and a comment on DeferFileObservationCommit noting that any caller with its own output layer has to set it.

Nice work on this one — the staged-observation design ended up cleaner than the fix I originally suggested.

@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. Everything blocking across four review rounds is closed. I verified the two fixes in this delta independently, including reproducing the Windows-only failure on macOS so it is not taken on trust.

Re-reviewed at 73e07cd3, base d37de921 (level with origin/main). Previously approved at 74c06a13; the delta is 7d16bda4 "fix: defer file observations across retries" and 73e07cd3 "test: normalize patch line endings".

Verified in this delta

The retry helpers now defer their observation commit, and the assertion is load-bearing. runToolForNetworkRetry and runToolForUnsandboxedRetry previously built a fresh tools.RunOptions carrying FileTracker but not DeferFileObservationCommit, so credit landed inline — before RebudgetAfterHook could trim what actually reaches the model. Flipping all three occurrences of the flag to false fails three tests:

--- FAIL: TestRunRetriesShellUnsandboxedAfterSandboxNamespaceLimitedOutput
--- FAIL: TestRunRetriesNetworkDeniedShellWithNetworkGrant
--- FAIL: TestExecuteToolCallDoesNotCommitReadObservationBeforeHookBudget

The Windows CRLF failure is genuinely fixed, and I confirmed it without Windows. @Vasanthdev2004 reported TestApplyPatchCompleteCreationCreditsSuppliedFile failing on windows-latest because Git for Windows ships core.autocrlf=true in its system config, which the tool's temp workspace inherits. I reproduced that condition on darwin by pointing HOME at a scratch dir with core.autocrlf=true set globally, then reverted the assertion to its pre-fix exact-byte form:

=== pre-fix assertion, autocrlf=true
--- FAIL: TestApplyPatchCompleteCreationCreditsSuppliedFile
    file_safety_test.go:219: follow-up edit content = "updated content\r\n", want "updated content\n"

=== fixed assertion, autocrlf=true
ok  github.com/Gitlawb/zero/internal/tools

That is his reported failure byte for byte, so the simulation is faithful and the normalization is what closes it. Worth recording the technique: this class of Windows-only test failure is reproducible anywhere by overriding the global gitconfig, which is cheaper than waiting on CI.

Gauntlet at this head, darwin/arm64, non-/tmp checkout: go build ./..., make fmt-check, go vet ./..., git diff HEAD --check all clean; internal/tools, internal/agent, internal/tui, internal/contextreport all pass. Level with origin/main.

Everything blocking, across four rounds

Finding Raised by Closed at
write_file locked out on files > 128 KiB me a1a9503b
Recap change undocumented in the description me description rewrite
Permission normalization wiring untested me 2ddb1340
Rename/copy destination granted whole-file credit Vasanth 74c06a13
Byte credit for registry-stripped content Vasanth 74c06a13
Retry helpers committed credit before rebudget Vasanth / CodeRabbit 7d16bda4
Windows CRLF test failure Vasanth 73e07cd3

Eight mutations across four rounds; every mechanism is now pinned by a test that fails for the right reason.

Non-blocking — both carried from Vasanth's review, both still open

  • A denied byte-mode read still gives the model no reason to try a smaller chunk. byte_limit defaults to 65536, which is also its maximum, and on CJK content a 65536-byte request delivers ~290 bytes, is correctly denied credit, and returns a message naming byte_offset/byte_limit but never "smaller" (read_file.go:211, :213; file_tracker.go:380). An identical retry returns identically, so nothing pushes the model toward the 16384 that would converge. Either name a fitting limit in the denial or have the tool shrink the chunk itself — it knows the content is multibyte before it renders.
  • The defer-flag invariant is documented but not enforced. RunOptions.DeferFileObservationCommit carries a two-line comment (registry.go:34-36) and nothing more. "Any caller with an extra output layer must set this flag" was already missed twice in loop.go on the day it was introduced, which is the repo's recurring "two things that must agree, with nothing asserting they do" shape. The established remedy here is a drift test — an AST walk over internal/agent asserting that every tools.RunOptions literal setting FileTracker also sets DeferFileObservationCommit would make a third miss impossible rather than merely unlikely.

Not verified

  • The prune-on-pressure and context-report changes, beyond confirming their packages pass.
  • The prompt/guidance rewrite, which is behavioural in a way tests cannot settle.
  • The recap rework beyond internal/tui passing; Vasanth broke each of its four guarantees in turn and I did not repeat that.
  • Actual Windows CI. My reproduction simulates the core.autocrlf condition, which is the mechanism he identified, but it is not a real windows-latest run.
  • The full go test ./...; I ran the four affected packages.

One process note for the record, not a reason to hold this: the read-before-edit change accounted for six of the seven blocking findings above, each needing its own follow-up commit. Landing it as its own PR would have made every one of them cheaper to find, bisect and revert. Worth doing that way next time rather than unpicking this one now.

@anandh8x
anandh8x merged commit 8e26679 into main Jul 31, 2026
9 checks passed
gnanam1990 added a commit to gnanam1990/zero that referenced this pull request Aug 1, 2026
ONE REAL CONFLICT, in the TUI model's fields. main replaced the /retitle
backfill with a local /rename (Gitlawb#826), so its side deletes retitleQueue and the
four counters beside it and adds renamePrompt; this branch's side carries the
orchestrate plan surface main has never seen. Both, not either: keeping our copy
of the retitle fields would have resurrected state whose only callers main
removed, leaving it compiling and unreachable.

THE POSTURE-OFF GOLDEN MOVED, and it was checked rather than assumed. Gitlawb#838
reworded four tool descriptions (glob, grep, list_directory, read_file), which
changes the definition bytes the fingerprint freezes. A moved golden is exactly
what a posture leak from this branch would look like, so the two were told apart
by measurement: a posture-off run's first request body, compared byte for byte
against a binary built from this same main, across --auto low/medium/high/member
and --use-spec. All five identical. The absolute sizes moved with main's new
wording (33549 -> 31851 on --auto low); the difference between the binaries
stayed zero, which is the property the guard exists for.

Everything else auto-merged.
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