mathema claims¶
The claim authoring surface for one function: list what's declared, render the standard claims mathema suggests for it, and adopt a suggestion into the declared layer. Adoption is an explicit step, which a person or an agent may take; a suggestion never lives in any record until it is adopted.
mathema claims KEY # list the declared claims
mathema claims KEY --suggest # render the suggested standard claims
mathema claims KEY --adopt NAME # write one into the declared layer
mathema claims KEY --write # write the policy rows
Arguments¶
| Flag | Meaning |
|---|---|
key |
module-qualified function key (functions.softmax) |
--suggest |
render the suggested standard claims with laws, in three sections: individual claims, questions with candidate answers, and claims likely to be unknowable |
--adopt NAME |
write the named suggestion into claims/adopted.claims.yaml |
--write |
write the policy rows mathema suggests, what each parameter does with a value that is not there, into claims/policies.claims.yaml, each under the name the record prints, a contradicted one with the contradiction in its note |
--root |
project root (default: the nearest ancestor holding .mathema/ within the enclosing git repository, else that repository, else .; never the home directory) |
--format |
text (default) or json: emit --suggest's rows columnar, matching the MCP suggest_claims tool |
--output FILE |
write the report to a file instead of stdout |
Policy rows¶
Beside the declared claims, mathema claims KEY lists the policy rows
the record carries: what the function does with a missing or absent
input, grouped by state (missing values says
what each word means). --write writes them to
claims/policies.claims.yaml under their record names (missing[x],
missing[xs, null], absent[x], absent[d.note, unset] for a key
along a path), each with a note saying where it
came from. A row the code contradicts is written too, its note saying
so with the date, and the write line names the three ways out: change
the word, change the code, or accept it as a discovery. A raise no
claim accounts for has no word to write; the write line names the claim
to state instead. Changing a policy is then editing one word.
Where suggestions live (and where they never do)¶
Suggestions are helpers for authoring standard claims, determinism, reproducibility, domain safety, a missing-value policy, inferred from the function's structure and types. They are rendered for a decision, not recorded as fact:
- A verified record (
.mathema/verified/) never contains a suggestion.mathema checkdisplays suggested claims' adjudications so you can see whether one is worth adopting, but only claims you actually stated gate an exit code. A falsified suggestion is still shown prominently: it's real knowledge about the function, and a reason not to adopt. - The declared layer is a consolidation of authoring surfaces
(docstring claims, decorators, declared YAML), so an adopted
suggestion goes there, as an ordinary declared claim in
claims/adopted.claims.yaml, indistinguishable from one you wrote by hand, and gated like one from then on.
Worked example¶
functions.py holds the softmax from the
check worked example,
without its Claims: block:
import math
from typing import Annotated
from mathema.types import Shape
def softmax(scores: Annotated[list[float], Shape("n")]) -> Annotated[list, Shape("n")]:
"""Turn a vector of real-valued scores into a probability distribution."""
if not scores:
raise ValueError("softmax needs at least one score")
m = max(scores)
exps = [math.exp(s - m) for s in scores]
total = sum(exps)
return [e / total for e in exps]
$ mathema claims functions.softmax
functions.softmax: no declared claims (to list candidates, run: mathema claims functions.softmax --suggest)
$ mathema claims functions.softmax --suggest
functions.softmax: 9 suggested claim(s) (adopt with: mathema claims KEY --adopt NAME)
effects: no side effects
individual claims:
- is_deterministic: f(scores) == f(scores) [route best]
- is_state_safe: f(scores) == f(scores) [route best]
- is_empty_safe[scores]: is_empty_safe(scores) [route examine]
- is_dimension_safe[f]: is_dimension_safe(f) [route examine]
- preserves_length: dim(f(scores), 0) == dim(scores, 0) [route probe]
- is_permutation_of_input: sorted(f(scores)) == sorted(scores) [route probe]
- preserves_type: type(f(scores)) == type(scores) [route probe]
- is_sorted_output: is_sorted_output(f(scores)) [route examine]
- is_missing_safe[f]: is_missing_safe(f) [route examine]
$ mathema claims functions.softmax --adopt is_deterministic --root .
adopted is_deterministic into ./claims/adopted.claims.yaml: f(scores) == f(scores)
$ mathema claims functions.softmax
functions.softmax: 1 declared claim(s)
- is_deterministic: f(scores) == f(scores) [route best]
functions.softmax: 1 policy row about scores
confirmed by the code (to write these, run: mathema claims functions.softmax --write):
holds missing[scores]: missing(f, scores) propagates [default for a list[float] slot that may be nan; confirmed on 4 calls. Change the word to raises or drops if f should do otherwise; to keep it, run: mathema claims functions.softmax --write]
The adopted stanza is plain declared-claims YAML, so it's yours to edit or delete like anything else in the file:
cat claims/adopted.claims.yaml
functions.softmax:
claims:
- name: is_deterministic
statement: f(scores) == f(scores)
route: best
grammar: mathema
The three sections¶
--suggest lists its suggestions in three sections.
- Individual claims stand alone: each answers a question no other suggestion answers.
- Questions with candidate answers. The battery volunteers every
candidate it knows, so a scalar function earns both monotonicity
directions and all three curvature answers per parameter. Those are
not independent claims:
monotonic_increasing[x]andmonotonic_decreasing[x]answer one question (which way does f move in x), andaffine[x],convex[x],concave[x]answer another (which way does f bend in x). Each question is listed by itsaspect[target](monotonicity[x],shape[x],symmetry) with its candidate answers under it. More than one answer may hold (an affine function is convex and concave too), so adopt every answer that does; they are never contradictions. The table ismathema.families.CLAIM_ASPECTS. - Likely to be unknowable.
is_state_safe,is_deterministicandis_reproducibleare decided by reading the function's source. When that reading meets something it cannot read (getattr, a library function it has no entry for), the suggestion is listed here with that reason on the line below it. It is never adopted unless named.
The effects the reading finds are always shown, on a line under the
count. is_state_safe is suggested only for a function with no side
effects at its default values: when the reading already sees a write,
the effects line states it and there is nothing to adopt. For a function
that stores a rate in the environment:
import os
def remember(rate: float) -> float:
"""Store the rate for later runs and return it."""
os.environ["R"] = str(rate)
return rate
mathema claims rates.remember --suggest --root .
rates.remember: 12 suggested claim(s) (adopt with: mathema claims KEY --adopt NAME)
effects: changes os.environ (os.environ['R'] = ...)
individual claims:
A stronger relation, a genuine contradiction where adopting a second
member is not a refinement but a conflict, lives in the separate
mathema.families.EXCLUSIVE_GROUPS: --adopt refuses a member whose
exclusive group already has a declared member, naming the clash. No
exclusive group is populated today, since every shipped family that
shares a question does so as alternatives (affine implies both convex
and concave, so those three are alternatives, not rivals), not as a
contradiction.
Relation to enforce_domain¶
The enforce_domain decorator works from the same
declared layer in the other direction: it reads every parameter
interval already declared on the function's claims and wraps the
function with runtime guards, so arguments outside the declared domain
raise DomainError instead of silently computing. A function whose
domain is actually enforced has answered the domain-safety question a
suggestion would otherwise be asking.
--format json¶
mathema claims KEY --suggest --format json emits the suggestions
columnar, the same shape and columns the MCP suggest_claims tool
returns:
cols: ["name", "statement", "route", "declared", "aspect", "section", "reason"]
declared is true when that name is already in the declared layer,
and aspect names the question a suggestion answers ("" when no
other suggestion answers it, a computed-empty value, never null).
section is individual, question or unknowable, and reason
is the one-line reason for an unknowable row ("" on every other
row). --output FILE writes it to a file instead of stdout.