API stability and versioning

Copy Markdown View Source

This page lists exactly what the Hex package promises across a release line, and what it does not. The repository's test suite checks the module lists below against the architecture gate that pins the package's public exports and struct fields, so the page and the code cannot drift apart.

Two version numbers

  • Package versions (0.9.1, 1.0.0, 1.1.0) are Hex releases of this library, following Semantic Versioning. "Package 1.x" means every release from 1.0.0 before 2.0.0.
  • Contract-majors (1, 2, 3) are closed wire profiles, each with its own namespace (BoundedAuthorityProtocol.V1, V2, V3), suite (BAP1-Ed25519-SHA256, BAP2-Ed25519-SHA256, BAP3-ES256-SHA256), specification, and corpus.

The numbers are independent. One package release carries several contract-majors, a new contract-major arrives in a package minor release, and a package major release changes no wire profile.

What a release may change

From package 1.0.0 (governance ยง Package versions is the normative text):

ReleaseMay contain
Patch (1.0.x)An editorial erratum, or a fix that changes no documented behavior or verdict.
Minor (1.x.0)A new contract-major or sibling profile; a new public function, optional argument, or struct field with a default; a soundness repair that meets every governance condition; a raised Elixir or Erlang/OTP floor, announced in the changelog.
Major (2.0.0)Removing a namespace, or changing a struct field, a function arity, a return shape, an enforced key, or a documented error.

A soundness repair is the one way a verdict changes inside a contract-major: it changes verdicts only from accept to reject, only on inputs no conforming producer emits, and it is recorded in the errata registry. Pin the minor-bounded requirement (~> 1.0 admits every 1.x release) and run the packaged corpora after each upgrade (Recipes).

Within a contract-major, the accepted bytes and verdicts never change except through such a repair. Every function keeps returning {:ok, value} or exactly {:error, :invalid}, and the facts structs keep their not-evaluated markers.

Stable surface

Within package 1.x, these modules keep their public functions (name, arity, argument and return shapes), their struct fields, and their documented errors. New functions and new defaulted fields may be added.

Contract-major 1 facade and structs:

Shared building blocks:

Contract-major 2 facade and structs:

Contract-major 3 facade and structs:

Signature suites:

Sibling profiles:

Conformance:

  • BoundedAuthorityProtocol.Conformance.Cli: run/1 and the bounded_authority_conformance command. Its flags (--corpus DIR, required; --report PATH; --help; --version), its exit statuses (0 complete agreement, 1 any disagreement, integrity, completeness, or I/O failure, 2 a usage error), and its report's JSON fields (format, agreement, exit_status, total, agreed, disagreed, index_sha256_base64url) are part of the contract.

Not covered

These are public only because Elixir has no private modules, are hidden from these docs, and may change in any release:

  • BoundedAuthorityProtocol.V1.Runtime, BoundedAuthorityProtocol.V2.Runtime, BoundedAuthorityProtocol.V3.Runtime, and every other Runtime module;
  • BoundedAuthorityProtocol.Conformance.Corpus, BoundedAuthorityProtocol.Conformance.Runner, and BoundedAuthorityProtocol.Conformance.Report, the CLI's internals;
  • BoundedAuthorityProtocol.Conformance.Cli.Main, the escript entry point;
  • BoundedAuthorityProtocol.V1.Jwk.thumbprint_digest_unchecked/1;
  • the signature gate helpers BoundedAuthorityProtocol.Ed25519.signature_gate?/1 and BoundedAuthorityProtocol.Ed25519.strict_gate?/2;
  • the selector helpers that verification and the producers share, in each of BoundedAuthorityProtocol.V1.Selector, BoundedAuthorityProtocol.V2.Selector, and BoundedAuthorityProtocol.V3.Selector:
    • BoundedAuthorityProtocol.V1.Selector.float_zero_free?/1, BoundedAuthorityProtocol.V1.Selector.integral_float_free?/1, BoundedAuthorityProtocol.V1.Selector.match_all/3, BoundedAuthorityProtocol.V1.Selector.semantic_equal?/2;
    • BoundedAuthorityProtocol.V2.Selector.float_zero_free?/1, BoundedAuthorityProtocol.V2.Selector.integral_float_free?/1, BoundedAuthorityProtocol.V2.Selector.match_all/3, BoundedAuthorityProtocol.V2.Selector.semantic_equal?/2;
    • BoundedAuthorityProtocol.V3.Selector.float_zero_free?/1, BoundedAuthorityProtocol.V3.Selector.integral_float_free?/1, BoundedAuthorityProtocol.V3.Selector.match_all/3, BoundedAuthorityProtocol.V3.Selector.semantic_equal?/2;
  • every function or module marked @doc false or @moduledoc false.

Also not covered: the text of inspect/2 output (it redacts credentials, arguments, and nonces, and its exact form may change), the order of keys in maps you did not build, and the wording of any message the CLI writes to standard error.

What never changes

Whatever the package version:

  • every verification and production function returns {:ok, value} or exactly {:error, :invalid}, and signals every failure with that one value;
  • the facts are redacted and never authorize (authorization: :not_evaluated, trust: :not_evaluated);
  • the package performs no I/O, reads no clock, and holds no keys, outside the conformance CLI's documented file reads.