Skip to content

Audit log

The optional Orchestra Audit Trail submodule (orchestra_audit_trail) records every process transition into the Audit Trail chain: a durable, tamper-evident log that survives instance deletion. It complements the live process trace; the trace shows the current run, the audit log is the permanent record of who did what, and when.

How it works

The engine and the inbox dispatch a neutral OrchestraAuditableEvent at each meaningful transition, with no knowledge of any backend. This submodule subscribes to that event and writes each one into the Audit Trail chain. The engine itself keeps zero dependency on audit_trail: enable the submodule to turn the events into chain rows, or leave it off and consume the events another way (an ECA model, a custom subscriber).

Enabling the submodule provisions a dedicated orchestra chain in audit_trail (flag mode) that claims the orchestra channels. Flag mode keeps the chain to the structured lifecycle events this module records, leaving out plain engine log lines that happen to share the orchestra channel. Recording then needs audit_trail to have a signing secret configured (see audit_trail's own setup). A write that fails (for example before a secret exists) is logged on the Orchestra channel and never breaks the running workflow, since the audit log is an optional add-on.

Every row carries the instance UUID as its correlation id, so the audit trail groups all the rows of one process run together.

What it records

Channel Actions
orchestra.instance started, completed, canceled, failed, incident_raised
orchestra.task assigned, claimed, completed, reassigned, released, reoffered, canceled
orchestra.token parked, resumed, canceled
orchestra.variable set

Every event can be toggled on the settings form. All of them are on by default except variable set, which is off, as variable writes are high-volume. A variable event records the variable name and scope (instance-wide or local to one token branch); its value is dropped unless Also record the value is turned on, since a value can hold arbitrary or personal data.

Permanent and transient context

Audit Trail keeps two context buckets per row: a permanent, HMAC-signed bucket, and a transient bucket that a retention policy can purge. The subscriber routes the structured, non-PII fields (workflow, node, tenant, outcome, reason, instance) to the permanent bucket, and leaves the actor and assignee user IDs in the transient bucket, so they stay GDPR-purgeable. A variable's name and scope are non-PII metadata and go to the permanent bucket; a recorded value stays transient, so it is purgeable along with the user IDs.

A task claimed or completed under a delegation carries an extra on_behalf_of context key naming the person whose work it was. It is a user ID, so it belongs with the actor in the transient, purgeable bucket.

Configuration

At Configuration > Workflow > Orchestra > Audit trail, toggle which (channel, action) pairs are recorded. Every pair is on by default except variable set. The setting is read at dispatch time, so a missing entry counts as enabled and only an explicit off drops that event; that lets you silence a noisy transition without touching code.

Alongside the variable Set toggle sits Also record the value, off by default. On, the value is serialized, length-capped and written to the transient bucket, which is what makes a forensic record of every data change possible. Off, only the name and scope are kept. It applies only while Set is enabled.

When a write fails

By default a chain-write failure is caught and logged on the orchestra channel, and the workflow proceeds: a transition that happened is worth more than a transition refused for want of a log row. Strict mode re-throws it instead, for deployments where an auditable record is mandatory.

Strict mode does not by itself roll the transition back, and it is worth knowing why before relying on it. Audit Trail stages a write made inside a caller's transaction and chains it after that transaction commits, which is what stops two writers taking the same head hash. So on its default write mode the chain write happens when the transition is already committed, and a failure there is retried by cron from the outbox rather than undoing anything: the durability comes from the outbox, not from strict mode. Setting Audit Trail's in-transaction write mode to inline restores the older behavior, where a failing write aborts the caller's transaction, at the cost the staging exists to avoid. And two of the transitions recorded here, a cancel and the completion check, emit outside any transaction at all, so their fact is committed before the write is attempted whichever mode is set.

Trace versus audit log

The trace and the audit log answer different questions. The trace is live observability: the token trail of a run, rebuilt from its retained tokens, and gone when the instance is deleted. The audit log is the durable record: an append-only, tamper-evident chain that outlives the instance, for compliance and forensics.

Requirements