Files
Andrey Kumanyaev 275780299a fix(mcp): expose the disk-commit boundary when a mutating tool is abandoned
A tool call is bounded by a transport deadline; when it fires, boundHandler
answers the client and lets the handler keep running. agents.AtomicWriteFile
takes no context, so a handler that had already reached its rename committed to
disk anyway — and the caller was told only "the work may still complete in the
background, so treat any side effect as unknown".

That single message covered two opposite outcomes. A client reading it as
"nothing happened" retried, or fell back to its own editor, and applied the same
logical change twice.

Split the two states and make both observable:

- Every disk commit registers in a durable ledger BEFORE the write and is
  stamped terminal immediately after it, so a receipt exists for any mutation
  that is still reachable.
- commitFileMutation adds a cancellation gate between registration and the
  write. Stopping there is a guarantee that nothing was written, not a guess;
  the remaining window is one atomic rename wide and is covered by an
  in_flight receipt.
- The abandoned-call error now reports what actually landed — committed with
  path and new_sha, not_applied, or genuinely unknown — plus a machine-readable
  mutation_commit={...} tail. Read tools keep the original wording.
- Edit responses carry disk_status and graph_status as independent fields:
  bytes reaching disk and the graph catching up are different questions with
  different failure modes.
- mutation_status (facade: change/receipt) queries a receipt by id,
  mutation_id, or path for 30 minutes, refreshing a still-pending graph state
  rather than answering from a stale snapshot.
- edit_file / write_file / edit_symbol take an optional mutation_id
  idempotency key, mirroring batch_edit's transaction_id: the same key with the
  identical edit replays the original result instead of writing twice, and a
  different edit under the same key is refused.

rename_symbol and the batch symbol/file edits register in the same ledger; a
coordinated rename now stops at its first cancelled write instead of attempting
every remaining file.

The agent preset's tools/list ceiling is re-based 28200 -> 28400 for the
mutation_id parameter on the two edit tools (148 bytes measured); the preset
itself did not grow.

Fixes #548
2026-08-19 23:01:25 +02:00
..