DEV Community

Haley
Haley

Posted on

Show Empty Evidence Slots Before Approving Agent Copy

The approve button already had focus on my review card. I still had not asked a single hard question. An overnight agent pass had rewritten every settings label.

The agent stamped every line as accessible copy. Who actually owns that dangerous last click? I do, and a wrong click ships a lie.

Where does reversibility still live for this change? It lives only before publish. After publish, recovery turns into hallway folklore.

I almost treated fluent confidence as research evidence. Have you seen that finished-looking review card? It looks complete while every evidence slot stays hollow.

This is not another essay about trusting models. This is a from-zero research tutorial. We stop approval when required evidence slots are empty.

Stage 0: Name the decision, not the vibe

Write the live decision in one plain sentence. Mine read like this, on purpose.

"May this agent copy replace live field labels?"

Name the owner, the harm, and the last reversible moment. If those three names will not fit, stop now. You are styling a guess, not reviewing a change.

Verification comes from disagreement. Read the sentence to a teammate. Can that person refuse it without embarrassment? If nobody could refuse, you wrote a mood.

I keep this sentence at the top of the packet. It is not a vision statement. It is the only question the card may answer.

Stage 1: Build the evidence packet before the model runs

I refuse to let the agent write the design record first. I open an empty packet on purpose. Empty slots are the interface, not a chore.

Here is the packet I use in critique. Treat it as a proposed pattern, not a completed study.

# Proposed evidence packet. Not a field-study result.
decision_id: settings-labels-2026-09-06
decision: "Replace live labels with agent copy?"
owner: design-reviewer
reversible_until: before-publish-to-cms
original:
  labels: {}
  helper_text: {}
  alt_text: {}
agent_pass:
  environment: free-shared-server
  generated_at: null
  copy: {}
evidence:
  contrast_ratio: null
  screen_reader_script: null
  original_preserved: false
  purpose_confirmed_by_human: false
hypotheses:
  - "Shorter labels reduce scan time"
stop_conditions:
  - original copy missing
  - contrast_ratio empty
  - screen_reader_script empty
  - purpose_confirmed_by_human is false
noise_fields:
  - server hostname
  - token spend
  - model temperature
Enter fullscreen mode Exit fullscreen mode

See the nulls sitting in public view? Those nulls are the product. An empty slot is a stop condition, not a personal failure.

Verification is a null count. Count them before any model runs. If you already have zero nulls, you prefilled a fantasy. Reset the file.

Separate evidence from design hypotheses in that same file. Contrast is evidence. "Users will like shorter labels" is a hypothesis. Mixing them is how a card starts lying.

Stage 2: Capture original copy like it might vanish

Agents overwrite in a polite voice. Original labels then vanish into a tiny diff. Recovery becomes a Slack legend nobody can prove.

I dump live strings before anyone prompts a model. It feels boring. Boring is the point.

mkdir -p packets/settings-labels
# Proposed capture. Point this at your copy deck or CMS export.
printf '%s\n' \
  'email: Email address' \
  'digest: Weekly digest' \
  'tone: Product updates may include offers' \
  > packets/settings-labels/original.txt
test -s packets/settings-labels/original.txt && wc -l packets/settings-labels/original.txt
Enter fullscreen mode Exit fullscreen mode

Verification is a non-empty file. Every live control needs one original line. If a control has no original line, the agent cannot improve it. It can only invent it.

Would you approve invented helper text on a legal checkbox? I would not, and neither should the card. Invention is not a copy tweak. Invention is a new product claim.

Stage 3: Generate candidate copy in a cheap rehearsal room

I needed a sketch room that could not touch production. MonkeyCode offers free model access and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I use that room to generate candidates only. I never use it as a silent publisher.

Keep the prompt small and slightly rude. Ask for candidates. Forbid accessibility boasts.

cat > packets/settings-labels/prompt.txt <<'EOF'
Propose alternate labels for these controls.
Do not claim accessibility.
Do not delete the original wording.
Flag any purpose you are guessing.
Return YAML only.
EOF
cat packets/settings-labels/original.txt packets/settings-labels/prompt.txt
Enter fullscreen mode Exit fullscreen mode

Verification is a forbidden claim. If the model still says the copy is accessible, log that sentence as a defect. Do not reward the boast with a merge.

Why rehearse on a free shared server at all? Because a sketch should be cheap to throw away. Because a stall should not hit your CMS. The packet is the work. The vendor is scenery.

If you already have a safe sandbox, stay there. Do not move your source of truth for this tutorial.

Stage 4: Score empty slots before anyone argues about tone

Tone arguments get loud in five minutes. Empty evidence stays quiet unless you score it first. Score the quiet thing.

# Proposed validator. Unexecuted until it reads a real packet.
from pathlib import Path
import yaml

packet = yaml.safe_load(Path("packets/settings-labels/packet.yaml").read_text())
stops = []
evidence = packet["evidence"]

if not packet["original"].get("labels"):
    stops.append("original labels missing")
if evidence.get("contrast_ratio") in (None, "", 0):
    stops.append("contrast_ratio empty")
if not evidence.get("screen_reader_script"):
    stops.append("screen_reader_script empty")
if evidence.get("purpose_confirmed_by_human") is not True:
    stops.append("human never confirmed purpose")

print("STOP" if stops else "READY")
for line in stops:
    print("-", line)
Enter fullscreen mode Exit fullscreen mode

Then run it against the fresh packet.

python3 score_packet.py
Enter fullscreen mode Exit fullscreen mode

Verification is a STOP on a new packet. READY would mean the script is lying, or you smuggled evidence in. Either case blocks approval.

This is the annotated review pattern I want in the design system. Four slots sit on the card: original copy, contrast, screen-reader script, and purpose confirmed. Color is never the only state. Each slot also speaks in text: Empty, Recorded, or Conflict.

Can a reviewer understand the card with grayscale on? If not, the card is decoration. Decoration is how bad copy gets a green chip.

Stage 5: Walk three research scenarios, then force a stop

I do not need a thirty-person study to gate this click. I need scenes that can fail in public. Write them before the critique starts.

First scene. The agent reads a field named tone and writes Marketing opt-in. The original line was a legal warning about offers. Does the packet stop that swap, or do people debate friendliness?

Second scene. The agent writes alt text from a filename, hero-final-v3. A screen-reader user then hears a version string. The script slot is empty. Do you still feel the card is mostly done?

Third scene. The free server returns a partial packet and drops helper text. The layout still looks tidy. Do you approve a tidy hole?

Success is a spoken refusal in under two minutes. Failure is a taste debate that never names a slot. If voice wins, the card failed its job.

Verification is a prewritten refusal. I write I refuse because contrast is empty. If a reviewer cannot say that line, rebuild the card before another session.

Notice what we are not measuring here. We are not scoring eloquence. We are not scoring how "on brand" the shorter line feels. Those scores are hypotheses. They can wait until the slots are full.

Stage 6: Test the review interface like it can harm people

An inaccessible review tool will bless inaccessible copy. That irony does not help a single user. Test the gate the way you test a checkout.

Keyboard order should hit Reject before it hits Approve. Stop reasons must exist as text, not as a red dot. Original copy cannot live behind a hover tooltip.

Never chip the status as accessible. Announce evidence incomplete instead. A flow only earns its place if it can stop someone.

flowchart TD
  A[Open review card] --> B{Original copy present?}
  B -->|No| S[Stop: do not approve]
  B -->|Yes| C{Contrast recorded?}
  C -->|No| S
  C -->|Yes| D{Screen-reader script present?}
  D -->|No| S
  D -->|Yes| E{Human confirmed purpose?}
  E -->|No| S
  E -->|Yes| F[Edit, then hand back to record]
  F --> G[Publish with original and new copy]

Verification is a keyboard pass on a mock card. Can you reject without a mouse? Can a screen reader hear the blocking reason? If either answer is no, you designed applause, not review.

I also check focus order after a stop. The reviewer should land on the empty slot, not on Approve. A focus trap on Approve is a product bug with manners.

Stage 7: Hand the decision back, and keep discarded lines

Approval is not closure. The discarded original must remain in a concrete record. Future you will need those lines on a bad Thursday.

ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
{
  echo "time: $ts"
  echo "decision: refused-or-accepted"
  echo "stop_reasons: contrast empty"
  echo "original_kept: yes"
} >> packets/settings-labels/decision.log
tail -n 5 packets/settings-labels/decision.log
Enter fullscreen mode Exit fullscreen mode

Verification is a log that still holds original_kept. The CMS must still show live strings. You should reverse without digging through chat history like a detective.

Which missing evidence should stop approval cold? Contrast, original wording, the screen-reader script, and human purpose confirmation. Which extra information only adds noise? Server hostname, token spend, temperature, and a confidence number with no method.

Ask that pair out loud during critique. Teams will offer dashboards. Many dashboards are noise wearing a chart.

The hand-back is the humane part. The agent does not get to close the ticket. A person files the record, including what was thrown away.

Limits, and who should skip this

I am not claiming free models write worse labels than paid ones. I did not run that comparison. I am not claiming quotas, hardware, uptime, or lasting capacity. Those numbers are not in this article.

Skip this protocol if no human will read the packet. Skip it if originals, contrast notes, and screen-reader scripts already live in one record. Skip it if a human already wrote the copy and you are only delaying them.

Do not twist this tutorial into permission. The packet can block publish. It cannot bless publish.

If your labels touch medical or legal meaning, stop. This YAML is too light for those products. You need counsel and a real accessibility evaluation. A research card is not a lab.

I still want those empty slots in the open. Confidence is a costume that talks fast. Evidence is a door you can still close.

Keep production out of the sketch room. Rehearse the refusal while reversal is cheap.

Top comments (0)