# Events
This note covers `src/event/*`.
## Design intent
The crate models three event shapes directly instead of forcing all callers through one runtime-discriminated payload. The optional [[#Event]] enum exists only for adapter convenience.
## `AttrSet`
**Defined in:** `src/event/attr_set.rs`
A borrowed event-time bundle of attribute values.
### Internal shape
`SmallVec<[(AttrId, Value<'a>); 8]>`
### Why this shape exists
Most events are small. Inline storage avoids a heap allocation in the common case.
### Public API
- `new()`
- `push(id, value)`
- `len()`
- `is_empty()`
- `iter()`
- `FromIterator`
### Relationships
- used by [[#StateUpdate]] and [[#Trigger]],
- contains [[Modules/Identifiers and Time#AttrId]] plus [[Modules/Schema#Value]].
## `Event`
**Defined in:** `src/event/event_enum.rs`
A convenience enum for callers that deserialize one wire payload and then dispatch.
### Variants
- `Update(StateUpdate<'a>)`
- `Register(ActionIngest<'a, T>)`
- `Trigger(Trigger<'a>)`
### Important nuance
This enum is **not** the engine's hot-path abstraction. The performance-sensitive API remains the three explicit ingest methods.
## `KindRef`
**Defined in:** `src/event/kind_ref.rs`
A caller-facing kind handle.
### Variants
- `Id(KindId)`
- `Name(&str)`
### Semantics
- `Id` is the zero-lookup fast path.
- `Name` trades a small amount of lookup work for ergonomics.
## `ActionIngest`
**Defined in:** `src/event/action_ingest.rs`
The registration-time input for one action.
### Fields
- `location: LocId`
- `action_id: ActionId`
- `start: UnixTime`
- `end: UnixTime`
- `priority: u8`
- `kind: KindRef<'a>`
- `scorer: ScorerSpec<'a>`
- `payload: T`
- `post: Option<Arc<dyn Fn(&T, &LocationView) -> T + Send + Sync>>`
### Semantic meaning
This is where a business-level candidate becomes an engine-level action.
### Important implementation note
The current engine compiles the scorer and stores the payload, but it does **not** preserve `kind` in [[Modules/Location State#ActionEntry]]. So `kind` is part of the registration API surface, but not part of current action eligibility logic.
## `StateUpdate`
**Defined in:** `src/event/state_update.rs`
A mutable event that writes values into a location's state.
### Fields
- `location`
- `kind`
- `attrs`
### Semantics
A successful update overwrites the prior values for the addressed slots, marks the kind as present, and increments the location version.
### Current behavior detail
If `apply_update` fails, `Engine::ingest_update` currently collapses that failure into `IngestErr::UnknownKind`, even though the real cause could also be an unknown attribute or a type mismatch.
## `Trigger`
**Defined in:** `src/event/trigger.rs`
A decision request event.
### Fields
- `location`
- `kind`
- `attrs`
### Semantic intent
The trigger is supposed to represent a scoring opportunity, optionally carrying per-trigger context.
### Current implementation reality
- `kind` is currently not used to filter actions.
- `attrs` are currently not visible to scorers because [[Modules/Location State#LocationView]] has no trigger-attribute channel.
So the current trigger path is driven entirely by persisted location state plus action registration state.
## Summary
The event layer is clean and expressive, but it is slightly ahead of the currently enforced runtime semantics. That is why the distinction between **API shape** and **current behavior** matters when reading the codebase.