Scenario: a payment design lead approves a “simplified” checkout flow from a free model. The before/after screenshot looks clean, so it ships. Two weeks later, support discovers the one-line dispute summary is gone. The model had rejected it in its internal comparison, but the lead never saw the rejection. The decision was reversible, but only if someone had noticed the missing field before release.
The problem wasn’t the model. It was that the approval happened without a record of what the model left out.
I keep seeing the same pain in the current wave of agent gatekeepers. People add more permission checks, but the real missing piece is review evidence: can the human see what was discarded, what evidence is absent, and where the decision can be reversed?
So my workflow is simple: don’t ask one model for a final flow. Ask two models for a decision card, compare what they omitted, and block approval until the cards expose the missing evidence.
I ran this with MonkeyCode’s free model access and free server option. Disclosure: This article was prepared as part of MonkeyCode’s product outreach.
I won’t name the specific models here, because the cheap one you have today may be rate-limited by the time you read this. The protocol works with any two models that can return structured JSON.
The decision card
The only artifact that matters is the card. Every approval request must include five fields:
-
chosen_option— what the model wants to keep or change. -
rejected_options— what the model explicitly chose not to use, with a reason. -
missing_evidence— what is not known yet, written as a testable statement. -
stop_condition— the specific condition that blocks approval. -
reversibility— how a human can roll back the decision after release.
I also keep evidence_supplied separate from design_hypothesis. A hypothesis like “one-line summary reduces cognitive load” does not satisfy a stop condition. Only evidence does.
Here’s a concrete card for the checkout decision:
{
"decision_id": "checkout-014",
"decision_owner": "payment design lead",
"action_requested": "approve simplified checkout flow",
"chosen_option": "Keep dispute summary as a one-line support link",
"rejected_options": [
{
"option": "Remove dispute summary",
"reason": "support uses it to reverse disputed charges",
"evidence": false
}
],
"evidence_supplied": [
"support handle time increased after last week's test"
],
"design_hypothesis": "one-line summary reduces visual clutter",
"missing_evidence": [
"screen-reader announcement for dispute status",
"support reversal flow after summary is removed"
],
"stop_condition": "No approval until the screen-reader announcement and reversal flow are specified",
"reversibility": "Roll back to previous flow without data loss",
"accessibility_checks": [
"contrast",
"focus order",
"error recovery copy"
],
"model_claim": true,
"human_confirmed": false
}
model_claim means the model asserted something. human_confirmed means a person checked it. Approval requires the second field to become true.
Why two models instead of one
One model gives you a plausible answer. Two models show you where the answer is unstable.
If both models list the same missing evidence, you have a stronger signal that the gap matters. If they list different missing evidence, that is even more useful: you now know the decision is underspecified and you should stop before asking a human to approve it.
This is what I run on a free server. The flow looks like this:
flowchart TD
A[Designer writes decision prompt] --> B[Model A returns decision card]
A --> C[Model B returns decision card]
B --> D[Compare rejected_options and missing_evidence]
C --> D
D --> E{Do stop conditions agree?}
E -- No --> F[Human stops approval until missing evidence is resolved]
E -- Yes --> G[Human approves only if reversibility is explicit]
F --> H[Decision log]
G --> H
H --> I[Free server serves the log]
The server doesn’t make the decision. It just keeps the rejection record next to the proposed design.
A small diff script
The script below compares the missing_evidence sets from two cards. It runs anywhere, including a free server tier.
import json
from pathlib import Path
def missing(card):
return set(card.get("missing_evidence", []))
a = json.loads(Path("card_a.json").read_text())
b = json.loads(Path("card_b.json").read_text())
only_a = missing(a) - missing(b)
only_b = missing(b) - missing(a)
if only_a or only_b:
print("Stop: the cards disagree about what is missing.")
print("Only A:", sorted(only_a))
print("Only B:", sorted(only_b))
else:
print("Agreed missing evidence:", sorted(missing(a) & missing(b)))
If both cards agree that “screen-reader announcement” is missing, stop and write that copy before asking a human to approve. If they disagree, stop and run the question as a small user research scenario instead of shipping.
Example scenarios
| Scenario | What the model left out | Stop until |
|---|---|---|
| Shorten onboarding | Recovery email for password reset | Fallback flow and screen-reader path are written |
| Simplify checkout | Dispute summary for support | Support reversal flow is tested |
| Add urgency toggle | Focus order on keyboard | Focus order and announcement are specified |
In each case, the final design isn’t blocked forever. It’s blocked until the missing evidence is owned by a human and written down. That’s the kind of friction that prevents a clean screenshot from becoming a support incident.
Success and stop measures
A card is ready for approval when:
- every
rejected_optionhas a reason, - every
missing_evidenceitem has an owner, -
stop_conditionreferences at least one missing evidence item, -
reversibilityis explicit and supported by the code or content path, -
accessibility_checksare filled, not left empty, -
human_confirmedistrue.
Stop the workflow when:
- either model claims evidence that no one can find,
- the two cards disagree about what is missing and neither one can be verified quickly,
- the decision has no reversibility point,
- the change affects health, safety, legal rights, or irreversible data migration.
Who should not use this
This is not an approval process for high-stakes, irreversible decisions. If your change affects health, safety, legal rights, or a migration that cannot be rolled back, use a formal human review board and risk assessment, not a free model’s card.
This is also not for teams that won’t maintain the decision log. The log is the whole point. If the rejected options disappear after the meeting, the workflow gives you nothing.
Finally, this is not for sub-second approvals. If you need a model to act immediately on a server write, this gate is too slow. Use it for design decisions that a human can still reverse after a short review window.
What I would change next
I want to add a rollback_test field: after approval, someone must show that the rollback path actually works, not just that it is described. That would make reversibility a tested behavior rather than a promise.
I keep this card in the same Git history as the proposed design, so the rejection record travels with the change. What stop condition would you add for your team?
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Top comments (1)
The card captures what the model considered and rejected. The failure I would watch for is the option it never considered, which never lands in rejected_options because nothing in the model registered a choice there at all.
Two cards agreeing is where that gets dangerous. Both models share most of their training, so they tend to go quiet in the same places. Matching missing_evidence reads like corroboration, and sometimes it's two systems averaging toward the same blind spot. Disagreement is the more informative outcome of the two, which your flow half admits already by treating it as a stop.
One thing that helped me: a stop condition is far easier to write against the cases your team has already decided than against the ones nobody has. A short list of situations where you know which way it goes, kept somewhere the model reads before it proposes anything, turns part of that silence into a refusal instead of a plausible fill.
The rollback_test idea is the strongest thing in here. Reversibility nobody has exercised is a claim, same category as model_claim before human_confirmed.