Model programs
A model program is the C# artifact at the heart of a SEK model. It defines the state space and the actions that move between states.
Anatomy
using Sek.Modeling;
public sealed class Turnstile : ModelProgram // 1. derive from ModelProgram
{
public bool Locked { get; set; } = true; // 2. state = public properties
[Rule("Turnstile.Coin")] // 3. actions = [Rule] methods
public void Coin()
{
Require(Locked, "already unlocked"); // 4. guards with Require
Locked = false; // 5. effect = state mutation
}
[AcceptingCondition] // 6. goal states
public bool AtRest() => Locked;
}
- Derive from
ModelProgram— the base class providesRequire. - State is public properties. The engine snapshots a state by serializing the instance to JSON, so state must be public, read/write, and JSON-friendly, and the class must have a parameterless constructor.
- Actions are
[Rule]methods. The action label isType.Methodby default, or supply one:[Rule("Area.Action")]. - Guards with
Require(condition, "reason")— see Rules and guards. - Effects are ordinary state mutations.
- Accepting conditions mark goal states — see Accepting conditions.
State and identity
SEK identifies a state by a canonical hash of its serialized JSON. Canonical hashing normalizes the structure so that states which are equal as data map to the same node — for example, two collections with the same elements in a different order are treated as the same state. This structural view of state is what lets models with sets and dynamic objects explore into finite, well-behaved graphs.
Consequences worth knowing:
- Put all relevant state in public properties; anything not serialized is invisible to state identity (and will not be restored between steps).
- Prefer structural collections (
List<T>, records) so set-equal states collapse. - Keep the state minimal — only what's needed to decide guards and acceptance.
Determinism
Exploration is deterministic: rules are considered in a stable order, parameter domains are enumerated in order, and state hashing is canonical. The same model and Cord always produce the same transition system, which makes diffs and CI meaningful.
The model is not the implementation
A model program describes intended behavior abstractly. It is deliberately not your production code. To check that the real system agrees with the model, use conformance, which replays the explored graph against a binding to the system under test.