Verify the Outcome
Last reviewed · content updated
IntermediateWhat you'll learn
~15 min- Distinguish a tool call that returned without error from an outcome that actually held
- Explain that receipts identify the envelope policy and version used for verification, and that change control must bump the policy version whenever the postcondition changes
- Recognize a self-asserted result in the wild and say why it is a claim, not a verification
Before the detail — Decision: every executed action gets checked against a fact defined outside the agent, not against the agent’s own report of what happened. Outcome: a receipted PASS or FAIL that a reviewer can trust because the agent could not have written it. Artifact: the versioned envelope policy containing the postcondition, accepted when every judged receipt carries its policy_id and policy_version and change control requires a version bump for every postcondition edit. Status of what follows: binding.
Prompt first: who checked, and where does the check live?
Pick one automated action from the last week that reported success.Answer without asking the same tool that ran the action: 1. What field, in what system, would have to hold what value for this to actually be true - not "the call returned 200," the real-world condition it claims happened? 2. Who or what checked that field after the action ran, and is the check defined somewhere the agent cannot edit? 3. If the honest answer to #2 is "nothing" or "the agent's own closing message," write that down as the true state of verification for this action. Do not round it up to "verified."An assistant can draft the three questions and even propose what field to check next time. It cannot tell you, for last week’s action, whether anyone actually looked. That answer comes from the target’s owner.
Tool success is not outcome success
A tool call finishing without an exception says only that the call finished without an exception. Whether the thing the caller wanted actually happened is a separate question, and treating the two as the same question is how an agent action goes wrong without ever failing.
The substrate carries a committed run of exactly this failure, not a hypothetical: transcripts/fielddesk.clamp.txt sends scale_pool {"max_conns":60} — a value fully inside the envelope’s own allowed range of 8 to 64. The database behind FieldDesk has a hard ceiling of 56, unrelated to and unknown by the envelope, and the target clamps and reports success exactly as its own code is written to: STEP 5 execute pool_max 32 -> 56 (requested 60, clamped at the database ceiling). By every signal a tool-calling loop watches, that call is a success — allowed, executed, succeeded. Only the next step disagrees, because it checks the one thing the target’s own response never claims: STEP 6 verify FAIL pool_max is 56, the action asked for 60. Allowed, executed, succeeded, still wrong — caught only because something asked whether the requested value was the value that actually landed. The guard then runs the declared inverse, STEP 7 compensate scale_pool {"max_conns":32}: pool_max 56 -> 32, and the run closes RESULT compensated exit 5, not verified.
The substrate’s own negative-test suite makes the stakes concrete: test 41 disables step 6 on this identical run, and the clamp goes unnoticed — RESULT verified exit 0 with pool_max still 56, not 60, and no compensation ever fires.
The check has to come from somewhere the agent cannot edit
The fix is not a smarter agent. It is a postcondition that lives in the same envelope file the agent cannot write to — policy/, receipts/, and control/ are all outside the paths a guarded action may touch — and that gets evaluated after execution, independently of what the tool itself reported. For the pool-scaling action, the postcondition is a single comparison: does the field the action was supposed to change now equal the value the caller asked for? That is exactly the line the clamp run above prints at step 6 — no agent-authored text enters that judgment, only a field read back from the target and compared to what was requested.
Every row names the policy_id and policy_version that judged it. The substrate does not version the postcondition separately or enforce a bump; if change control bumps policy_version on every postcondition edit, later receipts expose which version did the judging.
The self-assertion trap, in a vendor’s own words
The alternative to an independent postcondition shows up constantly in agent tooling, and it is worth reading in a real product’s own published sample rather than a hypothetical. Azure SRE Agent’s own example output reads: “Done: I’ve restarted app-service-staging. Memory usage is now normal.” Read it closely: the agent is asserting both that it took the action and that the very condition it is being judged on — memory usage being normal — now holds, in the same breath, from the same process, with no second source. “I did it and it worked” is a report, not a check; the postcondition pattern this lesson builds exists precisely so that sentence is never the only evidence in the file.
What “normal” would actually mean for a live service — an error-budget burn rate, checked against an objective — is not this lesson’s question; Operating in Production 2.2 (a separate training in this series) answers it, making the burn rate against that objective the thing that pages a human. What belongs here is narrower and more basic: whoever is judging whether an action worked cannot be the same process that performed it, whatever the two sentences sound like stitched together. A remediation agent that grades its own restart is a contract risk the moment its output feeds a service-level-agreement report (SLA — a contractual service commitment) nobody else checks.
Stop and escalate when an action has no postcondition declared. The guard’s fallback is blunt: “no post-condition declared — an unverifiable action.” The action does not run unattended until the envelope owner supplies an independent postcondition.
An agent asks FieldDesk's connection pool to scale to 60 - well inside the envelope's allowed range of 8 to 64. The database's own hard ceiling is 56. What does the guard's verify step record?
Key takeaway
A tool call that finishes without error is not evidence the world changed the way it was asked to; only a postcondition defined outside the agent, evaluated after execution and stamped with its own version in the receipt, earns that claim. The next lesson picks up from a FAIL: what happens once verification catches a gap, and which gaps a compensating action can actually close.
LEADERSHIP DECISION no agent action is treated as successful on its own report; every execution is judged by a postcondition the agent cannot editPRACTITIONER ACTION for each tool, write the field-level postcondition before the first unattended run, and confirm its version is in every receiptSUCCESS MEASURE zero production incidents traced to a self-reported "done" with no independent check behind it - audit finding avoided