Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Workflow

For(entity).Audit

<Workflow>.For(entity).Audit → List<WorkflowAuditEntry>

Reads a running instance's lifecycle timeline — every transition, claim, deposit, reminder and refusal as an WorkflowAuditEntry you can filter and count. The artifact ops reads in a dispute, and the one a reminder is observed through.

stable2 examples compiled by CIworkflowauditauthoring

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

Related

subscribe

Declares that a workflow state waits on an event, and configures the wait — who may hold it, who may hand it on…

TestClock.Advance

In a test, moves the run's clock FORWARD by a duration, then lets the next Workflow.Settle fire every workflow timer…

[Test] / [TestFixture]

A test is an ordinary function marked [Test]. It runs against a throwaway clone of the app, so it may create rows and…