0.3.0 (2026-09-23)
Added
- Untagged states: a state that declares no
status:is its properties, and they alone decide whether the record is in it.match/2runs them without a tag check;match_any/2decides by tag where one matches and otherwise tries the untagged states in declared order; the commit positions an untagged state by a full match and writes no tag, so the body's own writes are the move, withtoasserted on the re-read all the same. field:on a state: the tag is read from the named column rather than:status.Hoare.State.tag/1,{field, value}ornil.Hoare.State.classify/2: the one state of a list the record is in, else:unclassifiedor{:ambiguous, states}. Exhaustive and exclusive, made executable; run it over the rows before moving a writer onto a transition.- A module declaring states with
defstate/3gainsall/0, in declared order, andclassify/1over them. Hoare.Graph.leaving/2andentering/2.
Changed
status/0,field/0andmissing/0are optionalHoare.Statecallbacks; an untagged state defines none of them.Hoare.Transition.from_statuses/1returns the tag values of the taggedfromstates and skips the untagged ones.
0.2.0 (2026-09-21)
Breaking
Hoare.Store:fetch/2is replaced byread/3, which takes the preloads the commit needs.- The commit re-reads the record with the transition's preloads and runs the
whole check on it under the lock, properties and guards, not the status
alone. Guards therefore run twice and must be functions of the context. The
body receives the re-checked context, the status is written on the record
just read, and
tois asserted on a second read rather than on what the caller loaded.
Added
preloads/0onHoare.State(optional) andpreloadsonHoare.Transition;Hoare.Transition.preloads/1is the one list the caller's fetch and the commit's read share.strandedon a transition: told when a run fails after a bare effect.Hoare.Transition.commit_error/0anderror/1types;from_statuses/1.use Hoare.StateandHoare.State.defstate/3, which declares several states in one module;:missingdefaults to:not_<status>and the struct's type ist/0.use Hoare.Transition: the declaration as a module, withtransition/0,check/1,run/3,preloads/0andfrom_statuses/0.Hoare.Result.ensure/2lifts a predicate into an arrow.Hoare.Graph: edges, states and a Mermaid diagram from transition modules.Hoare.Store.Memory: a process-local store for tests..formatter.exsexportsdefstatewithout parentheses.
Fixed
- An undo that fails no longer stops the older undos from running; the first failure is raised once all have had their turn.
0.1.0 (2026-09-20)
Initial release.
Hoare.State: a behaviour naming the status that tags a record, the reason when it does not, and the properties that refine it into a struct of witnesses;match/2andmatch_any/2build that struct or say why not.Hoare.Transition:fromandtostates, guards and effects composed as Kleisli arrows;run/4checks, performs the effects, then commits through the store in one locked transaction with afromre-check and atoassertion. Bare effects are idempotent and retried by re-running; effects paired with an undo are reverted newest first when anything after them fails. A record already intoconverges only when every completed effect was bare.Hoare.Store: the three operations the commit needs,transact_with_lock/2,fetch/2andupdate/1.Hoare.Result:bind/2,kleisli/1,tap_ok/2,tap_error/2,map_error/2over tagged tuples.