agent procedural compliance July 23, 2026 • 6 min read

Your Agent Skips Step 3 Every Time: Stop Describing Your Procedure and Verify Its Trace Instead

Turn your workflow's "always do X before Y" rules into machine-checkable invariants that catch out-of-order tool calls before they cause damage.

You wrote the procedure. It's right there in the system prompt: "Always verify the customer's identity before issuing a refund." The agent read it. And then, on run 47, it issued the refund first and verified nobody.

This is the failure that prose SOPs cannot fix. A paragraph in the system prompt is advice. The model weighs it against everything else in context and sometimes decides a different order feels more helpful. Your instruction was a suggestion. What you needed was a wall.

The fix is to stop describing the procedure and start checking it. Express your "X before Y" rules as ordered invariants over the agent's tool-call trace, then run a verifier that replays the trace and fails any run that broke the order. The reframe is the whole point: a prompt is a suggestion, a trace check is enforcement.

Why the prompt was never going to be enough

There's good research on this now. Sierra Research's τ-bench injects the domain policy verbatim into the system prompt of every agent and gives zero reward for any policy violation, even when the customer's actual request got fulfilled. The SOP was in the prompt the entire time. Frontier models still failed constantly: Claude 3.5 Sonnet passed 69.2% of retail tasks and 46.0% of airline tasks, GPT-4o landed at 60.4% and 42.0%. The instruction being present did not make the agent follow it.

The math explains why this compounds. If each step in an 8-step workflow succeeds 85% of the time, end-to-end you're at 0.85^8, roughly 27%. Three out of four multi-step runs break somewhere. Order-of-operations is not an edge case. It's the default outcome of a long chain.

And the worst part is that your current metrics hide it. In one study of the τ²-bench airline domain, 78% of failures were silent wrong-state failures with no tool error at all. The agent returned a clean, plausible answer. The refund went out. The identity check never ran. Answer-correctness scoring passed it. An LLM judge passed it. You are not measuring the thing that breaks you.

The July 2026 AgentLTL paper (arXiv:2607.02599) makes the argument cleanly: agents get graded on final-answer correctness or an LLM judge, and neither captures how the answer was produced. In safety-critical work, the procedure is part of correctness. Their answer is a language derived from temporal logic that expresses rules over the tool-call trace and produces a deterministic, judge-free compliance score. Three property types cover most real SOPs: ordering (call A must come before call B), call presence (call C actually happened), and grounding (every claim in the answer has a witness in some tool result).

Here's how to build all three into your own agent without a research lab.

Step 1: Write the invariant block, not the paragraph

Replace the prose SOP with a list of rules stated as constraints over tool calls. Keep them atomic. Each rule names the tools and the required relationship.

The Prompt:

## PROCEDURAL INVARIANTS (enforced by trace verifier, not optional)
Each rule is checked against your tool-call log after every turn.
A violation blocks the run and returns you here to re-plan.

R1 [ORDER]    verify_identity(customer_id) MUST occur before any issue_refund(...)
R2 [ORDER]    check_inventory(sku) MUST occur before ship_order(sku)
R3 [ORDER]    write_audit_log(action) MUST occur before commit_transaction(...)
R4 [PRESENCE] every issue_refund MUST be preceded by exactly one get_order(order_id)
              for the same order_id
R5 [GROUND]   any dollar amount in your reply MUST match a value returned by
              get_order or get_refund_policy in this trace

Why This Works: Each rule is a testable predicate over a log of tool calls, so a checker can pass or fail it mechanically instead of a human reading intent into a paragraph. Naming the exact tool functions and the relationship (before, preceded-by, matches) removes the ambiguity that lets the model rationalize a different order.

Expected Output:

The agent doesn't "reply" to this block. It becomes the contract the verifier holds it to. On a compliant run, the trace reads get_order → verify_identity → get_refund_policy → issue_refund → write_audit_log → commit_transaction, and every rule passes.

Step 2: The verifier that replays the trace

Now you need something that reads the tool-call log and emits pass or fail per rule. The honest recommendation: write this as deterministic code, not another LLM call. It runs in milliseconds, it's reproducible, and it can't hallucinate a passing grade. The FORGE work (arXiv:2602.16708) added exactly this kind of runtime enforcement over natural-language business rules and moved average pass rate from 58% to 98% across Claude Opus 4.5, GPT-5.2, and Gemini 3 Pro. The two failures left standing were model reasoning errors, not policy violations. The enforcement layer erased the compliance failure class.

When you don't have code yet and want to prototype the check with an LLM, structure the verifier prompt so it can only answer per-rule, never in prose.

The Prompt:

You are a trace verifier. You do not reason about intent. You only check
the tool-call log against the rules. Output strict JSON, one entry per rule.

RULES:
R1 verify_identity before any issue_refund
R2 check_inventory(sku) before ship_order(sku), same sku
R3 write_audit_log before commit_transaction
R4 each issue_refund preceded by get_order(same order_id)

TRACE (ordered tool calls):
1. get_order(order_id="A-1188")
2. issue_refund(order_id="A-1188", amount=42.00)
3. verify_identity(customer_id="C-77")

For each rule output: {"rule": "...", "status": "PASS"|"FAIL", "evidence": "..."}
Do not add commentary. Do not fix the trace. Report only.

Why This Works: Forcing structured, per-rule JSON output stops the model from smoothing over a violation with a helpful paragraph, which is the same failure the agent has. Feeding it the ordered trace (not the conversation) keeps it checking sequence, not vibes.

Expected Output:

json [ {"rule": "R1", "status": "FAIL", "evidence": "issue_refund at step 2 precedes verify_identity at step 3"}, {"rule": "R3", "status": "PASS", "evidence": "no commit_transaction in trace"}, {"rule": "R4", "status": "PASS", "evidence": "get_order(A-1188) at step 1 precedes refund"} ] R1 failed. The refund fired one step before the identity check. Answer-correctness would have called this run a success. The verifier caught it.

Step 3: The block-and-warn repair turn

A verdict is useless if the refund already went out. The pattern that works is prefix checking: gate each tool call by verifying the trace prefix online, before execution. AgentLTL uses one specification for both jobs, scoring finished traces and blocking bad calls mid-run. Reported enterprise deployments require the same shape. Coinbase wanted a runtime block plus an alert. The agent never calls the production tool directly. A policy engine sits between the proposed call and the executor and returns allow, deny, or hold.

When a call is denied, you feed the specific broken rule back and force a re-plan.

The Prompt:

TOOL CALL BLOCKED before execution.

Attempted: issue_refund(order_id="A-1188", amount=42.00)
Violated: R1 [ORDER] verify_identity(customer_id) must occur before issue_refund.
Trace so far: get_order(A-1188)

You may not retry issue_refund yet. Re-plan so the required predecessor runs
first. State the corrected tool order, then make only the next single call.

Why This Works: The block happens before the side effect, so nothing irreversible has run. Naming the exact violated rule and the missing predecessor gives the model a concrete constraint to plan around instead of a vague "try again," which is what turned FORGE-style enforcement into near-total compliance.

Expected Output:

The agent replans: "Corrected order: verify_identity(C-77), then issue_refund. Next call: verify_identity(customer_id='C-77')." The refund only fires after identity passes. The invariant held because it was a wall, not a note.

What this actually buys you

You don't need a bigger model. You don't need an LLM judge grading transcripts. You need a small list of ordered rules and a checker that replays the log. That's a cheap, deterministic technique that makes an agent you already have trustworthy enough to touch refunds, inventory, and commits. The remaining failures, as FORGE showed, stop being "the agent ignored the policy" and become ordinary reasoning bugs you can debug like any other.

Start with three rules. The one order that must never invert, the one call that must always happen, the one number that must be grounded. Write them as invariants, verify the trace, feed violations back. Then add more as you find them.

If your team is wiring up tool-using agents and wants procedural constraints that actually hold in production, we run live prompt engineering training on exactly this. Connect with Kief Studio on Discord or schedule a session.

Training

Want your team prompting like this?

Kief Studio runs hands-on prompt engineering workshops tailored to your stack and workflows.

Newsletter

Get techniques in your inbox.

New prompt engineering guides delivered weekly. No spam, unsubscribe anytime.

Subscribe