Marketing

Applying an Audit's Edit List Without Breaking the Draft

Antonio Evans8 min read

A split-screen scene: on the left, a printed draft with numbered lines and a stack of sticky notes, each with a line number and a short instruction; on the right.
Key points

Key points

  1. 1Treat a model's edit list as a patch with line targets, not as a finished rewrite you paste over the draft.
  2. 2Validate every line reference against the current file first, because inserted or deleted paragraphs above a target shift every line number below it.
  3. 3Apply the accepted edits in one reversible batch: back up the file, run on a copy, and confirm every changed span sits inside the flagged range.
  4. 4Review the output as a side-by-side diff before you commit, and watch for stray changes outside the flagged spans that signal voice drift.

Why line references go stale

A line-referenced edit list is a set of coordinates. Each finding says, in effect, "at line 41, change this." The coordinates were accurate when the model read the draft. They stop being accurate the moment anyone edits the document: adds an example, cuts a paragraph, or reorders a section.

The mechanics are simple and unforgiving. Insert three lines above line 41 and the target is now at line 44. Delete a paragraph and it moves up. This is the same problem diff and merge tools solve for source code every day. Review Board's diff viewer tracks added, removed and changed lines and even flags lines that moved without changing, so a reviewer can tell a cut-and-paste from a genuine edit Review Board's diff documentation. That is the behavior you want to imitate: know what moved before you accept anything.

The practical risk is silent: no error, no warning, just wrong text in the wrong place, discovered later by a reader.

Worked example: line drift in numbers

Suppose a 120-line draft comes back with five findings:

FindingOriginal lineChange
F112Replace a vague claim with a cited figure
F241Split a 60-word sentence
F358Remove a repeated phrase
F474Fix subject-verb agreement
F5101Tighten the closing paragraph

Now a colleague inserts a six-line example after line 20 and deletes two lines at line 60. Apply the list unchanged and F1 lands correctly, F2 lands six lines early, inside the paragraph above the intended target. F3 and F4 land four lines early because the deletion sits above them. F5 also lands four lines early. Every one of those misplaced edits succeeds silently. Line numbers alone cannot save you; you need a check that compares what the model quoted against what is actually at that line now.

Step 1: Freeze the draft and record a fingerprint

Before you touch anything, snapshot the file. Copy the draft to a working directory, compute a hash of its contents, and store it with the timestamp. Every later step runs against that snapshot, not against a live document someone might be editing in another window.

Keep the model's raw edit list exactly as it arrived. Do not hand-clean it, because the raw list is your record of what was asked for, and the cleaned list is what you chose to apply. If the edit list came back as free-form text, parse it into a fixed schema before anything else. The reliability argument for structured output applies here: a fixed shape with named fields and types makes the list programmatically checkable, while loose prose forces you to unpick it with string matching every time Agenta's guide to structured outputs. If your model returned prose findings, ask for JSON with a line number, the quoted original text, and the replacement text.

The general principle behind a good request is the same one that makes prompt engineering work when it is done well: be specific about what you want, and give the model the exact text it should be reasoning about rather than a vague description Prompting Guide's general tips. A finding that quotes its target precisely is easy to re-anchor. A finding that says "fix the intro paragraph" is not.

Step 2: Validate every line reference before applying anything

This is the step people skip, and it is the one that catches drift. For each finding, do three checks:

  1. Does the line number exist in the current file?
  2. Does the text at that line, or within a small window around it, match the excerpt the model quoted?
  3. Is the match unique, or does the same phrase appear several times?

When the excerpt matches exactly at the stated line, mark the finding as anchored. When it matches within a window of a few lines, you can infer the drift and correct it, but log the correction. When it does not match at all, mark it as unanchored and set it aside for a human read.

A short script turns this into a checklist you can scan in seconds:

import json

def anchor(findings, lines, window=5):
    results = []
    for f in findings:
        quoted = f["original"].strip()
        hits = [i for i, line in enumerate(lines)
                if quoted and quoted in line]
        near = [i for i in hits if abs(i - f["line"]) <= window]
        status = "anchored" if near else ("drifted" if hits else "missing")
        results.append({"id": f["id"], "status": status,
                        "claimed": f["line"],
                        "actual": near[0] if near else None})
    return results

lines = open("draft.md").read().splitlines()
findings = json.load(open("edits.json"))
for row in anchor(findings, lines):
    print(row)

Run it on the snapshot before and after any manual edit. A finding that flips from anchored to missing between runs tells you the draft changed under you, and the batch should wait.

Step 3: Sort findings into apply, re-anchor and hold

You now have three buckets: anchored findings, drifted findings you can confidently correct, and findings that need a human to locate them. Only the first two go into the batch. The third goes back to a person, with the draft open and the finding text beside it.

Before batching, decide whether any finding is actually a rewrite in disguise. A finding that says "replace line 41" is an edit. A finding that says "rewrite the section" is a new draft wearing an edit's clothes. Rewrites do not belong in the batch, because you cannot review them for voice drift against a specific span, and they turn one controlled change into a broad regeneration.

This is where a comparison table helps, because the categories behave differently under automation:

CategoryDetectable automaticallySafe to batchAction
Anchored, single lineYesYesApply
Anchored, multi-line spanYes if start and end both matchYesApply
Drifted within windowYesYes, with the correction loggedApply after re-anchor
Duplicate excerpt, several matchesYesNoHuman picks the right location
No match at allYesNoHuman locates or discards
Rewrite requestedNoNoTreat as a fresh drafting task

The decision rule is blunt: batch anything you can point to mechanically, hold anything that needs judgment. Applying a deferred finding by guesswork is worse than not applying it, because a silent misplacement is harder to find than a missing fix.

Step 4: Batch the edits as a transaction

Apply nothing one at a time in place. Instead, load the snapshot, apply every accepted edit to an in-memory copy in a single pass, and write the result to a new file. If any step fails, you throw the copy away and the original is untouched. This is the same discipline a diff viewer enforces when it lets you accept or revert a hunk individually rather than saving as you go: the accept action is separated from the file write IntelliJ's diff viewer documentation.

Order matters. Apply edits from the bottom of the file upward, so that a change on line 101 cannot shift line 41. If you apply top-down, every earlier insertion moves the targets below it, and a batch that half-succeeds leaves you with exactly the drift problem you were trying to avoid.

Write the batch as a small manifest before it runs: finding id, old line, new text, and a hash of the original line. Then the apply step can verify the hash at the moment of writing, which is the last chance to catch a target that moved between validation and application. Print the manifest count and compare it to your accepted findings before you write anything. A mismatch means a finding was dropped in the assembly step, and you want to know that before the diff, not after.

Step 5: Preserve voice by limiting the changed span

Voice drift almost never comes from the edit you asked for. It comes from everything else that changed while the edit was applied: a sentence reflowed, a comma added, a contraction spelled out, a paragraph split into three bullets with new lead-ins.

The defense is a span rule. Each accepted edit may change only the lines the finding points at. Anything outside that span must come out byte-identical, and you prove it by diffing the batch output against the snapshot. If a line outside the accepted spans appears in the diff, the batch violated the rule. You do not need to decide whether the change was good; you only need to know it happened without permission.

There is one legitimate exception: when the edit list explicitly, and separately, approves a formatting change. Line spacing, for example, is a document-level setting in most word processors, applied through a paragraph style rather than per-line editing Microsoft's line spacing guide. Formatting-level findings belong in their own batch with their own review, never mixed into text edits, because their diffs can be large and unreadable and they swamp the review of the actual prose changes.

Step 6: Review the result as a diff before committing

Open the snapshot and the batch output side by side. A good diff view colors added, modified and deleted lines distinctly, and lets you jump between changes without reading the whole file Review Board's diff documentation. Read the diff like a reviewer, not like a proofreader: confirm every hunk maps to a finding id, and confirm nothing else changed.

GitClear makes a useful point about diff quality: a tool that recognizes moves, updates and repeated find-and-replace patterns cuts review noise substantially, because a reviewer can see the shape of the change instead of a sea of red and green GitClear's rich diff checker. You can emulate the useful part without their tool by sorting your diff by finding id rather than by line number. Each finding's change then appears next to the finding that requested it, and your eye does not have to travel between a line of prose and a list of ids that may be forty entries long.

Three things to look for in the diff:

  • Hunks that do not correspond to an accepted finding. These violate the span rule; revert the batch and investigate.
  • Edits that landed on the right line but the wrong paragraph, which usually means a drifted finding slipped through with a weak match.
  • Voice changes inside the accepted span that exceed what the finding asked for, such as a rewritten sentence where a comma fix was requested.

If any of the three appear, discard the batch output and rerun. You have lost only compute time, and the snapshot is still clean.

Step 7: Commit, log and hand off the leftovers

When the diff is clean, promote the batch output to the working file. Write a log entry with the snapshot hash, the number of accepted findings, the number rejected or deferred, and the ids in each bucket. Store the raw edit list and the diff alongside the log, so anyone later can answer why a given sentence reads the way it does.

Rerun the anchoring check against the committed file after the commit. Findings that were anchored before the batch should still be anchored after it, changed or not. A finding that now matches nothing may point at a line you deleted in an earlier batch, which means your edit history and your draft have diverged, and the next batch needs a fresh snapshot.

The deferred bucket is not waste. It is the part of the edit list that needs a person, and it should go to someone who can read the paragraph in context. If the list is large and the deferred items are numerous, a specialist who reads your draft and returns a reviewed edit list can absorb that work faster than a queue of manual fixes. Quanta Experts is built for that kind of handoff: you give the context, and a specialist returns a finished, reviewed deliverable rather than a raw list Quanta Experts. And if you are feeding a model your own text to produce the next edit list, one gateway that reaches every kind of model makes the plumbing simpler; Quanta Inference exposes text, image and embedding models behind one key Quanta Inference.

FAQ

FAQ

Why not just ask the model to rewrite the whole draft with the fixes applied?

Because a whole-draft rewrite gives you one enormous diff and no way to attribute individual changes to individual findings. You cannot tell a fixed defect from an unrequested restyling, and voice drift hides inside the noise. Batched, span-limited edits keep every change traceable to a finding.

How large a window should I allow for line drift?

Small. A few lines is enough to catch the usual insertions and deletions above a target, and anything larger starts matching the wrong paragraph. The deciding factor is the excerpt: if the quoted text matches at a line far from the claimed one, the finding has moved, but if nothing matches within a few lines, a human should look.

What do I do when the same phrase appears several times in the draft?

Flag it as ambiguous and do not batch it. Ask the model to re-issue the finding with more surrounding context, which usually makes the target unique. The reliability gain from giving the model the exact text to reason about is well established in prompt design Prompting Guide's tips.

How does this relate to structured output settings in the API?

Native JSON mode reduces malformed syntax but does not guarantee the format is correct, so you still parse and validate the result before use. Treat the edit list the same way: even a schema-enforced list needs the anchoring check, because the schema constrains the shape, not the truth of the line numbers PromptQuorum's overview of JSON mode.

Can I automate the voice check?

Partly. The span rule catches most drift mechanically because it flags any change outside the accepted lines. What it cannot catch is a change inside the accepted span that sounds wrong for your publication, so a human pass over the diff, sorted by finding id, is still worth the few minutes it takes.

Sources

Sources

  1. Reviewing Code (Diffs) | Review Board latest Documentation
  2. The guide to structured outputs and function calling with ...
  3. General Tips for Designing Prompts
  4. Diff Viewer for files | IntelliJ IDEA Documentation
  5. Change the line and paragraph spacing in Word
  6. Rich Diff Checker
  7. Structured Output & JSON Mode in LLMs: When to Use, ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles