Marketing

The Evidence Packet a Reviewer Sees Before an Edit Is Approved

Antonio Evans9 min read

A split screen scene: on the left, a document with a highlighted passage and a green proposed replacement; on the right, a compact card titled EVIDENCE PACKET showing four labeled rows (Passage, Proposed change.
Key points

Key points

  1. 1An evidence packet has four fields: the exact passage under review, the proposed change as a diff, a match score from 0 to 1, and one sentence of reason.
  2. 2A script assembles the packet by pulling the passage and diff, computing the score, and asking a small model for the reason and enforcing a JSON schema.
  3. 3Budget tokens per packet as passage plus diff plus reason plus a fixed system prompt, and cache the system prompt to cut repeat cost.
  4. 4Sample packets weekly, measure median decision time per packet, and move the match score threshold until reviewers decide in seconds without opening the full document.

The four fields, and why each one earns its place

A reviewer opening a pending edit asks three silent questions: what is the original text, what does the tool want to change, and why should I believe it. An evidence packet answers all three before the reviewer scrolls, and it does so in a fixed layout so the eyes learn where to look. Four fields are enough:

FieldWhat it containsWhat it replacesFailure mode if missing
PassageThe exact source text, usually 1 to 3 sentences, with its location id"See section 4"Reviewer hunts the document, decision time triples
DiffOld line in red, new line in green, unified formatA rewritten paragraphReviewer cannot see what actually moved
Match scoreA number from 0 to 1 plus the threshold bandReviewer's gut feeling about supportEvery edit gets full scrutiny, approval stalls
ReasonOne sentence, under 30 words, no hedgingA paragraph of model proseReviewer distrusts the change and re-reads the source

The diff field matters more than it looks. Review tools converged on the same convention years ago: green for added lines, red or gray for removed lines, with unchanged context around the change so the reviewer can see what stayed put in the IntelliJ diff viewer documentation and in Review Board's guide to reviewing diffs. A richer diff algorithm that classifies moves and updates rather than only additions and deletions reports 30 percent fewer lines to read in the same change according to GitClear's comparison research. Translate that to prose: show the sentence as a move plus an update, not as a delete of one paragraph and an insert of another.

The passage needs a boundary rule. Patch tools learned early that too little context makes an edit land in the wrong place, and too much context makes the edit fail because unrelated nearby changes break the match as Neil Fraser explains in his fuzzy patch writeup. His measurements are useful here: in English prose a 15 character pattern has less than a 2 percent chance of appearing twice in the same chapter. Prose is far less repetitive than code, so one sentence of context on each side of the edit is usually enough to identify the spot uniquely.

A worked example with a real diff

Take a support policy document. The source passage in revision 7 of the doc reads:

Refunds are issued within 14 days of the request.

The proposed change, produced by an assistant that was asked to align the policy with a new contract clause, reads:

Refunds are issued within 7 business days of the request.

The packet the reviewer sees:

{
  "packet_id": "pkt_8841",
  "doc": "support-policy",
  "rev": 7,
  "locator": "sec-4.2/para-3",
  "passage": "Refunds are issued within 14 days of the request.",
  "diff_unified": "- Refunds are issued within 14 days of the request.\n+ Refunds are issued within 7 business days of the request.",
  "match_score": 0.86,
  "score_band": "review-fast",
  "reason": "Contract clause 6.1 sets a 7 business day refund window, so the current 14 day wording conflicts.",
  "sources": ["contract-2024.pdf#clause-6.1"],
  "model": "small-reasoner",
  "tokens": {"passage": 13, "diff": 26, "reason": 21, "system": 180, "total": 240}
}

Notice what the packet does not contain. It does not contain the whole document, because the reviewer does not need it. It does not contain a paragraph of explanation, because the reviewer will skim it and trust the edit less. It does not contain the model's confidence in its own answer, because a self-reported confidence and a retrieval match score measure different things and mixing them confuses the reviewer.

The diff follows the same convention the reviewer already knows from code review: a minus line for the old text, a plus line for the new text, and enough surrounding context to locate it. If the change is a pure insertion, the packet shows the insertion point with one line of context above and below. If the change is a replacement of three sentences, the diff shows all three, because collapsing them would hide the actual edit.

Assembling the packet in a script

The assembly step is deterministic except for one model call. Pull the passage, render the diff, compute the match score with a retrieval or similarity function, and only then call a small model for the reason. Keep the reason call separate from the scoring call so a scoring regression does not silently change the wording reviewers read.

import json, re

SYSTEM = (
    "You write one sentence explaining why a proposed edit is supported by a source. "
    "Return JSON only: {\"reason\": string}. "
    "Do not exceed 30 words. Do not use hedging words such as maybe or possibly. "
    "Name the source element that supports the edit."
)

def build_packet(passage, proposed, locator, score, source_ref, reasoner):
    diff = f"- {passage}\n+ {proposed}"
    raw = reasoner.complete(
        system=SYSTEM,
        user=f"SOURCE: {source_ref}\nOLD: {passage}\nNEW: {proposed}",
        response_format={"type": "json_object"},
    )
    reason = json.loads(raw)["reason"].strip()
    if not reason or len(reason.split()) > 30:
        raise ValueError("reason failed the length gate")
    return {
        "locator": locator,
        "passage": passage,
        "diff_unified": diff,
        "match_score": round(score, 2),
        "reason": reason,
        "sources": [source_ref],
    }

Two details make this robust in production. First, the model is asked for JSON and the script validates it, because free text from a model drifts in shape and field names change without warning when string parsing is the only check as the Agenta guide to structured outputs points out. Second, the system prompt is delimited and stable, with the variable content last, which is the same structure recommended for consistent parsing in LaunchDarkly's prompt engineering guide and in the Prompting Guide's tips on instructions and separators.

Put the instruction first and the data second, and label each part. That is the advice that survives every model change per the Coursiv cheat sheet's anatomy of a strong prompt. It also keeps the reason sentence short: "Use 2-3 sentences" is measurably better than "keep it short," because the model has a number to hit rather than a vibe to interpret.

The token budget per packet

Cost lives in four numbers. For the refund example the packet total was 240 tokens: 13 for the passage, 26 for the diff, 21 for the reason, and 180 for the system prompt. Scale that to a document with 400 proposed edits and you are at about 96,000 tokens of reason-generation work, and roughly 75 percent of it is the same system prompt sent 400 times.

That is the cached prefix. Prompt caching keeps the processed keys and values of an identical prefix so the next request skips prefill for it, and on Bedrock a cache read is billed at roughly 10 percent of a standard input token while writing a new cache entry carries a premium of about 125 percent per Karini's explanation of prompt caching. For a batch of 400 packets built in one run, the system prompt is written to cache once and read 399 times, so the dominant cost nearly disappears and the packet total falls toward the sum of passage, diff and reason.

Use the budget table as a planning tool rather than a promise:

ComponentTypical sizeGrows withControl
Passage10 to 40 tokensSentence length, number of context sentencesCap at 3 sentences
Diff20 to 80 tokensSize of the proposed changeSplit multi-sentence edits into separate packets
Reason15 to 30 tokensModel verbosityWord cap plus JSON schema
System prompt150 to 250 tokensFew-shot examplesCache it, keep it unchanged

Prompt compression can cut token use substantially while holding output quality according to LaunchDarkly's guide, but apply it to the system prompt before you apply it to the passage. The passage is evidence; a compressed passage is a paraphrase, and a paraphrase is exactly what the reviewer does not trust.

Tuning the match score threshold so decisions take seconds

The match score is a support number, not a confidence number. It answers one question: how strongly is the proposed change backed by the cited source. Compute it with a retrieval embedding between the proposed change and the source element, or with a similarity function over the passage and the source. Fuzzy matching libraries give you the mechanics: Levenshtein and n-gram measures quantify how far one string sits from another as this survey of fuzzy matching algorithms describes, and the practical guidance is to pick the measure by the kind of error you expect rather than by habit per Data Ladder's fuzzy matching primer.

Then set bands, and let the band decide how much of the packet the reviewer sees first:

Score bandReviewer experienceExpected decision timeRoute
0.85 to 1.0Packet card only, one click to see passage in contextUnder 10 secondsApprove or reject in the card
0.60 to 0.85Card plus highlighted source excerpt10 to 30 secondsApprove if reason names the source element
0.40 to 0.60Card, excerpt, and a link to the full source section30 to 90 secondsReviewer must open the source
Below 0.40No packet, returned to the proposing systemNot shownDo not spend reviewer attention

The decision rule is simple: move the top band boundary down until median decision time in that band crosses your target, then stop. If reviewers in the 0.85 band take 40 seconds, the packet is missing a field or the reason is vague, not that the threshold is wrong. If they take 4 seconds and later reverse the edit, the threshold is too low.

Keep two counters per band: median time and reversal rate after five days. The pair is the health signal. A threshold that produces fast approvals and near-zero reversals is working. A threshold that produces fast approvals and a rising reversal rate is letting unsupported edits through, and the fix is usually the reason field, not the score.

Sampling packets to check reviewer speed

You cannot tune what you do not measure, and you should not measure every packet. Sample between 5 and 10 percent of approved packets each week, stratified by score band, so the top band is not overrepresented. The sample does not need a reviewer's time to collect: log the packet id, the band, the time between first render and click, and whether the edit was reversed within five days.

select
  score_band,
  count(*) as packets,
  percentile_cont(0.5) within group (order by decision_seconds) as median_seconds,
  avg(case when reversed_within_5d then 1.0 else 0.0 end) as reversal_rate
from packets
where approved_at >= now() - interval '7 days'
group by score_band
order by score_band desc;

Read the result against three checks. Median decision time should rise as the band falls; if it does not, reviewers are ignoring the band and reading everything. Reversal rate should stay flat across bands; if the top band reverses more often than the middle, the score is miscalibrated against the source. And the packet count in the top band should grow over successive weeks if the proposing system is improving; if it does not, the fix is upstream of the reviewer.

A grounded review workflow helps here. Content teams that document brand voice, classify content by risk before drafting, and keep a fixed edit checklist see more consistent quality than teams that rely on intuition at the review step according to Glean's guide to AI content review workflows. The packet is the fixed checklist made concrete for one edit. Journals that suspect AI-written reviews have the same problem from the other side: comments arrive detailed but cite issues that do not exist in the manuscript, and detection is unreliable per the COPE case on suspected AI reviewers. A packet that cites the exact source element makes that failure visible, because a reviewer who claims a problem can point at the passage.

What the reviewer should never have to do

Write down the loop the reviewer should not enter: open the document, search for the phrase, read the surrounding section, decide whether the proposed wording is better, check whether the source supports it, come back to the change, click approve. Each of those steps is a way for the decision to take a minute instead of ten seconds. The packet removes every one of them by putting the passage, the diff, the score and the reason in one card.

There is a second, quieter failure: the reviewer accepts everything because the packet looks like work. Guard against that by asking for one rejection reason from a fixed list (unsupported by source, changes meaning, wrong location, style mismatch) and by reviewing rejected packets monthly against approved ones. If the rejection list is empty for a week, sample harder.

When you need the reason call and the embedding call to go through one endpoint across many models, a single key removes a setup step. Quanta Inference puts text, image, video, audio and embedding models behind one OpenAI-compatible API with prepaid pricing in US dollars: https://quantaintelligence.ai/inference. For teams that want a person to review the packet design and the sampling plan with them, a consulting call covers the score bands and the token budget in one session.

FAQ

FAQ

What exactly belongs in an evidence packet?

Four fields: the exact passage under review, the proposed change rendered as a unified diff, a match score from 0 to 1 that says how strongly a source supports the change, and one sentence of reason. Add a packet id, a document locator and the source reference so the reviewer can audit it later. Anything else, including confidence numbers, model commentary and full document text, slows the decision.

How do I keep packets cheap in tokens?

Budget the packet as passage plus diff plus reason plus a fixed system prompt, and expect the system prompt to be the largest single item. Keep it byte-identical across requests so prompt caching can bill it at the cache-read rate rather than full input price per Karini's prompt caching writeup. Compress the system prompt, not the passage, because the passage is the evidence the reviewer relies on.

Why use a diff instead of showing the rewritten passage?

A diff shows what moved and what was replaced, which is the difference between a reviewer who checks the edit and a reviewer who re-reads the paragraph. Modern diff viewers color added, modified and deleted lines and let you collapse unchanged fragments as the IntelliJ documentation shows, and richer diff algorithms report 30 percent fewer lines to review per GitClear. The same convention transfers directly to prose edits.

How should I set the match score threshold?

Start with four bands and a target median decision time per band, then move the top boundary down until the fast band hits your target without raising the five-day reversal rate. Scores are computed with similarity measures, and the choice of measure depends on the kind of error you expect per Data Ladder's fuzzy matching guide. The threshold is right when the fast band is fast and stable, not when it is fast alone.

How often should I sample packets?

Sample 5 to 10 percent of approved packets each week, stratified by score band, and log decision time plus reversal within five days. Track the two numbers per band, not per reviewer. Rising packet counts in the high-support band over successive weeks tell you the proposing system is improving; a flat reversal rate across bands tells you the score still predicts support.

Sources

Sources

  1. Diff Viewer for files | IntelliJ IDEA Documentation
  2. Reviewing Code (Diffs) | Review Board latest Documentation
  3. Rich Diff Checker
  4. Writing: Fuzzy Patch - Neil Fraser
  5. The guide to structured outputs and function calling with ...
  6. Prompt Engineering Best Practices: Tutorial & Examples
  7. General Tips for Designing Prompts
  8. Prompt Engineering Cheat Sheet: Techniques, Templates ...
  9. Prompt Caching for AI Agents: Cut LLM Costs
  10. Fuzzy matching algorithms
  11. Fuzzy Matching 101: The Complete Guide to Accurate ...
  12. How to implement an AI content review workflow
  13. Editors suspect that reviewers are using artificial intelligence
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