mathema accept¶
The human decision verb: annotate one adjudicated claim with an explicit acceptance. Prompted; the exact write is printed first and nothing happens without a yes. Deliberately CLI-only: acceptance is a human act, never exposed to agent tooling or any MCP surface.
mathema accept KEY CLAIM --as evidence|risk|discovery [--by NAME] [--note TEXT]
mathema accept KEY --as reconciled [--from OLD_KEY]
Three acceptances cover the everyday loop (evidence, risk,
discovery). Four more handle record housekeeping, each with its own
section below: historical and superseded retire a claim with its
history intact, reconciled restamps a record after a merge or rebase,
and trusted records testimony from a source you vouch for. --intent
and --concepts accept the function's stated intent and concept tags.
Arguments¶
| Flag | Meaning |
|---|---|
key |
function key (the record under .mathema/verified/) |
claim |
claim name inside that record (omit for --as reconciled, which acts on the whole record) |
--as |
evidence, risk, discovery, historical, superseded, trusted, or reconciled (see below). In text mode you can omit it and mathema reads the claim's verdict and proposes the natural kind; --format json never guesses, and without --as it exits 2 |
--all |
with --as reconciled and no key: reconcile every record whose checksum no longer matches, in one act |
--from OLD_KEY |
with --as reconciled: rename OLD_KEY's record to KEY, for a function that moved (see moved functions) |
--accept-form-change |
with --from: rename even though the record's form hash differs from the live function's |
--by |
who decided (default: git config user.name) |
--note |
free-text rationale, kept in the record |
--yes |
skip the confirmation prompt (for scripted use by a human; never wire this into agent tooling) |
--root |
project root (default .) |
--format |
text (default) or json: emit the acceptance as data. Without --yes this is a preview that writes nothing; JSON mode never prompts |
--output FILE |
write the report to a file instead of stdout |
The three everyday acceptances¶
--as evidence: aholdsverdict has enough empirical support for your purposes. The record keeps the acceptance alongside the verdict; a later run with weaker evidence warns.--as risk: you own anunknownorskippedgap. The claim reclassifies to an accepted state thatverify --lenientproceeds past (named in the row as accepted risk) while strict mode still refuses it. This is the only way an unknown claim stops failing the gate, see what fails the run.--as discovery: a falsification that was right about the code and wrong about the claim: the function's actual behavior is the interesting fact. Accepting it retires the claim into the record's discoveries section, permanently, with the counterexample kept as the witness; every falsified claim can be accepted this way, whatever its shape. A corrected claim is declared alongside only when it is verified first. State it yourself with--corrected "<law>"and mathema adjudicates it against the live function before anything is written (a correction that itself falsifies is refused, with the counterexample named). Without--corrected, a mechanically sound inverse (a bare single relation flipped, or a predicate through the grammar'snotform) may be offered, but only after it has been adjudicated and holds; a chained comparison, anassumingpremise, aletsection, or an inverse that fails adjudication is never guessed at, and the discovery is simply recorded with no replacement. When a correction is written, it carries its real adjudicated verdict. The acceptance also keeps the declared layer honest: any claims file stating the retired law is rewritten as part of the act (the stanza replaced by the correction, or removed when there is none), because a leftover declaration would regenerate the falsification on the next real sweep. A docstring or decorator surface cannot be rewritten by an acceptance, soverifyskips the retired law there with a non-fatal note naming the remedy until the source changes; a DIFFERENT law under the same name is new authorship and adjudicates normally.
What is acceptance? Verification says what the machine established;
acceptance is where a person takes accountability for what to do about
it. It is integral to the CDD loop, not an add-on: evidence is adjudicated
by the tool, but the decision to rely on a holds, to own a gap, or to
adopt a corrected claim is a human's, and the record carries whose. You do
not have to learn the vocabulary first. Run mathema verify to see which
records fail on an unknown or falsified claim, then type mathema accept KEY
CLAIM with no --as (at a terminal; --format json always needs --as),
and mathema reads the claim's verdict and proposes
the natural kind (a holds is evidence, an unknown is a risk, a
falsification is a discovery), then asks you to confirm. You take the
decision by saying yes, not by memorising a vocabulary.
A configured PIN is prompted for before any acceptance
writes, and the record's accepted block gains a
verified_by: {method, key} stamp, evidence the decision was made by
a person rather than an agent. Optional, and off until
mathema pin set; a record with no human sign-off states pin: none
in its identity block, so the absence is explicit, never inferred.
There is deliberately no accepting a bug: if the code is wrong, fix the code, the recorded counterexample replays on every re-adjudication until the claim proves, so a falsified claim can't be waved through.
Machine-readable acceptance¶
--format json emits the acceptance as data, and writes nothing
unless --yes is also given: without it you get the plan
(applied: false, plus the actions that would run), so a client can
render the decision for a human and only then commit it. JSON mode
never prompts, so a non-interactive caller can't hang waiting on
stdin, and the human gate stays exactly where it always was. A refusal
comes back as {"ok": false, "error": ...} with the same exit code
the prose path uses; --output FILE writes the payload to a file.
The same envelope covers every acceptance path, claim, function
intent, scope intent (module or __project__), and concepts, with
kind naming which one.
Form-bound¶
Every acceptance binds to the function's form hash at the moment of
the decision. Change the function and the acceptance goes stale
outright; the gap or evidence you accepted was about different code,
so the claim fails the gate again until someone re-decides.
Worked example¶
A running balance in balances.py, with three claims in
claims/running_total.claims.yaml:
def running_total(xs: list, y0: float) -> float:
"""Add every value in xs to a starting balance y0."""
total = y0
for v in xs:
total = v + total
return total
balances.running_total:
claims:
- name: shifts_with_start
statement: "f(xs, y0) == f(xs, 0) + y0"
- name: nonneg_for_nonneg_steps
statement: "for xs in [0, 1]^n, f(xs, 0) >= 0"
- name: never_overshoots_much
statement: "assuming nonneg_for_nonneg_steps is proven, for xs in [0, 1]^n, f(xs, 0) <= len(xs)"
shifts_with_start is proven (and its shifts_with_start[float]
companion holds). nonneg_for_nonneg_steps only holds: the probe
agrees, but derive cannot settle the sign of the lifted sum.
never_overshoots_much rests on it being proven, so it comes back
unknown with the note prerequisite nonneg_for_nonneg_steps is holds,
not proven, nothing to rest this claim on, and verify fails on it
(see mathema verify):
$ mathema verify --root .
FAIL balances.running_total: no baseline record; 2 proven, 2 holds, 0 falsified, 1 unknown <- 1 unknown claim(s)
0 fresh (form unchanged, skipped), 1 adjudicated, 1 problem(s)
grammars detected: mathema; verified by this run: mathema
Owning that gap is a decision. At a terminal, mathema prints the exact
write and asks write this acceptance? [y/N]; --yes answers it here:
$ mathema accept balances.running_total never_overshoots_much --as risk --note "the premise only holds empirically; monitored" --by "Charles Babbage" --yes
accepting balances.running_total :: never_overshoots_much (verdict unknown) as risk, by Charles Babbage
- reclassify never_overshoots_much: unknown -> skipped:unknown_but_accepted (strict mode still refuses it; lenient proceeds)
written: reclassify never_overshoots_much: unknown -> skipped:unknown_but_accepted (strict mode still refuses it; lenient proceeds)
--as historical¶
A claim the code has moved past, a parameter renamed or removed, so
its variables no longer match the signature, is flagged by verify
and accepted as history: the row leaves the live claims for the
append-only historical: section, carrying the git commit its last
supported adjudication was stamped with. It stops gating and never
resurrects.
--as superseded¶
Re-authoring a claim that is already in the verified layer (the same name with a different statement, region, tolerance or route on any authoring surface) is a conflict verify flags, and the verified version keeps adjudicating until a human adopts the change:
mathema accept mypkg.mod.fn claim_name --as superseded
Any verdict can be superseded. The old row moves to the record's
superseded: section (carrying the commit of its last supported
adjudication), and the next sweep adjudicates the authored version
as the live claim under the same name. This is how a claim's meaning
changes without its history being silently rewritten.
--as reconciled: after a merge, rebase, or a declared-claim edit¶
Every verified record carries an
integrity checksum over its
claims, verdicts, and sign-offs, and an anchor (the commit it was stamped at).
When the record's contents no longer match the checksum, verify says
so, and now that .mathema/ is tracked, ordinary git makes this happen
without anyone hand-editing anything: a merge or rebase brings in a
different version of a record, a stash pop restores an in-progress one,
or you append a declared claim to a function that already has a verified
row. The warning names the likely cause (a moved anchor reads as a
history rewrite; an intact one as a content change) and never accuses
you of tampering. Under a policy with
require_verification, the mismatch fails the run instead of warning.
Two ways to clear it:
- Re-verify (
mathema verify <key>, or the whole sweep): re-adjudicates against the live code and re-stamps. This is the default and the right move after a merge, it re-checks as well as re-stamps. - Reconcile when the contents are already correct and you just want to bless them as they stand (a large suite, a record you have reviewed):
mathema accept mypkg.mod.fn --as reconciled
The key is the function record (its module.qualname), and reconcile
covers ALL of that record's claims at once, never one claim at a time. A
human vouches for the current contents, re-stamps the integrity, and
re-anchors to HEAD, records who reconciled it and when, and carries the
PIN stamp when one is configured, so an agent cannot pass it
off as a human decision. With no PIN set it still works and records
pin: none, so an unpinned reconcile stays visible as exactly that.
A merge usually touches more than one record, so clear the whole set in
one act with --all (no key):
mathema accept --as reconciled --all
It lists every record whose checksum no longer matches, asks once, and re-stamps them all under a single sign-off.
Moved functions: --as reconciled --from¶
A record is keyed by the function's dotted module.qualname, so moving
a function to another module (or renaming it) leaves its record behind
under a key that no longer resolves. verify notices when that orphan's
form hash matches a function that has no record, and prints the rename
as the remedy. Moving running_total from balances.py to
ledger.py, with its claims file stanza renamed to match:
mv balances.py ledger.py
ledger.running_total:
claims:
- name: shifts_with_start
statement: "f(xs, y0) == f(xs, 0) + y0"
- name: nonneg_for_nonneg_steps
statement: "for xs in [0, 1]^n, f(xs, 0) >= 0"
- name: never_overshoots_much
statement: "assuming nonneg_for_nonneg_steps is proven, for xs in [0, 1]^n, f(xs, 0) <= len(xs)"
$ mathema verify --root .
FAIL balances.running_total: cannot resolve to a live function (declared in .mathema/verified/balances.running_total.yaml); its form hash matches ledger.running_total, which has no record. If it moved, a human keeps its history with: mathema accept ledger.running_total --as reconciled --from balances.running_total
FAIL ledger.running_total: no record yet, and its form hash matches the orphan record balances.running_total; nothing was adjudicated or written for this key. If it moved, a human keeps its history with: mathema accept ledger.running_total --as reconciled --from balances.running_total; if it is a different function, remove the orphan record instead
0 fresh (form unchanged, skipped), 0 adjudicated, 2 problem(s)
grammars detected: (none); verified by this run: mathema
The new key gets no fresh record in the meantime, because a fresh
record would start its history over. The rename is a human act, since
only a person can say the two are the same function (again with
--yes standing in for the prompt, write this rename? [y/N]):
$ mathema accept ledger.running_total --as reconciled --from balances.running_total --by "Charles Babbage" --yes
reconciling ledger.running_total from balances.running_total: a record rename, by Charles Babbage
- rename the record balances.running_total to ledger.running_total, carrying its claims, acceptance history, lineage and sign-offs
- remove .mathema/verified/balances.running_total.yaml
- re-stamp the integrity and re-anchor it to HEAD
written: reconciled: balances.running_total renamed to ledger.running_total (by Charles Babbage)
next: `mathema verify ledger.running_total` re-adjudicates it at its new location
The record moves whole: every claim row with its acceptance and
acceptance history, the discoveries, historical and superseded
sections, the lineage, and a lock if there is one. Like any reconcile
it re-stamps the integrity, re-anchors to HEAD, and records who did
it, when, and where the record came from (identity.reconciled.from),
with the PIN stamp when one is configured. The old record
file is removed, so no orphan is left behind.
The rename is refused (exit 1, nothing written) when the old key still
resolves (that is a copy, not a move) or the new key already has a
record. An old key with no record, or a new key that does not resolve
to a live function, is exit 2. When the record's form hash differs
from the live function's, the rename asks a second question at the
prompt, since the record was made for different code; --yes does not
answer it, and --accept-form-change does. The record then keeps its
recorded form, so the next verify re-adjudicates it against the code
it now names, and identity.reconciled.form_changed states both hashes.
Working with git. The advice is one line: after a merge, rebase, or
conflict resolution that touched .mathema/, run mathema verify to
re-adjudicate and re-anchor. The integrity warning in that window is
expected, not evidence of tampering, and either fix above clears it.
mathema init scaffolds the git ergonomics for a tracked
store: a .gitattributes marking .mathema/verified/**/*.yaml
linguist-generated (a records diff collapses by default and the store
drops out of the repository's language stats, while staying expandable
when you do want to read it), and a .mathema/.gitignore that tracks the
durable evidence and required artifacts (verified/, meta/,
compendium/, badges/) while ignoring regenerated state (declared/,
issues/). It is additive and idempotent, so running it on an existing
project only fills in what is missing.
To review what actually changed in the store between two states, read it
by CLAIM rather than by raw YAML: mathema review [<ref>]
reports which verdicts flipped, which claims were added or removed, which
are newly falsified, and which records were reconciled, since a base ref
(default HEAD). --format json emits the same delta for a CI job to
post as a PR comment. It is the counterpart to a git diff over
.mathema/verified/, whose re-anchored lineage and reordered rows bury
the handful of facts a reviewer needs.
--intent and --concepts¶
mathema accept <key> --intent is the human rung: it moves the
function's stated intent from declared to documented, binding to
the signature, the raised-exception surface, and the intent text
(a body-only refactor keeps it; any of those changing re-opens it).
The key can also be a module (mypkg.mod) or the literal
__project__: scope-level intents (module docstring or README
sections) accept the same way, bound to the intent text alone, and
land in .mathema/meta/intent.yaml; the index reports each scope's
rung and flags a stale acceptance when the text has moved on.
--concepts a,b accepts tags as documented; --dismiss-concepts c
records a dismissal in .mathema/meta/concepts.yaml so the
suggestion never repeats. All prompted, all CLI-only, like every
acceptance.
--as trusted¶
A compendium row (curated knowledge about a library, materialised
into the store at declared status when a premise first references
it) accepted at the level its curator claims. The row's verdict
becomes that level, the acceptance records the source
(compendium:numpy-2.5), and every conclusion resting on the row
caps there. The alternative needs no verb at all: mathema verify
re-adjudicates the row against the installed library, and the local
verdict replaces the testimony. See
Claims transfer.