Back to all articlesEnterprise Workflows

Before the Agent Acts: Designing Approval Gates for Reversible Automation

Design approval gates that bind to exact agent actions, survive long waits, and preserve rollback paths before autonomous workflows create external side effects.

Mapki

Mapki

Oct 11, 2026•9 min read
Share:
Before the Agent Acts: Designing Approval Gates for Reversible Automation

Before the Agent Acts: Designing Approval Gates for Reversible Automation

The hardest part of an autonomous workflow is not asking a model what to do. It is deciding when a proposed action is allowed to become an external fact.

An agent can draft an email, prepare a database change, or assemble a refund request without creating much risk. The risk begins at the boundary where a proposal sends, deletes, spends, deploys, or changes a customer record.

Many teams solve this with a single human approval button. That is a useful start, but it is not a complete control. A production approval gate must identify the exact action, preserve the state needed to undo it, survive a human taking hours or days to respond, and prevent later tool calls from inheriting approval they never received.

The practical rule is:

Let the agent plan broadly, but let policy decide which exact side effect may execute.

Approval is an execution boundary

Prompt instructions are advisory. A model may be told “ask for approval before sending” and still produce a send call when the context changes, a tool result is malicious, or a later agent step compresses the earlier instruction.

The Parallax paper makes the architectural version of this argument: the reasoning component should be separated from execution, with an independent validator and reversible execution between them. Its reference design combines cognitive-executive separation, graduated validation, information-flow control, and pre-destructive state capture. In its reported evaluation, the reference implementation blocked 98.9% of 280 adversarial test cases in its default configuration and 100% in its maximum-security configuration. Those are paper-specific results, not a universal guarantee, but the design lesson is broadly useful: the actor should not be the final authority over its own action.

A useful production path looks like this:

User request
|
v
Agent proposes intent + exact parameters
|
v
Policy gateway classifies action and verifies scope
|
+--> safe read/draft --------> execute
|
+--> reversible write --------> capture undo state -> execute
|
+--> high-impact action ------> durable approval request
|
v
human approves/edits/rejects
|
v
revalidate + execute once

The human is not approving the model in the abstract. The human is approving a specific action under a specific identity, target, parameter set, and expiration time.

Classify actions by impact and reversibility

Do not put every tool call behind the same approval screen. That creates reviewer fatigue and encourages teams to bypass the control. Instead, classify each action at execution time.

action_policy:
read:
effect: allow
draft:
effect: allow
write:
effect: conditional
require_when:
- outside_workspace
- customer_visible
send:
effect: require_approval
spend:
effect: require_approval
require_when:
- above_workflow_limit
- new_recipient
delete:
effect: require_approval
production_change:
effect: require_approval
credential_change:
effect: deny

A simple risk matrix uses two axes:

  • Impact: What is the financial, privacy, operational, or reputational blast radius?
  • Reversibility: Can the exact prior state be restored reliably, and how long does that remain true?

A draft email is usually low-impact and reversible. Sending that email is customer-visible and may be impossible to retract. A database update may look reversible until another process reads the changed value and triggers a downstream action. Reversibility is therefore not a permanent property of a tool; it depends on what happens next.

The policy should also consider scope, confidence, novelty, and approval freshness. A familiar read inside one workspace may be safe. The same operation against a new tenant, a larger-than-normal export, or a new external destination may require review.

Approve intent plus parameters, not tool names

Approving send_email is too broad. It could authorize a harmless internal notification or a message containing sensitive data to an external recipient.

Create a normalized approval payload before the request reaches the reviewer:

{
"approval_id": "apr_01JX9F",
"run_id": "run_01JX8H",
"subject": "agent:billing-ops",
"action_class": "send",
"tool": "send_email",
"parameters": {
"to": ["[email protected]"],
"subject": "Invoice exception review",
"body_hash": "sha256:...",
"attachment_ids": ["report_8841"]
},
"scope": {
"tenant_id": "acme",
"workspace": "finance",
"policy_version": "finance-policy-v8"
},
"risk": {
"impact": "medium",
"reversibility": "low",
"new_destination": false
},
"expires_at": "2026-10-11T16:00:00Z"
}

The reviewer should see a readable preview, but the gateway should bind the decision to the normalized machine payload. If the recipient, amount, attachment, tenant, or policy version changes, the old approval is invalid.

This prevents approval laundering: an agent receives approval for “prepare and send the report,” then silently expands the chain into “send the report, update the CRM, issue a coupon, and schedule a follow-up.” Each consequential downstream action must either be included explicitly in the approval bundle or trigger its own gate.

Pause durably instead of blocking a worker

Human review is an asynchronous distributed-systems problem. A reviewer may respond in Slack, email, or a web console hours after the agent proposes the action. Keeping a process and its model context in memory is expensive and fragile.

LangGraph’s current human-in-the-loop middleware pauses tool execution with an interrupt, persists graph state through a checkpointer, and resumes with one of four decisions: approve, edit, reject, or respond. It also supports conditional interrupts so safe calls can proceed while only risky arguments reach a reviewer. Production deployments need a persistent checkpointer rather than an in-memory test saver.

Temporal’s reference workflow uses a Signal to deliver the human decision. The workflow can wait for hours or days without consuming worker compute, use durable timers for expiration, and retain an audit trail. The same pattern supports multiple approvers, escalation, and custom approval interfaces.

from dataclasses import dataclass
from datetime import datetime, timezone

@dataclass
class ApprovalDecision:
approval_id: str
decision: str  # approve | edit | reject
reviewer_id: str
payload_hash: str
decided_at: str


def decision_is_valid(request, decision: ApprovalDecision, now=None):
now = now or datetime.now(timezone.utc)
if decision.approval_id != request.approval_id:
return False
if decision.payload_hash != request.payload_hash:
return False
if now.isoformat() > request.expires_at:
return False
return decision.decision in {"approve", "edit", "reject"}

The approval service should fail closed on timeout for mutations, spending, deletion, external messages, and production changes. If the request expires, the agent can save a draft, ask for a fresh decision, or stop. Silence must not become consent.

A Temporal-style flow is straightforward:

proposal = await workflow.execute_activity(propose_action)

if policy.requires_approval(proposal):
await notify_reviewer(proposal)
decision = await workflow.wait_for_approval(
approval_id=proposal.approval_id,
timeout=timedelta(hours=8),
)
if not decision_is_valid(proposal, decision):
return {"status": "expired_or_invalid"}
if decision.decision == "reject":
return {"status": "rejected"}

await workflow.execute_activity(
execute_action,
args=[proposal, decision],
)

The execution activity must re-check policy. A decision from eight hours ago is not a substitute for current authorization, current tenant membership, or current resource state.

Capture undo state before destructive work

Approval is not rollback. A human can approve an action that later fails partially, or a downstream system can change state between approval and execution.

For reversible actions, capture the minimum state required to restore the prior condition:

{
"effect_id": "eff_0042",
"target": "crm://customer/acme-8841",
"before": {
"lifecycle_stage": "trial",
"owner_id": "usr_104",
"tags": ["needs-review"]
},
"operation": {
"set_lifecycle_stage": "customer",
"add_tags": ["converted"]
},
"undo": {
"strategy": "compare_and_swap",
"expected_version": 17,
"expires_at": "2026-10-18T00:00:00Z"
}
}

Use idempotency keys for the forward action and compare-and-swap or version checks for the undo action. Never blindly restore an old snapshot over newer legitimate changes.

For irreversible actions, the policy should not pretend to offer rollback. Require stronger approval, a narrower scope, and a preflight receipt. For example, deleting a customer export may be irreversible, but moving it into a quarantined retention bucket may provide a safer intermediate state.

Make the approval interface useful

A reviewer cannot make a reliable decision from “Agent wants to call execute_tool.” The approval card should answer five questions:

  1. What will change? Show the exact operation and affected records.
  2. Why now? Include the user request, relevant policy, and the agent’s short rationale.
  3. What is the blast radius? Show amount, recipient, tenant, count, environment, and external visibility.
  4. Can it be undone? Show the undo method, expiry, and any irreversible step.
  5. What happens next? Explain whether approval covers one call, a bounded bundle, or only a draft.

Do not expose hidden chain-of-thought. A concise evidence receipt is enough: source records, tool arguments, policy decisions, confidence signals, and the proposed effect.

Test the gate as an adversary

A happy-path approval test is not enough. Add scenarios where:

1. The agent changes one argument after approval.

2. A reviewer approves a draft, but a later step attempts to send it.

3. The destination changes from internal to external.

4. The policy version changes while the request is waiting.

5. The approval expires during a provider outage.

6. Two workers try to execute the same approval concurrently.

7. A malicious tool result asks the agent to bypass the reviewer.

8. The undo snapshot is stale because another process changed the target.

The key assertions are deterministic:

assert changed_parameters_reject_old_approval()
assert expired_approval_never_executes()
assert concurrent_execution_has_one_winner()
assert downstream_action_requires_explicit_scope()
assert rollback_uses_version_check()

The Reddit practitioner discussion linked below converges on the same design: classify reversibility, impact, external side effects, and data exposure; bind approvals to exact parameters; do not let one approval silently cover cascading calls; and fail closed when a high-impact gate times out.

A Hacker News discussion adds the enforcement point that teams often miss: place a middleware proxy between the agent and sensitive systems, evaluate every tool call with deterministic policy, and record the policy decision alongside the tool-call audit.

References & Community Insights

Final checklist

Before allowing an agent to create external side effects, verify:

1. Is the decision made by policy outside the acting model?

  1. Is approval bound to exact normalized parameters, identity, scope, and expiry?

3. Can the workflow pause without holding a worker or losing state?

4. Are high-impact actions fail-closed on timeout and policy drift?

5. Is undo state captured before a reversible mutation?

6. Are irreversible actions isolated behind stronger controls?

7. Can every approval, edit, rejection, execution, and rollback be audited?

  1. Are downstream cascading actions prevented from inheriting unapproved authority?

The goal is not to put a person in front of every tool call. It is to make autonomy proportional to risk. Let agents move quickly through safe, bounded work; pause at the point where a decision becomes consequential; and preserve enough state to recover when the world changes after approval.

Want to implement this in your business?

Mapki designs bespoke AI agents, custom workflow automations, and tool-agnostic integrations tailored specifically to your existing ERP, CRM, and databases.

Tags:AI AgentsHuman-in-the-LoopApproval GatesDurable WorkflowsAgent SecurityWorkflow Automation