read_state: flag write overwriting a file the agent never read - #241
Open
bobzhang wants to merge 1 commit into
Open
read_state: flag write overwriting a file the agent never read#241bobzhang wants to merge 1 commit into
bobzhang wants to merge 1 commit into
Conversation
…ession Adds a session-scoped ReadState (agent_tool/read_state) — a seen-set the file tools share for one agent run. `read` and `edit` record the paths they touch; `write` consults it and, when it overwrites an existing file that was never read or written this session, appends " (overwrote existing file you had not read this session)" so a wholesale replacement of unseen content is visible in the transcript. The agent loop (tool_definitions) creates one ReadState and hands it to read/edit/write; standalone tool use (no ReadState) keeps the prior behavior. Two deliberate, data-driven choices (from analyzing 19 recorded toml-parser runs, where 175/395 writes were blind re-writes of self-authored files): - It is a soft annotation, not a hard "read first" error. A hard guard would loop on those self-rewrites; `write`/`edit` record into ReadState after a successful write so a re-write of a file the agent itself created is not flagged. - It tracks only "seen vs not seen", not modification times. The "changed since you read it" half guards against concurrent editors/linters, which do not exist in a single batch CLI session. This stays dormant in from-scratch tasks (nothing pre-exists to clobber) and earns its keep on pre-existing codebases. The type is a public subpackage because the agent loop (outside agent_tool) must construct it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a session-scoped
ReadState(agent_tool/read_state) — a seen-set the file tools share for one agent run — and uses it to flag awritethat overwrites a file the agent never read this session:readrecords a path only on a complete read (whole file shown, untruncated);writerecords after writing (it authored the content) and checks before overwriting. The agent loop creates oneReadStateand hands it toread/write. Standalone tool use (noReadState) keeps prior behavior.ReadState::ReadState()is the constructor, as requested.Why a soft flag, and these exact rules (data-driven)
I analyzed 19 recorded toml-parser agent runs before building this. Across 395 writes: only 71 (18%) followed a read; 175 were blind re-writes of self-authored files; 149 were first-touch creates. In a from-scratch task (empty workspace) that's almost all benign — there's nothing pre-existing to clobber. So:
writerecords the path after writing, so re-writing a file the agent itself created is never flagged.(The live e2e against DeepSeek is firewalled in CI, so those recorded runs are the evidence.)
Subtleties (caught by codex review, now fixed)
start_line, smallmax_lines, or amax_output_charstruncation) must not mark the file fully seen — otherwise a later overwrite of the unseen remainder wouldn't warn. Recording now requiresshown_lines == total_lines && !truncated(a highmax_linesthat still covers the file counts).editdeliberately does not record. openseek doesn't require read-before-edit, so an edit only shows the agent a fragment; promoting an edit-only path to "fully seen" would wrongly suppress a later write's warning.Validation
moon check+moon fmtclean; 75 tests pass across the touched packages (incl. partial-vs-full read and unread-overwrite cases).read/writedefinition()gain an optionalread_state?; newagent_tool/read_statepackage.editunchanged.🤖 Generated with Claude Code