# Public API surface

This page enumerates every callable, attribute, and configuration value Bond
considers part of its **public surface** under the [stability
guarantees](stability.md). If something Bond exposes isn't on this list, it's
implementation detail — Bond reserves the right to change it without a
deprecation cycle. If you depend on something here, you can expect it to stay
backwards-compatible until the next major.

The full set of modules in published API docs is the source-of-truth for
"public module":

  * `Bond`
  * `Bond.Behaviour`
  * `Bond.Protocol`
  * `Bond.Protocol.Impl`
  * `Bond.Server`
  * `Bond.Config`
  * `Bond.Predicates`
  * `Bond.Test`
  * `Bond.PropertyTest`
  * `Bond.PropertyTest.FilterTooRestrictiveError`
  * `Bond.Coverage`
  * `Bond.PreconditionError`
  * `Bond.PostconditionError`
  * `Bond.InvariantError`
  * `Bond.CheckError`
  * `Bond.AssertionEvaluationError`

Everything under `Bond.Compiler.*` and `Bond.Runtime.*` is internal (marked
`@moduledoc internal: true` and filtered out of hexdocs by `filter_modules`
in `mix.exs`). Code that calls into those namespaces is using a private API
and may break on a patch release.

## Module-attribute syntax (in `use Bond` scope)

By default Bond overrides `Kernel.@/1` while `use Bond` is in scope to
intercept four attribute names (plus `@state_invariant` and
`@transition_invariant`, which only a `Bond.Server` module consumes — see
"Stateful process contracts" below); everything else forwards through to
`Kernel.@/1` unchanged (verified by `test/bond/attr_compat_test.exs`).
(Under `at_annotations: false` the override is disabled and the qualified
`Bond.pre`/`Bond.post`/`Bond.invariant` calls are used instead — see
"Qualified-call syntax" below.) The accepted forms for the intercepted
attributes are:

### `@pre` and `@post`

  * `@pre expr` — bare expression. Recognised forms are documented in the
    `Bond.Predicates` moduledoc.
  * `@pre label: expr, other_label: other_expr` — keyword list of
    `label: expression` pairs. Labels are atoms; quote the key for spaces or
    punctuation (`@pre "must be positive": x > 0`).
  * `@post` accepts all the same forms. In addition, `result` is bound to the
    function's return value, and `old(...)` (see below) is recognised inside
    a postcondition expression.

The keyword-list form is the only labelling syntax. The positional forms
`@pre label, expr` and `@pre expr, label` were removed in 1.0 and raise a
`CompileError` pointing at the keyword form. Mixing a bare assertion with a
labelled assertion in a single annotation (e.g. `@pre is_binary(x), positive:
x > 0`) likewise raises a `CompileError` with a specific diagnostic.

#### Destructuring binding forms

  * `@pre where(pattern = source), <assertions>` — asserts the shape (a
    non-match is a contract violation) and scopes `<assertions>` to the names
    `pattern` binds.
  * `@pre whenever(pattern <- source), <assertions>` — conditional (a non-match
    is vacuously satisfied).
  * `<assertions>` are ordinary bare and/or labelled assertions, exactly as
    above. `@post` accepts both forms (binding from `result` or arguments), as
    do `@invariant` (from `subject`), the `Bond.Server` `@state_invariant` /
    `@transition_invariant`, and inherited contracts (`Bond.Behaviour` callbacks
    and `Bond.Protocol` functions). The keyword fixes the arrow (`where` ⇒ `=`,
    `whenever` ⇒ `<-`); a mismatched pair, a non-binding argument, or an empty
    body each raise a `CompileError`. See
    [Destructuring bindings](writing-contracts.md#destructuring-bindings-where-and-whenever)
    for semantics and rendering.
  * **All-inside form** — `where(pattern = source, <assertions>)`, with the
    assertions inside the call. Used by the fixed-arity call macros:
    `Bond.pre`/`Bond.post`/`Bond.invariant` (`at_annotations: false`) and
    `check/1`. Also accepted in the `@` annotations as an alias of the prefix
    form. In `check/1` the bindings are scoped (they do not leak past the check)
    and a violation raises `Bond.CheckError`.

### `@invariant`

  * `@invariant expr` — single expression. Implicit binding `subject`
    references the value being checked.
  * `@invariant label: expr, other_label: other_expr` — keyword list of
    labelled invariants. Bare-form unlabelled, single-expression syntax also
    works.

The 2-argument legacy form `@invariant name, expr` was removed in 0.16.0 and
raises a `CompileError` pointing at the migration.

### `@doc`

  * `@doc` is intercepted to append `#### Preconditions` and `#### Postconditions`
    sections (if any) to the user-authored docstring. The intercepted
    behaviour is part of the public surface; the exact rendering of those
    sections is documented under `Bond` and is part of the public surface as
    well.

## Qualified-call syntax (`at_annotations: false`)

For modules that opt out of the `@` override with `use Bond, at_annotations: false`,
contracts are written as fully-qualified macro calls. These register into the
same compiler machinery as the `@` forms and accept the same arguments:

  * `Bond.pre/1`, `Bond.post/1` — bare expression or keyword list of
    `label: expression` pairs (the same single-form labelling as `@pre`/`@post`;
    quote the key for spaces or punctuation).
  * `Bond.invariant/1` — single expression or keyword list of labelled
    invariants; references the implicit `subject` binding.

These macros are **never imported** (even under the default `at_annotations: true`),
so they cannot collide with user function names; they are only ever reached
through the `Bond.` prefix.

## Macros and operators (after `use Bond`)

  * `check/1` — runtime assertion of an expression or a keyword list of
    labelled expressions. Behaviour under the three `:checks` modes
    (`true | false | :purge`) is documented in
    [Configuring Contracts](configuration.md).
  * `old/1` — captures a value at function-entry for use in a `@post`
    expression. Only valid inside `@post`.
  * `subject` — implicit binding inside `@invariant` expressions, bound to
    the struct being checked at each check site.
  * `~>/2`, `<~/2` — pattern-matching operators imported from
    `Bond.Predicates`. Precedence and associativity are documented in the
    `Bond.Predicates` moduledoc.
  * `|||/2`, `xor/2`, `implies?/2` — boolean operators imported from
    `Bond.Predicates`. See "Bond.Predicates" below for direct calls outside
    a Bond module.
  * `forall/2`, `exists/2` — quantifiers imported from `Bond.Predicates`,
    each taking one `pattern <- enumerable` generator and one predicate
    expression: `forall(x <- items, x > 0)`. Both return a plain `boolean()`,
    so they compose with `and`/`or`/`not`/`~>`, and both are valid in `@pre`,
    `@post`, `@invariant`, `@state_invariant`, `@transition_invariant`, and
    `check/1`. The **fact** that a failure carries element-level detail (the
    failing element and its index for `forall`; the absence of a witness for
    `exists`) is part of the public surface; the rendered `counterexample:`
    wording is not. A multi-generator or filter form raises a `CompileError`.
    See [Quantified assertions](writing-contracts.md#quantified-assertions).

## `use Bond` options

Each option is one of `true`, `false`, or `:purge` unless noted. Options
passed to `use Bond` override both the global `:bond` application config and
any `:overrides` entry that matches the module:

  * `:preconditions` — mode for the module's `@pre` annotations.
  * `:postconditions` — mode for the module's `@post` annotations.
  * `:checks` — mode for the module's `check/1` calls.
  * `:invariants` — mode for the module's `@invariant` annotations.
  * `:at_annotations` — boolean (default `true`). When `false`, Bond does not
    override `Kernel.@/1` in the module, so the `@pre`/`@post`/`@invariant`
    forms are unavailable and contracts must be written as the qualified
    `Bond.pre`/`Bond.post`/`Bond.invariant` calls (see below). Use it to
    coexist with another library that overrides `@` (e.g. Norm's
    `@contract`). See the FAQ entry "Can I use Bond and Norm in the same
    module?"
  * `:warn_skipped_invariants` — boolean (default `true`). Controls the
    compile-time warning Bond emits when a public function in an
    invariant-declaring module never mentions the struct at all, so its
    invariants are skipped. See the FAQ entry "Why is Bond warning about
    skipped invariants?"
  * `:warn_unavailable_preconditions` — boolean (default `true`). Controls the
    compile-time warning Bond emits when a **public** function's precondition
    calls a **private** function of the same module, which a caller cannot
    evaluate — Meyer's Precondition Availability rule. Postconditions are
    exempt. See the FAQ entry "How do I reuse a predicate across several
    functions?"
  * `:behaviours` — a module or list of `Bond.Behaviour` modules whose callback
    contracts this module inherits and enforces. Also emits `@behaviour` for
    each. See "Contract inheritance" below.

## Per-function module attribute

  * `@bond_warn_skipped_invariants` — tri-state (omit / `true` / `false`),
    consumed by Bond's `__on_definition__` handler and scoped to the **next**
    `def` only. Omitting the attribute inherits the module/global setting;
    `false` suppresses the warning for that single function; `true` re-
    enables the warning for that single function even under a module-wide or
    global `false`.
  * `@bond_warn_unavailable_preconditions` — the same tri-state, same scoping,
    for the Precondition Availability warning.

## Contract inheritance

Two modules let an abstraction declare contracts that every implementation
enforces. Both are part of the public surface; the full rules are in the
[Contract Inheritance](contract-inheritance.md) guide (see
[Behaviours](contract-inheritance.md#behaviours) and
[Protocols](contract-inheritance.md#protocols)).

  * **`Bond.Behaviour`** — `use Bond.Behaviour` in a behaviour module enables
    `@pre`/`@post` immediately preceding each `@callback`. The accepted contract
    forms are the same as `@pre`/`@post` under `use Bond` (bare or labelled
    keyword list); contract expressions reference the callback's argument names
    and `result`. A module inherits them with `use Bond, behaviours: […]`.
  * **`Bond.Protocol`** — `use Bond.Protocol` in a `defprotocol` enables
    `@pre`/`@post` immediately preceding each `def`. Contracts are enforced at
    the protocol's dispatch boundary across all implementations; expressions
    reference the function's declared argument names and `result`.

By default an implementation inherits its contracts verbatim; a plain
`@pre`/`@post` on an inherited operation is rejected. An implementation that
inherits a **behaviour** callback's contract may *refine* it with two further
annotations (Eiffel-style behavioural subtyping):

  * `@pre_weaken` / `Bond.pre_weaken/1` — weakens the inherited precondition
    (effective pre = `inherited or pre_weaken`).
  * `@post_strengthen` / `Bond.post_strengthen/1` — strengthens the inherited
    postcondition (effective post = `inherited and post_strengthen`).

They accept the same bare/labelled forms as `@pre`/`@post`, and their
expressions reference the abstraction's canonical argument names — the callback's
or protocol function's (plus `result` for `@post_strengthen`) — not the
implementation's own parameter names. The qualified `Bond.pre_weaken/1` /
`Bond.post_strengthen/1` forms serve the `at_annotations: false` path. Refining a
*protocol* contract uses the same annotations inside a `defimpl` that does
`use Bond.Protocol.Impl`.

The *fact* that the documented compile-time rules fire (e.g. a plain
`@pre`/`@post` on an inherited operation is rejected; `@pre_weaken` requires an
inherited precondition; a contract may reference only declared names) is part of
the public surface; the exact wording of those diagnostics is not.

## Stateful process contracts

`use Bond.Server`, **after** `use GenServer`, enables module-wide invariants on a
server's process state:

  * **`@state_invariant expr`** / **`@state_invariant label: expr, ...`** — same
    bare-or-keyword-list shape as `@invariant`. The implicit binding is `state`,
    bound to the new state the callback produced. Checked after every
    state-transition callback returns a new state: `init/1`, `handle_call/3`,
    `handle_cast/2`, `handle_info/2`, `handle_continue/2`, `code_change/3`. A
    violation raises `Bond.InvariantError` with `:kind` `:state_invariant`; its
    `:function` field is the callback the invariant was checked after.
  * **`@transition_invariant expr`** / **`@transition_invariant label: expr, ...`**
    — same shape. The implicit bindings are `old_state` (the callback's incoming
    state) and `new_state` (the state it returned). Checked across every
    transition callback — `handle_call/3`, `handle_cast/2`, `handle_info/2`,
    `handle_continue/2` — but **not** `init/1` or `code_change/3`, which are
    treated as re-creations. A violation raises `Bond.InvariantError` with `:kind`
    `:transition_invariant`.

Both are gated under the `:invariants` configuration kind: they honour the
precondition ≤ postcondition ≤ invariant chain, respond to
`Bond.Config.enable/1`/`disable/1` at runtime, and are compiled out entirely
under `invariants: :purge`. `use Bond.Server` accepts the same options as
`use Bond`. Declaring either in a module that does not `use Bond.Server` emits a
compile warning; the bare-form qualified-call equivalents for
`at_annotations: false` are not part of this version.

## Reusable named contracts

A bundle of `@pre`/`@post` declared once and applied to many functions. The full
rules are in the [Reusable Contracts](reusable-contracts.md) guide.

  * **`defcontract name(arg1, …) do … end`** — a macro available after
    `use Bond` (in either `:at_annotations` mode). Declares a contract identified
    by `{name, arity}`; the head's parameter list supplies the canonical argument
    names and order. The body accepts `@pre`/`@post` (the same bare/labelled forms
    as `@pre`/`@post`; expressions reference the declared arguments and `result`/
    `old/1` in a `@post`) and `include` directives (see below). Same name at
    different arities are distinct contracts.
  * **`include name(args)`** / **`include Module.name(args)`** — inside a
    `defcontract`, composes another named contract's clauses into this one. Each
    argument is an expression over this contract's parameters, substituted into the
    included contract's clauses; the argument count selects the included overload.
    Works in either `:at_annotations` mode.
  * **`@apply_contract :name`** / **`@apply_contract {Module, :name}`** — applies
    a named contract (local or cross-module) to the next function, immediately
    preceding it like `@pre`. The function's parameters rebind positionally to the
    contract's canonical names; the function's arity selects the overload. A
    function may add its own `@pre`/`@post` alongside (conjoined with the contract,
    referencing the contract's canonical names). Requires Bond's `@` syntax
    (unavailable under `at_annotations: false`).

A function applies a single named contract directly (use `include` to combine
several). An applied contract may not be combined with behaviour/protocol
inheritance on the same function, nor refined with `@pre_weaken`/`@post_strengthen`.
The *fact* that these rules fire at compile time is part of the public surface; the
diagnostic wording is not.

`use Bond.Behaviour`'s `__bond_contracts__/0` has a named-contract counterpart,
`__bond_named_contracts__/0`, generated on a module that declares `defcontract`s.
It is an internal reflection hook read by `@apply_contract {Module, …}` at the
applying module's compile time; you should not call it directly.

## `Bond.Predicates`

When called directly (i.e. not through `use Bond`), `Bond.Predicates`
provides:

  * `xor/2`, `implies?/2`, `|||/2` — `def`s. Takes two `as_boolean(term())`
    arguments, returns `boolean()`.
  * `~>/2`, `<~/2` — `defmacro`s. See the `Bond.Predicates` moduledoc for the
    precedence/associativity rules and the canonical example.

`__opaque__/1` and `__truthy__/1` in `Bond.Predicates` are infrastructure
called by Bond-generated code. They are *not* a direct-use API and are
excluded from hexdocs (`@doc false`). Their stability is guaranteed only
insofar as Bond's generated code depends on them — user code should not
call them directly.

## `Bond.Test`

Brought into ExUnit modules via `use Bond.Test`. Provides:

  * `assert_precondition_violation/2`
  * `assert_postcondition_violation/2`
  * `assert_check_violation/2`
  * `assert_invariant_violation/2` (covers struct `@invariant` and `Bond.Server`
    state/transition invariants; pass `kind:` to be specific)

Each accepts an expression and a keyword list of optional fields to verify on
the raised error struct (`:label`, `:module`, `:function`, etc.). The full
keyword shape is documented in the `Bond.Test` moduledoc.

## `Bond.PropertyTest`

Brought into ExUnit modules via `use Bond.PropertyTest`. Provides:

  * `contract_holds/2` — runs StreamData-generated input through a single
    function and asserts every call satisfies its contracts.
  * `probe_contract/2` — like `contract_holds/2`, but mixes the boundaries
    implied by the function's `@pre` into the generators — both value edges
    (`x >= 0`) and size edges (`length(items) <= 3`, building collections of
    the boundary size) — and uses the precondition as a *filter* (discarding
    violating inputs rather than failing on them), so the `@post` is the oracle
    and the precondition edges are probed deliberately.
  * `invariants_hold/2` — runs random sequences of operations over a
    struct module and asserts the module's `@invariant`s (and any
    per-function contracts) hold across every reachable state.
  * `server_invariants_hold/2` — drives a `Bond.Server` through random
    `call`/`cast`/`info` message sequences and asserts its
    `@state_invariant`/`@transition_invariant` hold across the reachable
    state space, in a `:callbacks` (default) or `:process` execution mode.

Requires the optional `:stream_data` dependency in the consumer's `mix.exs`.

`Bond.PropertyTest.FilterTooRestrictiveError` is raised by `probe_contract/2`
when a function's precondition discards too many consecutive generated inputs
for the property to proceed. It is a *test-harness* error rather than a contract
violation — it is not raised by any contract, does not fire telemetry, and does
not share the error-struct shape described under "Error structs" below. Its
existence and its name are part of the public surface; its message text is not.

## `Bond.Coverage`

A compile-time-opt-in test diagnostic (enabled with `config :bond, coverage: true`) that
records, per assertion, how many times it was checked and how many of those were failures —
surfacing assertions that ran but were never observed to fail. Public functions:

  * `record/2` — the recording hook the runtime calls; not called directly.
  * `entries/0` — accumulated coverage as structured data.
  * `report/0` — the coverage as a human-readable table.
  * `reset/0` — clear accumulated coverage.
  * `install_reporter/0` — print `report/0` after the ExUnit suite (call in `test_helper.exs`).

## Mix tasks

  * `mix bond.audit` — reports contract density: which public, non-callback functions in
    modules that `use Bond` carry a contract of their own, and which carry none. The
    complement to `Bond.Coverage`, which can only report assertions that exist. Switches:
    `--verbose` (list every uncontracted function), `--only <string>` (restrict to matching
    module names), `--min <integer>` (exit non-zero below that percentage, for a CI ratchet).

The task's **existence, name and switches** are public surface. Its report text is not — it is
human-facing prose that may be reworded, so do not grep it in CI; use `--min` instead. See
[Testing Contracts](testing-contracts.md#contract-density-which-functions-carry-a-contract-at-all).

## `Bond.Config`

Runtime control over which kinds Bond evaluates, for kinds compiled in as `true`
or `false`. `:purge`d kinds have no runtime presence and are unreachable from
here. The state lives in a single `:persistent_term` entry, lazily seeded from
application env on first use — so `Application.put_env/3` after the first
contracted call has no effect (use `reset/0` to re-seed). See
[Configuring Contracts](configuration.md#runtime-toggling).

  * `kinds/0` — the list of kinds this module controls.
  * `enable/1` / `disable/1` — turn a kind on or off; equivalent to
    `put(kind, true)` / `put(kind, false)`.
  * `put/2` — set a kind's runtime state to a boolean explicitly.
  * `enabled?/1` — whether a kind currently evaluates.
  * `all/0` — the effective state of every kind, as a map.
  * `reset/0` — discard the cached state and re-seed from current application env.

The toggle is **global**, not per-module: per-module control is a compile-time
concern, expressed with `:overrides` or `use Bond` options. Toggling a lower kind
off also skips the kinds above it, per the contract-checking chain.

## Telemetry

Bond emits exactly one telemetry event:

  * **Event name:** `[:bond, :assertion, :failure]`.
  * **Measurements:** `:system_time` (`System.system_time/0`) and
    `:monotonic_time` (`System.monotonic_time/0`), both captured at the failure.
  * **Metadata:** map with keys `:kind` (`:precondition` | `:postcondition` |
    `:invariant` | `:state_invariant` | `:transition_invariant` | `:check`),
    `:label`, `:module`, `:function` (`{name, arity}`
    tuple), `:expression` (string source), `:file`, `:line`, `:binding`
    (keyword list of variables in scope at the assertion site), and
    `:assertion_id`. For inherited
    contracts the metadata also carries `:source_behaviour` (the originating
    `Bond.Behaviour`) or `:source_protocol` and `:impl` (the originating
    `Bond.Protocol` and the resolved implementation module); for an applied named
    contract it carries `:source_contract` (the originating `{module, name}`).

`:assertion_id` identifies the assertion and is stable across firings of that
same assertion, which makes it safe as an aggregation key in a counter or
alerting pipeline. Its stability as a key is guaranteed; the term's internal
structure is not — treat it as opaque and don't parse it.

When the event reports an assertion that could not be *evaluated* (see
`Bond.AssertionEvaluationError` under "Error structs"), the metadata also
carries `:exception` (the original exception raised by the assertion
expression) and `:original_stacktrace`. Both are **absent** for an ordinary
violation, which is how a handler distinguishes the two; `:kind` remains the
contract kind in both cases.

The event is published *before* the corresponding error struct is raised, so
telemetry handlers see every assertion failure even when an upstream
`rescue` swallows the exception.

## Error structs

All five are raised by Bond, all five are catchable, all five share the same
shape (defined by the internal `Bond.AssertionError` `__using__` macro). Being
catchable does not make them control flow — see
[Should I rescue a `Bond.PreconditionError`?](faq.md#should-i-rescue-a-bond-preconditionerror)

  * `Bond.PreconditionError`
  * `Bond.PostconditionError`
  * `Bond.InvariantError` — covers struct `@invariant` and, for `Bond.Server`,
    `@state_invariant` / `@transition_invariant`; the `:kind` field distinguishes them
  * `Bond.CheckError`
  * `Bond.AssertionEvaluationError` — raised when an assertion *expression* itself
    raises rather than returning truthy/falsy. Not a violation: the assertion could
    not be evaluated, so it is neither known to hold nor known to fail. See the
    "Assertions must be total" section of the
    [Writing sound assertions](writing-sound-assertions.md) guide.

Public fields on every error struct:

  * `:label` — `t:Bond.assertion_label/0` (`atom() | binary() | nil`).
  * `:kind` — the assertion kind: `:precondition`, `:postcondition`, `:invariant`,
    `:state_invariant`, `:transition_invariant`, or `:check`. On `Bond.InvariantError`
    it distinguishes the three invariant flavours; on the others it is redundant with
    the struct type.
  * `:expression` — `t:Bond.assertion_expression/0` (the AST of the asserted
    expression).
  * `:file` — `Path.t()`.
  * `:line` — `integer()`.
  * `:module` — `module()`.
  * `:function` — `{name :: atom(), arity :: non_neg_integer()}` tuple.
  * `:binding` — `keyword()` of in-scope variables at the assertion site. Bond's
    own generated variables are filtered out, so the keys are names you wrote,
    with one exception: an argument whose clauses disagreed on a name has no name
    to show, and appears under a 1-based positional label (`arg_1`, `arg_2`, …).
  * `:exception` — `Exception.t() | nil`. Set only when the assertion *expression*
    raised rather than returning truthy/falsy, in which case the raised error is a
    `Bond.AssertionEvaluationError` and this is the original exception. `nil` for an
    ordinary violation, which is what distinguishes the two in a handler.
  * `:original_stacktrace` — `Exception.stacktrace() | nil`. The stacktrace of
    `:exception`, when set.
  * `:source_behaviour` — `module() | nil`. The behaviour an inherited contract
    came from (`Bond.Behaviour`), or `nil`.
  * `:source_protocol` — `module() | nil`. The protocol a contract was declared
    on (`Bond.Protocol`), or `nil`.
  * `:impl` — `module() | nil`. When `:source_protocol` is set, the
    implementation the failing call resolved to (or `nil` if unresolved).
  * `:source_contract` — `{module(), name :: atom()} | nil`. The named contract
    (`defcontract`/`@apply_contract`) an applied assertion came from, or `nil`.

The `Exception.message/1` format is rendered by `Bond.AssertionError.message/2`
and is human-readable — the exact text is *not* part of the public surface
(see the stability doc).

## Application config keys

All under the `:bond` application. These are read at compile time (and, for the
per-kind modes, used to seed the runtime state that `Bond.Config` controls):

  * `:preconditions` — mode (`true | false | :purge`).
  * `:postconditions` — mode.
  * `:checks` — mode.
  * `:invariants` — mode.
  * `:overrides` — list of `{module() | Regex.t(), keyword()}` tuples.
    The keyword list uses the same per-kind keys above (`:preconditions`,
    `:postconditions`, `:checks`, `:invariants`, `:warn_skipped_invariants`,
    `:warn_unavailable_preconditions`).
    First exact-match module wins over regex matches; regex matches are
    tried in list order.
  * `:warn_skipped_invariants` — boolean (default `true`).
  * `:warn_unavailable_preconditions` — boolean (default `true`).
  * `:lint_assertions` — boolean (default `true`). Compile-time: emit warnings
    for statically vacuous assertions (see `Bond.Compiler.Linter`).
  * `:coverage` — boolean (default `false`). Compile-time: instrument every
    assertion so `Bond.Coverage` can record checked/failed counts. A build that
    leaves it off is unchanged and pays nothing.

The contract-checking chain `preconditions ≤ postconditions ≤ invariants` is
enforced at compile time and at runtime. Compile-time: if a lower kind is
`:purge`, every higher kind must also be `:purge` (this raises a
`CompileError` with a specific diagnostic). Runtime: if a lower kind is
`false`, every higher kind is also skipped, and Bond logs a one-time
`Logger.warning` per process per `(higher, lower)` pair. `:checks` is
orthogonal to the chain.

## Types

Two public types referenced from public specs:

  * `t:Bond.assertion_label/0` — `binary() | atom()`.
  * `t:Bond.assertion_expression/0` — a quoted expression AST tuple
    (`{atom(), Macro.metadata(), list()}`).

An internal `assertion_kind` type also exists in `Bond` (`@typedoc false` —
the union `:precondition | :postcondition | :check | :invariant`), but it's
referenced only from internal-to-internal sites. Direct use is not supported.

## What is *not* part of the public surface

The following exist in Bond's source tree but are explicitly **not** covered
by the stability guarantees:

  * Every module under `Bond.Compiler.*` and `Bond.Runtime.*` (all marked
    `@moduledoc internal: true`, all filtered out of hexdocs). These are
    Bond's compile-time and runtime implementation; direct use of any of them
    is unsupported and may break on a patch release.
  * The `__opaque__/1` and `__truthy__/1` helpers in `Bond.Predicates` —
    called by Bond-generated code, not by users. Their existence is stable
    insofar as the generated code relies on them, but the *interface
    contract* (what they accept, return, or do internally) is not.
  * The shape of the wrapper and helper functions Bond generates into the
    user's module. The names (`__bond_preconditions__<fun>__<arity>`,
    `__bond_postconditions__...`, `__bond_invariants__...`) are not stable.
  * `__bond_contracted__/0`, the reflection `mix bond.audit` reads. Every module
    that `use Bond` exports it, and it is emitted even when the module contracted
    nothing, so `function_exported?/3` distinguishes "uses Bond and contracts
    nothing" from "does not use Bond". Both that behaviour and the shape of the
    map it returns are **provisional**: `mix bond.audit` is the supported way to
    get at this data. Building other tooling on the reflection directly is
    exactly the use case that would promote it — open an issue.
  * The text of compile-error diagnostics raised by Bond's macros. These are
    user-facing prose that may be reworded for clarity; the **fact** of a
    diagnostic firing (e.g. "labelled @invariant 2-arg form is removed")
    is stable, but the exact wording is not.
  * The text of runtime error messages emitted by `Exception.message/1` on
    `Bond.PreconditionError` et al. The error **struct fields** are stable
    (see above); the rendered message is not.
  * Telemetry handler invocation order (Bond emits a single event; if
    multiple handlers are attached, the OTP-defined order applies — not
    Bond's concern).

If you need any of the above to remain stable for a use case, open an issue
describing the use case; we'll consider promoting the specific piece into the
public surface in a future minor.
