Skip to content

0.62.0

Choose a tag to compare

@b10x-bot b10x-bot released this 17 Oct 12:29
· 876 commits to main since this release
a500f9f

Added

  • The generated Rust decoder of a newtype enforces what the newtype declares: its alphabet, its
    prefix and its invariants. A value that breaks one is refused with the path and the constraint
    (broken_constraint on the type), so a served route no longer admits it
    (#579, decoder half). A constraint the emitter cannot check refuses the target by
    name.
  • A suite can fix the instant a target reads as now for one command: the hold_now step
    ({step: hold_now, seconds: <n>}, suite ess-conformance/50, or /51 with coverage) stands
    before the execute_command it holds and names a now_offset, so a value sent as a now_offset
    can sit exactly on a now boundary. The runner holds its command clock at that instant, or asks
    the target through the new optional ConformanceTarget::hold_now (the generated Go runtime's
    NowHolder, the TypeScript runtime's holdNow); a target without it reports the scenario
    unsupported, naming hold_now. A suite without the step keeps its format and
    bytes (#586).
  • Synthesis adds one scenario on each now boundary a command decides by — an input guard, or a
    when_subject:/when_related: predicate over a stored field written from an input — with the
    value sent exactly on the boundary and a hold_now 0 before the command under test, filed as
    <command>/outcome/<outcome>/held/<field>/<seconds>. A value is not moved onto a boundary across
    another now boundary on the same field, so every other comparison, and every row set a
    decision counts, stays as it was. The guard-boundary mutant (< to <=)
    answers apart there, so a target that holds now kills it; the interpreted target of
    ess verify conform mutate is given no clock and reports it inconclusive, not survived.
    A model with such a guard therefore gets a suite in
    ess-conformance/50 (/51 with coverage); its off-boundary scenarios keep their bytes, and a
    target without hold_now reports only the new scenario unsupported, named and counted; unlike
    any other unsupported scenario it does not fail the run, so a target that passed before keeps
    its verdict and exit status in the Rust, Go and TypeScript runners
    (#586).
  • The Rust spec-types crate a model realizes enforces a String newtype's alphabet and the text
    length its value.count invariants bound. Such a type is still serialized as its plain string,
    but its decoder refuses a value outside the alphabet or the length, naming the type's schema
    pointer and the broken constraint (broken_constraint on the type). The types report no longer
    lists model_alphabet as an obligation for it (#579, spec-types half). A newtype
    that declares neither keeps its exact generated bytes.
  • The generated Go and TypeScript sequential explorers (Explore) draw a Timestamp input, as
    the concurrent ones already did, and decide a guard over now against a clock,
    ExploreOptions.Now (TypeScript now), the wall clock by default. Where a guard compares a
    Timestamp with now, a drawn instant lies an hour to a day either side of an instant it
    compares with, so a target reading its own clock decides the step as the model does, and a step
    whose answer would still turn on when the target reads its clock is reported in Undetermined
    rather than sent. Before, every command with a Timestamp input was excluded
    (#582).
  • The sequential explorers perform an outcome that deletes: its supplied subject: the row leaves
    the model, every view must lose it, and a later step may name the deleted identity, which the
    model answers as an unknown instance, so a single-use resource is explored through its
    redemption. Concurrent exploration still leaves such a command out and now says why: its
    workload is drawn before any call runs, so a later call can name the deleted row
    (#583).
  • Runtime format ess-runtime/2, compiled to ess-runtime-ir/2, beside /1. A workload may
    declare schedule: (a cron expression, an optional IANA time_zone, overlap: forbid, replace
    or allow, history limits, suspended, start and run deadlines, a retry limit and a restart
    policy), and ess generate project helm renders it as a batch/v1 CronJob whose job template
    carries the pod a Deployment would, with a PersistentVolumeClaim per named volume that every
    run mounts. A scheduled workload without run_deadline_seconds is refused as unbounded; an
    invalid cron expression, an unknown time zone, replicas, legacy storage, a provided endpoint
    or a readiness probe beside a schedule, a deadline below one and a negative retry limit are
    refused naming the workload. Every workload kind also takes pod settings: container resources
    (cpu and memory requests and limits) and read_only_root_filesystem, workload security
    (run_as_user, run_as_group, fs_group, run_as_non_root) and service_account_token, a
    secret slot mount: rendered as a read-only secret volume with items and an octal mode,
    and a process image given as a reference pinned by digest, rendered verbatim. An
    ess-runtime/1 document keeps its compiled bytes, digest and chart, and refuses the new keys
    naming ess-runtime/2 (docs/design/runtime-workload-kinds.md).
  • ess-runtime/2 containers take TCP probes (readiness_tcp_port, liveness_tcp_port, rendered as
    tcpSocket), and workloads take pod annotations and affinity (node_labels as required node
    affinity, spread_across as pod anti-affinity against the workload's own pods, preferred unless
    spread: required). An ess-runtime/2 document is refused, naming the field, where the chart
    would not install or not say what the document says: a day of week of 7, an int32 count or a
    pod security id above 2147483647, a container, workload, volume or mounted secret slot whose pod
    name is not a DNS-1123 label, a secret item key Kubernetes refuses or an item path starting with
    .., a request above its limit, and {{ in any string the chart renders as written, which Helm
    would evaluate at install time. ess-runtime/1 documents compile as before.

Fixed

  • No generated document carries a $serde_json::private::Number map any more. In a build where
    another crate turns on serde_json's arbitrary_precision, an Integer enum attribute was
    published in x-ess-attributes as {"$serde_json::private::Number": "2"} instead of 2, in the
    OpenAPI and AsyncAPI documents and the /openapi.json a generated server serves. Every YAML
    write now writes such a number as the number, as a build without the feature does, and a corpus
    test pins every projection of every example to the bytes of a build without it
    (#579).
  • Format ess/26: an external refusal (external: or external_when:) beside an existing-row
    branch reads the addressed row back and requires it unchanged, so a witness of the refusal can
    no longer pass while the command deletes or rewrites the row (#587). Models below ess/26
    keep their suite bytes.
  • The caller-swapped half of a synthesized scenario draws fresh values for every input a
    when_related: guard, a row-set selector or its forall: test reads, and for every input
    written into a field such a selector reads, whatever its type (#580). A key unique across
    callers, such as a name refused when any row already holds it, no longer makes a correct model
    fail its own suite on --target interpreted. Suites of models without such guards keep their
    bytes.
  • Synthesis arranges a guarded stored value or a related row's state through the declared command
    that reaches it: a when_subject: defined(field) branch whose field only a later updates:
    writes, a when_related branch over an owned row moved to the state it reads, and a row-set
    guard over the subject's owned rows in a moved state now get scenarios instead of
    ESS-SYNTH-003/ESS-SYNTH-001. A field written by another command's affects: is not yet
    arranged (#553).
  • ess verify conform mutate scores a mutant whose synthesized suite asks what the baseline's
    asks (the same scenarios and steps, digests aside) as unwitnessed (ESS-MUTATE-004, "the
    suite does not change") rather than survived or inconclusive, so a survivor always has a
    suite that differs and still passes. One is a precedence-swap of two refusals with the same
    error whose payloads no scenario tells apart.
    Such a report is ess-mutation-report/7, with unchanged_suite on the mutant; every other
    report keeps its version and bytes (#586).

Changed

  • ess-deployment: Process::image is a ProcessImage, Workload::replicas an Option<u32>,
    and SecretSlot::environment and SecretSlot::key are Option<String>, for ess-runtime/2;
    ContainerRole gains readiness_tcp_port and liveness_tcp_port, and Workload gains
    annotations and affinity (Affinity, Spread).