Anvil

Reference

The EngineEvent envelope, the event types, the journal and replay contract, and the typed domain model.

This page is the reference for Anvil's journal: the event envelope, the event types, and the contract that makes a journal replayable. It summarizes the formal journal specification that ships with the platform; the spec is the normative source for exact field types and MUST/SHOULD requirements.

The EngineEvent envelope

Every journal record is an EngineEvent — a common envelope wrapping a typed payload. The envelope carries the metadata that makes a run reproducible and auditable; the event_type discriminates the payload.

{
  "schema_version": 1,
  "seq": 184213,
  "ts": "2026-06-30T14:02:11.480Z",
  "event_type": "Fill",
  "correlation": "c-9f2a…",
  "causation": "e-184211",
  "prev_hash": "b3:1d88f0…",
  "state_hash": "b3:7c41a9…",
  "payload": { "…": "type-specific fields" }
}
FieldMeaning
schema_versionEnvelope/payload schema version for forward compatibility
seqMonotonic per-run sequence number; defines replay order
tsEvent timestamp from the deterministic clock
event_typePayload discriminator (see the table below)
correlationGroups events belonging to one logical flow
causationThe seq/id of the event that caused this one
prev_hashblake3 of the previous record — the hash chain
state_hashblake3 of state after applying this event

State is the fold of the reducer over the envelope sequence, in seq order: state = events.fold(genesis, reduce).

Event types

The payload is one of a fixed set of typed events spanning the runtime's full lifecycle:

EventRecords
RunMetaRun identity, mode, and configuration fingerprint
ModeChangeA transition between operating modes
ConfigChangeA validated configuration change
MarketEventNormalized market data input
StrategyIntentAn order intent proposed by the strategy
RiskDecisionThe gateway's accept/reject of an intent, with reason
ExecutionCommandA command dispatched to an exchange adapter
AckVenue acknowledgement of a command
RejectVenue or gateway rejection
FillA (partial or full) execution
OrderStateAn order lifecycle transition
ReconcileResult of reconciling journal state against the venue
RiskStateA risk stop-state transition
CheckpointA state snapshot marker bounding replay
HeartbeatLiveness / time progress

Encoding

The journal is encoded as newline-delimited JSON (NdJson) for inspection and tooling, or CBOR for density. Both encodings carry the same envelope and are interchangeable for replay.

The typed domain model

Anvil's domain types make illegal states unrepresentable:

  • Money is exact. Price, Quantity, and notional values are rust_decimal-backed newtypes — no raw f64, no silent rounding drift.
  • Identifiers are typed. Instrument, venue, side, and order ids are distinct types; mixing them is a compile error.
  • Time is explicit. Timestamps come from the deterministic clock, never the wall clock, so replay reproduces them exactly.

Replay contract

A journal replays correctly when:

  1. Events are applied in strict seq order from the genesis state.
  2. The reducer is pure — reduce(state, event) has no I/O and no ambient inputs.
  3. Each replayed state_hash equals the hash recorded live; the first divergence halts replay.

Because live, paper, backtest, and recovery all use this contract, a verified replay is proof the run was deterministic end to end.

Integrity and tamper-evidence

The prev_hash / state_hash chain makes the journal tamper-evident: altering, inserting, or dropping any record breaks the chain at that point, and the break is detectable in O(1) at the next link. Checkpoints let recovery start from a snapshot without replaying from genesis while preserving the same guarantee.

For the runtime that produces these events, see Runtime architecture; for how strategies emit StrategyIntent, see the Strategy SDK.