# vera-core
**VERA — Verified Effect-Rule Architecture**
Generic infrastructure for effect-verified game loops. Pure rule functions return effect enums, a mechanical apply function mutates state, and a trace records everything that happened for verification.
## What this crate provides
- `Trace<E>` — records effects during test runs for assertion and debugging
- `TraceEntry<E>` — a single recorded effect with turn number and source
- `TraceSource<E>` — where an effect came from (rule or reaction)
- `RuleOutput<E, P>` — what a rule function returns (game effects + presentation effects)
All types are generic over your effect type. Your game crate defines the concrete enums.
## Usage
```rust
use vera_core::{Trace, TraceSource, RuleOutput};
// Define your game's effect types
#[derive(Debug, Clone, PartialEq)]
enum Effect {
Heal { amount: i32 },
SpendAp { amount: i32 },
}
#[derive(Debug, Clone)]
enum Presentation {
LogMessage(String),
}
// Rule functions are pure: input → effects
fn rule_heal(amount: i32) -> RuleOutput<Effect, Presentation> {
RuleOutput {
effects: vec![Effect::Heal { amount }],
presentation: vec![Presentation::LogMessage(format!("+{} HP", amount))],
}
}
// Trace records what happened
let mut trace = Trace::<Effect>::default();
trace.enabled = true;
let output = rule_heal(25);
for effect in &output.effects {
trace.record(effect, TraceSource::Rule { name: "rule_heal" }, 1);
}
assert!(trace.contains(&Effect::Heal { amount: 25 }));
assert_eq!(trace.from_rule("rule_heal").len(), 1);
```
## The VERA pattern
1. **Rules** are pure functions: `(args, &Context, &mut RNG) → RuleOutput<E, P>`
2. **Effects** are enums describing state mutations — never applied by rules directly
3. **Apply** is a mechanical `match` on effects — no logic, just field assignments
4. **Traces** record all effects for test assertions and debugging
The pattern enforces separation: rules describe what should change, apply does the mutation, traces prove what happened.
## License
MIT