Skip to content

Changelog

All notable changes to this project are recorded in this file.

The format is based on Keep a Changelog, and this project follows Semantic Versioning. Before 1.0, a minor release may contain breaking changes; each one is listed under Changed or Removed and never made silently.

  • Contracts (spec 01): @contract on a Protocol class, @action with idempotent=, @implements, and Contract.of(...) with a neutral description of the actions and their JSON Schemas. Identities, action names, request and reply types and implementations are checked when the module is imported, and fail with ContractDefinitionError.
  • Contract errors (spec 01, ADR 0008): ContractError with a kind, a message and a detail in data, and @action(errors={...}) to declare an action’s own error kinds with their detail records. Declared kinds are checked when the contract is declared, may not use a standard or reserved kind’s name, and appear in the neutral description. A kind the receiver does not know is held with an untyped, read-only detail.
  • Action gains errors, a frozen mapping from each declared kind to its detail record, empty by default.
  • @action marks a method once, and implementation methods are not marked, including through wrappers such as functools.cache or property. @implements reads the implementation class statically, so it never evaluates a lazy attribute.
  • Wire encodings (spec 01, ADR 0019): the neutral description states each form’s range or pattern. Integers are limited to ±(2^53 − 1) and numbers to the finite doubles. neolith.Duration, neolith.Decimal128 and neolith.Binary (ADR 0020) are Annotated types for durations, decimals and bytes that read and write exactly their wire forms ("1.500s", "-12.50", "_w=="); a plain timedelta, Decimal or bytes field is refused, naming the type to use. Binary reads base64url from JSON text only, so a receiver validates the text itself (model_validate_json). A default is refused unless Pydantic writes it in its form.
  • The call context (ADR 0017): neolith.CallContext, a frozen value with the principal, the trace, the deadline, the idempotency key and the calling app of one call, and neolith.Principal, a frozen issuer, subject and claims. An implementation’s action that reads the context takes it after the request, as (self, request, ctx: CallContext); @implements accepts that shape and (self, request), and no other.
  • Runtime dependency on Pydantic v2 (ADR 0006).