Skip to content

fix(tools): classify no-op file mutations#97000

Closed
wuqxuan wants to merge 1 commit into
openclaw:mainfrom
wuqxuan:codex/no-op-file-mutations
Closed

fix(tools): classify no-op file mutations#97000
wuqxuan wants to merge 1 commit into
openclaw:mainfrom
wuqxuan:codex/no-op-file-mutations

Conversation

@wuqxuan

@wuqxuan wuqxuan commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes #96983.

No-op file mutations in agent-controlled tools could previously look like successful progress or ordinary retryable failures. In particular, identical write calls rewrote the file and returned success, identical edit calls threw only an unstructured no-change error, and apply_patch update hunks could report a modified file even when the patch produced identical content.

Why This Change Was Made

This change classifies no-op file mutations at the built-in file-tool boundary instead of adding broader loop policy:

  • write now returns a terminal blocked result with reason: "no-op-write" when precheck proves the target already has identical content, without calling the write operation.
  • edit now converts its no-change edit condition into a terminal blocked result with reason: "no-op-edit", without writing the file.
  • apply_patch now skips no-op update hunks and returns a terminal blocked result with reason: "no-op-patch" when the entire patch changes nothing.

Real write, edit, add, delete, move, and patch mutation paths remain unchanged.

User Impact

Agents get a machine-readable terminal result for no-op file mutations instead of false progress or a generic retryable error. This should reduce repeated identical write/edit/patch loops while preserving normal file mutation behavior.

Evidence

Behavior addressed: no-op file mutations should be terminal blocked tool results, not successful writes or unstructured retryable failures.

Real environment tested: local OpenClaw source checkout on branch codex/no-op-file-mutations, commit c74a317888f201ea73797002b222dbf0ac7d7c4a.

Exact steps or command run after this patch:

node scripts/run-vitest.mjs src/agents/sessions/tools/write.test.ts src/agents/sessions/tools/edit.test.ts src/agents/apply-patch.test.ts
node scripts/run-vitest.mjs src/agents/tool-loop-detection.test.ts src/agents/embedded-agent-subscribe.handlers.tools.test.ts src/agents/embedded-agent-runner/run/payloads.errors.test.ts
git diff --check
node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
node scripts/run-oxlint-shards.mjs --only=core --split-core
.agents/skills/autoreview/scripts/autoreview --mode local --base origin/main

Evidence after fix:

  • Focused file-tool tests: 3 files passed, 33 tests passed.
  • Adjacent terminal-result plumbing tests: 3 files passed, 179 tests passed across 2 Vitest shards.
  • git diff --check: passed.
  • tsgo core production: passed.
  • tsgo core tests: passed.
  • Core oxlint split shard: passed.
  • Autoreview: clean, no accepted/actionable findings.

Observed result after fix:

  • Same-content write returns details: { ok: false, status: "blocked", reason: "no-op-write" }, sets terminate: true, and does not call the write operation.
  • Identical edit returns details: { ok: false, status: "blocked", reason: "no-op-edit" }, sets terminate: true, and does not call the write operation.
  • No-op apply_patch returns details: { ok: false, status: "blocked", reason: "no-op-patch" }, sets terminate: true, and leaves file content unchanged.

What was not tested:

  • node scripts/check-changed.mjs could not start remote Testbox proof because the local crabbox binary failed its sanity check before provisioning. The touched core surface was covered with focused Vitest, core tsgo, core oxlint, git diff --check, and autoreview instead.
  • No live agent-loop replay was run; the repair is covered at the built-in tool-result boundary that feeds existing terminal-result plumbing.

AI-assisted: This PR was authored with AI assistance. The behavior and verification above were checked in the local repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(tools): treat no-op edits and identical writes as terminal tool-loop failures

1 participant