Skip to content

11. Evidence, Audit, and Replay Records

An audit row says that something changed. An ActionRecord preserves the decision that produced the change: declaration revision, commands, rule results, evidence, snapshots, events, effects, results, and failures.

Declare evidence as a requirement

dart
const releaseChecklist = Evidence(
  name: 'area_release_checklist',
  title: 'Area release checklist',
  kind: EvidenceKind.checklist,
  required: true,
  source: EvidenceSourceRef('ops.checklist.area_release'),
  retentionRef: 'gxp_10_years',
);

const activateArea = Action(
  name: 'activate',
  evidence: [releaseChecklist],
  rules: [
    Rule(
      id: 'ops.area.activate.checklist',
      kind: RuleKind.evidence,
      condition: EvidencePresentCondition(
        evidence: 'area_release_checklist',
      ),
    ),
  ],
  audit: AuditEnvelope(
    requireSignature: true,
    requireReasonCode: true,
    evidence: [releaseChecklist],
    replayable: true,
  ),
);

Required evidence blocks commit when absent. Evidence kinds include artifact, log, controlled document, photo, record, signature, checklist, generated report, and external reference.

Snapshot mutable decision inputs

dart
capture: ActionCapture(
  snapshot: ContextSnapshot(
    targets: [
      SnapshotTarget(
        name: 'policy.area_release',
        sourceRef: 'policy.ops.area_release',
      ),
      SnapshotTarget(
        name: 'master.area_category',
        strategy: SnapshotStrategy.value,
        sourceRef: 'ops.area.category',
      ),
    ],
  ),
)

Use reference (the default) when the referenced revision is immutable and retained. Use value when the decision needs the exact resolved blob inside the record.

Read the durable envelope

text
ActionRecord
  + ActionReplayContext
  + ActionCommandRecord[]
  + ActionRuleRecord[]
  + ActionSnapshotRecord[]
  + ActionEvidenceRecord[]
  + ActionDomainEventRecord[]
  + ActionEffectRecord[]
  + ActionIntegrityRecord[]
  + ActionResult[]
  + ActionFailure[]
QuestionCurrent durable facts
Who?actor/scope request context and signer facts when supplied
When?recorded time, scope action sequence, commit sequence, event sequence, stream sequence
What?qualified commands, payload, results, failures, snapshots, and events
Where?tenant/site scope and entity stream identity
Why?reason, justification, rule records, policy snapshots, and integrity records
Under what definition?Blueprint name:version and runtime version

Denied and failed attempts return action records with typed failures instead of disappearing into UI-only error state.

Evidence is a structured record

ActionEvidenceRecord persists:

  • declared evidence name, kind, and requiredness;
  • action command lineage and capture time;
  • source and retention ref;
  • inline value or immutable object ref;
  • digest, MIME type, size, and verification flag;
  • additional typed metadata.

The object bytes may live outside PostgreSQL. The record links the accepted proof to the action that consumed it.

Ordering uses sequences, not only clocks

The PostgreSQL runtime schema stores:

  • scope_sequence for actions inside a replay scope;
  • commit_sequence as the global action commit order;
  • event_sequence as the global event order;
  • (stream_key, stream_sequence) as the per-entity event order;
  • request-local protocol frame sequences.

Timestamps remain useful for display, but equal or skewed clocks do not decide record order.

Declared events become committed facts

Action.emits defines the event. During execution, required payload fields are materialized and validated. A missing required value blocks the transaction. Committed events persist atomically in action_events with action/command, entity/facet, stream, payload, and sequence facts.

Events are projections of committed work. They do not replace current entity state or the action ledger.

Effects carry delivery state

Every planned runtime effect becomes an ActionEffectRecord with:

  • kind and target;
  • current state;
  • idempotency key;
  • attempt count;
  • recorded, dispatched, and acknowledged times;
  • failure payload and metadata.

Outbox workers update delivery state without applying the committed business mutation again.

Explain one request

dart
final record = await runtime.execute(request);
final explanation = await runtime.explain(record.id);

Use the record and explanation together:

  1. confirm the Blueprint revision and durable sequence;
  2. inspect commands and rule results;
  3. inspect snapshots and evidence;
  4. inspect results, failures, and integrity findings;
  5. follow domain event streams and effect lineage.

Studio renders human summaries from these records and preserves exact wire JSON in request/response inspectors.

Checkpoint

Execute area.activate once and verify:

  • required checklist evidence is persisted;
  • missing evidence blocks commit;
  • the action record pins the Blueprint revision;
  • action, global commit, event, and entity-stream ordering facts exist;
  • emitted event and effect records point back to the action command;
  • retrying with the same idempotency key returns the completed record.

Next: Extension points.

Reference: Execution Replay Contract.

Blue is the Vyuh Blueprint documentation surface.