vera-effects
VERA — Verified Effect-Rule Architecture
An architectural pattern and supporting types for game loops where every state mutation is inspectable, testable, and traceable. Designed for codebases developed with AI coding agents, where self-verification is the primary constraint.
The problem
In a typical game loop, actions mutate state directly:
// Traditional: opaque mutation
When this breaks, you debug the entire game state. When an AI agent writes this, there's no structural gate between "compiles" and "works." The scaffold-and-abandon pattern — code that exists but isn't wired into gameplay — is invisible until a player hits it.
The VERA pattern
VERA separates deciding what should change from applying the change from recording what happened:
// VERA: inspectable, testable, traceable
// 1. RULE — pure function, no mutation, returns a description of what should change
// 2. APPLY — mechanical match, no logic, just field assignments
// 3. TRACE — records what happened for test assertions
for effect in &output.effects
What this gives you
| Without VERA | With VERA |
|---|---|
| Test requires full game state setup | Test requires only a QueryContext (borrowed refs) |
| Debugging means tracing call chains | Debugging means reading the trace log |
| "Does this feature work?" → play the game | "Does this feature work?" → assert on effects |
| New effect variant compiles silently | New effect variant → compiler error if unhandled |
| AI agent writes code that compiles but isn't wired | AI agent must produce effects or tests fail |
The three verification layers
- Rule unit tests — pure input→output. No game state needed. Assert on the
Vec<Effect>returned. - Integration tests — drive the full loop (command → rule → apply → state). Assert on final state AND on the trace.
- Compiler — exhaustive
matchon Effect and Command enums. Unhandled variants are compile errors.
What this crate provides
The generic infrastructure types. Your game defines the concrete Effect/Command enums.
use ;
// Specialize for your game's types
type GameTrace = ;
type GameRuleOutput = ;
Types
| Type | Purpose |
|---|---|
Trace<E> |
Ordered record of effects. Enabled during tests, zero-cost when disabled. |
TraceEntry<E> |
Single entry: effect + source + turn number |
TraceSource<E> |
Where an effect came from: Rule { name } or Reaction { name, trigger } |
RuleOutput<E, P> |
What a rule returns: game effects (traced) + presentation effects (not traced) |
Trace API
let mut trace = default;
trace.enabled = true;
// Record effects
trace.record;
// Query
trace.contains; // did this happen?
trace.from_rule; // all effects from this rule
trace.effects_matching; // filter by pattern
The full pattern (not in this crate)
This crate provides the generic types. The full VERA pattern also includes:
- Commands — enum of player/system intentions (your game defines these)
- Effects — domain-scoped enums describing state mutations (your game defines these)
- Rules — pure functions:
(args, &Context, &mut RNG) → RuleOutput<E, P> - Apply — mechanical
matchon effects → field assignments - Reactions — functions triggered by effects:
(effect, &Context, &mut RNG) → Vec<Effect> - QueryContext — borrowed read-only view of game state for rules
- TestContext — builder for constructing QueryContext in unit tests without full game state
These are domain-specific and live in your game crate, not here.
When to use VERA
VERA is designed for:
- Turn-based games where actions produce discrete state changes
- Codebases developed with AI coding agents that need self-verification
- Projects where "it compiles" is not sufficient proof that a feature works
VERA is not designed for:
- Real-time physics simulations (continuous state, not discrete effects)
- Procedural generation pipelines (data transformation, not command→effect loops)
- Rendering (read-only, no state mutation)
License
MIT