---
name: audit-log-instrumentation
description: Add audit logging to a mutation or sensitive read via em-audit. Use on every state change.
---

# Skill: Audit Log Instrumentation

## When to use

Every create/update/delete, auth event, role change, and sensitive-data access.

## Steps

1. Inject `AuditDispatcher` (Node) — or the .NET equivalent once it exists.
2. After the mutation succeeds, `await audit.emit({ action, entityType, entityId, userId, tenantId, correlationId, metadata })`.
3. The worker (`AuditProcessor`) persists to `audit_logs` via `PrismaAuditSink`.

## Action naming

`<entity>.<verb>` — e.g. `user.create`, `role.assign`, `document.download`, `auth.login`, `pdpa.anonymize`.

## Gotchas

- Emit AFTER the operation succeeds (don't audit an action that then rolls back).
- `correlationId` comes from the request (`X-Correlation-Id`) — thread it through.
- `metadata` is JSON — put before/after diffs there for updates, but **never** secrets/PII values.
- Audit must never break the request — the dispatcher logs + swallows enqueue failures.
- `audit_logs` is append-only — no updates/deletes (except PDPA anonymization of the actor reference).

## Validation

Mutation produces exactly one audit row; correlationId present; no PII/secret in metadata; failure doesn't break the request.
