d flagging the thread.
- Database Update: Compensation involves reverting to a pre-action snapshot.
- Resource Creation: Compensation involves deletion or archiving.
interface ActionContract<TParams, TResult> {
id: string;
params: TParams;
execute: () => Promise<TResult>;
compensate: (result: TResult, context: ExecutionContext) => Promise<void>;
riskProfile: RiskLevel;
}
enum RiskLevel {
LOW,
MEDIUM,
HIGH,
CRITICAL
}
2. Implement the Transaction Manager
The transaction manager orchestrates execution, maintains the LIFO (Last-In-First-Out) stack for unwinding, and enforces approval gates based on risk profiles.
class AgentTransactionManager {
private stack: ActionContract<any, any>[] = [];
private approvalPolicy: ApprovalPolicy;
constructor(policy: ApprovalPolicy) {
this.approvalPolicy = policy;
}
async execute<T>(contract: ActionContract<any, T>): Promise<T> {
// Gate check for high-risk actions
if (this.approvalPolicy.requiresApproval(contract.riskProfile)) {
await this.requestHumanApproval(contract);
}
// Execute forward action
const result = await contract.execute();
// Push to stack for potential compensation
this.stack.push({ ...contract, result });
return result;
}
async unwind(): Promise<void> {
// Unwind in LIFO order
while (this.stack.length > 0) {
const action = this.stack.pop()!;
try {
await action.compensate(action.result, this.getContext());
} catch (error) {
// Compensation failure requires alerting;
// do not block further unwinding
this.logCompensationFailure(action, error);
}
}
}
}
3. Action-Aware Compensation Handlers
Compensation handlers must be implemented per connector type. Generic rollback logic is insufficient because external systems have different capabilities.
// CRM Connector: Snapshot-based revert
const crmUpdateContract: ActionContract<UpdateParams, CrmRecord> = {
id: 'crm-update-001',
params: { recordId: 'rec_123', data: { status: 'closed' } },
execute: async () => {
const snapshot = await crmClient.getSnapshot('rec_123');
const updated = await crmClient.update('rec_123', { status: 'closed' });
return { ...updated, snapshot };
},
compensate: async (result) => {
await crmClient.revert('rec_123', result.snapshot);
},
riskProfile: RiskLevel.MEDIUM
};
// Email Connector: Correction-based compensation
const emailSendContract: ActionContract<EmailParams, EmailResult> = {
id: 'email-send-001',
params: { to: 'user@example.com', subject: 'Invoice' },
execute: async () => {
return await emailClient.send({ to: 'user@example.com', subject: 'Invoice' });
},
compensate: async (result) => {
// Cannot unsend; must send correction
await emailClient.send({
to: result.to,
subject: 'CORRECTION: Previous email was sent in error',
body: 'Please disregard the previous message.'
});
},
riskProfile: RiskLevel.HIGH
};
4. Approval Gate Configuration
Not all actions require human intervention. Approval gates should be configured based on a risk matrix that considers data sensitivity, external impact, and irreversibility.
class ApprovalPolicy {
private thresholds: Map<RiskLevel, boolean> = new Map();
constructor() {
this.thresholds.set(RiskLevel.LOW, false);
this.thresholds.set(RiskLevel.MEDIUM, false);
this.thresholds.set(RiskLevel.HIGH, true);
this.thresholds.set(RiskLevel.CRITICAL, true);
}
requiresApproval(level: RiskLevel): boolean {
return this.thresholds.get(level) ?? false;
}
}
Pitfall Guide
1. Assuming Symmetric Undo Operations
- Explanation: Developers often assume that compensation is the inverse of the action (e.g.,
delete undoes create). This fails for actions like email dispatch or financial charges where the action has external consequences.
- Fix: Design compensation handlers that are action-aware. For irreversible actions, implement corrective measures (e.g., sending a correction email) rather than attempting impossible reversals.
2. Ignoring Partial Failures During Unwind
- Explanation: If a compensation handler fails, the system may leave resources in an inconsistent state. For example, if a database revert succeeds but a Slack notification correction fails, the systems are out of sync.
- Fix: Implement idempotent compensation handlers that can be safely retried. Log compensation failures separately and trigger alerts for manual review. Never allow a compensation failure to block the unwinding of subsequent actions.
3. Over-Approving Low-Risk Actions
- Explanation: Applying approval gates to all actions creates bottlenecks that negate the value of automation. Human-in-the-loop latency can stall agent workflows.
- Fix: Use granular risk thresholds. Reserve approval gates for actions with high blast radius or irreversibility. Allow low-risk, compensatable actions to proceed autonomously.
4. Missing Pre-Action Snapshots
- Explanation: Attempting to revert a resource without capturing its state before modification makes compensation impossible.
- Fix: Always capture a snapshot of the resource state within the
execute function before mutation. Store this snapshot in the transaction result so the compensation handler has the necessary data to revert.
5. Lack of Intent Context in Audit Logs
- Explanation: Standard logs record what action was taken but not why. When an agent makes a mistake, understanding the intent is crucial for debugging and improving the model.
- Fix: Enrich transaction logs with intent metadata. Include the agent's goal, the reasoning chain, and the confidence score at the time of execution. This enables better post-mortem analysis and model fine-tuning.
6. Testing Only Happy Paths
- Explanation: Compensation handlers are rarely tested in isolation. When a failure occurs in production, the rollback logic may contain bugs that exacerbate the issue.
- Fix: Implement chaos engineering for compensation paths. Write unit tests that force action failures and verify that compensation handlers execute correctly. Simulate compensation handler failures to ensure the system degrades gracefully.
7. State Drift in Distributed Systems
- Explanation: In multi-agent or distributed environments, an agent may attempt to compensate for an action that has already been modified by another process.
- Fix: Use optimistic concurrency control or version vectors when reverting resources. Verify that the resource state matches the expected snapshot before applying compensation.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Read-only queries | Direct execution | No state mutation; zero risk of corruption | None |
| Internal data updates | Compensating transactions | Fast automated recovery; low blast radius | Low development cost |
| Customer-facing communications | Approval gates + Correction | Irreversible action; high reputation risk | Latency increase; manual review cost |
| Financial transactions | Approval gates + Audit | Regulatory compliance; irreversible | High latency; strict governance |
| Multi-step workflows | Saga pattern with unwind | Complex dependencies; partial failure risk | Medium complexity; high reliability |
Configuration Template
{
"agentSafety": {
"policies": {
"github.delete_repository": {
"risk": "CRITICAL",
"approval": "MANUAL",
"compensation": "NONE"
},
"crm.update_contact": {
"risk": "MEDIUM",
"approval": "AUTO",
"compensation": "SNAPSHOT"
},
"email.send_notification": {
"risk": "HIGH",
"approval": "AUTO",
"compensation": "CORRECTION"
},
"slack.post_message": {
"risk": "LOW",
"approval": "AUTO",
"compensation": "DELETE"
}
},
"unwind": {
"strategy": "LIFO",
"onCompensationFailure": "ALERT_AND_CONTINUE",
"timeout": "30s"
},
"audit": {
"captureIntent": true,
"captureSnapshot": true,
"retention": "90d"
}
}
}
Quick Start Guide
- Wrap Existing Clients: Replace direct API calls with wrapped versions that implement the
ActionContract interface. Ensure each wrapper defines execute and compensate functions.
- Initialize Transaction Manager: Instantiate the transaction manager with your risk policy configuration. Pass this manager to your agent's execution loop.
- Define Risk Thresholds: Configure approval gates based on your organization's risk tolerance. Start with conservative thresholds for external actions and relax as confidence grows.
- Execute and Monitor: Run agent workflows through the transaction manager. Monitor logs for compensation events and approval requests. Verify that unwind operations restore state correctly.
- Iterate on Compensation: Review compensation handler performance. Refine logic based on real-world failure modes. Add corrective actions for irreversible operations where necessary.