Skip to content
Coding AgentsPatch application and conflict handling

Mid · Core path · 7 chapters

Patch application and conflict handling

Validating an edit before it lands

Patch handling is a senior-level reliability boundary: a superficially successful edit can silently corrupt code or waste an entire agent run.

Read these first

What you will know

  • Apply a patch and detect a conflict rather than corrupting a file

    Context drift, duplicate matches, and offset shifts can make a syntactically valid result semantically wrong.

  • Validate an edit before it lands

    Parsing catches syntax, while linting and compilation expose unresolved names, type errors, and generated-file mismatches.

  • Roll back a bad edit cleanly

    A snapshot, inverse patch, or clean checkout must restore both contents and the index without discarding unrelated work.

  • Handle a patch that applies but breaks the build

    A successful hunk match says nothing about tests, imports, types, or behavior exercised only at runtime.

  • Reproduce a blind-apply corruption case and add a guard that prevents it

    Fuzzy context matching and partial writes can leave plausible-looking code that passes superficial inspection.


Chapters

  1. 1

    A non-zero offset is a conflict wearing a success message

    "Hunk #2 succeeded at 812 (offset 47 lines)" should stop the loop. The anchor matched somewhere other than where the patch aimed, and in a file full of copy-pasted retry blocks the applier resolves that ambiguity by proximity — a coin flip that put the payments edit into the refunds path. Compares a strict applier that rejects on any fuzz with a permissive one, and prices the failure each turns into. Build the fixture that proves it: two near-identical blocks and a patch whose anchor is ambiguous corrupts on demand, and the same file is what shows the guard refusing to apply.

  2. 2

    The base moved between the read and the apply

    The agent read the file at turn 3 and emits its edit at turn 9. In between, its own earlier hunk landed, a formatter ran, a generator rewrote the file, or the engineer typed in another window — and a byte-exact anchor can still match a file that no longer means what the model believed, so zero offset and zero fuzz prove nothing here. Capture a content hash when the file is read, compare it immediately before applying, and re-read and re-plan rather than reapplying when it differs. Otherwise the in-memory validation that follows is checking a candidate assembled on a base that no longer exists.

  3. 3

    Parse the candidate in memory, then write by rename

    One run in seven comes back after six minutes with a collection error and nothing ran, because a syntax error reached disk. Parse the candidate content in memory first — milliseconds against six minutes, and every downstream result is meaningless until it passes. Then write through a temporary file in the same directory and rename over the target, so a cancelled run cannot leave a half-written module that happens to parse at a function boundary.

  4. 4

    A clean apply plus a parse is a claim about one file

    A patch applying with no offset and no fuzz, on a file that then parses, has established exactly two things: the text landed where it was aimed, and the result is syntactically valid. Neither reaches unresolved names, types, imports or behaviour, and the module's own green suite does not extend them beyond the file. Naming that boundary is what stops a loop accepting an edit on the strength of a clean apply.

  5. 5

    Validation depth has to match the blast radius of the edit

    An edit to a shared response model applies, parses and passes its module's suite, and CI then fails: a checked-in generated client still declares the old field, and two dependent services no longer compile. Every check the loop ran was local and the change was not. Running the full build on every iteration prices the loop out of existence, so the rule must recognise which paths carry a wider obligation.

  6. 6

    Roll back exactly the paths the patch touched

    git checkout -- . at the repository root restores the broken file and takes forty minutes of unrelated uncommitted work with it; git stash hides the human's changes while the agent runs and skips untracked files. Restore instead from a snapshot taken immediately before the edit, covering only the touched paths and leaving the rest of the tree and the staged index as the engineer left them. Includes when to refuse and hand it to a person.

  7. 7

    Order the validation ladder around the moment of writing

    Parse, format, lint, type-check, compile, module tests, affected-target build: sequencing them is the design, and the file is written only once the cheap checks pass, so a failure is a no-op rather than a rollback. Writing first means an unparseable file exists on disk while formatters, language servers and test runners observe it. Answers the objection that CI already runs this, and names the check to drop first under pressure.

External resources