Skip to main content
Format version history | ESSWhat each ESS format version number means, which release introduced it, and what an older reader does with a newer document.ESSreferenceessreferenceadopterdevelopertry-spec-driven-developmentspecify

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.

VersionIntroduced inWhat changed
ess/10.1.0The first format: types, entities, commands, events, errors, views, actors, components, bindings and topology.
ess/20.20.0Finite Binary64 fields, distinct from integer and decimal values.
ess/30.23.0when_subject_state; binding accessors into an event envelope.
ess/40.23.0Error 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/50.27.0An enum variant's own wire, display, summary and code.
ess/60.28.0An input guard beside an external cause; when_subject over an enum field; preserves.
ess/70.29.0replays; an effect-free named error as the default of subject-state branches.
ess/80.34.0The string operators starts_with, ends_with and contains.
ess/90.34.0when_subject: {predicate: …} over the subject's stored fields.
ess/100.34.0Aggregate views: aggregate: and group_by:.
ess/110.34.0alphabet:, input example:, and .count on a String.
ess/120.34.0outcome_groups:, one refusal declared once for many commands.
ess/130.35.0fixture_inputs: on a command.
ess/140.36.0Value expressions in payload: and sets:.
ess/150.37.0Outcome shapes, input. in subject guards, case-insensitive comparison, prefix:, Json, presence:, and aggregates over Optional fields.
ess/160.38.0input_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/170.39.0returns: true on an outcome.
ess/180.41.0Several states in when_subject_state:, state in when_subject, when_related:, and a binding's delivery context.
ess/190.46.0payload: sources for the fields of the error an outcome reports.
ess/200.49.0state, the related row's held lifecycle state, in a when_related: predicate.
ess/210.53.0one_time_response: names required String response fields whose values may be disclosed only by their originating response.
ess/220.53.0A 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/230.54.0An 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/240.58.0undeclared_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/250.60.0A 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/260.62.0A 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/270.63.0One 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/280.64.0A 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/290.67.0A 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/300.68.0A 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/310.69.0A 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/320.70.0A 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/330.78.0An 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).

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.&lt;field&gt;, 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​

VersionReleased inWhat changedAn older reader
ess-diff/10.1.0The first delta format.—
ess-diff/20.19.0Previously 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/30.23.0Cause, selection-plan and reading-contract deltas.Refuses the delta.
ess-diff/40.23.0Error and response deltas.Refuses the delta.
ess-diff/50.27.0VariantWireNameChanged, VariantDisplayNameChanged and VariantSummaryChanged on TypeChange.Refuses a delta carrying any of the three.
ess-diff/60.29.0Typed 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/70.34.0GroupingChanged and FieldAggregateChanged on ViewChange: an aggregate view's group keys and what one field computes.Refuses a delta carrying either.
ess-diff/80.34.0AlphabetChanged on TypeChange, related by set membership, and InputExampleChanged on CommandChange.Refuses a delta carrying either.
ess-diff/90.38.0PagingChanged 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/100.41.0CauseChanged 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/110.42.0PrefixAdded, 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/120.46.1OutcomeErrorPayloadAdded, 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/150.57.0Added 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/160.57.0shapes {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/170.57.0narrows 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/180.58.0UndeclaredFieldsChanged 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/190.60.0AbsentChanged 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/200.63.0ShorthandChanged 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/210.64.0FieldSourceChanged 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/220.78.0TransitionSummaryChanged 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.

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.

VersionReleased inWhat changed
ess-conformance/10.1.0The canonical scenario IR.
ess-conformance/20.7.0The expectation vocabulary grew.
ess-conformance/30.16.0The step vocabulary grew.
ess-conformance/40.18.0The step vocabulary grew again. Written as 0.17.0 and released in 0.18.0; the CHANGELOG section says so.
ess-conformance/50.21.0Selected generated and authored coverage, omitted scenarios, source identities and every refusal occurrence.
ess-conformance/60.23.0Authored ess-scenario/2 entity setup, as an ordinary suite.
ess-conformance/70.23.0The same, with declared coverage.
ess-conformance/80.23.0Corrected structured text comparison; response-mapping value comparison.
ess-conformance/90.23.0The same, with declared coverage.

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​

VersionReleased inWhat changed
ess-normalization/10.19.0Strict recipes, explicit external dispatch, ordered input/output schema boundaries, separate missing/null behavior.
ess-normalization/20.20.0Ordered string concatenation and joining, exact integer rendering, list concatenation, original collection indices, filtered mapping, first-match selection.
ess-normalization/30.20.0Model-owned stage roots, pinned to complete compiler provenance and explicit type selections.
ess-normalization/40.20.0Selected JSON field, array-item or root tokens captured as canonical standard base64 before first-stage validation.
ess-normalization/50.20.0Explicit input paths; token-preserving binary64_literal constants and finite binary64 conversion steps.
ess-normalization/60.20.0Fixed string array preparation and checked position reads.

Generated maps for the earlier formats stay byte-identical at the same generator version.

Envelopes revised once​

FormatRevised inWhat 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.0ess-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.0ess-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.0ess-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.

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.

VersionIntroduced inWhat it is
ess-service-interface/10.1.0A retained OpenAPI service interface.
infra-spec/10.1.0Declared desired infrastructure state.
infra-graph/10.1.0A cluster's typed graph. infra-graph/2, introduced in 0.21.0, is the namespace topology profile.
infra-simulation/10.1.0Desired state evaluated against a snapshot. infra-simulation/2, introduced in 0.21.0, is the namespace topology profile.
infra-projection/10.1.0A gap turned into patches a person can review.
ess-browser-catalog/10.4.0The versioned catalog the browser target and documentation hosts read.
ess-client-plan/10.4.0The selected surfaces a composition generates clients from.
ess-docs/10.4.0The document representation between a model and its pages.
ess-realization/10.8.0An 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/10.8.0A compiled realization. ess-realization-ir/2, introduced in 0.21.0, compiles ess-realization/2.
ess-transport/1, ess-transport-ir/10.52.0How 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/20.53.0Adds 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/10.60.0Binds 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/10.53.0 (experimental)Finite communicating participants with typed state and messages, bounded channels, logical timers and safety properties.
ess-prototrace/10.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/10.9.0An authored build and its compiled form.
ess-runtime/1, ess-runtime-ir/10.9.0An authored runtime mapping and its compiled form.
ess-runtime/2, ess-runtime-ir/20.62.0Adds 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/10.9.0A release manifest, and the catalog of candidate releases.
ess-stack/1, ess-stack-lock/10.9.0Stack constraints, and the exact releases a resolution selected.
ess-environment/1, ess-deployment/1, ess-deployment-diff/10.9.0An environment, the deployment compiled for it, and the difference between two deployments.
ess-component/1, ess-component-ir/10.13.0A deliverable component and its compiled form.
ess-release-bundle/10.13.0Independently released runtime and chart releases, bundled.
ess-types-report/30.19.0Structural target accounting for a generated type library. The family's first published version is /3.
ess-client-report/10.52.0Accounting for a generated event publisher: its operations and the obligations it leaves to the application.
ess-client-report/20.53.0Accounting for a generated event publisher with at least one parameterized subject: each such operation adds its normalized parameters.
ess-normalization-target/10.19.0A 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/10.20.0An OpenAPI import envelope, and the fixed import profile it names.
ess-conformance-input/1, ess-conformance-replay/10.21.0A retained original suite and its parents, and a paired browser replay.
ess-inputs/10.21.0A directory's input manifest, ess-inputs.yaml. ess-inputs/2, introduced in 0.34.0, adds requires:.
ess-ui/10.47.0A 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/10.21.0The 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/10.21.0A 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/10.21.0The generated CLI package's manifest, and the report ess generate cli prints.
ess-execution-registry/1, ess-execution-authority/10.21.0The deployment recovery registry, and one authority inside it.
ess-execution-store/1, ess-execution-lock/1, ess-execution-evidence/10.21.0A recovery store's header, its per-cluster claim, and one journal entry.

Release numbers this page cites​

Five versions appear in the CHANGELOG with no GitHub Release behind them.

VersionWhyWhere its code shipped
0.3.0tagged in one clone, never pushed0.4.0
0.5.0tagged in one clone, never pushed0.5.1
0.15.0tagged in one clone, never pushed0.16.0
0.21.0tag pushed; the tree does not pass the current gate, so no release can be cut from itthe tag itself
0.26.1never tagged0.27.0

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.