Format version history
An ESS document declares its own format in its bytes — ess/14, ess-diff/7,
ess-conformance/19. That number is the format's major version and nothing else. It is not the
release that produced the document, and not the specification version the document describes;
Formats and digests separates those three. This page says what each number changed,
which release introduced it, and what happens when an older reader meets a newer document.
When the number moves
A format version is required when meaning, identity, references, canonicalization, names, or the persisted envelope changes. A new internal capability that leaves the persisted shape alone does not move it.
Every family is read by a build that states which versions it implements and refuses the rest. The refusal is the point: a reader that accepts a shape it does not understand returns a wrong answer about somebody's system, and blames the document for the age of the tool.
A version number is per family. ess/14 and ess-conformance/19 count
separately and always have.
ess/ — the authored specification
The format of the system a person writes. Read by ess specify validate and everything downstream
of it.
Declare the lowest version that admits every construct the specification uses. A build refuses a
header newer than it implements, and refuses each construct under a header older than the one that
introduced it with unsupported_format_version. A specification that uses none of a version's
constructs keeps its bytes and its compiled digest under the older header. ess specify formats
prints the same history from the ess you run, offline.
| Version | Introduced in | What changed |
|---|---|---|
ess/1 | 0.1.0 | The first format: types, entities, commands, events, errors, views, actors, components, bindings and topology. |
ess/2 | 0.20.0 | Finite Binary64 fields, distinct from integer and decimal values. |
ess/3 | 0.23.0 | when_subject_state; binding accessors into an event envelope. |
ess/4 | 0.23.0 | Error wire names; command response fields mapped into event payloads. Emitted payload ownership is explicit and complete; below ess/4 an emitted payload keeps its sparse semantics. |
ess/5 | 0.27.0 | An enum variant's own wire, display, summary and code. |
ess/6 | 0.28.0 | An input guard beside an external cause; when_subject over an enum field; preserves. |
ess/7 | 0.29.0 | replays; an effect-free named error as the default of subject-state branches. |
ess/8 | 0.34.0 | The string operators starts_with, ends_with and contains. |
ess/9 | 0.34.0 | when_subject: {predicate: …} over the subject's stored fields. |
ess/10 | 0.34.0 | Aggregate views: aggregate: and group_by:. |
ess/11 | 0.34.0 | alphabet:, input example:, and .count on a String. |
ess/12 | 0.34.0 | outcome_groups:, one refusal declared once for many commands. |
ess/13 | 0.35.0 | fixture_inputs: on a command. |
ess/14 | 0.36.0 | Value expressions in payload: and sets:. |
ess/15 | 0.37.0 | Outcome shapes, input. in subject guards, case-insensitive comparison, prefix:, Json, presence:, and aggregates over Optional fields. |
ess/16 | 0.38.0 | input_absent:, existing_instance:, actor attributes:, view paging:, bounded retry, instances: and affects:. A guard that cannot hold because every way it could hold needs an input that is not Optional to be absent (not defined(f), missing(f)) is refused as a type mismatch; below ess/16 it validates as before. |
ess/17 | 0.39.0 | returns: true on an outcome. |
ess/18 | 0.41.0 | Several states in when_subject_state:, state in when_subject, when_related:, and a binding's delivery context. |
ess/19 | 0.46.0 | payload: sources for the fields of the error an outcome reports. |
ess/20 | 0.49.0 | state, the related row's held lifecycle state, in a when_related: predicate. |
ess/21 | 0.53.0 | one_time_response: names required String response fields whose values may be disclosed only by their originating response. |
ess/22 | 0.53.0 | A when_related: guard's via: input.<field> may name an Optional<…> input, checked only when present; a command may guard on several related rows named by its input, each with its own exists: false. A {related: …} value may read through an Optional<…> reference, absent where it is, or across two references: via: [<field>, <field of the row it names>]. An affects: entry may move the records it selects: moves: <Entity>.<transition>, skipping a selected record outside the move's from states (beyond10x/ess#229); below ess/22 it is refused naming ess/22. An event binding may carry when.where, a finite condition over the event payload; it invokes only when the condition holds, and an Optional member the condition proves present may fill a required input. An actor's may: may name a view, which only the actors naming it may read. On the right of a comparison an unquoted word naming a field of the place is that field ({fact: x} written back); a plain when: reads input.<field>; two Timestamp fields compare as instants (as: timestamp); identity inputs compare only by == and !=; the right side may be one fact moved by one constant, upper <= lower + 5 or expires_at <= issued_at - 24h ({offset: {fact, add|subtract}} written back), compared exactly for an Integer and by elapsed seconds for a Timestamp; <text>.utf8_bytes on either side of a comparison is the UTF-8 byte length of a String ({utf8_bytes: <text>} written back), refused in every other position and below ess/22, while a struct member named utf8_bytes keeps its meaning. A union variant may be declared with no payload (Open:): a unit variant, written on the wire as its tag alone ({"kind": "Open"}) and generated as a unit enum variant; below ess/22 it is refused naming ess/22. on_failure: may select its policy per refusal of the invoked command: drop, retry and escalate keyed, each with outcomes: or except:, exactly one except: as the explicit fallback. An aggregate may declare where:, the rows of its group one measure reads (beyond10x/ess#363); below ess/22 it is refused at the where: naming ess/22. A sets: or payload: value may read input.<path>, a member of a struct input, absent where an Optional on the path is; {input: <path>, else: …} falls back where it is, and else: may read another input required along its whole route. distinct: {in, as, by} holds when no two elements of a list share a key, the element or one scalar member, compared exactly or as instants (kind: written back); below ess/22 it is refused naming ess/22. A when_related: guard may test the rows a selector selects — {entity, where} with exists, count or forall — and a value may read one field of the one row a selector selects — {related: {entity, where, field}} (beyond10x/ess#228, #299); below ess/22 the guard is refused naming ess/22, and the value keeps its nested-mapping meaning. A command guard — its when:, when_subject: or when_related: predicate — may hold an instant to a calendar window at UTC or a fixed offset, window: {at: now | <Timestamp field>, days: [mon, …], from: "HH:MM", to: "HH:MM", offset: Z | ±HH:MM}; a named time zone is refused, so a window does not follow daylight saving. An external: refusal marked compensates: true changes the record its instance: names — moves: or updates: with sets: — and then answers its error (beyond10x/ess#197); every unmarked refusal still changes nothing, and below ess/22 the marker is refused naming ess/22. An outcome declaring returns: true is answered 200 with the command's response under response, in the OpenAPI projection and the synthesized Rust and Go servers; below ess/22 it keeps 202 and no response member. |
ess/23 | 0.54.0 | An updates: whose sets: writes the entity's identity re-keys the record: the row read under instance: comes to rest under the written identity, every field sets: does not name carried over, and the old identity names nothing (beyond10x/ess#429). The command must declare its collision answer, a refusal guarded by when_related: {entity: <the entity>, where: <identity> == input.<field>, exists: true} over the input the identity is written from, or validate refuses the outcome as missing_declaration; the identity write is refused by name beside compensates:, in a create-or-update pair, on an entity a declared relation carries and on a struct identity, and below ess/23 it is refused naming ess/23. A value may read the held lifecycle state, {subject: state}, wherever {subject: …} is admitted — an error payload, an event payload and sets: — the state before the move (beyond10x/ess#458); below ess/23 it is refused naming ess/23. deletes: takes instances:, removing every stored row a filter selects and counting them with {count: changed}; an affects: entry may declare deletes: <Entity> over an entity of the outcome's own domain, and affects: is admitted beside a deletes: subject (beyond10x/ess#452). An enum may declare typed variant attributes, attributes: [{name, type}], each variant filling them with typed literals; guards, invariants and view filters read <fact>.<attribute>, lowered to variant membership (beyond10x/ess#450). A refusal selected by when_subject: {predicate: …} asserts the whole record unchanged, as a state-guarded refusal does, and a predicate on state is witnessed in each state it claims that no earlier branch answers (beyond10x/ess#461). Synthesis scopes a row-set selector by an equality between a String or Uuid member of a struct identity and the input or the subject, at.region == input.place.region, reads each row's literal identity member by member, arranges its decoys under other identities and never creates an identity a row already carries; the whole-struct at == input.place stays a type mismatch, and below ess/23 such a selector validates and is refused by synthesis as unscoped, as before (beyond10x/ess#463). A row-set selector that compares with the input is decided on a command that also names an existing record through the input, an update, a delete or an upsert; below ess/23 such a branch stays refused (beyond10x/ess#462). An affects: entry may write one record per element of an input list with each: {in: input.<list>, as: <name>} and instance: <name>.<member>: it updates the record an element names when it is held and creates it in the initial state when not, admitted only where a declared distinct: keeps that member distinct (beyond10x/ess#459). |
ess/24 | 0.58.0 | undeclared_fields: ignored | refused (default refused) on a kind: struct type and on a command with a non-empty response:, where it governs the response only: ignored admits fields the declaration does not declare, while every declared field stays required and typed; the key is refused by name on a command without response: (missing_declaration), on an event, an error and every other declaration, and below ess/24 it is refused naming ess/24 (beyond10x/ess#500). |
ess/25 | 0.60.0 | A create-or-update command may select among its update branches with when_subject: predicates over the stored row's fields and held state beside an unknown_instance: branch that creates: the row: the creating branch answers an identity no row carries, before any predicate reads a row, and the predicates must partition the stored rows alone; below ess/25 the pairing is refused as conflicting_declaration, its hint naming ess/25 (beyond10x/ess#530). An outcome with instances: may publish an event once per row it changed, listed in emits: as {event: <name>, each: changed} with an optional when_state: naming the states a row held before the outcome; its payload reads that row with {changed: <field>} and {changed: state}, as it was before the outcome, and occurrences follow in ascending order of identity; the entry is refused by name on any other outcome, and below ess/25 it is refused naming ess/25 (beyond10x/ess#531). An external: refusal may declare before_row: true: the implementation decides it from the request alone, before it reads the addressed row, so it answers at step 2 of the precedence order, among the input-guarded refusals in declaration order, before existence and the held state, and the branches the held state selects may be declared after it; the key is refused as conflicting_declaration on a branch that is not external:, on one naming no error:, beside compensates: true, where the error payload reads a row, declared after a branch a later step answers and on a command with a when_related: branch, and below ess/25 as unsupported_format_version naming ess/25 (beyond10x/ess#534). A command guard may compare a text fact with its surrounding ASCII whitespace removed, {trimmed: {<text operator>: …}} around equals, in, equals_ignore_case, in_ignore_case, starts_with, ends_with or contains; below ess/25 it is refused naming ess/25, and outside a command guard as unsupported_construct (beyond10x/ess#532). A view whose filter is the one comparison <identity> == param.<name> may declare absent: {row: {<field>: <literal>…}}, its answer for an identity no row carries: one default row holding the requested identity, each literal typed as a sets: literal is, and nothing in the Optional fields it leaves out; refused as conflicting_declaration on any other filter, beside an aggregate or paging:, and on the identity field in row:, as missing_declaration where a required projected field has no value, and below ess/25 as unsupported_format_version naming ess/25 (beyond10x/ess#533). |
ess/26 | 0.62.0 | A named external: refusal of a command that addresses an existing row, before_row: true included, changes nothing on that row: its scenario snapshots the complete row before forcing the branch and requires it unchanged afterwards, as a held-state refusal's does, so a target that deletes or rewrites the row on the forced branch fails; a compensates: true refusal keeps its read-back of the declared change, and below ess/26 the scenario keeps its bytes (beyond10x/ess#587). |
ess/27 | 0.63.0 | One precedence rule: a branch answers in the order of what it must read, the request alone (the input-guarded refusals and an external: refusal marked before_row: true), then whether the addressed record exists (existing_instance: on every command, then unknown_instance:), then what it holds (when_subject_state:, when_state_changes:, when_subject:, then wrong_state:), then the rows around it (every exists: false over a row the input or a stored field names, in declaration order, then every present related row's and row set's refusal), then the accepting and external branches, and within one step the first declared whose condition holds; a missing row the input names, which answered before everything else below ess/27, answers after the addressed record's existence and held state, existing_instance: on a command reading a related row answers with the addressed record's existence, and a when_related: refusal answers before every accepting branch on every command; below ess/27 every command keeps the order and the answers it had (docs/design/generic-language-features.md § G4, beyond10x/ess#554). Under the one precedence rule every guard pair once refused for want of an order validates and is answered at its steps: when_related: beside when_subject:, when_subject_state:, when_state_changes:, input_absent:, wrong_state: in any composition and an external: marked before_row: true; when_subject: beside when_subject_state:; wrong_state: beside explicit subject-state guards, closing the held-state step; and two refusals over one related row that both hold, the first declared answering; below ess/27 each pair stays conflicting_declaration, its hint naming ess/27 (beyond10x/ess#554, beyond10x/ess#282). A creating unknown_instance: branch may pair with a branch that preserves the record its input names ("ensure the record exists"): the creation answers at step 2 of the one precedence rule for an identity no record carries, and the preserving branch every stored one; a deletes: sibling stays refused, and below ess/27 the pairing keeps its conflicting_declaration, its hint naming ess/27 (beyond10x/ess#535). A binding condition and a binding selection where may compare a Boolean leaf with true or false, event.<path> == false or item.<path> != true, beside the String and enum comparisons and under all/any/not; a definite comparison proves its path present as any comparison does, and the condition's IR read of such a leaf is {kind: boolean}. A text literal against a Boolean leaf stays type_mismatch and a bare Boolean path stays outside the bounded fragment; below ess/27 the comparison is refused as unsupported_format_version naming ess/27, and a Boolean leaf read only by defined(...) keeps {kind: other} and its bytes (downstream report, 2026-10-18). A command guarding on a related row (when_related:) may declare an unknown_instance: branch for the row it addresses through its input: the one precedence rule places it: the input-guarded refusals, then the unknown addressed identity, then the held state, then an exists: false over the row the input names and the present related row's predicates; below ess/27 the pairing is refused as conflicting_declaration, its hint naming ess/27. shorthand: <field> on a kind: struct type: a value of the struct may be written as that field alone, so with shorthand: op the scalar getIssue is the value {op: getIssue}, every writer the model generates writing the long form; the field must be declared, required and a scalar on the wire (a primitive other than Json, an enum, or a newtype over one of those), and every other field Optional, each breach refused by name at <type>.shorthand; the key is refused as unsupported_construct on a newtype, an enum, a union and every declaration that is not a type, and below ess/27 as unsupported_format_version naming ess/27; a model without it keeps its IR bytes and digest, and the JSON Schema of such a struct is oneOf the field's schema and the struct's object, closed unless it declares undeclared_fields: ignored, annotated x-ess-shorthand (beyond10x/ess#594). A minted value may be required present in an Optional field, {generated: true, present: true}, wherever {generated: true} is admitted: the implementation must supply a value, and the interpreted target and synthesis treat it as present; it is refused over a required target and with present: false (type_mismatch). A sets: entry may store the value this outcome publishes, {payload: <Event>.<field>}, naming an event this outcome fills under payload: and a field given a source there, at a type assignable to the stored field without a conversion; it is refused in a payload, an error payload and after else:. Below ess/27 both shapes keep the nested-mapping reading they had, and a refusal of that reading names ess/27 (beyond10x/ess#545). An actor may declare system: true, the system itself; a command granted to at least one actor, every one of them a system actor, is system-issued, and conformance awaits its outcome rather than invoking it. A system-issued command may declare await_within: PT<seconds>S, how soon the system takes its step. system: true beside attributes:, await_within: on a command that is not system-issued and a binding invoking a system-issued command are refused (conflicting_declaration), and below ess/27 both keys are refused naming ess/27 (beyond10x/ess#542). A value may read the head of an ordered selection, {related: {entity, where, order_by, first}}: the first row the selector selects by order_by: [<field> [desc], …, <identity>], the identity last as the tie-break, and no value where it selects none; below ess/27 the shape is refused naming ess/27 and keeps no other meaning (beyond10x/ess#543). A set effect's instances: or affects: filter may read the candidate row's identity, <identity> == input.<field> or, in an affects: entry, <identity> == subject.<field>, as a row-set selector reads it, while state stays unreadable; below ess/27 the read is refused alone, naming ess/27, and a filter not reading the identity keeps its meaning (beyond10x/ess#547). A selector's where: may read a value its own outcome publishes, payload.<Event>.<field>, naming an event the outcome fills and a field given a source there, so one selector scopes another's rows; values that read each other are refused, and below ess/27, or over an entity declaring a field payload, the path keeps the meaning it had (beyond10x/ess#549). An affects: entry over an input list (each:) may move or delete the row each element names, moves: <Entity>.<transition> or deletes: <Entity>, and each: may carry a where: over the element and the input, so one call takes each named row to its own transition by the answer the input carries for it: the entries apply in the order written, an element its filter does not select, one naming no row and one whose row rests outside the move's from states are skipped, and nothing is created; two such entries may move rows of one entity, the distinct: requirement is unchanged, and where: on the entry beside each: stays refused; below ess/27 the entry's moves: or deletes: keeps its conflicting_declaration, its hint naming ess/27, and a where: inside each: is refused as unsupported_format_version naming ess/27; an entry without them keeps its IR bytes and digest (beyond10x/ess#596). The selector of a related read or a head and of a row-set when_related: may test each candidate's related rows, exists: {in: {entity: <Entity>}, as: <name>, that: <predicate>}, true when some row of the entity bound to <name> satisfies the body, a bare name still reading the candidate; the body must tie the rows to the candidate with a top-level <name>.<field> == <candidate field> (missing_declaration), forall over rows is refused with its not: {exists: …} rewrite and a rows test inside another as unsupported_construct, a binder naming a candidate field, state or a root as conflicting_declaration, and every other predicate site refuses it as unsupported_construct; below ess/27 it is refused as unsupported_format_version naming ess/27, where it was a parse refusal at every format (beyond10x/ess#551). A value may be computed by an expression, {expr: "<expression>"}, in sets:, an event's payload: and an error's payload:, and a view field may be computed from its source row, {name: elapsed, type: Duration, expr: "ended_at - started_at"} (G1, docs/design/generic-language-features.md): + - * / over Integer and Decimal, exact, / an Optional<Decimal> at six places half-even and absent at a zero divisor; round(x, digits, half_even | half_up | down), abs, min, max, coalesce(a, b); Timestamp - Timestamp a Duration, Timestamp ± Duration, Duration ± Duration, Duration * Integer, literals 60s, 5m, 1h; reading input.<path> and, on an existing subject, subject.<field>, or a view's source fields; typed against the field it fills (type_mismatch, an Optional result into a required field naming coalesce), now refused as a value (unsupported_construct), a set effect's sets: and an aggregate view refused (unsupported_construct); below ess/27 the source keeps its nested-mapping reading and a refusal of it names ess/27, and expr: on a view field is refused as unsupported_format_version naming ess/27; the generated Rust and Go behaviours and queries and Entity Runtime keep such a command or view an obligation, named by the expression (beyond10x/ess#560). A value reads what its branch established: a refusal guarded by a related row the addressed record's stored reference names, when_related: {via: <field>, …}, reads that record's stored fields with {subject: …} in its error payload; an Optional input reads at its present type in a when_related: branch over it, via: input.<field>, since an absent reference selects no such branch; a stored Optional field reads at its present type under its own when_subject: {predicate: defined(<field>)}, and {related: {via, field}} under when_related: {predicate: defined(<field>)}; every other Optional read keeps its refusal, and below ess/27 these keep theirs, the hint naming ess/27; the generated Rust and Go behaviours keep a command copying a narrowed value an obligation, named by the read (beyond10x/ess#555, beyond10x/ess#556). A command outcome's guard (when:, when_subject:, when_related:) may read a fact through a digest or encoding function, written unquoted on the right of a comparison, challenge != base64url(sha256(ascii(input.verifier))) (RFC 7636 PKCE S256): sha256(x) the SHA-256 digest (FIPS 180-4) of a String's UTF-8 bytes or of Bytes, base64url(x) Bytes in base64url without padding (RFC 4648 § 5), ascii(x) a String's ASCII bytes and unknown for a non-ASCII text, one fact through any chain of them, canonically {expr: "<expression>"}; a misuse is refused as type_mismatch naming the type the function takes, a function elsewhere (an invariant, a view filter, a selector) as unsupported_construct, and below ess/27 the unquoted spelling as unsupported_format_version naming ess/27, while quoted it stays the text it spells; synthesis arranges the stored value the input it sends computes, and witnesses a held-state refusal on a row and input where one declared after it holds too; the generated Rust and Go behaviours keep such a command an obligation and Entity Runtime refuses the guard as FunctionCallUnsupported (beyond10x/ess#584). |
ess/28 | 0.64.0 | A value may read the lifecycle state of the row a reference names, {related: {via, field: state}}, through a chained via: too, typed as that entity's State and read as the row's guards read state; a refusal's error payload reading the row its when_related: guard reads is asserted by the refusal's scenario; below ess/28 the read is refused as unsupported_format_version naming ess/28 (beyond10x/ess#557). A view may read the row a reference of its source names, one hop, as that row is when the view is read: a field declaring field: {related: {via: <reference>, field: <field | state>}}, typed Optional because it is absent where the reference is absent or names no row, and a filter path <reference>.<field>, unknown there, so the row is not shown; a reference is a field typed as one entity's identity, or Optional of one, by the rule {related: …} follows. Navigation in an aggregate view, beside paging: or absent:, or as an order_by: key is refused as unsupported_construct, a field read through a reference under the name of a source field as conflicting_declaration, and below ess/28 each is refused as unsupported_format_version naming ess/28; a model without it keeps its IR bytes. Each such view is witnessed by a <view>/reference/<field> scenario (suite/54 and /55) reading it before and after the referenced row changes, and generated Rust and Go keep its query an obligation, named (beyond10x/ess#564). A branch may require several related rows at once, when_related: {all: [{via: input.<field>, predicate: …}, …]}: at least two rows, each named by a distinct input identity, every one present and satisfying its own predicate; it answers among the present related rows' refusals, each row it lists needs its own exists: false answer, an element that is not a row an input names with a predicate:, a repeated row, a single row and all: beside another key are refused, and below ess/28 the branch is refused as unsupported_format_version naming ess/28; generated Rust and Go keep the command an obligation and Entity Runtime lowering refuses it, each by name (downstream report 2026-10-19, finding 11). A when_related: guard may read an input typed List<…> of one entity's identity, when_related: {via: input.<list>, exists: false}: taken when some element names no row of that entity, so an empty list selects no such branch; the branch's error or event payload may read the first element, in list order, that names no row, {missing: input.<list>}, typed as the element. A predicate: over the rows a list names, a list in all:, a stored list field and a list beside another related row are refused by name; below ess/28 the list guard keeps its type_mismatch, its hint naming ess/28, and {missing: …} is the nested mapping it was. Synthesis sends the refusal a created row then an identity no row carries and asserts the payload names the second, sends the accepting branch two created rows, and every other run an empty list; generated Rust and Go keep the command an obligation and Entity Runtime lowering refuses it, each by name (beyond10x/ess#558). |
ess/29 | 0.67.0 | A command outcome's guard (when:, when_subject:, when_related:) may call a function of one fact on the left of a compact comparison, coalesce(is_error, true) == false or coalesce(retries, 0) > 3, the spelling of the structured {compare: {left: {expr: "…"}, op, right}}: a guard over an Optional fact says what an absent value compares as, and is decided for every record, absent ones included. Text on the left that is no function of exactly one fact is refused as type_mismatch, a call on the left outside a command outcome's guards as unsupported_construct, and below ess/29 the spelling is refused as unsupported_format_version naming ess/29, where it was a parse refusal at every format (beyond10x/ess#620). An external: branch may carry when_subject: {predicate: …}, which narrows it to the records the predicate selects: the provider is asked, and the branch taken, only on such a record, and the one precedence rule answers it at the held-state step in declaration order among the branches the stored row selects, before wrong_state:. A refusal naming no subject reads the subject its siblings name. before_row: true beside it is refused as conflicting_declaration, so is the {field, equals} shape beside external:, and below ess/29 the pair keeps its conflicting_declaration, its hint naming ess/29 (docs/design/generic-language-features.md § G4, beyond10x/ess#554). A guarded branch declared after a branch a later step of the one precedence rule answers is refused as conflicting_declaration wherever one request can satisfy both, for every pair of steps 1 to 5, naming both branches, their steps and the order to declare them in; input guards the finite prover shows disjoint may come in either order, and a marker (unknown_instance:, wrong_state:, an exists: false) declared below a guarded branch is not refused. It replaces the held-state rule (beyond10x/ess#486) and the before_row: order rule (beyond10x/ess#534), which hold one pair each and keep holding below ess/29 (docs/design/generic-language-features.md § G4). |
ess/30 | 0.68.0 | A command reading the row a stored reference names needs no exists: false branch where the specification keeps that row present: every branch writing the field writes nothing, its own value or an input its command refuses first with exists: false over the same entity, every branch creating the subject sets it, and no branch deletes a row of the referenced entity. A deleting branch or an unchecked writer keeps the branch required as non_exhaustive_branches, its hint naming each; below ess/30 the branch stays required, its hint naming ess/30. Generated Rust and Go read the row such a command names with no answer for a missing one; where a branch deletes it, synthesis witnesses the exists: false answer by deleting the row an earlier creation linked, and where none does it reports that answer unreachable, naming the writers (docs/design/generic-language-features.md § G2, beyond10x/ess#509). Where a reading command leaves that branch out, the suite reads the row each arranged reference names again after every accepting branch writing a row of the referencing or the referenced entity, through a view of the referenced entity, and requires it present, so a target that removes it fails; the reads are filed under that branch's <entity>/invariant/after/<command>/<outcome> scenario of the referencing entity, joining the declared invariants' reads where that scenario exists, so the suite keeps its major; a specification that leaves no branch out keeps its suite bytes (beyond10x/ess#509). The where: of a row-set guard (when_related: {entity, where, exists | count | forall}), of a filtered read ({related: {entity, where, field}}) and of an ordered head ({related: {entity, where, order_by, first}}) may compare coalesce(<field>, <literal>) of a candidate row's field with a literal, coalesce(enabled, true) == true: an absent value compares as the default, so the selector says whether a row without the field is selected. A forall: body, a set effect's filter and every other call there keep their unsupported_construct; below ess/30 the refusal is unchanged, its hint naming ess/30. Generated Rust and Go keep such a command an obligation named by its selector, and Entity Runtime refuses it as every row set (docs/design/generic-language-features.md § G1, beyond10x/ess#627). An authored scenario may state an exact value for a field its outcome marks {generated: true}, in an event's payload, an error's fields or a view row over a stored field a branch mints: the value is the scenario's own claim, for a value its earlier steps determine (a revision counting its commits, a cursor after the page it asked for), and the suite checks it exactly, so an implementation minting another value fails the scenario. Synthesis still never pins a minted value; below ess/30 such an act is refused as ESS-AUTHOR-042, its message unchanged and its help naming ess/30 (docs/design/authored-generated-values.md, beyond10x/ess#623). The where: of a set effect's selection, an affects: [{entity, where, …}] entry and instances: {where: …}, may read the candidate row's lifecycle state as state, state == Pending, as a row-set guard's where: does: the state the row holds before the outcome. A state the entity does not declare is refused as in a row-set guard; below ess/30 state there keeps its unobservable_fact, its hint naming ess/30. Synthesis arranges a row in another state beside each selected row, so a target ignoring the state conjunct fails (docs/design/generic-language-features.md § G2, beyond10x/ess#564). An external: race narrowed by when_subject: {predicate: …} may declare compensates: true: declared above a held-state branch, it answers where the predicate selects the row and the provider takes it, and its refusal moves or updates that row. Synthesis forces the provider on such a row and reads the row back in the compensating state. Below ess/30 the pair keeps its refusal_mutated_state, its hint naming ess/30 (docs/design/generic-language-features.md § G4, beyond10x/ess#623). A view's filter: may order a Timestamp field against now, expires_at > now, where now is the instant the view is read. Synthesis writes each row at a now_offset instant and claims a row on a side of the bound only when it stays there from 500 ms before its write to 3600 s after it, so no suite format moves. == and != against now, a window over it and now in a view field stay refused; below ess/30 the ordering keeps its refusal, its hint naming the from/to parameter idiom and ess/30. Generated Rust and Go view queries and Entity Runtime refuse such a filter by name (docs/design/current-time-guards.md, beyond10x/ess#560). |
ess/31 | 0.69.0 | A sets: entry may store the empty list in a required List<…> field, tags: [], so a creator fills a list it has no input for and a view publishing the field reads it. Only the empty list: a list holding anything keeps its refusal, [] over a field that is no List<…> (an Optional<List<…>> included) is refused as type_mismatch, and in an event's or an error's payload: and inside a nested mapping it is refused as a sets: source only. Below ess/31 it is refused as unsupported_format_version naming ess/31; a model without it keeps its IR bytes. The interpreted target stores the empty list, and generated Rust and Go store Vec::new() and an empty slice (an adopter report, 2026-10-22). An input whose type is a List<…>, through any newtype or Optional, may carry an example:, a list each of whose elements is a value of the element type, held as a precondition's literal is: a scalar as a scalar input's example, a struct naming its required members, a list or a map of them. An element its type refuses is refused as type_mismatch naming its position, one breaking an invariant of its type as conflicting_declaration, as a scalar example is, and a struct element missing a required member as missing_declaration; null and a Map<…> example stay refused. Synthesis sends the example at the plain instance wherever no guard reads into the list, as it sends a scalar input's; a list without one is sent as before. Below ess/31 a list example keeps its type_mismatch, its hint naming ess/31; a model without one keeps its IR bytes (an adopter report, 2026-10-22). A sets: entry over a List<T> or Optional<List<T>> field of an existing subject may append one input element, items: {append: input.item}: the stored value is the list the row held before the outcome, absent read as empty, with the element last. The element is input.<path> of type T exactly; another type, an Optional read included, is refused as type_mismatch naming both, as is a target that is no list and an element that is no input.<path>. On creates: and in an event's or an error's payload: it is refused as conflicting_declaration, inside a nested mapping as type_mismatch, and on a set effect as unsupported_construct. Below ess/31 the mapping is the nested one it always was, and over a List<…> field it is refused as unsupported_format_version naming ess/31; a model without it keeps its IR bytes. The interpreted target and generated Rust and Go append to the previous list (an adopter report, 2026-10-22). A field's presence: may be omitted_or_null, wherever presence: is taken (struct, entity, command input and response, event and error fields): the member may be left out or sent as null, and both read as one absent value. The property is projected as null_when_absent's anyOf [T, null] and is not required; a conformance suite never carries the value, so both spellings are admitted and the suite keeps the bytes of a field without a policy. On a field that is no Optional<…> it is refused as type_mismatch; below ess/31 it is refused as unsupported_format_version naming ess/31 (docs/design/omitted-or-null-presence.md, part of beyond10x/ess#678). A view field written field by field over a field of its source entity carries that field's presence: when it is Optional, in a view without shape: or aggregation, unless it is computed or read through a reference: its row schema and suite follow the policy, and the interpreted target leaves an absent member out under omitted_when_absent. Below ess/31 a view field carries none; a model whose views project no field with a policy keeps its IR bytes (docs/design/omitted-or-null-presence.md § 2, beyond10x/ess#677). |
ess/32 | 0.70.0 | A command may guard on rows its input names, when_related: {via: input.<field>, exists: false} or {via: input.<field>, predicate: …}, beside a row-set guard, when_related: {entity, where, exists | count | forall}: the one precedence rule answers a missing named row first, in declaration order, then every refusal over a present named row or a row set in declaration order, then the accepting branches. A when_subject guard beside a row set keeps its unsupported_construct, and below ess/32 so does the pair, its message unchanged and its hint naming ess/32. Synthesis witnesses each branch it can arrange on rows the declared commands create and names the branch it cannot, as ESS-SYNTH-001 does; generated Rust and Go keep the command an obligation, and Entity Runtime lowering refuses it by name (docs/design/generic-language-features.md § G4, beyond10x/ess#554). A struct may declare fields: [], open or closed: open (undeclared_fields: ignored), every object is a value and it projects as an object admitting any member; closed, {} is its only value. Generated Rust, Go and TypeScript decode it as such. Below ess/32 an empty struct keeps empty_declaration (ESS-TYPE-007), its message unchanged and its hint naming ess/32; an enum or a union with no variants keeps it at every format (beyond10x/ess#649). A lifecycle state may declare its wire spelling, states: [{name: Indexing, wire: indexing}, Ready]. The spelling is the wire value of the state's variant of <Entity>.State, so JSON Schema, OpenAPI, AsyncAPI and generated Rust, Go and TypeScript spell the state indexing and refuse Indexing; guards, transitions, moves: and conformance suites keep the declared name, and the adapter spells the wire. Two states of one lifecycle spelled alike are refused as conflicting_declaration. Below ess/32 the mapping is refused as unsupported_format_version naming ess/32, at the state; a lifecycle that spells no state keeps its IR bytes. ess verify diff reports a changed spelling as the state enum's variant_wire_name_changed, and Entity Runtime lowering refuses a spelled state by name (beyond10x/ess#639). Two variants of one enum spelled alike on the wire, by name or by declared wire:, are refused as conflicting_declaration; below ess/32 such an enum keeps validating (beyond10x/ess#639). |
ess/33 | 0.78.0 | An input whose type is a struct (open or closed), a Map<…> or Json, through any newtype or Optional, may carry an example:, held as a precondition's literal is: a struct names every required member, each of its type and true of the struct's invariants, a map names keys of its key type and values of its value type, and a Json example is any value but null. An open struct (undeclared_fields: ignored) admits members it does not declare and keeps them as written, as list example elements and precondition literals of one now do; a closed struct refuses them as undeclared_reference. A union example stays refused. Synthesis sends the example at the plain instance: a map or Json example as written, a struct example through its declared members, so a guard reading one keeps the scenario that refutes it, with undeclared members carried as written and an Optional member the example leaves out left out. Below ess/33 each keeps its refusal, its hint naming ess/33; a model without such an example keeps its IR bytes (a downstream report, 2026-10-30). A lifecycle transition may carry a one-line summary:, {name: release, from: [Held], to: Open, summary: …}, and a lifecycle state may carry one in its mapping form, {name: Held, summary: …}, with or without wire:. A state's summary is the summary of its variant of <Entity>.State; guards, transitions, moves: and conformance suites keep naming states and moves by name, and a summary-only state is not refused as a wire spelling. One state declared twice with two summaries is refused as conflicting_declaration. Below ess/33 either is refused as unsupported_format_version naming ess/33, at the state or the transition; a lifecycle without one keeps its IR bytes. ess verify diff reports a moved state summary as the state enum's variant-summary-changed and a moved transition summary as transition-summary-changed, compatible (a downstream report, 2026-10-30). An entity may declare provided: true: the deployment holds its rows, and no command of the specification need create one. Where synthesis needs a row of it that no declared outcome creates, the row a when_related: {via: input.<field>} guard reads, the scenario resolves an entity fixture {name, type, entity, state} before execution and sends its identity, and the exists: false branch is sent a fresh identity; such a suite is ess-conformance/60 or /61. The interpreted target creates the row in the named state, and the generated Go and TypeScript runtimes pass the entity and the state to their provider. A subject, an owner or a view's population that needs a provided row nothing creates is refused by name, and so is a guard over a provided row's fields. Below ess/33 the key is refused as unsupported_format_version naming ess/33; a model without it keeps its IR bytes (a downstream report, 2026-10-30). |
More columns: swipe horizontally, or focus the table and use the arrow keys.
The paragraphs below give each version's rules.
ess/2, introduced in 0.20.0, admits finite Binary64 fields, distinct from integer and
decimal values. Signed zero, subnormals and nearest-even rounding are preserved end to end. An
older reader refuses Binary64 at every declared type position, including as a map key.
ess/3, introduced in 0.23.0, admits when_subject_state, which combines a declared held
lifecycle state with input guards, and opt-in binding accessors that read two or three declared
field segments from an event envelope. An older reader refuses the document.
ess/4, introduced in 0.23.0, admits error wire names declared without merging semantic
error identities, and typed command response fields that fill emitted event payloads through
explicit response mappings, with complete payload ownership. An older reader refuses the document.
ess/5, introduced in 0.27.0, lets an enum variant carry its own wire, display,
summary and code; a variant is authored as a bare name or as a mapping. An older reader refuses
with unsupported_format_version at types.<type>.variants.<variant>.
ess/6, introduced in 0.28.0, admits an input eligibility predicate beside an external
cause. The fault remains independently arranged; the guard does not select the observed outcome.
Earlier source formats refuse this combination. It also admits when_subject over a
declared enum field of an existing subject and preserves for a successful silent no-op.
History is observed independently from lifecycle. The bounded arrangement search preserves
different histories that reach the same state; unknown or unobservable history refuses synthesis.
A preserving outcome cannot assign fields, emit events, or declare an error.
ess/7, introduced in 0.29.0, adds command-local replays, which returns the originating
success's retained typed result without repeating its effects. The origin supplies
the observable subject identity; the retry cannot invent another selector. It also
admits an effect-free named error as the finite default complement of explicit
subject-state branches sharing one existing subject. Earlier formats refuse these
constructs. A replay response containing Decimal or Binary64, including through
nested declarations, is outside the exact-result observation profile and refuses
synthesis. This does not change existing response-to-event comparisons.
ess/8, introduced in 0.34.0, admits the string operators starts_with, ends_with and contains in
every predicate position: command guards, invariants, view filters and binding selections. They
are map form only and apply to String and newtypes of it. Earlier source formats refuse them with
unsupported_format_version at the position that uses one. A model that uses none keeps its bytes
and its compiled digest. See string operators.
ess/9, introduced in 0.34.0, admits when_subject: {predicate: …}: a predicate over the declared
stored fields of the subject a command addresses, read immediately before selection and
conjunctive with an ordinary when:. It reads the entity's fields and nothing else — not the
input, not state. A refusal may carry it without naming a subject of its own; it reads the one its
sibling branches name. Closed stored-field domains enter the branch partition beside the input, and
an open one, such as weight_kg > 20, needs a genuine default. Conformance arranges a row to the
guard through the arranging commands' sets: mappings and observes it before the command runs. An
older build refuses the header; this build refuses the predicate form under an earlier header with
unsupported_format_version. {field, equals} keeps ess/6 and its bytes.
ess/10, introduced in 0.34.0, admits aggregate views: a view field may declare aggregate: — one of
count, count_distinct, sum, min, max and avg — and a view may declare group_by: over
its other fields. The filter runs per source row, the admitted rows are grouped, and a group with no
admitted row is absent; a view without group_by returns exactly one row. Each aggregate field
declares its result type exactly: Integer for the counts and for sum of an Integer, Optional<T>
for min and max, and Optional<Decimal> for avg, rounded to 6 places half-even. An older build
refuses the header, and this build refuses the construct under an earlier header with
unsupported_format_version. A model without it keeps its bytes and its compiled digest. See
aggregate views.
ess/11, introduced in 0.34.0, admits three things. A newtype of String may declare alphabet:, the
characters every value is drawn from. A command input may declare example:, the value synthesis
builds it from. And .count on a String is its length in Unicode scalar values, in every
predicate position. An older build refuses the header, and this build refuses each construct under
an earlier header with unsupported_format_version. A model without them keeps its bytes and its
compiled digest.
ess/12, introduced in 0.34.0, admits outcome_groups:, a top-level list that declares one external
refusal once for many commands. A group selects its members by an explicit commands: list, by
actor: (every command that actor may: invoke) or by domain: (every command that domain's
files declare), with except: beside a selector. Each member gains the group's outcomes after its
own, in ascending group-name order, before anything is validated, so a group and the same outcomes
copied by hand compile to the same IR and synthesize the same suite. An outcome of a group is
external: plus error: and nothing else. A member that already declares an outcome of the same
name, and two groups giving one command outcomes of the same name, are refused rather than
overridden. An older build refuses the header, and this build refuses a group under an earlier
header with unsupported_format_version. A model without groups keeps its bytes and its compiled
digest. See one outcome for many commands.
ess/13, introduced in 0.35.0, admits fixture_inputs: on a command: a map from a declared input
field to a lower-kebab fixture name, typed by that input. A deployed resource's identity or
canonical input, which a deterministic generator cannot invent, is then resolved from an
independent provider before the scenario starts, and the command request and its event-value
assertions use the same copied value. A fixture input that an outcome predicate reads, that
names an undeclared input or a scenario-owned subject, or that reuses one fixture name under a
different type is refused. An older build refuses the header, and this build refuses the key
under an earlier header with unsupported_format_version. A model without it keeps its bytes and
its compiled digest.
ess/14, introduced in 0.36.0, adds value expressions to payload: and sets:: {subject: <field>} reads the addressed entity as it was before the outcome, {increment: <number>} adds to a stored Integer or Decimal, {input: <field>, else: {generated: true}} takes an optional input or a minted value, a nested mapping gives each field of a struct-typed target its own source, and {generated: true} is admitted in sets:. Synthesis asserts each value where the arrangement determined what it reads, and makes no claim otherwise. An older build refuses the header, and this build refuses each construct under an earlier header with unsupported_format_version. A model without them keeps its bytes and its compiled digest. See value expressions.
ess/15, introduced in 0.37.0, admits the outcome shapes unknown_instance:, deletes:, into:, accepts: nothing and preconditions:; input. operands in subject guards; the case-insensitive comparisons equals_ignore_case and in_ignore_case; the value types prefix:, Json and presence:; and aggregates over Optional fields. This build admits the header; each construct states its own refusal under an earlier header.
ess/16, introduced in 0.38.0, admits the constructs described in the paragraphs below, together with {related: …} and a literal else:. This build admits the header; each construct states its own refusal under an earlier header.
Under ess/16 a command may declare input_absent: true with an error:: the answer for a request that carries no input at all (beyond10x/ess#170). It is refused below ess/16 with unsupported_format_version. Under ess/16, a guard that cannot hold because every way it could hold needs an input f that is not Optional to be absent (not defined(f), missing(f)) is refused as a type mismatch; below ess/16 it validates as before.
Under ess/16 an outcome may be selected by whether the addressed record exists (beyond10x/ess#164): a creates: branch marked unknown_instance: true beside the branch that updates the record the same input names (create or update), or an existing_instance: true branch with an error: beside a creation whose identity the caller supplies (create or refuse). Each is refused below ess/16 with unsupported_format_version. See selection by existence.
Under ess/16 an actor may declare attributes: its credential carries, which a command reads as {caller: <attribute>} in payload: and sets: and as caller.<attribute> in a when: or when_subject: comparison (beyond10x/ess#168). Below ess/16 the attributes and a caller. operand are refused with unsupported_format_version, and {caller: …} stays a nested mapping.
Under ess/16 a view with order_by: may declare paging: {page: <param>, size: <param>, first_page: 0|1, total: true|false} (beyond10x/ess#174): two declared Integer parameters that slice the declared order, size rows starting at (page - first_page) * size, with the number of rows the filter admits beside them where total: true; a read that sends neither answers every row. The parameters paging: names are exempt from the refusal of a parameter no filter reads. paging: is refused below ess/16 with unsupported_format_version. A caller-supplied filter expression is not part of it. See paging a view.
Under ess/16 a binding may bound its retry: on_failure: {retry: {attempts: 3, final: [<refusal>]}} (beyond10x/ess#165). attempts counts invocations including the first and is at least 2; final names refusals of the invoked command, by outcome or by error, that end the retry at once. The block is refused below ess/16 with unsupported_format_version; on_failure: retry written bare keeps its meaning.
Under ess/16 a moves: or updates: outcome may declare instances: {where: <predicate>} instead of instance:, changing every stored record the predicate selects over the entity's fields and input.<field> (beyond10x/ess#167), with {count: changed} as the number it changed; and an outcome with one existing subject may declare affects:, a list of {entity, where, sets} changing the records each filter selects, which may also read subject.<field> (beyond10x/ess#175). Each is refused below ess/16 with unsupported_format_version, and {count: changed} stays a nested mapping there. See set effects.
ess/3 and ess/4 both arrived in 0.23.0. There was never a release that implemented 3 and not
4, and there is no missing release between them.
A bare variant list is admitted by every version, and a variant that declares no naming serializes
back as a bare name, so a specification written before ess/5 keeps its exact bytes.
ess/17, introduced in 0.39.0, adds returns: true to an outcome whose command declares a nonempty
typed response. The outcome promises a successful return matching that schema; it makes no
claim about persistence or side effects. Those require their own declarations and real API
observations. It cannot also declare an error, accepts: nothing, or replays. Older readers
refuse the header, and this build refuses returns under an earlier header. A model without it
keeps its bytes and compiled digest.
ess/18, introduced in 0.41.0. It collects the new authored
constructs of that release; each is refused under an earlier header with
unsupported_format_version, and a model without them keeps its bytes and compiled digest.
when_subject_state: may list several held states, [Delivered, Cancelled], and a refusal may
carry it without naming a subject: it reads the subject its siblings name, so a command can accept
a re-send in one state no move starts from and refuse in others, where wrong_state: gives them
all one answer (beyond10x/ess#201). when_state_changes: still needs the branch's own move. A
when_subject predicate may read state, the lifecycle state the addressed row holds before
selection, beside its stored fields: {all: [state == Ready, hold_note != ""]}
(beyond10x/ess#204). A guarded branch selects before wrong_state: applies, and one taking a
move must be able to take it in every state its predicate may select it in. An outcome may carry
when_related: {via: input.<field>, exists: false} or when_related: {via: input.<field>, predicate: …}, a guard over the row of another entity whose identity the input carries
(beyond10x/ess#211). A missing row is answered by the exists: false branch before any other.
An event binding may declare when.context_fields, a typed record separate from the payload, and
when.context_authority, the external channel whose authority binds it, and read a field as
context.<field> in mapping: (beyond10x/ess#195).
ess/19, introduced in 0.46.0. It collects the new authored
constructs of that release; each is refused under an earlier header with
unsupported_format_version, and a model without them keeps its bytes and compiled digest. An
outcome that reports an error may say where the error's fields come from, with a payload: block
keyed by the error: payload: {orders.TooMany: {requested: input.quantity, limit: 10}}. Each
field takes the sources an event payload takes — an input, a literal, {subject: …},
{caller: …}, {generated: true} — and is checked the same way: a field the error does not
declare is undeclared_reference, and a source of another type is type_mismatch.
{subject: …} reads the row the refusal is answered for, so it is admitted on wrong_state: and
on a branch selected by a held state or a stored field, and refused on an input-guarded refusal
and on unknown_instance:, which answer before any row is read. A field with no source is
carried as none, as before. The conformance interpreter carries the declared fields, a
synthesized suite compares every one whose value a scenario determines, and the Rust target
generates a behaviour whose every error field has a source or is read from the held row.
ess/20, introduced in 0.49.0. It collects the new authored
constructs of that release; each is refused under an earlier header with
unsupported_format_version, and a model without them keeps its bytes and compiled digest. A
when_related: predicate may read the related row's held lifecycle state as state, as a
when_subject predicate reads the addressed subject's from ess/18:
when_related: {via: input.candidate, predicate: state != Accepted} (beyond10x/ess#229). The
path is typed by the related entity's lifecycle, so a state it does not declare is refused, and
it enters the same related-row × input partition as the row's stored fields. An entity cannot
declare a stored field named state, so no document that validated before changes meaning.
Under ess/18 and ess/19 the path is refused with unsupported_format_version naming
ess/20, not as an unobservable fact. A synthesized suite witnesses the guard on a related row
in a state that selects each side, between decoy rows in the other. Where the move that brings that row
into a state reads a related row of the same entity, synthesis arranges that row one level deep,
fresh in its initial state, from ess/20 only; an earlier document synthesizes the suite it did.
From ess/22 an actor's may: may name a view as well as a command (beyond10x/ess#286): one
grant table, with no second readable_by: on the view. A view some actor names is read-granted,
and only the actors naming it may read it; a view no actor names stays open to every caller, so a
document naming no view keeps its meaning, its IR bytes and its generated code. Under ess/21 and
earlier a grant naming a view is refused once, with unsupported_format_version naming ess/22.
The IR carries the views as the actor's may_read, left out where it is empty. A served
component (reached_by: network) answers a read of a read-granted view by an actor the grant
does not name, or by no actor, with the standard refusal a command answers an ungranted actor —
403 {"refused": "not granted", "actor": <name or null>} — before the view is read, and its
contract names the readers as x-ess-may-read.
From ess/24 a kind: struct type, and a command with a non-empty response:, may declare
undeclared_fields: ignored (beyond10x/ess#500). The record then admits fields it does not
declare, as a protocol does that requires a reader to ignore extension members it does not
recognise; every declared field stays required and typed. On a command the key governs the
response only, never the input. refused, the default, is what every record was before, and a
document that does not write the key keeps its meaning, its IR bytes and its compiled digest.
The key is refused by name, at its line: on a command without response: as
missing_declaration, and on a newtype, an enum, a union, an entity, an event, an error, a view
or an actor as unsupported_construct. Under ess/23 and earlier it is refused with
unsupported_format_version naming ess/24. The IR carries a command's key as its
undeclared_fields, and the structs that ignore undeclared fields as undeclared_fields_ignored
beside types, each left out when nothing ignores them.
From ess/25 a create-or-update command may select among its update branches with when_subject:
predicates over the stored row's fields and held state, beside an unknown_instance: branch that
creates: the row under the same identity (beyond10x/ess#530). The creating branch answers an
identity no row carries, before any predicate reads a row, so the predicates must partition the
stored rows alone; a text field compared in them still needs a default branch for the rest, as on
any command. Under ess/24 and earlier the pairing keeps its conflicting_declaration refusal,
whose hint names ess/25. No key is added, and a document that does not use the pairing keeps its
meaning, its IR bytes and its compiled digest.
From ess/25 an outcome with instances: may also publish an event once per row it changed
(beyond10x/ess#531): emits: lists it as {event: <name>, each: changed}, with an optional
when_state: naming, as when_subject_state: does, the states a changed row must have held before
the outcome. Its payload: block reads that row with {changed: <field>} and {changed: state}, as
it was before the outcome, and the occurrences follow at the entry's place in ascending order of
identity. The entry is refused by name on any other outcome, and under ess/24 and earlier as
unsupported_format_version naming ess/25. The compiled set subject carries the entries as
events, left out where there are none, so every other document keeps its IR bytes and digest.
From ess/25 an external: refusal may declare before_row: true (beyond10x/ess#534): the
implementation decides it from the request alone, before it reads the addressed row, so it answers
at step 2 of the precedence order, among the input-guarded refusals in declaration order, before
existence and the held state. A branch the held state selects may then be declared after it. The
key is refused on a branch that is not external:, on one naming no error:, beside
compensates: true, where the error payload reads a row, declared after a branch a later step
answers, and on a command with a when_related: branch; under ess/24 and earlier it is refused
as unsupported_format_version naming ess/25. A document without the key keeps its meaning, its
IR bytes and its compiled digest.
Also from ess/25, a command outcome's guards (when:, when_subject: and when_related:) may
wrap a text operator in trimmed:, which applies it to the fact with its surrounding ASCII
whitespace removed (beyond10x/ess#532; Predicates). Under ess/24 and earlier the
key is refused as unsupported_format_version naming ess/25. It adds a predicate form, no
declaration key, and a document that does not use it keeps its IR bytes and digest.
Also from ess/25, a view whose filter is the one comparison <identity> == param.<name> may
declare its answer for an identity no row carries, absent: {row: {<field>: <literal>…}}
(beyond10x/ess#533): one default row, holding the requested identity, each literal of row:
and nothing in the Optional fields it leaves out. The key is refused on any other filter,
beside an aggregate or paging:, and below ess/25 as unsupported_format_version naming
ess/25. A document without the key keeps its meaning, its IR bytes and its compiled digest.
From ess/26 a named external: refusal of a command that addresses an existing row changes
nothing on that row, before_row: true included (beyond10x/ess#587). Its scenario snapshots the
complete row before it forces the branch and requires it unchanged afterwards, as a held-state
refusal's does, so a target that deletes or rewrites the row on the forced branch fails. The IR
marks such a refusal complete_refusal. A compensates: true refusal keeps its own read-back of
the declared change. Under ess/25 and earlier the scenario keeps its steps and its bytes; no key
is added.
From ess/27 a binding condition and a binding selection compare a Boolean leaf with true or
false: where: [event.direction == inbound, event.bridged == false] on a binding cause, and
where: item.held != true on a selector. A definite comparison proves its path present, as the
String and enum comparisons do, and the condition's IR read of the leaf is {kind: boolean}.
condition-false flips the flag. A text literal against a Boolean leaf stays type_mismatch, and a
bare Boolean path, event.bridged, stays outside the bounded fragment. Under ess/26 and earlier
the comparison is refused as unsupported_format_version naming ess/27, and a Boolean read only
by defined(...) keeps {kind: other} and its IR bytes.
From ess/27 a kind: struct type may name one field as its shorthand, shorthand: <field>
(beyond10x/ess#594). A value of the struct may then be written as that field alone: with
shorthand: op, the scalar getIssue is the value {op: getIssue}, and the struct's invariants
apply to that value. The field must be declared, required and a scalar on the wire — a primitive
other than Json, an enum, or a newtype over one of those — and every other field Optional,
because the short form fills nothing else; each breach is refused by name at <type>.shorthand.
The key is refused as unsupported_construct on a newtype, an enum, a union and every declaration
that is not a type, and below ess/27 as unsupported_format_version naming ess/27. The JSON
Schema of such a struct is oneOf the field's schema and the closed object, annotated
x-ess-shorthand with the field's wire name; the two branches differ by JSON type. A document
without the key keeps its meaning, its IR bytes and its compiled digest.
ess/29 was added in 0.67.0. From it a command outcome's guard may call a function of one fact on the
left of a compact comparison, coalesce(is_error, true) == false, so a guard over an Optional
says what an absent value compares as (beyond10x/ess#620,
Predicates). It compiles to the
structured {compare: {left: {expr: "…"}, op, right}} that ess/27 admits, so a document using
it compiles to the IR the structured form gives; below ess/29 the compact spelling is refused as
unsupported_format_version naming ess/29, where it was a parse refusal at every format.
From ess/29 an external: branch may also be narrowed to the records a subject guard selects,
when_subject: {predicate: …} beside external:: the provider is asked only on such a record, and
the branch answers at the held-state step of the one precedence rule in declaration order
(Predicates). Below
ess/29 the pair keeps its conflicting_declaration, its hint naming ess/29.
ess/29 is also stricter about declaration order: a guarded branch declared below a branch a later
step of the one precedence rule answers is refused wherever one request can satisfy both, for every
pair of steps, where ess/28 held only a held-state branch below an accepting or external one and
a before_row: refusal below a later step. To take a document to ess/29, declare each refused
branch above the one its refusal names.
ess/30 was added in 0.68.0. From it a command reading the row a stored reference names
may leave out its exists: false branch where the specification keeps that row present: every
write of the field checks the row first and no branch deletes a row of the referenced entity
(beyond10x/ess#509, Predicates). Below ess/30 the branch
stays required.
Where a command leaves that branch out, the suite checks that the row stays present: after every
accepting branch writing a row of the referencing or the referenced entity, it reads the row each
arranged reference names through a view of the referenced entity and requires it, so a target
that removes the row fails. The reads go under the referencing entity's
<entity>/invariant/after/<command>/<outcome> scenario, beside its declared invariants' reads,
so the suite format does not change. A specification that leaves no branch out keeps its suite
bytes.
From ess/30 an external: race narrowed by when_subject: {predicate: …} may declare
compensates: true, so "commit unless the head moved" can move the transaction to Stale as it
refuses (beyond10x/ess#623). Below ess/30 the pair is refused as refusal_mutated_state, its
hint naming ess/30.
From ess/30 the where: of a row-set guard, a filtered read and an ordered head may compare
coalesce(<field>, <literal>) of a candidate's field with a literal,
coalesce(enabled, true) == true, so a row whose field is absent is selected as the default says
(beyond10x/ess#627,
Predicates). Below
ess/30 the call keeps its unsupported_construct, its hint naming ess/30.
From ess/30 an authored scenario may state an exact value for a field its outcome marks
{generated: true}, where the scenario's own earlier steps determine it: a revision counting the
commits it made, a cursor after the page it asked for. The suite checks the value exactly, so an
implementation minting another one fails the scenario (beyond10x/ess#623,
Author scenarios). Synthesis still never pins a minted
value. Below ess/30 the act is refused as ESS-AUTHOR-042, its message unchanged and its help
naming ess/30.
From ess/30 the where: of instances: and of an affects: entry may read the candidate row's
lifecycle state, state == Pending, as a row-set guard's where: does: the state the row holds
before the outcome, so cancelling a feed can discard its pending items and leave the played ones
(beyond10x/ess#564). Below ess/30 state there keeps its unobservable_fact, its hint naming
ess/30.
From ess/30 a view's filter: may order a Timestamp field against now,
filter: [expires_at > now], where now is the instant the view is read (beyond10x/ess#560,
Predicates). The suite format does not move: synthesis writes each row at a
now_offset instant and claims a row on a side of the bound only when it stays there from 500 ms
before its write to 3600 s after it. Generated Rust and Go view queries and Entity Runtime refuse
such a filter by name. Below ess/30 the ordering keeps its refusal, its hint naming the
from/to parameter idiom.
ess/31 was added in 0.69.0. From it a sets: entry may store the empty list in a required
List<…> field, tags: [], so a creating command fills a list it has no input for and a view
publishing the field reads it (Values and views). Only the
empty list: a list holding anything keeps its refusal, [] over any other type, Optional<List<…>>
included, is refused as type_mismatch, and an event's or an error's payload: refuses it. The
interpreted target stores the empty list, and generated Rust and Go store Vec::new() and an empty
slice. Below ess/31 it is refused as unsupported_format_version naming ess/31.
From ess/31 an input of List type, through any newtype or Optional, may carry an
example:, a list each of whose elements is a value of the element type, a struct element naming
its required members (Fields and invariants).
Synthesis sends it at the plain instance wherever no guard reads into the list, as it sends a
scalar input's example. Below ess/31 a list example keeps its type_mismatch, its hint naming
ess/31.
From ess/31 a sets: entry over a List<T> or Optional<List<T>> field of an existing subject
may append one input element, items: {append: input.item}: the row holds the list it held before
the outcome, an absent one read as empty, with the element last
(Values and views). The interpreted target and generated
Rust and Go append to the previous list. Below ess/31 the mapping is the nested one it always
was, and over a List<…> field it is refused as unsupported_format_version naming ess/31.
From ess/31 a field's presence: may be omitted_or_null: the member may be left out or sent as
null, and both read as one absent value. Its property is nullable and not required, and a suite
admits both spellings (Wire names). Below ess/31 it is refused
as unsupported_format_version naming ess/31. From ess/31 too, a view field written field by
field carries the presence: of the source field it projects, so its row schema says what the
served row sends.
ess/32 was added in 0.70.0. From it a command may guard on rows its input names,
when_related: {via: input.<field>, …}, beside a row-set guard, so "connect two ports that exist
and face the right way, unless a wire already leaves the source" is one command (beyond10x/ess#554,
Predicates). A missing named row answers
first, then every refusal over a present named row or a row set in declaration order, then the
accepting branches. Below ess/32 the pair keeps its unsupported_construct, its message
unchanged and its hint naming ess/32; a when_subject guard beside a row set keeps it at every
format.
From ess/32 a struct may declare fields: [] (beyond10x/ess#649). Open
(undeclared_fields: ignored), every object is a value; closed, {} is its only value. Below
ess/32 an empty struct keeps empty_declaration (ESS-TYPE-007), its message unchanged and its
hint naming ess/32. An enum or a union with no variants keeps it at every format.
From ess/32 a lifecycle state may declare its wire spelling, states: [{name: Indexing, wire: indexing}, Ready] (beyond10x/ess#639, Wire names). The spelling
is the wire value of the state's variant of <Entity>.State; guards, transitions and suites keep
the declared name. Two states spelled alike are conflicting_declaration. Below ess/32 the
mapping is refused as unsupported_format_version naming ess/32, at the state.
ess/32 is also stricter about enums: two variants of one enum spelled alike on the wire, by name
or by wire:, are refused as conflicting_declaration. To take such a document to ess/32, give
each variant its own spelling.
From ess/33 a lifecycle transition may carry a one-line summary:, {name: release, from: [Held], to: Open, summary: …}, and a lifecycle state may carry one in its mapping form,
{name: Held, summary: …}, with or without wire:. A state's summary is the summary of its
variant of <Entity>.State; guards, moves: and suites keep naming states and moves by name. One
state declared twice with two summaries is conflicting_declaration. Below ess/33 either is
refused as unsupported_format_version naming ess/33, at the state or the transition. A named
type takes its summary under naming:, and a flat summary:, wire:, display: or code: on
one is refused naming naming: {summary: …}.
ess-diff/ — what moved between two revisions
| Version | Released in | What changed | An older reader |
|---|---|---|---|
ess-diff/1 | 0.1.0 | The first delta format. | — |
ess-diff/2 | 0.19.0 | Previously omitted constructs, served views and reusable row shapes are accounted for. Sliced provenance moves to the explicit slice-sha256/2: digest profile. | Regenerate sliced artifacts; a bare legacy slice digest is refused. |
ess-diff/3 | 0.23.0 | Cause, selection-plan and reading-contract deltas. | Refuses the delta. |
ess-diff/4 | 0.23.0 | Error and response deltas. | Refuses the delta. |
ess-diff/5 | 0.27.0 | VariantWireNameChanged, VariantDisplayNameChanged and VariantSummaryChanged on TypeChange. | Refuses a delta carrying any of the three. |
ess-diff/6 | 0.29.0 | Typed deltas retain the before/after originating replay relation and complete refusal-observation requirement. | Refuses the new vocabulary; existing changes retain their earlier format. |
ess-diff/7 | 0.34.0 | GroupingChanged and FieldAggregateChanged on ViewChange: an aggregate view's group keys and what one field computes. | Refuses a delta carrying either. |
ess-diff/8 | 0.34.0 | AlphabetChanged on TypeChange, related by set membership, and InputExampleChanged on CommandChange. | Refuses a delta carrying either. |
ess-diff/9 | 0.38.0 | PagingChanged on ViewChange: a view's paging: (ess/16) declared, dropped or changed, carrying the parameters, the first page and whether a total is answered on each side. OutcomeSetEffectChanged on CommandChange: an outcome's instances: or affects: (ess/16) declared, dropped or changed, one line per construct on each side. | Refuses a delta carrying it. |
ess-diff/10 | 0.41.0 | CauseChanged on BindingChange whose before or after is an external cause: an event binding's ess/18 delivery context (beyond10x/ess#195), carrying the event, the channel (authority) and the typed context_fields, each with any wire name, on each side. ContextFieldDisplayChanged and ContextFieldSummaryChanged on BindingChange: a context field's display or summary moved (documentation only). A cause change without an external side keeps its earlier format. | Refuses a delta carrying it. |
ess-diff/11 | 0.42.0 | PrefixAdded, PrefixRemoved and PrefixChanged on TypeChange: a newtype's prefix: (beyond10x/ess#219) declared, dropped or replaced, which the residual reported as unclassified-changed before. | Refuses a delta carrying it. |
ess-diff/12 | 0.46.1 | OutcomeErrorPayloadAdded, OutcomeErrorPayloadRemoved and OutcomeErrorPayloadChanged on CommandChange: an outcome's error payload: sources (beyond10x/ess#253) declared, dropped or replaced, one change per outcome, and OutcomeAcceptsNothingChanged, OutcomeReturnsChanged and OutcomeDecidedByCallerChanged on CommandChange: an outcome's accepts: nothing, returns: or caller-decided refusal moved, each {outcome, before, after} booleans. The residual reported each as unclassified-changed before. | Refuses a delta carrying it. |
ess-diff/15 | 0.57.0 | Added and Removed on DomainChange, the domain category between system and type: a domain entered in, or dropped from, system.yaml's domains: list (beyond10x/ess#469), which the residual reported as unclassified-changed before. Classified: added compatible, removed breaking for callers and readers. | Refuses a delta carrying it. |
ess-diff/16 | 0.57.0 | shapes {before, after} beside a command input-type-changed change's compatibility: the wire form of the input field's type in each revision, read through Optional and newtypes, one of scalar, record (a struct or a union), list or map. Recorded only when the two have different JSON containers (a value, an object, an array), and then the change is breaking for callers, unknown for readers and compatible for history, where it was unknown for callers. A kind-changed, representation-changed, field-type-changed or variant-type-changed change of a type with an input use records the same shapes for what moved under one name and is breaking for callers, its readers and history answered by its uses as before. A change between two types of one wire form, or with Json on either side, records nothing and keeps its earlier answer and format. | Refuses a delta carrying it. |
ess-diff/17 | 0.57.0 | narrows beside a command change's compatibility: required-input on an added input whose type is not Optional, refusal-added on an added refusal and refusal-widened on a refusal whose when: guard changed, each recorded only where the change refuses an input the earlier revision accepted (the refusals only where plain when: and otherwise branches decide it; an input the earlier revision already refused does not count). Such a change is breaking for callers, unknown for readers and compatible for history, where it was unknown for callers. Anything else records nothing and keeps its earlier answer and format. | Refuses a delta carrying it. |
ess-diff/18 | 0.58.0 | UndeclaredFieldsChanged on TypeChange and ResponseUndeclaredFieldsChanged on CommandChange, each {before, after} of refused and ignored: an ess/24 struct's, or a command response's, undeclared_fields: moved (beyond10x/ess#500), which the residual reported as unclassified-changed before. Opening is expanded and closing narrowed; a struct is answered through its uses like any widened or narrowed type, an opened response is breaking for readers and a closed one compatible. | Refuses a delta carrying it. |
ess-diff/19 | 0.60.0 | AbsentChanged on ViewChange, {before, after}, each side the default row (field to literal text) or null: an ess/25 view's absent: gained, lost or changed (beyond10x/ess#533), which the residual would report as unclassified-changed. Relation changed; breaking for readers, compatible for callers and history. | Refuses a delta carrying it. |
ess-diff/20 | 0.63.0 | ShorthandChanged on TypeChange, {before, after}, each side the field's declared name or null: an ess/27 struct's shorthand: declared, dropped or moved to another field (beyond10x/ess#594), which the residual would report as unclassified-changed. Declaring one is expanded, dropping or moving one narrowed, answered through the struct's uses like any widened or narrowed type. DisplayNameChanged and SummaryChanged on DomainChange, {before, after}: a domain both revisions declare shown as, or summarised as, something else, which the residual reported as unclassified-changed; both compatible everywhere. | Refuses a delta carrying it. |
ess-diff/21 | 0.64.0 | FieldSourceChanged on ViewChange, {field, before, after}, each side <reference>.<field> or null: an ess/28 view field came to read the row a reference of its source names, stopped, or reads another one (beyond10x/ess#564), which the residual would report as unclassified-changed. Relation changed; breaking for readers, compatible for callers and history. | Refuses a delta carrying it. |
ess-diff/22 | 0.78.0 | TransitionSummaryChanged on EntityChange, {transition, before, after}, each side the summary or null: an ess/33 lifecycle transition's summary: added, dropped or edited, which the residual would report as unclassified-changed. Relation changed; compatible everywhere, as documentation. A moved state summary is the state enum's VariantSummaryChanged. | Refuses a delta carrying it. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
ess-diff/5 exists because a variant's own name does not move when its wire spelling does. Before
it, the variant set and the variant order both said nothing, and the comparison returned an empty
delta for a change that breaks a deployed consumer.
ess-conformance/ — the suite
The family that has moved most, because its step and expectation vocabulary is exactly what the persisted document's shape is.
| Version | Released in | What changed |
|---|---|---|
ess-conformance/1 | 0.1.0 | The canonical scenario IR. |
ess-conformance/2 | 0.7.0 | The expectation vocabulary grew. |
ess-conformance/3 | 0.16.0 | The step vocabulary grew. |
ess-conformance/4 | 0.18.0 | The step vocabulary grew again. Written as 0.17.0 and released in 0.18.0; the CHANGELOG section says so. |
ess-conformance/5 | 0.21.0 | Selected generated and authored coverage, omitted scenarios, source identities and every refusal occurrence. |
ess-conformance/6 | 0.23.0 | Authored ess-scenario/2 entity setup, as an ordinary suite. |
ess-conformance/7 | 0.23.0 | The same, with declared coverage. |
ess-conformance/8 | 0.23.0 | Corrected structured text comparison; response-mapping value comparison. |
ess-conformance/9 | 0.23.0 | The same, with declared coverage. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
ess-conformance/10 and ess-conformance/11 arrive in 0.28.0. Version 10 adds
expect_no_error, snapshot_subject, and expect_subject_unchanged; version 11
carries the same steps with coverage. Snapshots capture exactly one actual row by
identity before a command and compare every returned field afterward. Synthesis
requires immediate views covering all subject fields, including generated values.
Missing or duplicate rows fail. Legacy suite formats refuse these steps.
ess-conformance/12 and /13, introduced in 0.29.0, add exact retained-result capture and
comparison, plus an explicit empty-direct-event assertion. Version 12 is ordinary;
13 carries the same declared coverage and exact-parent rules as earlier coverage
formats. Rust, Go and TypeScript execute these steps with report/2. Browser replay
refuses these envelopes. Older envelopes refuse the new
steps even if the rest of their document is well shaped.
A write-once snapshot binds the actual original response, command/outcome, subject identity, input and actor. Retry comparison requires the admitted original values, no error and no direct events, including unknown event names. Paired subject snapshots compare the complete original subject independently. Integers compare exactly, text retains its admitted spelling, collections compare recursively, and an absent optional field differs from explicit null. Decimal and Binary64 are not admitted in this response profile. This immediate witness cannot distinguish a current-head result while it still equals the original; adopters must separately test later-head and restart retries through their real handlers.
ess-conformance/14 and /15, introduced in 0.34.0, carry a string operator where a suite carries a
predicate: a satisfies expectation or an observed selection plan. Version 14 is ordinary and 15
carries declared coverage; each implies every major below it. Rust, Go and TypeScript evaluate them,
and refuse an operand that is not a JSON string. Older envelopes refuse the operators, and the
browser replay refuses these envelopes by their version. A string guard over
command input is decided at synthesis and never reaches the suite, so such a suite keeps its
earlier format.
ess-conformance/16 and /17, introduced in 0.34.0, carry the <view>/aggregate scenario: rows created
through the declared creating outcome with values only that scenario uses, and one read asserting
every group's exact aggregates and the absence of every group whose rows the filter refuses.
Version 16 is ordinary and 17 carries declared coverage; each implies every major below it.
Coverage 17 also carries the refusals ESS-SYNTH-016 (no group key or parameter scopes the
view's rows) and ESS-SYNTH-017 (the rows cannot be arranged). Rust, Go and TypeScript run them;
older envelopes refuse an aggregate scenario or refusal, and browser replay readers
refuse these envelopes by their version.
ess-conformance/18 and /19, introduced in 0.35.0, carry fixture values: a leading resolve_fixtures
prelude naming each fixture and its source-owned type declarations, {kind: fixture} scenario
values, and expect_event_values, which compares the first direct occurrence of an event, chosen by
name, with literal and fixture values, so a later correct occurrence cannot hide an earlier wrong
one. Version 18 is ordinary and 19 carries declared coverage; each implies every major below it.
Rust, Go and TypeScript resolve and validate the values before BeginScenario with report/2: a
malformed, incomplete or wrongly typed value stops before any target activity, and a missing
provider is an explicit unsupported result. Browser replay
refuses fixtures. A suite without fixtures keeps its earlier format, and older envelopes refuse
the new steps.
ess-conformance/20 and ess-conformance/21, introduced in 0.37.0, They carry the case-insensitive text
operators equals_ignore_case and in_ignore_case (ASCII folding only) where a suite carries a
predicate: a view's satisfies expectation and an observed selection plan. Version 20 is ordinary
and 21 carries declared coverage; each implies every major below it. Rust, Go and TypeScript admit
and evaluate them identically and refuse an operand that is not a JSON string; older envelopes
refuse the operators, and browser replay refuses these envelopes by their version. A
case-insensitive guard over command input is decided at synthesis and never reaches the suite, so a
suite without one in a view expectation keeps its earlier format.
ess-conformance/22 and ess-conformance/23, introduced in 0.37.0, add three steps for the outcome
shapes of ess/15: expect_subject_absent after a deletes: outcome, and snapshot_view /
expect_view_unchanged around an accepts: nothing outcome. Version 22 is ordinary and 23
carries declared coverage; each implies every major below it. Rust, Go and
TypeScript execute these steps with report/2.
ess-conformance/24 and /25, introduced in 0.37.0, carry a field's presence policy (ess/15, beyond10x/ess#139) as presence: null_when_absent or omitted_when_absent on a payload leaf, and a runner holding the suite fails an implementation that leaves a null_when_absent field out or sends an omitted_when_absent field as null. Version 24 is ordinary and 25 carries declared coverage; each implies every major below it. The Go and TypeScript runtimes execute both from 0.40.0 (beyond10x/ess#188); earlier runtimes refuse them by version. A suite without a policy keeps its earlier format.
ess-conformance/26 and /27, introduced in 0.38.0, carry the vocabulary below for the ess/16 constructs; /27 also carries declared coverage. Per-leaf struct values (beyond10x/ess#179): a nested mapping whose struct has an undetermined leaf, such as rank: {generated: true}, is asserted leaf by leaf, each determined leaf under its dotted path (lead.number) in the event payload or the view row, and the undetermined leaf by the payload shape for presence and type. Presence of an Optional aggregate (beyond10x/ess#176): a view satisfies predicate reading defined(x) or missing(x) where x is an Optional struct, list, map or Json in the view's fields, which a 0.37.0 runner would read as absent for a present value; over an Optional scalar the predicate selects nothing, and a view filter or when_subject guard is decided at synthesis and never reaches the suite. Version 26 is ordinary and 27 carries declared coverage; each implies every major below it. The Rust runner compares them, and from 0.40.0 so do the Go and TypeScript runtimes (beyond10x/ess#188); earlier runtimes refuse both by version. A suite with none of them keeps its earlier format and bytes. The pair also carries the changed_by view expectation (beyond10x/ess#148): an ungrouped aggregate view with no parameter is read and snapshotted before its scenario creates rows, and read again after them, holding exactly one row whose every named count and sum moved by exactly the stated amount. Only a skipping sum, listed in absent_is_zero, reads as zero where absent; a count or a required sum absent on either read fails. The pair also carries the now_offset scenario value (beyond10x/ess#171): an instant that many seconds from the moment the runner first sends it, which a guard over the current time is witnessed with.
The execute_command_without_input step (beyond10x/ess#170) belongs to this pair: it invokes a command with no input document, which is not execute_command with input: {}, and a suite carrying it takes /26 or /27. A target that cannot send a request without input reports the scenario unsupported.
The page view expectation (beyond10x/ess#174) belongs to this pair too: after a read of a paged view that sent its page and size parameters, the page holds exactly rows rows (at least rows, and at most size, with at_least: true), the answer carries a total of at least total_at_least where one is named, and with follows the page continues the one the run snapshotted before it — its rows in follows.order_by, none ranked before that page's last row, and none carrying that page's values in all of follows.distinct_by. Each claim holds on a target other users share. A suite carrying it takes ess-conformance/26 or /27; the Go and TypeScript runtimes execute it from 0.40.0 (beyond10x/ess#188).
A bounded retry (beyond10x/ess#165) belongs to this pair too: configure_external_outcome may carry times (force the outcome on the next times invocations), expect_invocation may carry count (exactly that many matching invocations), and a binding scenario may be filed under the final-failure aspect. A suite carrying any of them takes /26 or /27. A target that cannot force an outcome more than once reports the scenario unsupported.
ess-conformance/28 and ess-conformance/29, introduced in 0.39.0, add
expect_direct_response, which checks the immediately preceding invocation's actual return
against its complete typed response schema and any authored literals. Version 28 is ordinary;
29 carries declared coverage and exact-parent lineage. The Rust runner requires report/2.
Go and TypeScript also execute the observation with report/2. Older readers refuse these envelopes
before target callbacks. Released suites 26 and 27 retain their meaning and bytes.
Direct responses preserve exact integers, nested presence policies, collection order and
duplicate multiplicity; Binary64 remains outside the admitted profile. Responses are bounded
to 1 MiB, depth 128 and 65,536 members per collection, without truncation.
ess-conformance/30 and ess-conformance/31, introduced in 0.41.0, carry the ess/18 delivery context
(beyond10x/ess#195): deliver_event delivers one occurrence of an event from its external
channel with the context that channel binds, and expect_every_invocation requires every
invocation for one occurrence to carry what it was delivered with. Version 30 is ordinary; 31
carries declared coverage. Rust, Go and TypeScript execute both with report/2;
older readers refuse these envelopes before target callbacks. A suite without them
keeps its earlier format.
ess-conformance/32 and ess-conformance/33, introduced in 0.43.0, carry instance references inside a structured value (beyond10x/ess#242): a list value's
items and a members value's members are values of their own, each a literal, an instance
or another list or members, and the runner resolves each one before it sends the whole. An
authored {$instance: …} inside a list element, a map value or a struct member is written this
way. Version 32 is ordinary; 33 carries declared coverage. Rust, Go and TypeScript resolve both
with report/2. Older readers refuse these envelopes before target
callbacks. A suite without them keeps its earlier format.
ess-conformance/34 and ess-conformance/35 also carry read_as (beyond10x/ess#286): every later
read of the scenario is sent as that actor, as a command is sent as one, so a view an actor's grant
names is read as an actor it names; read_as with actor: null sends later reads as no actor at
all, and expect_not_granted with actor: null requires a refusal naming none. Synthesis files
<view>/grant/read/denied: the view read as each actor of its own domain the grant does not name,
or where that domain has none as the lowest-named declared actor it does not name, where one is
declared, and then as no actor, each followed by expect_not_granted, which then requires the
read's standard refusal; and <view>/grant/read/admitted/<actor> for each actor naming it. A read
the scenario needed answered and the target refused is failed in every runner. A Rust
target reads as the actor through query_view_as, whose default reads as query_view does — so
a target that checks no read grant fails the denied scenario, as does a Go or TypeScript target that
ignores the actor a generated runtime sends on the read. Older readers refuse read_as. A suite
without it keeps its earlier bytes.
ess-conformance/36 and ess-conformance/37 ship in 0.53.0. They carry the ess/22 binding
condition (beyond10x/ess#268): expect_no_invocation requires zero invocations of a binding's
command for the whole eventual window, and the condition-false and condition-absent binding
aspects file the scenarios that use it. Where the condition is Unknown on the occurrence the step
carries obligation: binding condition: the binding must report that unmet obligation
(unsupported), and an invocation or a silent window fails. Version 36 is ordinary; 37 carries declared coverage.
Each implies every major below it. Rust, Go and TypeScript execute the step with report/2. Older
readers refuse these envelopes before target callbacks. They also file one scenario per refusal a
refusal-selected on_failure: answers (beyond10x/ess#269), <binding>/binding/refusal/<outcome>,
witnessed with the existing count and event steps, expect_no_publication and
expect_publication_count, which require that an event is published no times, or exactly count
times, for the whole eventual window. A suite without them keeps its
earlier format.
ess-conformance/38 and ess-conformance/39 ship in 0.53.0. They carry the aggregate observation
of a conditional measure (beyond10x/ess#363): an <view>/aggregate scenario over a view one of whose
measures declares where:. The expected rows are ordinary rows; the number moves because a reader
that does not know the construct would call a correct implementation broken. Which views those are
is a fact about the model, so a reader holding the model — browser execution, replay — refuses such
a suite labelled earlier before target callbacks. Version 38 is ordinary; 39 carries declared
coverage. Each implies every major below it. Rust, Go and TypeScript execute them with report/2.
Older readers refuse these envelopes before target callbacks. A suite without such a scenario keeps
its earlier format.
ess-conformance/42 and ess-conformance/43, added in 0.53.0, carry explicit synthesis seeds
(beyond10x/ess#413): the provenance member synthesis_seeds records each selected source's digest,
each admitted setup row, and where each row was used in a generated scenario. They are written only
for a request that selected seeds, even when no seed was used; a seed-free suite keeps its earlier
format and bytes. Version 42 is ordinary; 43 carries declared coverage. Each implies every major below it
that readers implement. Rust, Go
and TypeScript admit both, run their establish_entity steps through the existing setup
capability with report/2, and refuse the record under any other major except the counted pair
below. Older readers refuse these envelopes before target callbacks.
ess-conformance/44 and ess-conformance/45, added in 0.54.0, count event claims (beyond10x/ess#427).
One command answer can publish one declared event several times, and a suite one of whose acts
claims one event more than once is written at 44 (ordinary) or 45 (declared coverage). Every event
claim after one command then takes an occurrence of its own: the first unclaimed occurrence carrying
its values, else the first unclaimed one, reported as ESS-CF-PAYLOAD; a claim left with none fails
ESS-CF-EVENT and names how many were published and how many the act claims. Each implies every
major below it, the seed-bearing pair included, and carries synthesis_seeds where seeds were
selected. Rust, Go and TypeScript execute both with report/2. Older readers refuse these envelopes
by version, so none under-checks a regenerated suite. A suite labelled 43 or below keeps first-match
semantics, and a suite with no repeated claim keeps its earlier format and bytes.
ess-conformance/46 and ess-conformance/47, added in 0.57.0, check String-newtype
constraints on returned values (beyond10x/ess#499). A command response that reaches a newtype of String with
alphabet:, prefix: or value invariants no longer costs its returning outcome every scenario:
expect_direct_response and expect_response_payload carry the rules as constraints, and every
runner holds each actual returned value to them, failing ESS-CF-PAYLOAD otherwise. A suite carrying
one is written at 46 (ordinary) or 47 (declared coverage); each implies every major below it, the
counted pair included. An invariant that reads anything but value or value.count is refused at
synthesis by name, and so are a record invariant and a reading on a response type. Rust, Go and
TypeScript execute both with report/2. Older readers refuse these envelopes by version, and a suite
with no constrained response type keeps its earlier format and bytes.
ess-conformance/48 and ess-conformance/49, added in 0.58.0, admit undeclared fields
where the specification declares undeclared_fields: ignored (beyond10x/ess#500). expect_direct_response
and expect_response_payload carry undeclared_fields: ignored for an opened response object and
undeclared_fields_ignored, the names of the opened struct declarations, each left out when
closed. Every runner admits an undeclared key at exactly those objects and still checks every
declared field's presence and type; a closed response, a closed sibling struct and a union still
fail an undeclared key with ESS-CF-PAYLOAD. An authored response: literal and a
response-mapped event field are compared with the returned value by their declared fields at an
opened struct, so an extension member is never read; a literal names declared members only. A
one-time response, a retained-result replay and a complete-subject snapshot compare a closed
record, so synthesis refuses each by name where it reaches an opened object. A suite carrying
either member is written at 48 (ordinary) or 49 (declared coverage); each implies every major
below it, the constrained pair included. Rust, Go and TypeScript execute both with report/2. Older readers refuse these envelopes
by version, every reader refuses either member under a lower major, and a suite with no opened
object keeps its earlier format and bytes.
ess-conformance/50 and ess-conformance/51, added in 0.62.0, carry the hold_now step
(beyond10x/ess#586): {step: hold_now, seconds: <n>}, immediately before the execute_command it
holds, asks the target to decide that one command at the instant the scenario's now_offset of
n names, so a value sent as a now_offset can sit exactly on a now boundary. The runner writes
the instant into the command clock it handed out, or calls the target's optional hold_now; a
target without it reports the scenario unsupported, naming hold_now. A hold_now anywhere but
before an execute_command is refused at admission. A suite carrying one is written at 50
(ordinary) or 51 (declared coverage); each implies every major below it, the opened pair included.
Rust, Go and TypeScript execute both with report/2: the generated Go runtime asks a target
implementing NowHolder, the TypeScript one a target with holdNow. Older readers refuse these
envelopes by version. A suite without the step keeps its earlier format and bytes.
ess-conformance/52 and ess-conformance/53, added in 0.63.0, carry the value_invariants view
expectation: a value type's invariants observed at a typed position inside a view field — a List
element, a Map value, an Optional's present value or a Union variant's payload. The
expectation carries the declarations the position reaches, so the runner checks every actual
occurrence against the type's invariants, alphabet: and prefix:, and requires at least one; an
empty collection, an absent Optional and another variant witness nothing. A suite carrying one is
written at 52 (ordinary) or 53 (declared coverage); each implies every major below it, the held-now
pair included. The reference runner executes it; the generated Go and TypeScript runtimes admit both
majors and report such a scenario unsupported, naming value_invariants. Older readers refuse
these envelopes by version. A suite without it keeps its earlier format and bytes.
The same pair states once what a scenario used to repeat for every declared event
(beyond10x/ess#570): the declared event catalog (events) and each marked command's one-time
response authority (one_time_response) sit at the suite root, a run of absent events or an
unpublished list that names the catalog is written by what it leaves out, and a one-time trace
keeps only its required origins and its longest wait. Rust, Go and TypeScript expand these before
admission, so the scenarios mean what their complete spelling meant. A suite whose scenario carries
a one-time trace is written at 52 or 53.
ess-conformance/54 and ess-conformance/55, added in 0.64.0, name a view read through a reference of
its source (beyond10x/ess#564): <view>/reference/<field>, one scenario per ess/28 view and
reference it reads through, which reads the view before and after the row the reference names
changes. Its steps are ones every runner already executes; only the identity is new. A suite
carrying one is written at 54 (ordinary) or 55 (declared coverage); each implies every major below
it, the 52/53 pair included. Rust, Go and TypeScript run it, older readers refuse these envelopes
by version, and every reader refuses the identity under a lower major. A suite without it keeps
its earlier format and bytes.
ess-conformance/56 and ess-conformance/57, added in 0.67.0, make a one-time read cell name its
reader (beyond10x/ess#614): <command>/disclosure/<outcome>/<field>/read/<view>/as/actor/<A>
issues the value as A where A is granted the issuing command, else as its first granted
actor, and then reads the view as A after a read_as step, so an actor who may read the view but
may not issue the value has a cell of its own. Below 56 the same id names the issuer and the view
is read as no actor, and every reader keeps that meaning for an older suite. A suite holding such a
cell is written at 56 (ordinary) or 57 (declared coverage); each implies every major below it, the
54/55 pair included. Rust, Go and TypeScript run it, and older readers refuse these envelopes by
version. A suite without such a cell keeps its earlier format and bytes.
ess-conformance/58 and ess-conformance/59, added in 0.70.0, let a view publish a
Decimal that an exact observer reads: a complete subject or a retained result compares it by
numeric value, so 1.5 and 1.50 are one value and 1.25 another. Before, such a view refused
every wrong-state scenario of its entity. A suite carrying one is written at 58 (ordinary) or 59
(declared coverage); each implies every major below it, the 56/57 pair included. Rust, Go and
TypeScript run it, older readers refuse these envelopes by version, and every reader refuses a
Decimal in an exact observer under a lower major. A Binary64 there is carried from
suite/62 (below). A suite without one keeps its earlier format and bytes.
ess-conformance/60 and ess-conformance/61, added in 0.78.0, let a fixture prelude name a row the
deployment provides: an entity fixture {name, type, entity, state} of an ess/33 entity marked
provided: true. The target's provider makes or finds a row of the entity resting in the state and
answers its identity before execution. A suite carrying one is written at 60 (ordinary) or 61
(declared coverage); each implies every major below it, the 58/59 pair included. Rust, Go and
TypeScript run it, older readers refuse these envelopes by version, and every reader refuses an
entity fixture under a lower major. A suite without one keeps its earlier format and bytes.
ess-conformance/62 and ess-conformance/63, added in 0.79.0, let a response observation name one
member of a nested value by its dotted path in expected, compared alone. A suite carrying one is
written at 62 (ordinary) or 63 (declared coverage); each implies every major below it, the 60/61
pair included. Rust, Go and TypeScript run it, older readers refuse these envelopes by version, and
every reader refuses a response member path under a lower major. Event payload, error and row paths
stay suite/26 dotted keys, which every reader of suite/26 already compares as paths. A suite
without one keeps its earlier format and bytes.
The same pair carries a finite Binary64: a model that reaches one in an entity's fields, a
command's input or response, an event's or error's fields, or a view's fields or row shape writes
its suites at 62 or 63, whether or not a scenario spells the value. Synthesis witnesses the n-th
instance as n + 0.5; the exact observers compare a Binary64 by its nearest binary64 under IEEE
equality, and a token with no finite binary64 image is refused. Every reader refuses a Binary64
record under a lower major (UnsupportedPrimitive, "a Binary64 value requires suite/62 or /63").
A Binary64 reached through an entity identity, a view parameter, an actor attribute, a binding or
a conversion is still refused (ESS-AUTHOR-036), as is every Binary64 in the browser player.
For ess/7, generated held-state refusals include ordinary wrong_state outcomes:
they compare the complete subject before and after the call and refuse every
direct event, including undeclared names. Incomplete subject views cause a named
synthesis refusal. Earlier source formats retain their existing witness bytes.
Integer exactness starts at the actual target adapter: it must preserve each handler value without a floating-point conversion before supplying the typed response. Native adapters can construct numbers directly from integers. A JSON adapter must decode declared Integer values losslessly or report the observation Unsupported; generic JSON-to-Node conversion does not provide this guarantee. Typed response parity does not claim equivalent parsing of arbitrary JSON number spellings. Existing numeric serialization remains unchanged.
Versions 6 through 9 all arrived in 0.23.0. They are two capabilities crossed with the
ordinary/coverage distinction, not four separate releases.
Two readers fail differently at the same document, which is why the number exists at all. An old
Rust reader parses a closed tagged enum and fails with unknown variant — a message that blames
the document. An old Go runner abandons a scenario whose first word it does not know and reports it
skipped, which is the right answer reached by accident. Neither is a verdict anyone should act on.
ess-scenario/ — authored conformance scenarios
ess-scenario/4, introduced in 0.39.0, lets an act declare response: {field: literal} to assert
selected fields of its command's return. Each literal must match its complete declared type;
unknown fields and invalid nested presence are refused before execution. An empty mapping
requests only the complete response shape check. Every selected returns: true outcome gets
that shape check even without authored literals. No event, stored subject or view is invented.
Earlier scenario readers refuse the header; earlier versions refuse the new key.
ess-scenario/5, introduced in 0.59.0, lets an act state the caller its command is sent
as, under caller: {attribute: value}: a literal of the attribute's declared type, or {$instance: name} for an
instance arranged with setup:. The values compile into the step's suite/26 caller, so no suite
format moves, and an act with no caller: keeps its suite's bytes. Earlier versions refuse the
key, and an older ess refuses the header.
ess-scenario/6, added in 0.79.0, lets a claim name one member of a nested value by its dotted path,
checkpoint.checkpoint_id: cp-1, in an act's response:, an event's payload:, an error's
fields: and a row's contains, excludes and at. Each path is compared alone; a nested value
written whole is still compared whole. Event, error and row paths compile to suite/26 dotted keys,
so their suites keep their format; a response path needs ess-conformance/62. Earlier versions
refuse a dotted key as an undeclared field, and an older ess refuses the header. From
ess-scenario/6 an act's literal input that its declared type refuses, at any depth, is
ESS-AUTHOR-015; earlier versions check its shape only.
ess-normalization/ — normalization recipes
| Version | Released in | What changed |
|---|---|---|
ess-normalization/1 | 0.19.0 | Strict recipes, explicit external dispatch, ordered input/output schema boundaries, separate missing/null behavior. |
ess-normalization/2 | 0.20.0 | Ordered string concatenation and joining, exact integer rendering, list concatenation, original collection indices, filtered mapping, first-match selection. |
ess-normalization/3 | 0.20.0 | Model-owned stage roots, pinned to complete compiler provenance and explicit type selections. |
ess-normalization/4 | 0.20.0 | Selected JSON field, array-item or root tokens captured as canonical standard base64 before first-stage validation. |
ess-normalization/5 | 0.20.0 | Explicit input paths; token-preserving binary64_literal constants and finite binary64 conversion steps. |
ess-normalization/6 | 0.20.0 | Fixed string array preparation and checked position reads. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Generated maps for the earlier formats stay byte-identical at the same generator version.
Envelopes revised once
| Format | Revised in | What the later version carries |
|---|---|---|
ess-conformance-report/ | 0.19.0 | /2 separates passed, failed, error, unsupported and skipped counts, bound to the exact executed suite bytes. |
ess-schema-bundle/ | 0.19.0 | /2 is a document-root import with explicit, replay-checked root identity. Component-bundle /1 bytes are unchanged. |
ess-impact/ | 0.19.0 | ess-impact/2 is the version 0.1.0 shipped. /3 versions the corrected dependency vocabulary and the embedded delta. |
ess-conformance-run/ | 0.20.0 | /2 is the checked detailed run output. |
ess-target-failure/ | 0.20.0, 0.23.0 | /2, then /3 with the accessor-resource cause. |
ess-scenario/ | 0.23.0, 0.35.0, 0.39.0, 0.59.0 | /2 authored setup establishes typed, isolated backend entity rows. /3, added in 0.35.0, adds typed fixtures: and {$fixture: name} references resolved before the scenario starts. /4, added in 0.39.0, adds literal response: assertions on an act. /5, added in 0.59.0, adds an act's caller: values. /6 lets a claim name one nested member by its dotted path. |
infra-observation/ | 0.1.0, 0.33.0 | /2 is a reduced, deliberately partial recovery profile, not a superset of /1. /3 is the full scan with each Secret value recorded as {"present": true}: the key name, no digest, no length. /1 wrote each value's unsalted SHA-256 and byte length, which confirm a guessed low-entropy secret to anyone holding the file. Same fields, new meaning, so a /1 reader must reject /3; this build still reads /1 and discards its digests. |
infra-ir/ | 0.33.0 | /3 records each Secret key as present and nothing derived from its value, and is what every full observation with a Secret key compiles to, /1 included. An IR without a Secret key keeps /1 and its bytes. A persisted /1 still reads, returned as /3 with its Secret digests dropped and a different model digest, so nothing derived from it chains to the /1 file's own digest; so drift reports a Secret's added and removed keys and never a changed value. An older reader refuses /3. |
infra-drift/ | 0.33.0 | /2 is the namespace topology profile. /3 is the full-scan comparison with one meaning changed: a Secret's changed_keys is always empty, so an empty list means the value is unknown, where under /1 it meant not rotated. Serialize-only; /1 documents already written keep their meaning. |
ess-observed-bindings-report/ | 0.32.0, 0.33.0 | ess-observed-bindings-report/1 and ess-observed-bindings/1 were introduced in 0.21.0. ess-observed-bindings-report/2 adds OBS-BIND-008: a container or native sidecar in a bound workload that no binding names is a violation. Same fields, new semantics; a document satisfied under /1 can be violated under /2, so a /1 reader must reject /2. The authored ess-observed-bindings/1 input keeps its version and fields; it now claims the bound workload runs nothing else. /3 adds each binding's acknowledged list, so a satisfied OBS-BIND-008 no longer means every entry is bound; a /2 reader must reject /3. |
ess-observed-bindings/ | 0.33.0 | ess-observed-bindings/2 adds optional foreign_containers: per bound workload, containers this realization does not build, each with a name and a nonempty reason. OBS-BIND-008 accounts for them without a binding; one running a declared image or artifact locator, or its @sha256: digest under another name, violates it, one naming no observed container or native sidecar leaves it unknown (plain init containers are not recorded), and one naming a bound container is refused. /1 is read unchanged, acknowledges nothing and keeps its binding digest; a /1 document carrying the key, even empty, is refused. An older reader refuses /2. The report moves to ess-observed-bindings-report/3, which adds each binding's acknowledged list; a satisfied OBS-BIND-008 there no longer means every entry is bound, so a /2 reader must reject /3. |
ess-composition/ | 0.38.0, 0.40.0 | /2 lets a reference name any type the selected component's owned domains declare, and adds conformances: an assertion that a consumer's local type has an imported component type's shape, checked field by field, where the consumer may treat a required value as optional and nothing else may differ (type_conformance_drift). The client plan is unchanged. The earlier format keeps its meaning and bytes and refuses the key, even empty; an older reader refuses /2. /3, added in 0.40.0, adds reader: true on a conformances entry. /4 adds roles and /5 payload conformance ends and value-constraint comparison, described below. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
ess-composition/3, introduced in 0.40.0. A conformances entry may carry reader: true: the consumer's
type only reads the imported one, so it may also read a newtype as what it wraps, an enum as
String, enum variants by wire name, a struct or String-keyed map as Map<String, Json>, and a
subset of the fields, with any extra field compared by wire name against every imported field.
Json itself read as a map, and anything else that could reject an imported value, stays
type_conformance_drift. reader: true also asserts that the consumer's reader ignores keys it
does not declare; ESS-generated closed types do not, so a consumer reading through them must not
use reader for a field subset. An entry without the key is compared as before. Earlier formats
keep their meaning and bytes and refuse the key whatever its value, null included; an older
reader refuses /3.
ess-composition/4, introduced in 0.60.0. A roles entry says that the component one
imported service selects plays the component another selects (service: and plays:), and
which local command stands where in that contract: commands: [{local, stands, contract}],
stands being implements (the local command answers the contract command; every contract
input field is a local input field of a conforming type, and a local input the contract does
not declare is Optional and not null_when_absent) or gates (the local command decides
before the contract command succeeds; recorded, not executed). Both commands must be on their
components' accepts surfaces. The compiled composition lists the roles in document order,
each end with the digest it was checked at. Refusals: unknown_role_service, conflicting_role,
role_input_drift. Earlier formats keep their meaning and bytes, and refuse roles, even empty,
as an unknown field; an older reader refuses /4.
ess-composition/5, added in 0.76.0. A conformances end may name an event, an error or a command's
input or response: exactly one of type, event, error or command, and a command end
carries part: input or part: response. A payload end is compared as a struct with the
payload's fields, against another payload or a struct type, by the same field rules, reader: true included; it must be on its selected component's surface. reader and roles stay
admitted. Earlier formats keep their meaning and bytes, and refuse the new keys as unknown fields
naming /5; an older reader refuses /5. Under /5 a conformance also compares value
constraints and variant attributes: newtype alphabet and prefix, newtype and struct invariants
(by parsed predicate) and enum variant attributes must agree, a reader admitting a wider alphabet,
a shorter prefix, and a subset of the invariants and attributes; earlier formats compare none of
it.
ess-history/ — recorded concurrent histories
ess-history/1, introduced in 0.39.0, is one run of several clients against a target:
each call's client, command, subject, invoke and return instants, Returned or Indeterminate
completion and outcome, the rows a view read answered, and the retry_of of a retried request.
ess verify conform check-history reads it; the Go and TypeScript concurrent explorers write it.
The document is specified in models/concurrent-history/ and published as
schemas/ess-history.schema.json.
ess-history/2, added in 0.53.0, adds one optional operation field, decision_time: the UTC instant the
call's command decision observed. A writer selects it exactly when an operation records one, so a
history with none is still written as ess-history/1, byte for byte; check-history reads both,
and refuses a decision_time in an ess-history/1 document. A reader of ess-history/1 only
refuses ess-history/2 by its format.
ess-history/3, added in 0.61.0, adds three optional operation fields: input, the command's input as
the client sent it; events, each event a returned command's answer published, in order, with its
payload; and arranged, the external: branches the client arranged before sending the call. A
writer selects it exactly when an operation records any of them, so a history with none keeps its
format and its bytes. A number inside input or a payload has one spelling, the one
JSON.stringify writes, and an object there repeats no key. check-history reads all three
formats, steps an operation with the input it recorded, holds it to the events and payloads it
recorded and to the external branches somebody arranged, and refuses the new fields in an
ess-history/1 or ess-history/2 document. A reader of ess-history/1 only refuses
ess-history/3 by its format.
ess-history-adapter/1, introduced in 0.39.0, maps each field of a JSON Lines call log to a
JSON pointer or declares it absent, for ess verify conform import-history.
ess-mutation-report/ and ess-mutation-manifest/ — the mutation audit
ess-mutation-report/1, introduced in 0.34.0, is what ess verify conform mutate writes.
ess-mutation-manifest/1, introduced in 0.37.0, is what --emit writes and --collect reads.
ess-mutation-report/2 and ess-mutation-manifest/2 were introduced in 0.41.0.
The report adds the unwitnessed verdict (ESS-MUTATE-004) with each mutant's
added_refusals, each mutant's excluded scenarios, and the baseline's not_scored list; a
baseline scenario reported unsupported or skipped is no longer red, and a mutant nothing
killed with an excluded scenario it changed is inconclusive. The manifest adds each
suite's refused list. --collect still reads a /1 manifest and judges gained refusals by count.
ess-mutation-report/3 and ess-mutation-manifest/3 were introduced in 0.42.0.
The report adds the equivalent verdict (ESS-MUTATE-005) with each mutant's
unsatisfiable_guard, counts.equivalent, and each mutant's baseline_refusals: a mutant on an
outcome whose scenario the baseline refused, or a from-drop or transition-to mutant on a
transition only such outcomes perform, is unwitnessed rather than survived. The manifest adds
each mutant's unsatisfiable_guard. --collect still reads /2 and /1 manifests, and refuses
either when it carries unsatisfiable_guard.
ess-mutation-manifest/4 and ess-mutation-report/4 were introduced in 0.53.0. The manifest adds the
sets-drop, precedence-swap and emit-swap classes, the component an emission was scoped to,
each mutant's out_of_scope, and unavailable_sites, the emit-swap sites with no admissible
alternative (beyond10x/ess#295); an emission declares /4 only where it holds one of these, and
/3 otherwise, so a /3 reader still collects it. The report adds component, the
out_of_scope list and unavailable_sites, and is written only for an emission scoped to a
component, under a known-failure declaration, or with an unavailable site; every other report stays
/3. --collect still reads /3, /2 and /1, and refuses any of them that carries a /4
class, a component, an out_of_scope mutant or unavailable_sites, naming /4.
ess-mutation-manifest/5 and ess-mutation-report/5 were introduced in 0.57.0. Each is
/4 with identical_answer on a precedence-swap mutant whose two branches answer alike
(beyond10x/ess#517), which the /4 that 0.53.0 to 0.56.0 wrote does not have. An emission or a
report is /5 only where some mutant carries it; every other one keeps /4 or /3 and its
earlier bytes. --collect still reads /4 and earlier, and refuses any of them that carries
identical_answer, naming /5.
ess-mutation-manifest/6 and ess-mutation-report/6 were introduced in 0.60.0. Each
is /5 with overlap_taken_by on a precedence-swap mutant whose overlap branches answered
before both take (beyond10x/ess#539), which the /5 that 0.57.0 and later releases wrote
does not have. An emission or a report is /6 only where some mutant carries it; every other
one keeps /5, /4 or /3 and its earlier bytes. --collect still reads /5 and earlier,
and refuses any of them that carries overlap_taken_by, naming /6.
ess-mutation-report/7 was added in 0.62.0. It is /6 with unchanged_suite on a mutant that is
unwitnessed because its synthesized suite asks what the baseline's asks (beyond10x/ess#586),
which the /6 that 0.60.0 and later releases wrote does not have. A report is /7 only where
some mutant carries it; every other one keeps /6, /5, /4 or /3 and its earlier bytes. No
manifest version moves: --collect decides it from the suites themselves.
Every other family
Each family below is read by a build that admits only the versions listed, and refuses a document claiming a higher number. Formats and digests says what each document holds.
| Version | Introduced in | What it is |
|---|---|---|
ess-service-interface/1 | 0.1.0 | A retained OpenAPI service interface. |
infra-spec/1 | 0.1.0 | Declared desired infrastructure state. |
infra-graph/1 | 0.1.0 | A cluster's typed graph. infra-graph/2, introduced in 0.21.0, is the namespace topology profile. |
infra-simulation/1 | 0.1.0 | Desired state evaluated against a snapshot. infra-simulation/2, introduced in 0.21.0, is the namespace topology profile. |
infra-projection/1 | 0.1.0 | A gap turned into patches a person can review. |
ess-browser-catalog/1 | 0.4.0 | The versioned catalog the browser target and documentation hosts read. |
ess-client-plan/1 | 0.4.0 | The selected surfaces a composition generates clients from. |
ess-docs/1 | 0.4.0 | The document representation between a model and its pages. |
ess-realization/1 | 0.8.0 | An authored realization: one exact ESS system bound to its implementations. ess-realization/2, introduced in 0.21.0, admits implementation-only selections. |
ess-realization-ir/1 | 0.8.0 | A compiled realization. ess-realization-ir/2, introduced in 0.21.0, compiles ess-realization/2. |
ess-transport/1, ess-transport-ir/1 | 0.52.0 | How the events of one exact ESS travel: broker, subject, envelope, delivery and the stream that captures each subject, and its compiled form. |
ess-transport/2, ess-transport-ir/2 | 0.53.0 | Adds channel subjects whose whole-token {name} expressions are bound to required String event payload paths, and its compiled form. A reader of the previous version refuses it. |
ess-http/1, ess-http-ir/1 | 0.60.0 | Binds the commands and views of one exact ESS to HTTP methods and path templates, optionally refining another binding by its digest, and its compiled form. |
ess-protospec/1 | 0.53.0 (experimental) | Finite communicating participants with typed state and messages, bounded channels, logical timers and safety properties. |
ess-prototrace/1 | 0.53.0 (experimental) | Ordered protocol actions and observations bound to a model digest, with explicit model or target origin and capture completeness. |
ess-build/1, ess-build-ir/1 | 0.9.0 | An authored build and its compiled form. |
ess-runtime/1, ess-runtime-ir/1 | 0.9.0 | An authored runtime mapping and its compiled form. |
ess-runtime/2, ess-runtime-ir/2 | 0.62.0 | Adds scheduled workloads, rendered as a Kubernetes CronJob, and pod settings (resources, security context, service-account token, secret volumes, images pinned by digest). A reader of the previous version refuses it; a version 1 document keeps its bytes and digest. |
ess-release/1, ess-release-catalog/1 | 0.9.0 | A release manifest, and the catalog of candidate releases. |
ess-stack/1, ess-stack-lock/1 | 0.9.0 | Stack constraints, and the exact releases a resolution selected. |
ess-environment/1, ess-deployment/1, ess-deployment-diff/1 | 0.9.0 | An environment, the deployment compiled for it, and the difference between two deployments. |
ess-component/1, ess-component-ir/1 | 0.13.0 | A deliverable component and its compiled form. |
ess-release-bundle/1 | 0.13.0 | Independently released runtime and chart releases, bundled. |
ess-types-report/3 | 0.19.0 | Structural target accounting for a generated type library. The family's first published version is /3. |
ess-client-report/1 | 0.52.0 | Accounting for a generated event publisher: its operations and the obligations it leaves to the application. |
ess-client-report/2 | 0.53.0 | Accounting for a generated event publisher with at least one parameterized subject: each such operation adds its normalized parameters. |
ess-normalization-target/1 | 0.19.0 | A normalization library report. ess-normalization-target/2 and ess-normalization-target/3, introduced in 0.20.0, report format-3 recipes and format-4, 5 and 6 recipes respectively. |
ess-openapi-import/1, ess-openapi-service-subset/1 | 0.20.0 | An OpenAPI import envelope, and the fixed import profile it names. |
ess-conformance-input/1, ess-conformance-replay/1 | 0.21.0 | A retained original suite and its parents, and a paired browser replay. |
ess-inputs/1 | 0.21.0 | A directory's input manifest, ess-inputs.yaml. ess-inputs/2, introduced in 0.34.0, adds requires:. |
ess-ui/1 | 0.47.0 | A renderer-neutral UI document: the application, the ESS system its views, commands and events resolve against, and its pages and widgets, read by ess ui load (reference). |
ess-output-state/1 | 0.21.0 | The generated-output checkpoint. ess-output-state/2, introduced in 0.34.0, records the producing release. ess-output-state/3 records the root binding only while a transaction is pending, so a settled checkpoint names no machine path. |
ess-cli/1, ess-cli-plan/1 | 0.21.0 | A CLI presentation binding, and the plan it resolves to. ess-cli/2 and ess-cli-plan/2 let a binding omit the config and output globals; state stays required, and a CLI without output writes JSON only. A reader of /1 refuses them. |
ess-cli-artifacts/1, ess-cli-generation/1 | 0.21.0 | The generated CLI package's manifest, and the report ess generate cli prints. |
ess-execution-registry/1, ess-execution-authority/1 | 0.21.0 | The deployment recovery registry, and one authority inside it. |
ess-execution-store/1, ess-execution-lock/1, ess-execution-evidence/1 | 0.21.0 | A recovery store's header, its per-cluster claim, and one journal entry. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Release numbers this page cites
Five versions appear in the CHANGELOG with no GitHub Release behind them.
| Version | Why | Where its code shipped |
|---|---|---|
| 0.3.0 | tagged in one clone, never pushed | 0.4.0 |
| 0.5.0 | tagged in one clone, never pushed | 0.5.1 |
| 0.15.0 | tagged in one clone, never pushed | 0.16.0 |
| 0.21.0 | tag pushed; the tree does not pass the current gate, so no release can be cut from it | the tag itself |
| 0.26.1 | never tagged | 0.27.0 |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Every format version first carried by the 0.21.0 tag is listed under 0.21.0, the tag itself.
The tag v0.3.0 is a fifth artifact of the same period, under the naming convention that
preceded bare versions. The release workflow triggers on bare versions only, so it never asked
for a release and promises none. ess-composition/1, ess-client-plan/1 and
ess-browser-catalog/1 first appear in its source; they are listed under 0.4.0, the first
published release that carries them.