Guarded Automation: Agents That Run Operations Module 3 · Before and After

Capture the Pre-State

Last reviewed · content updated

Intermediate

What you'll learn

~15 min
  • State why an approval must bind to a pre-state hash and a plan hash, not to a verb
  • Read a request document and name which of its eight bound fields moving invalidates a signed approval
  • Treat a saved plan, and a mode named for planning, as artifacts with real risk rather than passive previews

Before the detail — Decision: an approval is worthless unless it was signed against a captured world and a computed plan, not a verb. Outcome: a request document an approver can actually read, and a token that stops verifying the instant any part of it moves. Artifact: the request document, accepted when its eight bound fields all still match what is about to happen. Status of what follows: binding — the guard refuses to run the steps out of order.

Prompt first: what does your approval actually bind to?

Look at the last three times someone approved an automated change in
your environment - a chatops "yes," a pipeline click-through, a
verbal go-ahead before a script ran. For each one, answer:
1. Was the target's state captured and hashed BEFORE the ask?
2. Was the exact change computed and hashed - a plan, a diff, a
dry run - before the ask, or did the approver sign a verb
("restart it," "clamp the pool")?
3. If the target had moved between the ask and the action, would
anything have noticed and refused, or would the action have
run anyway against a world nobody re-checked?
List the three answers plainly, one row per approval. Do not backfill
a plan hash that was never computed, and do not credit an approval
for catching a race it was never wired to catch.

An assistant can format the answers; it cannot know whether the approval bound to a plan or a verb.

The order is not a style choice

A guarded action runs through a fixed sequence: prerequisite, then the envelope check, then a pre-state capture, then a plan computed and hashed, then approval, and only then execution, verification, compensation, and the receipt. The order of those three middle steps is the whole point of this lesson: pre-state, then plan, then approval — never the other way around.

The reason is blunt. An approver who signs off on a verb — “restart the pool,” “pre-position three crews” — has signed nothing worth defending later, because a verb says nothing about what that verb will actually do to the world as it stands right now. So the world gets hashed first, the exact change gets computed and hashed second, and only then is anyone asked to sign. You cannot approve what has not been planned: a request that skips the plan step never reaches a human, because there is nothing yet for a human to read. Getting this order wrong is the difference between an approval a reviewer can defend during a later review and one that reads, on inspection, as a rubber stamp.

What the approval actually binds to

The signature is not over the action’s name. It is a hash over eight fields, captured at the moment the plan was computed: action, agent, params, target, pre-state hash, plan hash, policy version, and request id. Here is what that request document looks like for one action, send_dispatch_notice, before anyone has signed anything:

action send_dispatch_notice
agent mu-ai-011
params {"audience":"feeder_crews","feeder_id":"F-2291"}
target meridian-work-management
pre_state_hash 59c537024772415174f404ce147e13393cbfb3a0…
plan_hash 7aa2734088c24b0d067c2a5cda495c9e97d8e223…
policy_version 2026-08-29.2
request_id REQ-C9B3918D8F

Every one of those eight is a way an approval can go stale, and the guard names which one moved rather than returning one generic failure. Two of the eight carry their own committed denial sentences: when the world changes after the signature but before execution, the guard reports “the world MOVED after this was approved (stale state): approved against pre-state {token}, this request’s pre-state is {current}” and refuses with exit 4 — the code reserved for approval problems, distinct from the envelope’s exit 3. When the target’s own state has not moved but the computed plan has — the same feeder, the same parameters, a different tool version underneath — the guard reports “the PLAN changed after this was approved (stale plan): approved plan {token}, this request plans {current},” also exit 4. A parameter edit, a policy-version bump, or reusing a request id that already produced a receipt row each get their own sentence too. Naming which of eight fields moved turns “the approval failed” into a one-line explanation a reviewer accepts without a follow-up call.

ℹWhat a request id is not

An unused approval is refused once its expires_at passes; an unexpired approval already consumed is refused on every later attempt. Expiry and single use answer different questions, and 4.1 builds both; keeping them separate saves assessor-hours on a denied request.

The plan itself is not safe to hand around

The industry precedent here cuts against the comfortable assumption that a plan is inert. Terraform’s own saved-plan file carries “your full configuration, all of the values… and all of the plan options including the input variables,” and that sensitive data is written “in cleartext.” The artifact that makes an approval verifiable — the exact thing an approver needs to read before signing — is, in the most widely used infrastructure-as-code tool on the market, itself a secret. A pre-state hash and a plan hash sidestep that trap by carrying a fingerprint instead of the payload, but a full request document or approval card built on top of them can still leak whatever variables it renders back to the approver, so it deserves the same handling as a credential, not the handling of a log line.

The second trap is sharper: a step named for planning is not automatically inert. One widely used command-line interface coding assistant’s own documentation says as much about its plan mode: it is not read-only, because commands its own classifier has already approved still run while the assistant is “planning.” A step’s name is a claim about what it will do, not a guarantee, and the only thing that actually earns the description “nothing happened yet” is a plan hash computed and inspected before execution, the way this training’s guard computes one. kubectl diff gives the same discipline for a live cluster — exit 0 for no drift, 1 for a real diff, anything higher for an error in the check itself — a plan you can inspect and hash before anyone runs apply.

What happens after an approved action succeeds or fails — promoting it forward, deciding whether to roll back — belongs to deployment and release engineering, not to this lesson. Cloud Modernization 4.3 (a separate training in this series) is where that decision lives, under its own rule — roll back before you debug — which sorts out a bad release rather than a single approved action. This lesson stops at the moment just before the signature; verifying whether the action actually did what it claimed is next.

Stop and escalate when the document in front of an approver does not carry all eight bound fields — action, agent, parameters, target, pre-state hash, plan hash, policy version, and request id. Sign nothing and run nothing until the envelope owner repairs the request path; nobody waives the binding for the current attempt.

KNOWLEDGE CHECK

An approver signs a token for send_dispatch_notice at 19:45. At 19:52, right before the guard executes, someone else changes the priority queue for the same feeder, F-2291 - a field the dispatch notice itself never touches. What happens when the guard tries to execute?

Key takeaway

An approval is only as good as the moment it was signed against: capture the pre-state, compute and hash the plan, and only then ask — anything that moves after that point names itself and gets refused rather than silently executed. The next lesson picks up where this one stops: an action that executed cleanly is not the same claim as an action that worked, and 3.2 builds the check that tells the difference.

LEADERSHIP DECISION no automated approval is valid unless it is
signed against a captured pre-state and a
computed plan, not a verb
PRACTITIONER ACTION before signing, confirm the request document
carries all eight bound fields, and treat the
plan itself as sensitive, not as a preview
SUCCESS MEASURE every denied approval in the receipt chain
names which of the eight fields moved -
assessor-hours saved per reviewed denial
Search lessons