Skip to content

0.10.0

Choose a tag to compare

@github-actions github-actions released this 03 Sep 17:31
· 431 commits to main since this release

Added

  • sets: on a command outcome: which fields of the entity the branch determines, and from
    what.
    The twin of payload:, pointed at the subject instead of an emitted event. Before it,
    nothing in the model related a command's input to the entity state it produced, so a generated
    scenario could find the row it had just created and say nothing about what was in it — an
    implementation that stored somebody else's amount passed. Validated like payload:: the field
    must exist on the entity, the source must be an input the command takes, and the types must be
    assignable or have a declared conversion.
  • A generated contains names the values the row holds, not only which row it is. Read from
    sets: where the source is an input the scenario chose, the types do not cross a conversion, and
    the view projects the field at the entity's own type; left out rather than guessed at otherwise.
    Measured on the normative billing example, which now declares sets: on CreateInvoice: the
    deliberate negative-total fault was caught by 6 of 29 scenarios before and is caught by 13 after.
    It is a claim about a row this scenario made, so it holds on a target §8 permits to be shared.
  • The documentation projection writes a sentence for sets: on every outcome that declares one.
  • The billing example declares an invariant over a top-level field of its own
    reminder_count >= 0, projected by InvoiceById so it can be decided. Nothing shipped here had
    that shape: the entity's other invariant is total.amount >= 0, which has a dot and parses the
    same either way, so the Go runner's left-operand defect below was invisible to every fixture.
  • cargo xtask schema [--check] regenerates schemas/generated/ess.schema.json from
    RawSpecFile, and task projection-check runs it. The file was documented as drift-checked and
    was checked by nothing; the schema an adopter validates against had not moved since the model
    gained its last two constructs.
  • ess conform synthesize --component <name>: the suite one component can be held to. A
    specification with two components obliges two implementations, and an implementation of one
    answers ErrUnsupported to every scenario about the other — which the runner reports as a skip,
    and a run with skips in it cannot say it passed. The scoped suite holds exactly the scenarios
    whose every command, event and view the component accepts, publishes or owns; the rest are
    printed as outside: with what they need, so they are visible somewhere other than by their
    absence. SuiteProvenance.component records the scope and is left out of an unscoped suite, so
    every existing suite is the bytes it was. The refusals are the whole system's, untouched.
    Measured on the ACD ↔ backend model: 44 scenarios for the system, of which the acd component
    can be held to the ones its own commands, events and views make answerable.
  • The emitted Go runner writes ess-conformance-report/1. ESS_REPORT_OUT=<file> go test
    leaves the same closed document the Rust runner writes — specification, digest, implementation,
    status, counts, the non-passing scenarios by status — so aep artifact evidence --from <file>
    records a Go implementation's run without anybody typing a count. Before this the Go suite
    produced a go test exit status and nothing a workflow system could read. A skipped scenario
    makes the run inconclusive: a target that could not answer has not shown the answer. Recording
    a skip means the runner routes every Skipf through one helper that sets the status first, which
    is exercised here for the first time — no shipped fixture skips, so nothing before this release
    ran that path at all.

Fixed

  • The emitted Go runner read the left-hand side of a comparison as a literal. Operand::parse
    is documented for the right side — a bare word is a literal there, which is what makes
    state == Bridged name an enum variant — and the Go mirror put both sides through it. So an
    entity invariant over a top-level field of its own compared the word: reschedule_count >= 0
    asked whether the string "reschedule_count" is at least zero, which is Unknown and reported as
    a defect in the view, and any: [{not: state == Bridged}, defined(agent_id)] evaluated
    "state" == "Bridged", which is false, so the not made the implication vacuously true and the
    invariant checked nothing. The Rust runner never had this: parse_expression puts the left side
    through FactPath::new. Found by the first run of a generated Go suite against an adopter.
  • ErrUnsupported from ExecuteCommand failed the scenario instead of skipping it. Every
    other method's sentinel was honoured; this one was compared and then reported as an execution
    error. A command whose actor is the implementation itself has no caller a target can be, and a
    target saying so was being told its implementation is wrong. Every sentinel comparison now goes
    through errors.Is, so a wrapped one carrying the reason is recognised too.

Changed

  • at is still not synthesised, and the reason is now a different one. The values are known —
    sets: says where each row's ranking value came from — but nothing says a view holds only what
    the scenario running it put there, so naming the first row would be a claim about another user
    of the target. The gap table records which half is answered.