Thrive AI Editorial
Thrive AI Editorial · AI-assisted worked example, not a member conversation.
2026-10-07
An approval must describe a particular action
A boolean such as approved=true is incomplete unless it refers to an immutable proposal. Bind the decision to the authenticated actor, tool, target, normalized arguments and proposal version. At execution, compare the exact proposal with the approved record. A changed proposal needs a fresh decision.
Human-in-the-loop pauses are useful orchestration primitives, not substitutes for execution authorization. LangGraph documents that a resumed interrupted node restarts from its beginning. Code before the interrupt may run again. Do not put an unprotected external side effect before a pause and assume resuming will skip it.
propose -> freeze payload -> human review -> verify same payload -> execute
changed payload -> require another review
Test approval binding
Python 3, standard library only. This local example detects mutation of JSON-compatible data. It is not a signed token and does not authenticate a caller.
import hashlib
import json
def fingerprint(proposal):
encoded = json.dumps(proposal, sort_keys=True,
separators=(",", ":"), allow_nan=False).encode()
return hashlib.sha256(encoded).hexdigest()
proposal = {"actor": "reviewer-a", "tool": "create_work_item",
"target": "project-alpha", "title": "Review run", "version": 1}
approved = {"digest": fingerprint(proposal), "used": False}
def consume(record, action):
if record["used"]:
raise ValueError("approval already used")
if record["digest"] != fingerprint(action):
raise ValueError("proposal changed")
record["used"] = True
changed = dict(proposal, target="project-beta")
try:
consume(approved, changed)
except ValueError as error:
print(error)
assert not approved["used"]
consume(approved, proposal)
assert approved["used"]
try:
consume(approved, proposal)
except ValueError as error:
print(error)
Expected output:
proposal changed
approval already used
What the simulation deliberately leaves out
In production, checking and consuming the approval must be atomic. Two workers must not both observe unused=true and both execute. Persist the reviewed proposal, expiry, reviewer identity and execution state. Recheck current authorization; a previously approved actor may have lost access.
Consuming approval before an external tool call introduces an uncertain-outcome problem if execution times out. Do not simply unconsume it and run again. Use an operation identifier, a provider idempotency mechanism where supported, and reconciliation. Approval integrity and exactly-once effects are separate concerns.
Define normalization rules before review. A digest of unstable serialization, floating-point amounts or differently ordered semantically equivalent data can produce confusing approvals. Our small JSON example avoids those application-specific questions rather than claiming to solve them.
Test the boundary, not the button
Change each material argument after approval. Replay a decision. Try an expired decision and a revoked reviewer. Race two execution workers. Restart during the approved-but-not-executed state. Assert that changed actions require review and uncertain effects are reconciled instead of blindly repeated.
Source checked 2026-10-08: LangGraph interrupts. The node restart and persistence behavior comes from the documentation. The proposal digest, atomic-consumption design and runnable example are our original AI-assisted engineering explanation, not built-in security guarantees of LangGraph.
Sign in to vote or contribute. Scores count actual member votes, not editorial endorsements.