Skip to content

Core Semantics

Nicolás Seijas edited this page Jul 20, 2026 · 3 revisions

Core Semantics (frozen V1 contract)

These are the behavioural guarantees of RamblaState as of V1. They are frozen — the generator and every adapter build on them, so changing one is a breaking change. Each is backed by tests. Canonical source: SEMANTICS.md.

1. Subscriber exceptions — fail-fast, never wedged

A PropertyChanged subscriber that throws propagates the exception (Rambla does not swallow consumer errors). Regardless, the engine is left schedulable (the scheduled flag is cleared and the dirty set emptied before notifications are raised), so a later mutation flushes normally. Remaining notifications in the aborting flush are not raised.

2. Notification order — unspecified

Within a single coalesced flush, the order of PropertyChanged events is not guaranteed. All dirty properties are notified exactly once per flush; only their order is unspecified. Don't depend on Bid notifying before Ask.

3. Equality and the meaning of "mutation"

SetField compares with EqualityComparer<T>.Default. An equal value is a no-op: no write, no dirty mark, no notification, and no mutation counted. StateMetrics.Mutations counts actual state changes, not write attempts.

4. Batching

Leaving the outermost BeginUpdate() scope schedules exactly one flush — unless nothing really changed, in which case none. Nested batches: only the outermost enables scheduling. Scopes may be disposed in any order; a double dispose is a no-op.

Batches provide notification coherence (no mid-batch notify). They do not provide cross-thread state atomicity — a background reader can still see a new Bid beside a stale Ask before the batch closes. Use immutable snapshots when you need snapshot consistency.

5. Scheduler may be synchronous or deferred

IStateScheduler.Post may run the flush inline (like ImmediateStateScheduler) or later (like a dispatcher). The engine is correct under both and posts the flush outside its lock, so an inline scheduler never raises notifications while the lock is held.

6. Lifetime and ownership

RamblaState owns no resources and is intentionally not IDisposable. It does not own or dispose its scheduler; scheduler lifetime is the caller's. There is no "closed" state in V1.

Clone this wiki locally