EffectMatch checks what an agent's tool call actually changed — Effect-based authorization — What does it mean?
The news. On September 25, 2026, researchers at Harbin Institute of Technology posted Beyond Approved Actions: Runtime Validation of Persistent Outcomes in Agent Workflows (arXiv 2609.31301). It introduces EffectMatch, a runtime that collects the persistent changes a tool call makes inside a controlled boundary, compares them with what the application approved for that execution, and lets the comparison decide both whether the changes commit and whether dependent steps may continue. On 206 public business tasks it kept every clean execution and blocked every tested incorrect commit. Read the paper →
Picture a renovation. You approve a blueprint that adds one light switch to the kitchen. The electrician finishes and says done, and the plasterer is booked for tomorrow to close the wall. If you take done at its word, the plasterer seals in whatever is behind the wall, including an extra outlet the electrician added because it was convenient. The inspection only works if it happens while the wall is still open, and if it compares the room with the blueprint rather than with the electrician's report.
The paper's running example maps onto that room directly. The application approves one change to invoice 4711: its status goes from pending to paid. The agent sends the SQL update, and the database runs it and returns success. But a database trigger on that table also inserts a row into a notifications table. Every local check passes: the call was allowed, and the database reported no error. Without another check, the workflow would now release the reconciliation steps that depend on the invoice being paid.
EffectMatch replaces the call succeeded with the result matches, in three moves.
- Bind the approval to one execution. Before anything runs, the application writes down the approved outcome: one invoice update, and no other change to the watched tables. The runtime ties that approval to the current task state and to a single use, so an approval issued before the vendor was blocklisted, or one that was already spent, cannot be reused.
- Run the call with the wall open. The runtime first checks that every route by which the call could leave a persistent change is either watched or blocked; if one route is unclassified, it refuses to run the protected call. It then executes the SQL inside a private transaction that is held open, and reads that transaction's own audit records to list what actually changed: one invoice update and one notification insert.
- Compare, decide, and save the decision. The observed list has one item the approved list does not, so the result is
DIVERGEDand the runtime rolls back both writes: the invoice stayspendingand the notifications table stays empty. The rejection is written to a journal, so a worker that starts later reads halt instead of the call's apparent success, and the dependent step fails safe instead of running.
| Result | Condition | What the workflow does |
|---|---|---|
EXACT | every change was observed, and the observed set equals the approved set | commit, and release dependent steps |
DIVERGED | every change was observed, but the sets differ: an extra, missing or altered change | reject; roll back if the change is not yet durable, and block dependent steps |
INDETERMINATE | the runtime cannot establish that it saw every change | never treated as success; automatic continuation halts |
Why not rely on the checks agents already have? A policy check or a tightly scoped capability approves the request. Even an operation-scoped approval, which fixes one exact call and its arguments, is still a statement about what was asked for. The paper tests this directly. An action rule in the style of AgentSpec, which inspects the SQL for forbidden writes, rejected all 9 explicit unapproved writes in its own control test; but when the submitted SQL stayed the same and a trigger added a write, removed a row or altered a value, it had nothing to reject, because the request looked identical. A plain transaction did not help either: in the MySQL tests, direct transactions committed every extra-write and omitted-statement variant. A transaction guarantees the changes land together; it says nothing about whether they were approved.
Put the paper's own numbers on it. In the business-task tests, one fault type duplicates a tool call, the kind of repeat a retry produces. Across the 36 duplicated executions, 9 changed the final state and 27 still ended exactly in the approved state, because repeating that particular call was harmless. A guard that rejects when a tool reports an error got both halves wrong: it accepted all 9 bad outcomes and blocked 12 of the 27 good ones, which is 21 wrong decisions out of 36. EffectMatch compared the final changes with the approval, rejected the 9 and committed the 27: 0 wrong decisions out of 36. The local cost is small in absolute terms: across 18 public tasks, holding and comparing added a median 1.08 ms per execution, with a median held-to-direct ratio of 4.35×. The ratio looks large because the direct database calls themselves took under a millisecond, and the timing excludes model calls and remote-service latency. Certifying the PostgreSQL boundary costs more, a median 15.16 ms per operation in the paper's test.
The guarantee has edges, and the paper states them. The check is only as complete as the boundary it watches. EffectMatch establishes every change inside a certified set of tables and channels, which is why an unwatched route blocks execution instead of being ignored. For a remote service with no held transaction (the paper tests GitHub issues), it can only read the state back after the call; a mismatch then blocks the next step and any automatic resend, but a change already made outside stays made and needs a separately authorized compensation. And the approved outcome must come from the application: if the agent both wrote the approval and reported the result, the check would reduce to the agent grading its own work.
Goes deeper in: Agent Engineering → Layered Guardrails → Policy Enforcement
Related explainers
- OpenClaw 2.0 — Operation-scoped approvals — scopes the request as tightly as possible; this article checks what the request left behind.
- Idempotency keys vs read-back verification — what to do when you cannot tell whether a write happened at all.
- Observation-effect separation — why a tool call can succeed while the workflow still fails.