DEE Docs
Core Concepts

Audit Log

The append-only execution log that makes every action traceable and verifiable.

Overview

Every action the engine takes is recorded in an append-only audit log. This log is the authoritative record of what happened, when, and why. It cannot be modified or deleted — only appended to.

Log Entry Structure

interface AuditLogEntry {
  id: string;              // unique entry ID (ULID)
  runId: string;           // execution run this belongs to
  planId: string;          // plan being executed
  stepId: string;          // step that produced this entry
  tick: number;            // logical clock tick
  timestamp: Date;         // wall-clock time (informational only)
  action: ActionType;      // what happened
  input: object;           // snapshot of inputs to the step
  output: object;          // result of the step
  context: object;         // execution context at time of action
  checksum: string;        // SHA-256 hash of the entry contents
  previousChecksum: string; // hash of the previous entry (chain integrity)
}

Action Types

ActionDescription
run.startedExecution run initiated
run.completedAll steps finished
run.failedUnrecoverable failure
step.enteredScheduler advanced to a new step
step.evaluatedBranch condition evaluated
step.executedAction performed (email sent, call initiated)
step.skippedStep skipped due to condition
wait.startedWait step began
wait.completedWait duration elapsed
event.receivedExternal event ingested (open, reply, bounce)
error.occurredError during step execution
error.retriedStep retried after transient failure

Hash Chain

Each log entry includes the checksum of the previous entry, forming a hash chain. This makes tampering detectable — modifying any entry breaks the chain for all subsequent entries.

Entry 1: checksum=abc123, prev=000000
Entry 2: checksum=def456, prev=abc123
Entry 3: checksum=ghi789, prev=def456

Verify chain integrity:

const valid = await engine.verifyAuditChain(runId);
// { valid: true, entries: 47, firstTick: 0, lastTick: 892 }

Querying the Log

// All entries for a run
const entries = await engine.audit.getByRun('run_abc123');

// Filter by action type
const sends = await engine.audit.query({
  runId: 'run_abc123',
  actions: ['step.executed'],
});

// Get the full context at a specific step
const snapshot = await engine.audit.getContextAt('run_abc123', 'step_welcome-email');

Compliance and Export

Export audit logs for regulatory compliance:

// Export as structured JSON
await engine.audit.export('run_abc123', {
  format: 'json',
  output: './audit/run_abc123.json',
});

// Export as PDF report
await engine.audit.export('run_abc123', {
  format: 'pdf',
  output: './audit/run_abc123.pdf',
  includeTemplates: true,
  includeEventTimeline: true,
});

Retention

Audit logs are retained indefinitely by default. Configure retention policies for storage management:

const engine = new Engine({
  audit: {
    retention: { days: 2555 }, // ~7 years
    archiveTo: 's3://dee-audit-archive/',
  },
});

On this page