Skip to main content
Intelliger
Verifiable Agent Operations

AI Agent Observability: Why Audit Logs Are Not Enough

AI agent observability needs more than logs. Learn how signed action receipts bind requests, authority, policy, execution and results for verification.

AI Agent Observability: Why Audit Logs Are Not Enough
Intelliger
13 minute read

AI agent observability becomes a governance problem when an enterprise agent issues a refund at 14:03. Six months later, finance asks which policy allowed it. Security asks whether the mandate was still active. Legal asks what the agent actually sent to the payment provider. The platform team has audit logs, traces, a model transcript, an approval record and an upstream transaction ID.

They still may not have an answer they can verify.

Logs are excellent operational data. They help engineers search, aggregate, alert and debug. They are usually mutable, system-specific and distributed across services. A log line that says policy=allow does not bind that decision to the exact request, active authority, approval, executed operation and observed result.

An action receipt is a signed, canonical record for one protected transaction. It does not replace logs or traces. It gives the transaction a portable evidence object that another verifier can check without trusting the application that displays it.

The difference becomes important when agents can spend money, change production, release sensitive data or act across company boundaries.

AI agent observability starts with audit logs

Logs tell you what a component reported at a point in time. A gateway might emit:

{
  "timestamp": "2026-08-10T14:03:18.119Z",
  "level": "info",
  "service": "refund-gateway",
  "requestId": "req_f2a7",
  "agentId": "agent:support:refund-4",
  "policyDecision": "allow",
  "upstreamStatus": 200
}

That line helps an operator find the request and correlate an error. It does not say which policy bundle produced the decision, what request was evaluated, whether the execution request changed, which mandate constrained the agent, what approval was attached or which upstream response the system observed.

You can add those fields. Soon the log entry contains payload digests, issuer chains, policy references, approval identifiers and signatures. At that point you are designing a receipt inside a log format, often without defining canonicalisation or verification semantics.

Other operational tools have the same boundary. A distributed trace explains the call path and latency. A SIEM correlates events and detects patterns. An append-only audit log preserves a sequence of administrative changes. A model transcript shows what the agent considered or said. Each remains useful. None alone is the transaction evidence object.

A receipt binds the transaction's security context

A useful receipt connects the facts that tend to drift apart in a service architecture:

  • the accountable organisation and agent;
  • the issuer and current trust or assurance state used at decision time;
  • the mandate and any delegation chain;
  • the canonical transaction envelope and request digest;
  • the policy version and structured decision;
  • the human approval, if required;
  • input or output transformations;
  • the executed operation and observed result;
  • external provider references;
  • timestamps, nonce and idempotency data;
  • signature metadata.

An illustrative receipt might look like this:

{
  "type": "ActionReceipt",
  "version": "example-1",
  "receiptId": "rcpt_01J8P27YFZ",
  "issuer": "org:example:gateway",
  "assurance": "unilateral",
  "subject": {
    "organisation": "org:example",
    "agent": "agent:support:refund-4",
    "passport": "passport_01J7...",
    "mandate": "mandate_01J8..."
  },
  "transaction": {
    "id": "txn_01J8P25K4R",
    "requestDigest": "sha256:44f8...",
    "idempotencyKey": "refund_charge_8721_v1",
    "action": "refund.create",
    "resource": "tenant/418/charge/8721"
  },
  "decision": {
    "result": "allow",
    "policyBundle": "refund-policy-2026-08-03",
    "requestDigest": "sha256:44f8...",
    "decisionDigest": "sha256:c9a1...",
    "approval": "apr_01J8P261MN"
  },
  "execution": {
    "requestDigest": "sha256:44f8...",
    "status": "accepted",
    "providerReference": "rf_294801",
    "responseDigest": "sha256:7b32..."
  },
  "issuedAt": "2026-08-10T14:03:18Z",
  "signature": {
    "algorithm": "Ed25519",
    "keyId": "key:gateway:2026-07",
    "audience": "oati-verifier:example",
    "createdAt": "2026-08-10T14:03:18Z",
    "expiresAt": "2026-08-10T14:08:18Z",
    "nonce": "01J8P27Z1K",
    "value": "base64url:MEUCIQ..."
  }
}

This is an explanatory shape, not the normative OATI schema. The design point is the binding. The same request digest appears in the decision and execution context, so a verifier can detect substitution. The receipt names the policy and approval rather than relying on a nearby log line. The assurance field says who signed the evidence.

Canonicalisation makes signatures portable

Signing raw JSON text is unreliable because equivalent objects can be serialised with different whitespace, property order or number formatting. A verifier needs a deterministic byte representation.

The receipt issuer should:

  1. validate the object against a versioned schema;
  2. remove the signature field from the signing payload;
  3. canonicalise the remaining object using a specified algorithm;
  4. compute any referenced digests using named algorithms;
  5. sign the canonical bytes with an identified key;
  6. attach the signature metadata without changing signed fields.

Verification reverses the process:

async function verifyReceipt(receipt: Receipt, trust: TrustResolver) {
  validateSchema(receipt);
  assert(receipt.version === SUPPORTED_RECEIPT_VERSION);
  assert(ALLOWED_ALGORITHMS.has(receipt.signature.algorithm));
  assert(receipt.signature.audience === EXPECTED_AUDIENCE);
  assert(receipt.signature.createdAt <= now());
  assert(now() < receipt.signature.expiresAt);

  const issuer = await trust.resolveIssuer(receipt.issuer);
  const key = await trust.resolveKey(receipt.signature.keyId);
  assert(key.issuer === issuer.id);
  assert(key.validFrom <= receipt.issuedAt);
  assert(receipt.issuedAt < key.validUntil);
  assert(await trust.isActive(receipt.issuer, receipt.issuedAt));
  assert(await trust.isActive(key.id, receipt.issuedAt));

  const payload = canonicalise(withoutSignature(receipt));
  assert(verifySignature(key.publicKey, payload, receipt.signature.value));
  assert(await replayStore.claim(receipt.signature.nonce));

  const currentIssuerStatus = await trust.currentStatus(receipt.issuer);
  const currentKeyStatus = await trust.currentStatus(key.id);

  return {
    validSignature: true,
    validAtIssuance: true,
    currentIssuerStatus,
    currentKeyStatus,
    assurance: receipt.assurance,
    transactionId: receipt.transaction.id,
    requestDigest: receipt.transaction.requestDigest,
  };
}

This is still an architecture sketch, not a replacement for the OATI verifier. A complete implementation must apply the selected proof profile, schema, audience, time, algorithm, nonce, replay, trust-chain and revocation rules. Verification policy must state whether it checks status at issuance time, verification time or both. Those questions answer different needs. An auditor may need to know that the key was valid when the receipt was issued and whether it has since been compromised.

OATI's implemented developer profile uses RFC 8785 JSON canonicalisation and supports Ed25519 and ES256 verification profiles. The broader lesson applies regardless of format: if independent implementations cannot recreate the signed bytes, the receipt is not portable.

Bind what was authorised to what was executed

The most important comparison is between the canonical transaction that policy evaluated and the request sent upstream.

Sometimes they should have the same digest. Sometimes the gateway intentionally transforms the request. It may remove a forbidden field, resolve a resource alias or inject a short-lived credential. In that case, the receipt should record both the proposed and executed request digests plus a structured transformation record.

{
  "transformation": {
    "policy": "minimise-refund-request-v3",
    "inputDigest": "sha256:02a9...",
    "outputDigest": "sha256:44f8...",
    "operations": [
      { "op": "remove", "path": "/customer/internalRiskNotes" },
      { "op": "replace", "path": "/tenant", "valueDigest": "sha256:8ac0..." }
    ]
  }
}

Avoid putting sensitive plaintext into the receipt just to make it self-contained. Digests, encrypted attachments and governed evidence references can preserve binding while keeping payload data in the customer environment. A verifier may confirm integrity without receiving every source field.

If a transformation changes business meaning, obtain a fresh policy decision and approval over the transformed transaction. Recording the change after the fact does not make it authorised.

State what the receipt does not prove

A valid signature proves that the holder of a signing key signed the canonical receipt. Trust resolution can connect that key to an issuer and status. The bound digests can show that referenced evidence has not changed.

The receipt does not automatically prove:

  • that an external data source told the truth;
  • that a supplier fulfilled an order;
  • that a payment settled because an API returned accepted;
  • that a model's reasoning was correct;
  • that a human approver understood the full context;
  • that no traffic bypassed the enforcement path;
  • that the signing system itself was uncompromised.

Those are separate claims with separate evidence.

For example, a receipt can bind a payment provider's transaction reference and the response observed by the gateway. Reconciliation later determines whether the payment settled, failed or reversed. Append a linked outcome event or issue a new status evidence object. Do not rewrite the original receipt to match later reality.

Likewise, an oracle signature proves which oracle supplied a reserve statement. It does not make the reserve statement true. Developers should preserve that distinction in schemas and UI labels.

Unilateral evidence is useful and limited

When one company operates the gateway, its receipt is unilateral. This is common and practical. An API provider can prove what its own system authorised and released even if the customer agent never signs an OATI object. A buying enterprise can prove what its gateway approved and sent to a supplier even if that supplier uses an unchanged API.

The receipt should expose the assurance level and signing parties:

{
  "assurance": {
    "level": "unilateral",
    "signers": ["org:buyer:gateway"],
    "counterpartySignature": null
  }
}

Do not call this "mutually verified" or "bilateral proof." It is still useful for internal controls, audit reconstruction and dispute preparation.

Assurance can progress as counterparties adopt more of the trust flow. A presented Passport improves agent and owner verification. A signed Mandate provides portable authority subject to issuer trust. A countersignature over the result creates bilateral evidence for the facts the counterparty actually signed.

Countersigning does not validate every field by implication. Define the countersigning payload. A supplier may sign only the order identifier and acceptance status, while the buyer signs the full local decision context.

Keep receipts and logs connected

Receipts work best as the spine of an evidence graph, not an isolated file.

Use one transaction identifier across the gateway, policy engine, approval workflow, credential broker, connector, ledger and receipt. Put the receipt identifier and transaction digest into logs and trace attributes. Keep raw telemetry under normal retention and access controls. Store the receipt and essential evidence references according to the transaction's legal and operational needs.

Transaction ID
  |-- gateway logs
  |-- distributed trace
  |-- policy decision record
  |-- approval record
  |-- credential issuance reference
  |-- provider operation reference
  |-- action receipt
  `-- later outcome and reconciliation events

Do not put the full receipt in every log event. That creates duplication, privacy exposure and inconsistent copies. Log the identifiers needed to retrieve and verify the authoritative evidence object.

Design for disputes before they happen

A dispute package should let an investigator answer a fixed set of questions:

  1. Who operated the agent, according to which issuer and assurance level?
  2. What authority was active, and what constraints applied?
  3. What exact transaction did the gateway evaluate?
  4. Which policy version returned the decision?
  5. Was human approval required, and what digest did it cover?
  6. What request reached the external system?
  7. What response did the gateway observe?
  8. What later outcome was reconciled?
  9. Were any relevant issuer, key, Passport or mandate records revoked?
  10. Can an independent verifier reproduce the digest and signature checks?

The evidence package may include signed objects, schema versions, trust records, policy artifacts, approval records and selected payload evidence. Use references and digests to avoid copying sensitive content by default. Apply retention, legal hold and access policy to the package itself.

The verifier should work offline when the required trust material is included. Online resolution can add current revocation status, but a central dashboard should not be the only way to interpret the evidence.

Failure cases to test

A log and receipt disagree

Treat the signed receipt as evidence of what the receipt issuer attested, not automatic truth. Compare digests, service clocks, request IDs and signing time. Preserve both records for investigation. Do not silently regenerate the receipt.

The signing key is revoked later

Record the key validity and status evidence used at issuance. Verification should report both historical validity and current status. A later compromise may change confidence without changing the bytes.

The policy bundle cannot be retrieved

A policy identifier alone may be insufficient for a long-lived dispute. Retain the signed policy bundle or its governed evidence artifact, subject to intellectual property and privacy controls. At minimum, preserve a digest and version that can detect substitution.

The external API times out

Issue a receipt with an unknown or pending execution state rather than guessing failure. Reconcile using the provider reference or idempotency key. Link the later observation to the original transaction.

Two receipts exist for one transaction

Use a durable idempotency claim before execution and enforce uniqueness for the authoritative receipt. If different parties issue their own receipts, identify each issuer and bind them through the shared transaction digest rather than pretending one overwrites the other.

Sensitive data leaks through evidence

Receipts should carry only fields required for verification. Use digests, selective disclosure, encrypted attachments or local evidence references for payloads. Test receipts and denial records for accidental secret, prompt and personal-data capture.

Implementation checklist

  • Define the receipt's claims and assurance vocabulary before choosing fields.
  • Use a versioned schema and deterministic canonicalisation.
  • Bind organisation, agent, authority, transaction, decision, approval and execution.
  • Name every digest and signature algorithm.
  • Compare the authorised request with the executed request.
  • Record transformations explicitly.
  • Keep secrets and unnecessary payload data out of the receipt.
  • Include issuer, key identifier, signing time and status references.
  • Make unilateral and countersigned evidence visibly different.
  • Preserve idempotency, nonce and replay information.
  • Model pending, unknown, settled, failed and reversed outcomes separately.
  • Link receipts to logs and traces through stable identifiers.
  • Retain the policy and approval evidence needed for later verification.
  • Build an offline verifier and publish conformance vectors.
  • Test substitution, replay, revocation, key rotation and partial failure.

Related engineering guides

OATI's current boundary

The public OATI Receipt framework implements schemas, builders, canonicalisation, signatures, verification, examples and conformance flows. Developers can generate and independently verify receipts today. The implemented cryptographic profile remains a developer preview until independent protocol and implementation review is complete.

Durable bilateral signing, long-term evidence retention, audit-package export and dispute workflows are target commercial capabilities and are not complete production features. That makes the distinction in this article practical rather than academic. A signed receipt can already improve the integrity and portability of transaction evidence, but production evidence operations require retention, key governance, reconciliation, privacy controls and tested recovery around the object.

Keep searchable logs for operations and a signed receipt for the transaction claim. Neither proves facts outside the evidence it binds.