DEV Community

Haley
Haley

Posted on

Show Stop Proof Before Approving an Agent Retry

The retry button looked harmless during Friday critique. An agent had rewritten onboarding consent copy overnight. The first pass missed a recovery path. Now the agent wanted another loop. Who should click approve with that hole still open?

I own that click as the reviewing designer. Another loop can overwrite a human edit. Reversibility dies once the retry is queued. I refuse the retry until stop proof exists on the card.

This is not a speech about trusting models. It is a from-zero workflow you can run today. You leave with a review card and a validator. You also leave knowing which missing evidence must stop approval.

Start from the failed loop, not the model

I do not open a playground first. I open a dated research folder instead. The failed loop is the artifact under review. The model is only a later witness, never the owner.

mkdir -p research/retry-2026-09-13
cd research/retry-2026-09-13
touch decision-card.yaml flow.md recovery.md
Enter fullscreen mode Exit fullscreen mode

Verification is boring on purpose, and that helps. The folder must exist before any critique starts. The three files must be empty and correctly named. If any file is missing, I stop the session.

Why three files for one retry decision? One card holds the human decision. One note holds the moment of choice. One note holds failure recovery for assistive tech. Mixing them hides missing evidence inside chat. Have you ever approved a retry from a thread? That thread is not a record.

Fill the decision card before any retry

I write the card in plain YAML. Designers can read it without a decoder. Engineers can lint it without a new app. The fields are the interface, not decoration.

decision: retry_agent_loop
owner: product_design
surface: onboarding_consent
reversible_until: before_retry_queued
user_consequence: overwritten_consent_copy
evidence:
  observed_failure: ""
  discarded_options: []
  source_of_failure: ""
  last_human_edit: ""
hypotheses:
  - ""
stop_conditions:
  - ""
a11y:
  rewrite_announced: false
  refusal_named: false
  focus_return: false
retry_allowed: false
Enter fullscreen mode Exit fullscreen mode

Verification is a read-back with the owner present. Every required field that is empty must stay visible. I never default retry_allowed to true. Empty means stop, not “fill later.” What extra field would only add noise here? Model nickname. Sample temperature. A confidence badge. Those do not change the human decision.

Separate evidence from a clever guess

Evidence is what a person observed on the surface. A hypothesis is a story about why it happened. I keep them in different keys on purpose. That split sounds petty until a fluent model launders a guess.

I fill a walkthrough from that Friday scene. Treat it as a labeled protocol. It is not a published study with metrics.

evidence:
  observed_failure: "Consent line offered no refusal after rewrite."
  discarded_options:
    - "Keep the original human sentence."
    - "Ask the user before rewriting consent."
  source_of_failure: "Agent treated consent as marketing copy."
  last_human_edit: "Design owner, 2026-09-12, recovery sentence intact."
hypotheses:
  - "The loop over-weighted brevity."
  - "The tool lacked a consent style rule."
Enter fullscreen mode Exit fullscreen mode

Verification is a two-column read, out loud. Left column is evidence. Right column is guess. If I cannot split a sentence, it is not evidence. Would you let a guess stop a legal consent line? I would not, and neither should the card.

Ask this with the team before anyone queues work. Which missing evidence should stop approval right now? Which extra note is only noise? I stop for a missing last_human_edit. I do not stop for a missing logit.

Draw the flow at the moment of choice

I sketch the flow in Mermaid next. The retry click sits in the middle. Everything else is a gate with an owner.

flowchart TD
  fail[Loop fails on user-facing copy] --> card[Owner opens decision card]
  card --> ev{Evidence slots filled?}
  ev -->|no| stop1[Refuse retry]
  ev -->|yes| sc{Stop conditions named?}
  sc -->|no| stop2[Refuse retry]
  sc -->|yes| rec{Recovery proven for AT?}
  rec -->|no| stop3[Refuse retry]
  rec -->|yes| critique[Optional second-pass critique]
  critique --> human[Human approves or refuses]
  human -->|approve| queue[Queue retry]
  human -->|refuse| handback[Hand back to owner]

Verification is a tabletop walk, not a slide review. I point at each diamond and name the owner. I name the reversible point in one sentence. If a diamond has no owner, the flow is fiction. Can you point to the last safe moment? If not, do not queue the loop.

The analogy I use is a fire door. A retry is not a hallway you stroll through. It is a door with a closer and a latch. You do not prop it open with hope.

Write stop conditions that can actually fire

Vague stops never fire when the room is tired. “Be careful with consent” is not a condition. I write conditions as observable states on the screen.

stop_conditions:
  - "Consent copy changed without a visible refusal."
  - "Last human edit would be overwritten."
  - "Rewrite is announced without naming the field."
  - "Refusal control has no accessible name."
  - "Source of failure is still unlabeled."
Enter fullscreen mode Exit fullscreen mode

Then I write success beside those stops in flow.md. Success is not “the model sounds better.” Success is a recoverable interface after a bad rewrite.

I keep both measures in prose so nobody hunts a wiki. Success means the refusal stays in the consent line. Success means the human edit remains in the record. Success means focus returns to the edited field. Success means a retry is refused when any stop fires. Stop means any evidence slot is still empty. Stop means any recovery flag is still false. Stop means the person clicking is not the owner.

Verification is a dry run with a stranger in the room. I read each stop aloud once. I ask whether that stranger could see it fire. If only the author can see it, I rewrite the stop. A private stop is just a wish.

Prove recovery before the model speaks again

Agent copy is still an interface, not a paragraph. A rewrite without recovery is a trap. I check three things only on this gate. Announced rewrite. Named refusal. Focus return.

I write recovery.md as sentences, not a dumped audit. The rewrite must be announced with the field name. The refusal control must expose a real accessible name. Focus must return to the edited field, not a banner. The discarded human sentence must remain readable in the record. I do not treat this as a full accessibility audit. It is a retry gate. Missing any line keeps retry_allowed false.

Verification is a keyboard and AT pass on the current screen. Does the announcement name the field that changed? Can I find the refusal without guessing the icon? If someone says we will fix recovery after retry, that is the failure. After is not a recovery. After is a hope with a release date.

Only then run a cheap second-pass critique

Sometimes I want a second reader, not a second actor. I want a critique that cannot queue the retry. That is the only place a disposable model lane belongs.

Disclosure: This article was prepared as part of MonkeyCode's product outreach. In this workflow, MonkeyCode is only that disposable critique lane. Free model access and a free server option are enough for rehearsal. I do not let that output write the card. I do not let it flip retry_allowed. If you already have an internal critic, skip this stage.

I paste a frozen bundle into the critique lane. The card, the flow, and the recovery note travel together. I ask for missing stops, not prettier copy.

You are a critic, not an actor.
Do not rewrite the consent line.
List evidence slots that are still empty.
List stop conditions that cannot be observed.
List recovery that is still unproven for assistive tech.
If you cannot point to a field, say UNKNOWN.
Enter fullscreen mode Exit fullscreen mode

Verification is refusal by the critic. The run must not produce new user copy. If it rewrites the sentence, I discard the whole run. The point is coverage, not fluency. Why invite a model that cannot act? Because I need a noisy highlighter. I do not need another author with a retry button.

Lint the card so blanks cannot hide

Chat will hide blanks with a confident tone. A linter will not do that favor. I keep a small validator next to the card.

# verify_retry_card.py
from pathlib import Path
import sys
import yaml

REQUIRED_EVIDENCE = [
    "observed_failure",
    "source_of_failure",
    "last_human_edit",
]
REQUIRED_A11Y = ["rewrite_announced", "refusal_named", "focus_return"]

def main(path):
    card = yaml.safe_load(Path(path).read_text())
    errors = []
    if not card.get("owner"):
        errors.append("owner missing")
    if not card.get("stop_conditions"):
        errors.append("stop_conditions empty")
    if not card.get("evidence", {}).get("discarded_options"):
        errors.append("discarded_options empty")
    for key in REQUIRED_EVIDENCE:
        if not card.get("evidence", {}).get(key):
            errors.append(f"evidence.{key} empty")
    for key in REQUIRED_A11Y:
        if card.get("a11y", {}).get(key) is not True:
            errors.append(f"a11y.{key} not proven")
    if card.get("retry_allowed") is True and errors:
        errors.append("retry_allowed true while card is incomplete")
    if errors:
        print("BLOCK")
        print("\n".join(errors))
        sys.exit(1)
    print("READY")

if __name__ == "__main__":
    main(sys.argv[1])
Enter fullscreen mode Exit fullscreen mode
pip install pyyaml
python verify_retry_card.py decision-card.yaml
Enter fullscreen mode Exit fullscreen mode

Verification is the word READY and nothing else. BLOCK means the retry stays closed. I paste the BLOCK list into the research note. That list is the missing evidence. It is not a backlog for a later sprint.

Hand the work back, then record the refusal

Approval is not the only honest ending. Refusal is a product event with an owner. I write the hand-back in the same folder so the next loop cannot pretend it never happened.

HANDBACK
owner: product_design
state: retry_refused
reason: rewrite_announced false
next_human_action: restore last_human_edit
discarded_retry_prompt: archived, not deleted
Enter fullscreen mode Exit fullscreen mode

Why keep the discarded prompt in the record? Because the next loop will try it again. Memory without rejection is amnesia with a smile. Teams retry until the sentence sounds right. That is how consent copy becomes an ad.

Verification is a named next action, not a vibe. Someone listed must own the restore. An unnamed owner is itself a stop. If the discarded prompt is deleted, I treat the record as broken.

Research the retry click with three scenarios

I run this as a scenario study, not a hallway poll. Three scenarios are enough for a rehearsal. Scenario A drops the consent refusal. Scenario B would overwrite the last human edit. Scenario C announces “Updated” without naming the field.

For each scenario I measure two things only. Did the validator print BLOCK? Did the human refuse without extra chatter? Extra chatter is noise around a missing field. A missing last_human_edit should stop the room. A missing model nickname should not.

I do not count fluency of the second pass. I do not count minutes saved in critique. Those metrics hide the decision under a productivity story. The only success is a recoverable no. The only stop that matters is an unproven recovery.

Limitations, and who should not use this

This workflow is a gate in the interface. It is not a model evaluation harness. It will not rank providers. It will not prove a design is finished. The validator is a proposal you can fork. It has not been a controlled study.

Do not use it for medical or legal advice surfaces. Do not use it when no designer owns the click. Do not use it to rubber-stamp a free critique. A cheap second pass is optional coverage. It is never evidence. If you cannot name the reversible point, stop. If you cannot name the user consequence, stop. The retry button can wait.

I still want one question on your desk after the lint. Which missing evidence should stop approval today? Which extra field would only add noise to that card?

Top comments (0)