← All articles
Tracify Team17 min read

AI Agent Audit Trails: Building Compliance-Ready Evidence for SOC 2 and GDPR

Design an audit trail that satisfies a SOC 2 auditor and answers a GDPR access request, without turning every trace into a retained liability.

engineering
A manila exhibit folder holding a printed run record with two black redaction bars, a red wax seal stamped SEALED AND HASHED, and a chain-of-custody tag, pulled open by a GDPR Article 15 request

At a glance

This is an engineering guide, not legal advice. It is written for an engineer or compliance-adjacent technical lead who has to make an AI agent's actions auditable — for a SOC 2 Type II evidence sample or a GDPR data-subject access request — without keeping every trace forever "just in case." It helps you name what belongs in an audit record, how long to keep it, and how to prove nobody altered it after the fact.

The boundary matters. AI agent security covers tool permissions and prompt-injection defense — the controls that stop a bad action. This guide covers what you write down after an action happens, so a person outside the engineering team can later verify that the control operated as designed. It does not replace your organization's legal or compliance counsel, and specific SOC 2 trust-service criteria or GDPR obligations should be confirmed with your own auditor before you rely on anything here as a finished control.

The audit-record framework

Use Actor → Action → Data → Basis → Disposition as the five fields every consequential agent action must produce:

  1. Actor: who or what triggered the action — the service identity, the user or account it acted on behalf of, and the session that connects the two.
  2. Action: what the agent proposed and what actually executed, as distinct events.
  3. Data: which records, fields, or documents the action read or wrote.
  4. Basis: the policy, threshold, or evidence the agent used to justify the action.
  5. Disposition: whether the action was auto-executed, approved, overridden, or blocked, and by whom.

Decision rule: If a field can't be filled in from the record alone — if answering it requires asking the engineer who wrote the prompt, or guessing from context — the record is incomplete. Rebuild the capture point, not the explanation.

The framework is narrower than "log everything." It names the minimum that turns a trace into evidence a third party can use, and it deliberately excludes the raw conversation transcript, which belongs in a separate, shorter-retention tier covered later in this guide.

What must be recorded for every consequential action

Consequential means reversible cost, not database writes

Not every agent action needs the full five-field record. A read-only lookup that never leaves the agent's own reasoning has nothing to audit against — there is no decision to contest. The line is consequence, not mechanism: did the action change something a person could later dispute, or expose something a person could later ask about? A tool call that reads a public FAQ is not consequential. A tool call that reads a customer's payment history — even without writing anything — touches personal data and belongs in the trail, because a GDPR access request can ask "what did you look at," not only "what did you change."

FieldWhat it capturesExample value
ActorService identity, acting-for subject, sessionsvc_billing-agent acting for user_4471, session 9c2
ActionProposed call vs. executed call, tool versionwaive_late_fee proposed and executed, tool v3
DataRecords and fields read or writtenaccount_id, invoice_id, dispute_reason
BasisPolicy version and the threshold it evaluatedfee-waiver-v6: tenure ≥ 18mo, first dispute
DispositionAuto-executed, approved, overridden, or blockedAuto-approved, no override, sealed 03:12 UTC

Five field tickets, each carrying a red ink stamp under the run stage — request, auth, tool call, policy check, execution, or completion — where that field is actually captured

Field-level detail by consequence tier

Treat the five fields as a floor, not a ceiling, and scale the detail inside each field to the consequence of the action. A read of a public document needs only actor and a coarse action label. An irreversible write — a payment, a record deletion, a communication sent to a third party — needs the full record plus the exact before-and-after state of whatever it changed. Human-in-the-loop design is the right place to decide which actions require a person in the loop; this guide assumes that decision has already been made and focuses on what gets written down regardless of which path the action took.

Field note: Record the proposed action and the executed action as two separate events, even when they match. A policy engine that silently changed the amount between proposal and execution is exactly the divergence an auditor is sampling for, and a single collapsed "action" field hides it.

Worked example: a billing-dispute agent waives a fee

Carry one action through the rest of this guide. A billing-dispute agent reviews a customer's account after they contest a $34 late fee. It reads the account's dispute history, checks a policy that auto-waives first-time disputes for customers with 18 months of tenure, and executes the waiver without human review because the amount is under the auto-approval threshold.

ts
// Illustrative: an audit-record shape, not a specific vendor schema.
// Adapt field names to your own event or trace model.

type Disposition = "auto_executed" | "approved" | "overridden" | "blocked";

interface AuditRecord {
  recordId: string;
  runId: string;
  actor: { serviceId: string; actingForSubjectId: string; sessionId: string };
  action: { proposed: string; executed: string | null; toolVersion: string };
  dataTouched: { entity: string; fields: string[] }[];
  basis: { policyId: string; policyVersion: string; evaluatedThreshold: string };
  disposition: { outcome: Disposition; reviewerId: string | null; sealedAt: string };
  contentRef: string | null; // pointer into the short-retention payload tier, or null once purged
}

That single run produces one record with all five fields filled at the moment they became true — actor at authentication, action at the tool call, data at read time, basis at the policy check, and disposition at completion. The last field, contentRef, is the seam between this record and the raw payload it points to; it is also the field that changes once retention runs, which the retention section below covers directly.

Answering a GDPR access request from the trail

The DSAR is the real test of the design

Four months after the fee waiver, the same customer submits a data-subject access request under GDPR Article 15: what personal data does your AI system hold about me, and what did it do with it? This is the moment an audit trail either pays for itself or reveals it was never designed as evidence — because a DSAR is not a request for logs, it is a request for an accounting of decisions, and most telemetry systems were built to answer "did it work," not "what did it decide and why."

DSAR questionWhere the answer comes fromWhat you can safely share
What data did the system process about me?The dataTouched field across every record where actingForSubjectId matchesField names and the record they came from, not raw payload if already purged
Was any decision made about me automatically?The disposition field, filtered to auto_executedYes/no, plus the policy that governed it
Can I contest the decision?The basis field, showing the policy and threshold evaluatedThe policy name and the criteria it checked
Did a human review it?The disposition.reviewerId fieldReviewer role, not necessarily a named individual, per your access policy

Answering this well requires two things the five-field model gives you for free: a stable actingForSubjectId you can query across every run, and a basis field that explains automated decision-making in the terms GDPR Article 22 actually asks about — was a decision made "based solely on automated processing," and does the subject have a right to a human review of it. If your billing agent's disposition shows auto_executed with no reviewer, that is the exact answer the request needs, and it needs to come from a query, not from a person's memory of how the fee-waiver feature worked in the spring.

Field note: Design the actor field around a query, not a search. If answering "every run touching this subject" requires grepping unstructured text across a log archive, you have a trail that exists but does not function as evidence within the one-month response window GDPR expects for most access requests.

What a DSAR does not require

A DSAR does not require you to hand over your prompts, your tool implementation, or another customer's data that happened to appear in a retrieved document during the same run. Redact cross-subject content before export, and treat the request as scoped to the subject's own data touched, not the full run payload. This is the same data-minimization instinct that governs retention, and it is worth applying at export time even when your retention policy would have allowed you to keep more.

Retention: how long to keep what

Retention by data category

The five-field record and the raw content it points to do not need the same retention period, and treating them as one blob is the single most common design mistake in this space. SOC 2 evidence collection typically wants to see that a control operated consistently across an observation period — often twelve months for a Type II report, sometimes longer depending on your auditor's sampling window. GDPR's storage-limitation principle says the opposite: keep personal data no longer than necessary for the purpose you collected it for. Those pull against each other only if you store them together.

Data categoryContainsTypical retentionRedaction approach
Decision metadataActor hash, action type, policy version, disposition, timestamps12 months to match your audit period; up to 7 years if a regulator or contract requires itPseudonymize actor and subject identifiers; no free-text fields
Content payloadAccount fields, dispute text, tool arguments, retrieved documents30–90 daysRedact structured PII (email, phone, card, SSN-shaped values) before export; purge on schedule
Approval and override evidenceReviewer identity, timestamp, reason textMatch decision-metadata retentionReviewer identity may be a role, not a name, once the review window closes
Full conversation transcriptComplete model input and outputShortest practical window, often 7–30 days, or not stored unredacted at allHighest sensitivity; store only if a real investigation need justifies it

The retention clock starts at the decision, not the ticket

A common mistake is anchoring retention to when a support ticket closes rather than when the underlying decision was made. If a dispute stays open for six months, don't let that extend the retention clock on the raw payload — the payload's job was to support the decision, and the decision was made and sealed on day one. Extend metadata retention if you need to prove the control operated over a longer observation window; do not extend raw content retention just because the surrounding workflow is slow.

Redaction and tokenization: the tension, resolved

Evidentiary completeness pulls one way, minimization pulls the other

This is the tension the brief for this article named directly, and it deserves to be stated plainly instead of softened. A SOC 2 auditor wants enough detail in a sample to verify the control actually fired as designed — which argues for keeping more, for longer, in case next year's sample lands on this exact run. GDPR's storage-limitation and data-minimization principles argue for keeping less, for a shorter time, and deleting personal data as soon as the purpose that justified collecting it is served. An engineer who tries to satisfy both by keeping one undifferentiated blob forever will fail the second principle. An engineer who deletes aggressively to satisfy the second will fail the first sample that lands outside the retention window.

The resolution is the same move the retention table above already makes: split the record into a layer that proves the control ran and a layer that contains the personal data the control acted on, and give them different lifecycles. The decision-metadata layer — actor hash, policy version, threshold evaluated, disposition — is evidence of process, not a copy of the customer's data. It can be pseudonymized once and kept for years without violating minimization, because a hash of an account identifier is not the account holder's personal data in any form a downstream reader can act on without the separate key. The content-payload layer is where the actual personal data lives, and it is where the short retention window and aggressive redaction belong.

A raw run record splitting into a locked bank vault holding decision metadata for seven years, and a paper shredder consuming the content payload after ninety days

Three techniques, three different jobs

Tokenization replaces an identifier with a stable, non-reversible-without-a-key token, preserving the ability to query "every run for this subject" without storing the subject's real identifier in the queryable path. Redaction removes or masks a value outright — email addresses, card numbers, government IDs — usually via a pattern-matching pass before telemetry leaves the process, the same discipline covered in AI agent security's data-protection section, applied here with a compliance rather than a breach-prevention motive. Aggregation collapses individual records into a count or rate for cases where the audit question is "how often did this policy fire," not "for whom" — useful for SOC 2 trend evidence that never needed subject-level detail in the first place.

Decision rule: Default every new field to redaction. Promote a field to tokenization only when you can name the query that needs it. Never promote a field to "keep in full" without a named retention justification attached to the promotion.

Non-repudiation and tamper evidence

Proving the trace wasn't altered after the fact

An audit record that can be quietly edited after the run completed is not evidence — it is a claim. Non-repudiation means a reviewer can trust that the disposition shown today is the disposition that was true at 03:12 UTC on the day of the run, not a version edited after someone noticed the auditor was sampling that period. Three controls do most of the work here, and none of them require exotic infrastructure.

Append-only storage. Write audit records to a store that does not support in-place update or delete for the retention window — object storage with a retention lock, or a database role that has insert and select privileges but no update or delete grant. This is a permissions decision, not a cryptography decision, and it closes the most common failure mode: an engineer with production database access fixing a "wrong-looking" record instead of writing a correction as a new event.

Hash chaining. Each record includes a hash of the previous record's content, so altering any record breaks the chain from that point forward and is detectable by recomputing hashes across the sequence. This does not require a blockchain; a simple sha256(previous_hash + record_content) field, checked on export, gives an auditor a mechanical way to verify continuity without trusting your assurance that nothing changed.

Signed export manifests. When you produce an evidence package for an auditor, sign the manifest — the list of record IDs, hashes, and the time range covered — so the auditor holds proof of exactly what was exported and when, independent of your production system's later state.

Security note: A tamper-evident log that only engineers can read is half a control. The other half is a role boundary: the people who can silence an alert or roll back a deploy should not be the same people who can edit the record of what the alert or deploy did. Where the same team must hold both capabilities for a small operation, log the edit itself as an event rather than allowing silent overwrite.

Separating who can write from who can read

Access to the audit trail deserves its own permission model, distinct from access to production data. A support engineer troubleshooting a live account does not need audit-log read access; an auditor reviewing a compliance sample does not need production write access; and neither should share credentials with the service account that writes the records in the first place. Three roles cover most organizations: a write-only service identity that appends records and cannot read or modify them after the fact, a narrow-read role for engineers investigating a specific incident, scoped to the runs relevant to that incident, and an export role, typically held by a compliance owner, that can produce a signed package for an external auditor without touching production systems at all. Log access to the audit trail itself using the same five-field model — an audit log has to survive being asked "who looked at the audit log," or it has not actually closed the loop.

SOC 2 evidence collection from agent trails

Mapping trust-service criteria to trace fields

SOC 2 Type II evaluates whether controls operated effectively over an observation period, typically under the Security, Availability, Processing Integrity, Confidentiality, and Privacy trust-service criteria. Your auditor defines which criteria apply to your engagement and the exact evidence they'll accept — this table names the kind of mapping that conversation usually produces, not a substitute for it.

Criterion (illustrative)What it typically asks forEvidence field that answers it
Logical accessWho could take a consequential action, and was access appropriately scopedactor field, plus the permission-matrix evidence in AI agent security
Change managementDid a policy or threshold change get reviewed before taking effectbasis.policyVersion, correlated with your policy change log
Processing integrityDid the system do what it claimed to do, consistently, across the periodaction.proposed vs. action.executed, sampled across the observation window
Privacy — automated decisionsWas a human involved where policy requires itdisposition.outcome and disposition.reviewerId

A useful habit before your audit period opens: pull a sample of ten runs yourself and try to answer your auditor's likely questions using only the stored record, with no access to the engineer who built the feature. Where you have to ask that engineer anything, you have found the gap before the auditor does.

Evidence collection is a query, not an archaeology project

The practical failure mode in most first-time SOC 2 engagements involving AI agents is not that evidence doesn't exist — it's that producing it takes three engineers and a week of grepping logs the trace schema in AI agent trace schema was never designed to answer at the field level this guide describes. Design the audit record as a first-class queryable object from day one, indexed on actor, subject, and time range, and a sample request becomes a query with a time bound, not a project.

What this framework does not solve

The boundary of an evidence-architecture guide

This framework does not tell you which SOC 2 trust-service criteria apply to your business, whether GDPR or a different regime (CCPA, a sector-specific rule) governs a given data category, or what your specific contractual retention obligations are — those are determinations for your auditor and counsel, made against your actual data flows and customer contracts, and they should be confirmed before you treat any retention period in this guide as your production policy. It also does not solve consent management, cross-border transfer mechanics, or the question of whether you should be processing a given category of data with an AI agent at all — those live upstream of the audit trail, in the decision to build the workflow in the first place.

It also assumes traces are structured enough to query in the first place. If your current telemetry is unstructured log lines with no stable subject or actor identifier, the honest first step is fixing capture, not designing a retention policy for data you can't yet reliably select.

Build the audit-trail checklist

  • [ ] Every consequential action produces actor, action, data, basis, and disposition, captured at the moment each becomes true.
  • [ ] Proposed and executed actions are recorded as separate events, even when they match.
  • [ ] Decision metadata and content payload are stored as separate objects with separate retention clocks.
  • [ ] A stable subject identifier lets you query "every action for this person" in minutes, not days.
  • [ ] The store is append-only for the retention window, and records are hash-chained or otherwise tamper-evident.
  • [ ] Read, write, and export access to the audit trail are three distinct roles, and access to the trail is itself logged.
  • [ ] Your named retention periods and redaction rules have been reviewed by your actual auditor or counsel, not inferred from an article.

Start with one consequential workflow — the one most likely to be sampled or most likely to touch a data subject who might ask. Instrument its five fields, split its retention tiers, and answer one realistic DSAR against it before you call the design finished. Expand to the rest of the system once that one workflow proves the model holds.

Frequently asked questions

Do I need a separate audit-trail system, or can I extend my existing trace pipeline?

Most teams extend their existing trace pipeline rather than building a parallel system. The requirement is structural, not architectural: your traces need a stable actor and subject identifier, a basis field capturing the policy or evidence behind each decision, and a disposition field distinguishing automated execution from human approval. If your current spans already carry run and tool-call data, adding these fields is usually additive.

How is this different from general observability or security logging?

Observability answers 'what happened, and is the system healthy.' Security logging answers 'was this action authorized.' An audit trail answers 'who is accountable for this decision, based on what evidence, and can a third party verify that without asking an engineer.' The three overlap in the data they capture but differ in who needs to read the result and how long it needs to survive.

What counts as a 'consequential' action that needs the full five-field record?

Anything that changes a system of record, that a person could later dispute, or that reads personal data even without writing anything — because a GDPR access request can ask what was read, not only what was changed. A read of public, non-personal data generally does not need the full record; when in doubt, capture it, since the cost of an unused record is far lower than the cost of a missing one.

Can I satisfy both SOC 2 evidence needs and GDPR storage limitation with one retention policy?

Not with one undifferentiated store. Split the record into decision metadata (pseudonymized, longer retention, proves the control ran) and content payload (the actual personal data, shorter retention, redacted or purged on a fixed schedule). Treated as two objects with two lifecycles, the two obligations stop competing for the same bytes.

Who should be able to read the audit trail, and does that access need to be logged too?

Use at least three separate roles: a write-only service identity that appends records, a narrow-read role scoped to a specific incident for engineers, and an export role for a compliance owner producing packages for an external auditor. Yes — access to the audit trail should be recorded with the same actor and disposition fields as any other consequential action, or the trail cannot answer 'who looked at this.'

Written byTracify Team

Practical field notes from the team building Tracify and operating AI agents in production.

#compliance#audit trail#SOC 2#GDPR

Next in the loop

Voice AI Agent Observability: Tracing Latency, Turn-Taking, and Failures in Real-Time Voice Agents

Keep reading →