Repository navigation
ESS 0.52.0
Added
-
ess-transport/1binds events from an exact specification to broker, subject, envelope,
delivery and stream declarations, compiling toess-transport-ir/1. Transport validation
refuses missing or ambiguous JetStream coverage; AsyncAPI generation uses the declared
bindings (#390, #392). -
ess generate clientemits typed Rust and Go event publishers with batching, flush/close
operations, transport seams and optional NATS JetStream adapters.ess-client-report/1
records generated operations and application obligations. At-least-once delivery remains
explicitly unsupported (#395). -
Integer field bounds declared by supported invariants are projected into JSON Schema.
Model-based Go and Rust type generation selects native integer widths for complete ranges;
incomplete ranges retain exact-number types. Integer newtypes carry their own bounds and
constants in schemas and generated native types (#394). -
Rust synthesis represents a struct's direct optional self-reference through deterministic
boxed references, shared by declarations, constructors, accessors and wire codecs. Both Rust
layouts and the shared Web codec support it; unsupported recursive layouts still refuse.
Existing acyclic generated artifacts and serialized names remain unchanged
(#400). -
ess generate types --rootaccepts an event and selects its payload plus referenced types.
--all-eventsselects all event payloads and can be combined with--all-types
(#393). -
ess-ui/1reads acceptfilter:for bounded listing and choice rows, with matching React
and terminal semantics after live effects and before local paging. Filters never reach the
server, share raw requests, and are not authorization. Sevenfilter_*checks reject invalid
expressions, scopes, placements and server paging, and warn about parameter and export
alternatives. Dynamic menu filters now follow the same fail-closed semantics in both renderers
(#365). Older readers refuse the new read key.
Changed
-
Breaking for generated model data libraries: timestamps use Go
time.Timeand Rust
EssTimestamp(time::OffsetDateTime)with RFC 3339 wire values and native spelling
normalization. Anonymous shapes use positional names with a deterministic collision fallback;
integer-constant newtypes expose constants and default constructors.ess generate types
andess generate clientaccept--names short, refusing ambiguous short names. Imported
schema bundle output is unchanged (#406, #407,
#408, #409). -
Release CI prepares verified artifacts with read-only permissions; the organization bot
publishes the verified release from the trusted delivery environment. -
Breaking for generated model data libraries with bounded integers: top-level integer
invariants publish JSON Schema bounds, and Rust/Go libraries use signed 32- or 64-bit fields
when both bounds fit that width. One-sided and unbounded integers retain their exact-number
representation; imported schema bundles are unchanged. Bounds and constants remain explicit
runtime validation obligations (#394). -
Breaking for a realization of a view with parameters, and for hand-written server code:
synthesized Go and Rust servers decode a view's declared parameters from the query string by
wire name and pass them, typed, to the view port, whose method now takes them. A missing
required or undecodable value is a400refusal; undeclared keys are ignored; queries for views
with parameters stay obligations. The generated Rusthttp::Requesthas a new public field
query: Stringand derivesDefault, so a hand-writtenRequest { … }literal setsqueryor
ends with..Default::default(). Two parameters of one view that spell one identifier in a
target are refused, and a served view with a non-scalar parameter is refused (#311). -
Served surfaces agree on what they refuse and in which words: Decimal, Uuid and Bytes values
and map keys admit exactly the published pattern in Go and Rust, and both answer431past
the request-head size or 100 headers. The Rust server no longer exits when a caller hangs up
early, and drops a connection silent for 1 s. -
Breaking for a Go realization:
ess generate synthesize --target gogenerates every command
behaviour and view query the plan marks generated, at parity with the Rust target, in a new
packagetypes/behaviour:<Entity>Storage(Get,Put,Delete,Listin a stable
order),Context,Ports(one field per storage port) andNew(ports) *Generated, evaluated in
Rust's order, existence selection included. Entities check their invariants
(BrokenInvariant()).<ctx>.Unimplementednow covers owed seams only, so code that passed it
as the whole behaviour bundle no longer compiles; passbehaviour.New(ports)and implement the
owed seams. Package namesbehaviourandinvariantare reserved, and a domain named like a
standard-library package a generated file imports gets a renamed package. A store and a server
entry point are not generated yet (#314). -
The gatepass example's
AdmitVisitorstores the printed badge (sets: {badge: input.badge}).
Fixed
- Recovery process diagnostics retain the observed Unix termination signal separately from
timeout and exit status. Failure assertions print the complete outcome without guessing
which actor sent a signal; non-Unix platforms report no signal. - Contradictory integer equality invariants stay unsatisfiable in generated JSON Schema
for required fields and integer newtypes, independent of declaration order. Optional
fields retain their existing null and absence semantics. - Synthesized server creation identities and Web/Clap existence handling agree with the
declared command behavior; generated contract guidance describes the actual seams. - Conformance synthesis handles the corrected optional inputs, copied-field guards,
Boolean outcomes, bindings and response expectations from the consumer defect batch. - Browser runner startup reports failures, isolates concurrent invocations and cleans up its
process resources consistently. - Generated Rust documentation prefixes every line and escapes standalone carriage returns,
so compiler-admitted multiline descriptions produce compilable source. Successful LF and
CRLF output stays byte-identical; source text and wire semantics are unchanged
(#400).