Skip to content

ESS 0.57.0

Choose a tag to compare

@b10x-bot b10x-bot released this 09 Oct 22:33
· 1153 commits to main since this release
b0762c4

Added

  • ess-cli/2: a CLI presentation binding may leave out the config and output globals; state
    is still required. ess specify cli compiles it to ess-cli-plan/2, which leaves out an
    undeclared global's key and never writes null. ess generate cli defines no flag for an
    omitted global, and a CLI without output writes JSON only. An ess-cli/1 binding still
    requires all three globals and compiles to the same ess-cli-plan/1 bytes as before
    (#481).
  • ess-diff/15: ess verify diff names a domain added to or removed from system.yaml as
    domain/<name>/added (compatible) or domain/<name>/removed (breaking for callers and
    readers), where it reported system/<name>/unclassified-changed. A purely additive revision now
    passes --fail-on breaking-or-unknown, and ess verify impact reaches only the domain's own
    constructs. A delta carrying a domain change is written as ess-diff/15; earlier formats refuse
    it (#469).
  • ess-conformance/46 (/47 with coverage): a command response that reaches a String newtype
    with alphabet:, prefix: or value invariants keeps its success scenarios, where synthesis
    refused them as ESS-SYNTH-001. The scenarios carry the type's rules as constraints, and the
    native, Go and TypeScript runners fail a returned value that breaks one (ESS-CF-PAYLOAD). A
    record invariant or a reading on a response type stays refused by name. Suites without a
    constrained response keep their bytes and format
    (#499).

Changed

  • ess-diff/16: ess verify diff rates a change that moves a command input's wire form between a
    value, an object and an array as breaking for callers, where it rated it unknown and
    --fail-on breaking passed it. That covers an input field retyped (String to a record, text to
    List or Map, and back) and a same-name type redefined so a use in an input moves (a String
    newtype redefined as a struct, a struct member retyped to a list). The delta records the shapes
    before and after; earlier formats refuse it. A move within one wire form, Json on either side,
    and a type with no input use keep their answer, format and bytes.

  • ess-diff/17: ess verify diff rates three changes that refuse an existing caller as breaking
    for callers, where it rated them unknown and --fail-on breaking passed them: an added input
    whose type is not Optional, an added refusal, and a refusal whose when: guard changed so it
    now refuses an input the earlier revision accepted. An input the earlier revision already
    refused, by any refusal under any name, does not count, and neither does an enum value it did
    not declare. The two refusals are decided only where every outcome of the earlier revision, and
    each up to the refusal in the later one, is a plain when: or otherwise branch the mutation
    audit's satisfiability check decides; anything else stays unknown. The delta
    records narrows (required-input, refusal-added, refusal-widened) beside the answer;
    earlier formats refuse it. An added accepting outcome, an added Optional input and every other
    delta keep their answer, format and bytes (#514).

  • ess specify validate refuses a domain, command or view wire name that contains /, or is .
    or .., as path_segment_wire_name (ESS-DOMAIN-012, ESS-COMMAND-012, ESS-VIEW-012), naming
    the declaration and the wire name. Such a name was copied into every generated HTTP path as it
    was, so it could address another route. Views are refused whether or not a network component
    serves them. Dots inside a name stay accepted.

  • Validation refuses a refusal whose when: always holds (when: true beside error:), as
    ESS-COMMAND-004 naming the branch, with the hint to give it the condition it refuses on or to
    drop when: and declare it as the default refusal. Such a refusal had no one step in the
    precedence order: beside another refusal that held, the model interpreter answered the other
    refusal, while Entity Runtime and the Rust and Go targets answered this one. An accepting
    when: true branch is unchanged (#489).

  • In ess-cli/1 and ess-cli/2, null, ~ and "" as a global's flag are refused with an error
    naming the global; before, they were read as a flag called null
    (#481).

Fixed

  • ess verify conform synthesize keeps the external: and success scenarios of a command that
    has an input no guard reads whose newtype invariant refuses the default witness, beside several
    string guards on another input. They were refused with ESS-SYNTH-003 ("no candidate of the 4
    tried"). The candidate search now starts that input at the first value its invariant admits,
    instead of varying it last and dropping every candidate before it. That value is the one the
    search reached first before, so suites the search already served keep their scenarios
    (#511).
  • ess verify conform run --target interpreted decides a command with a current-time (now)
    guard, where it answered every scenario of that command unsupported, authored ones included.
    The interpreter decides at the instant of the step being executed, which is also the instant
    that step's now_offset values resolve against. It reads that instant once per decision.
    The interpreted run reads no machine clock: its wall is the fixed
    now_offset::earliest_run() instant, so two runs print the same report. The text report now
    prints the diagnostic under an unsupported scenario, as it already did under an error one,
    so a guard the target cannot decide is named. The library adds Runner::command_clock, a
    command clock that reads the runner's step instant
    (#510).
  • ess verify conform mutate scores a guard mutant on a branch carrying both when: and
    when_subject: as equivalent (ESS-MUTATE-005) where its mutated when: can hold only with an
    input field absent that the when_subject: predicate needs to compare: such a comparison is
    Unknown on every row, never True, so the branch is selected on no row and no scenario can
    take it. when: defined(expected_version) beside when_subject: version != input.expected_version,
    negated to not defined(expected_version), was reported unwitnessed (its suite refused the
    branch with ESS-SYNTH-003). The entry's unsatisfiable_guard names the mutated when: and the
    stored predicate together. A stored predicate that can still hold, through a test reading no
    absent input or through another disjunct, keeps its scoring, and a failed scenario still kills
    the mutant.
  • ess verify conform mutate scores a precedence-swap of two branches that answer alike as
    equivalent (ESS-MUTATE-005), where it reported a survivor no implementation could kill:
    the same error, the same or no payload, and neither branch changing state, setting or emitting
    anything. The entry names the shared answer as identical_answer, apart from
    unsatisfiable_guard, which still means only that the two guards never overlap. A failed
    scenario still kills such a mutant. Two refusals that differ in error, payload or effect keep
    their scoring. A report or manifest carrying identical_answer is the new
    ess-mutation-report/5 or ess-mutation-manifest/5, and one carrying none keeps its earlier
    version and bytes; an earlier manifest carrying it, /4 included, or one carrying it on a mutant
    that is not a precedence-swap, is refused
    (#517).
  • Synthesis writes the wrong_state scenario of a command whose when_subject: sibling
    quantifies over an input list and compares its elements with the row, such as
    not (exists audience in input.aud: audience == {fact: client_id}). The candidate search drew
    that list from the input guards alone, so no candidate held the row's value and the scenario
    was refused as ESS-SYNTH-003, whatever the row. Where no candidate is found, the search now
    tries lists grounded on the row's values. Each sibling is still refuted through any one of its
    conjuncts (when: or when_subject:). A scenario where every row and input leave some sibling
    with all its conjuncts holding is still refused with ESS-SYNTH-003. Suites the first search
    already served keep their bytes (#516).
  • The doc comment on the generated Rust Generated<P> bundle names TryContext and its legacy
    Context blanket adapter only where the same synthesis emits them. Where no generated behaviour
    asks the context anything (for example when every command with an external: outcome is owed),
    it named two traits the crate does not have. Modules that emit them keep their bytes; no type,
    trait or signature changes.
  • The Go and TypeScript runners that ess verify conform synthesize --target go|typescript
    generates admit a suite whose shapes hold json. A model with a Json field synthesized such a
    suite, and both runners refused it at admission with suite admission: <Command>/outcome/<name>: unknown primitive. A json value is compared structurally, as the Rust runner compares it.
  • The test suites remove every scratch directory they create under TMPDIR when its guard
    drops, panics and read-only fixtures included; directories a process-lifetime cache holds live
    under CARGO_TARGET_TMPDIR. An ess-xtask check runs a set of suites with an empty TMPDIR and
    names any prefix left behind.
  • Synthesis no longer overflows the stack on a command with two identity guards over a
    self-reference. A search for a row beside the arranged entity is cut only where it re-enters
    itself, and the nearest Optional reference is left out before synthesis refuses; models that
    synthesized before produce the same suites (#474).
  • A refusal whose guard reads only the input id gets a witness again: the stored-row half of the
    scenario is searched with that id fixed, and is dropped when no stored row meets the guard,
    instead of failing ESS-SYNTH-019 (#479).
  • Arranged and steered creations take distinct identities per distinction, and boundary rows no
    longer re-send the first identity. A scenario that would still create one literal id twice with
    no delete between is withdrawn as ESS-SYNTH-001 naming it
    (#480, #471).
  • ess verify conform synthesize --component <c> --scenarios <dir> lists an authored scenario
    that drives a command, event or view the component does not realise as outside:, as it does a
    generated one, where it filed it in the component's suite and the scenario could only fail. The
    summary counts only the authored scenarios the suite keeps
    (#513).
  • The text conformance report prints <check code>: <cause> under each scenario that ended in
    error; the JSON report is unchanged (#471).
  • Synthesis witnesses every any: and all: of an input guard once per child at any depth, not
    only at the top level, so the guard-connective mutant of an all: nested in an any: (or the
    reverse, or one under not:) is killed. A per-child input none of the guard's own candidates
    provides is solved for directly, so an any: of four three-way all:s is witnessed at every
    child; one no search finds is an ESS-SYNTH-022 refusal beside the scenario that names it,
    rather than a child skipped silently. A child that cannot decide the connective alone is not
    refused: its text literals contradict the input it would need (starts_with "AB" beside
    starts_with "A", which the longer prefix implies). ess verify conform mutate decides defined tests of
    Optional input fields, so a precedence-swap of two branches no input selects together, such
    as defined(x) and not defined(x), is equivalent rather than survived. Suites for guards
    with only top-level connectives are unchanged (#501).