Skip to main content

Audit Trail

Every stage of the control path emits an immutable event to the audit trail powered by Trailproof. This produces a complete forensic record for every memory operation — from the moment it is received through to its final committed or blocked state. Trailproof provides SHA-256 hash chains, HMAC signing, query, and verification out of the box. Memproof delegates all audit trail responsibilities to Trailproof so you get tamper-evident logging without managing event storage internals.

Event Types

Events are namespaced under memproof.pipeline.*:
Event TypeStagePayload
memproof.pipeline.receivedRequest accepted
memproof.pipeline.risk_assessedRisk scoring completescore, level
memproof.pipeline.policy_decidedPolicy rule matchedaction, reason_codes
memproof.pipeline.approval_requestedSent to approval queue
memproof.pipeline.provider_attemptedAdapter called
memproof.pipeline.committedOperation succeeded
memproof.pipeline.blockedOperation denied/quarantined

TrailEvent Structure

Each event is a Trailproof TrailEvent with the following fields:
class TrailEvent:
    event_id: str           # globally unique ID
    event_type: str         # e.g. "memproof.pipeline.received"
    timestamp: datetime     # UTC timestamp
    actor: str | None       # who triggered the event
    metadata: dict          # stage-specific data (operation_id, tenant_id, etc.)
    hash: str               # SHA-256 hash for chain integrity
    prev_hash: str | None   # hash of the previous event in the chain
    signature: str | None   # HMAC-SHA256 signature (if signing is enabled)
The metadata field carries the operation_id, tenant_id, project_id, and any stage-specific payload. Querying by operation_id within metadata returns the full lifecycle trace for a single operation.

Storage Backends

Trailproof provides two storage backends:

In-Memory Store

Default. Events are stored in memory. Fast and zero-dependency, but events are lost on process restart. Suitable for development and testing.

JSONL Store

Durable persistence using append-only JSONL (JSON Lines) files. Each event is written as a single line to disk. Suitable for production deployments.

Configuring the Storage Backend

# In-memory (default)
mp = Memproof(policy="./memproof.yaml")

# JSONL with durable persistence
mp = Memproof(
    policy="./memproof.yaml",
    trail_store="jsonl",
    trail_store_path="./memproof_audit.jsonl",
)

HMAC-SHA256 Signing

For tamper-evident audit trails, provide a signing key. Trailproof signs each event with HMAC-SHA256 and includes the signature in the TrailEvent:
mp = Memproof(
    policy="./memproof.yaml",
    trail_store="jsonl",
    trail_store_path="./memproof_audit.jsonl",
    trail_signing_key="your-secret-key",
)
In production, source the signing key from a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.) rather than hardcoding it. If the key is compromised, all signatures become untrustworthy.

Hash Chain Verification

Trailproof links every event to its predecessor via SHA-256 hashes, forming an append-only chain. If any event is tampered with, the chain breaks and verification fails. Use the verify_audit_trail() / verifyAuditTrail() method to validate the entire chain:
result = mp.verify_audit_trail()

if result.valid:
    print(f"Audit trail verified: {result.event_count} events")
else:
    print(f"Tampering detected: {result.error}")
Run verification periodically (e.g., in a health check or scheduled job) to detect any tampering early. See Production Hardening for more guidance.

Querying the Audit Trail

Use the query_audit_trail() / queryAuditTrail() method to search events with filtering:
events = mp.query_audit_trail(
    event_type="memproof.pipeline.committed",
    metadata={"tenant_id": "acme"},
    limit=50,
)

for event in events:
    print(f"{event.event_type} at {event.timestamp}")

Retrieving a Full Operation Trace

To get every event for a single operation in chronological order, filter by operation_id in the metadata:
events = mp.query_audit_trail(
    metadata={"operation_id": "op-abc123"},
)

for event in events:
    print(f"{event.event_type}: {event.timestamp}")
# memproof.pipeline.received: 2026-01-15T10:00:00+00:00
# memproof.pipeline.risk_assessed: 2026-01-15T10:00:00.001+00:00
# memproof.pipeline.policy_decided: 2026-01-15T10:00:00.002+00:00
# memproof.pipeline.provider_attempted: 2026-01-15T10:00:00.003+00:00
# memproof.pipeline.committed: 2026-01-15T10:00:00.050+00:00

Learn More

For full details on Trailproof’s capabilities — including custom stores, advanced querying, and chain semantics — see the Trailproof documentation.