Skip to content

fix: prevent write_file from clobbering external edits via staleness check (#65604) - #65618

Closed
webtecnica wants to merge 1 commit into
NousResearch:mainfrom
webtecnica:fix/65604-staleness-check
Closed

webtecnica wants to merge 1 commit into
NousResearch:mainfrom
webtecnica:fix/65604-staleness-check

Conversation

@webtecnica

Copy link
Copy Markdown
Contributor

Adds a staleness check to write_file that detects if the file has been modified externally since the agent first read it. Uses mtime comparison to detect changes and warns before overwriting external edits from stale conversation context.\n\nCloses #65604

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/file File tools (read, write, patch, search) needs-decision Awaiting maintainer decision before any implementation labels Jul 16, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related: #65605 also addresses #65604 with a broader fresh-baseline/fail-closed guard; this PR adds an mtime staleness warning path.

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

Code Review Summary

Verdict: Comment

Scope

  • test files updated (tests/tools/test_file_staleness.py, tests/tools/test_file_state_registry.py)
  • Changes assertion from _warning to error for external modification cases.

Quality

  • Test updates reflect the new blocking behavior (error instead of warning when file modified externally).
  • Clear docstring updates.

Looks Good

  • Test-only changes — reflects the behavior change from the corresponding fix.

Reviewed by Hermes Agent

@webtecnica

Copy link
Copy Markdown
Contributor Author

👋 Friendly bump — this PR is ready and CI is green, awaiting a maintainer decision. Could you take a look when you have a moment? Thanks @teknium1!

@webtecnica
webtecnica force-pushed the fix/65604-staleness-check branch from 4b0aa59 to b36276f Compare July 18, 2026 01:55

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

Thanks for addressing the real write-after-stale-read problem. Current main calls file_ops.write_file() before adding the stale warning at tools/file_tools.py:1623-1633, so a pre-mutation refusal is valuable.

Problems

  • The proposed blocker at tools/file_tools.py:1629 only catches an existing read/write stamp. _check_file_staleness() returns no signal without a read timestamp (tools/file_tools.py:1519-1524), so an existing unread file can still be fully replaced. The related #65605 discussion identifies this full-baseline case.
  • The diff also makes stale patch calls fail at proposed tools/file_tools.py:1777. Current patch behavior deliberately reports a warning (tools/file_tools.py:1742-1784), and the PR title/body are scoped to write_file.

Suggested changes

  • Require a current complete read or prior successful same-task full write before replacing an existing file, with a preservation test.
  • Limit fail-closed behavior to write_file; retain stale patch warnings unless a broader semantic change is intended.

Automated hermes-sweeper review.

Comment thread tools/file_tools.py
cross_warning = file_state.check_stale(task_id, _resolved)
stale_warning = _check_file_staleness(path, task_id)
# Block on staleness — refuse to clobber external edits or
# sibling-subagent changes. The caller must re-read first.

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.

This only blocks when a tracker entry already exists. _check_file_staleness() returns None for an unread path, so a task can still fully overwrite an existing file without a fresh baseline. Add an existing-file/full-read baseline check here.

Comment thread tools/file_tools.py
cwd_warnings.append(_cwd)

# Block on staleness — refuse to apply a patch that would
# clobber external edits or sibling-subagent changes.

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.

This broadens the write_file fix into a hard behavioral change for targeted patches. Current patch staleness is warning-only; please retain that behavior unless the patch semantic change is intentionally approved.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 18, 2026
@webtecnica

Copy link
Copy Markdown
Contributor Author

Closing as duplicate — #65605 covers the same stale write_file overwrite protection with a broader fix (still open, updated Aug 3). Thanks for the coordination! 🙏

@webtecnica webtecnica closed this Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades tool/file File tools (read, write, patch, search) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants