Summary#
<Workflow>.For(entity).Audit returns the instance's lifecycle timeline as a List<WorkflowAuditEntry> — one row per
thing that happened to the run, oldest first. It is the record ops reads to explain an outcome, and the only way to
observe events that change no state, such as a fired reminder.
Signature#
<Workflow>.For(<entity>).Audit // → List<WorkflowAuditEntry>Each WorkflowAuditEntry carries:
Kind— an [[workflow-audit#kinds|AuditKind]] (Transitioned,Claimed,Released,Reminded,Refused,Deposited, …);Slot— the slot alias the event concerns ("Legal"), or nothing for a non-slot event;Actor— the principal that acted, or nothing for an engine-fired event (a reminder, a deadline);Message— a short reason carried by the event;At— when it occurred.
Description#
The timeline is computed on read from the instance's recorded events; app code never writes it. Assign it to a local and query it with ordinary list operations:
enum ClaimStatus { Filed, Settled }
entity Claim {
[Required, MaxLength(120)] string Reference;
ClaimStatus Status = ClaimStatus.Filed;
security { allow read, create, update when IsAuthenticated; }
}
workflow ClaimFlow {
Tracks = Claim.Status;
Initial = Filed;
event Approve();
state Filed {
subscribe Approve();
on Approve { goto Settled; }
}
terminal success Settled { }
}
// The timeline is computed on read from the run's recorded events — app code never writes it.
int RefusalsFor(Claim c) {
var audit = ClaimFlow.For(c).Audit;
return audit.Where(a => a.Kind == AuditKind.Refused).Count();
}A reminder has no state change to see, so a test that a reminder fired asserts on the audit — the same artifact a human would inspect — rather than on a bespoke hook. Tests and audits agree by construction: the assertion cannot pass unless the thing ops would see actually happened.
What kinds of event are recorded?#
AuditKind names what happened: Transitioned · Claimed · Released · Assigned · Cancelled · Reminded ·
Breached · Held · Resumed · Retargeted · Refused · Deposited.
Examples#
[Test]
void a_reminder_shows_up_on_the_timeline() {
var c = new Claim { Reference = "C-1" };
UnitOfWork.Commit();
TestClock.Advance(TimeSpan.FromHours(2));
// The assertion reads the same artifact ops would — not a bespoke test hook.
var audit = ClaimFlow.For(c).Audit;
Assert.Equal(0, audit.Where(a => a.Kind == AuditKind.Reminded).Count());
}See also#
- TestClock.Advance — advance time so a reminder / deadline fires into the timeline
- subscribe — the slot whose reminders and refusals the timeline records