Skip to main content
← Back to governance hub

Accountability Deep Dive

Build reliable ownership and defensible evidence across every autonomous decision, so teams don't lose track of responsibility.

Audit trail requirements

  • Unique execution IDs, actor IDs, and timestamps for every agent action.
  • Immutable records for policy checks, tool calls, and approval outcomes.
  • Versioned prompts, models, and tool manifests for reproducibility.
  • Evidence retention policy aligned with legal and contractual requirements.

Decision logging patterns

  • Capture structured fields: context, alternatives considered, chosen action, and confidence.
  • Attach policy evaluation results and rule IDs used during enforcement.
  • Store before/after state snapshots for high-impact mutations.
  • Tag logs by sensitivity tier for access control and retention.

Escalation protocols

  • Define severity classes with response SLAs and ownership.
  • Automatically page responders when confidence drops or policy checks fail.
  • Freeze risky capabilities until human review is complete.
  • Run post-incident reviews with corrective and preventive actions.

Human-in-the-loop gate design

Use risk-tiered gates so low-risk actions flow automatically and high-impact actions pause for reviewer approval. Always enforce explicit deny-by-default behavior when approval is missing or times out.

  • Define action classes with risk levels and required approver roles.
  • Set strict decision timeouts and safe fallback behaviors.
  • Capture reviewer identity, decision reason, and timestamp.
  • Audit gate bypasses with mandatory post-hoc review.

Code examples: logging agent decisions

type DecisionLog = {
  decisionId: string;
  timestamp: string;
  agentId: string;
  actorId: string;
  action: string;
  riskLevel: "low" | "medium" | "high";
  rationale: string;
  confidence: number;
  policyChecks: { ruleId: string; passed: boolean }[];
  escalationRequired: boolean;
};

export async function logDecision(entry: DecisionLog) {
  await auditStore.append({
    ...entry,
    timestamp: new Date().toISOString(),
  });

  if (entry.riskLevel === "high" || entry.escalationRequired) {
    await notifyHumanReviewer({
      decisionId: entry.decisionId,
      summary: entry.rationale,
      actorId: entry.actorId,
    });
  }
}

Code example: human approval gate

export async function runWithHumanGate(input: TaskInput) {
  const risk = assessRisk(input);

  if (risk.level !== "high") {
    return executeTask(input);
  }

  const approval = await requestApproval({
    requestedBy: input.actorId,
    summary: input.summary,
    timeoutMinutes: 30,
  });

  if (!approval.granted) {
    return { status: "blocked", reason: "human_approval_required" };
  }

  return executeTask(input);
}