Only the codes this command can produce. The full contract is on the commands index.
0ok
2usage
12missing artifact
13internal error
15refused
What the task owed, and what proves it
A task's scope says where a worker may write. Its requires says what the worker owes. Evidence discharges one obligation, and carries the hash of the files that obligation names, so that changing any of them takes the proof away rather than leaving it behind.
Recording a discharge
active task
yes
the task owes tests
yes
Given this repository
# ... and an active task that owes an obligation, with work done inside its scope. The
# obligation is written into the record the way a caller would declare it, because what the
# scenario is about is the discharge, not how the list got there.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" start "narrow the parser" --scope lib >/dev/null
echo work >> lib/a
python3 - <<'PY'
import io
p = '.ai/local/state/current.yaml'
s = io.open(p, encoding='utf-8').read()
io.open(p, 'w', encoding='utf-8').write(s.replace('outcome:', 'requires:\n - tests\noutcome:'))
PY
Run
$ majordomus evidence --covers tests --type test --command bash test/run.sh
Output contains
evidence: tests recorded
exit0
The line lands in the ledger, which is already append-only and integrity-checked, and carries the hash of the tracked files the obligation names. Nothing else is written; a second store of evidence would be a second account of the same facts.
For something the task never promised
active task
yes
the task owes tests
yes
Given this repository
# ... and an active task that owes an obligation, with work done inside its scope. The
# obligation is written into the record the way a caller would declare it, because what the
# scenario is about is the discharge, not how the list got there.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" start "narrow the parser" --scope lib >/dev/null
echo work >> lib/a
python3 - <<'PY'
import io
p = '.ai/local/state/current.yaml'
s = io.open(p, encoding='utf-8').read()
io.open(p, 'w', encoding='utf-8').write(s.replace('outcome:', 'requires:\n - tests\noutcome:'))
PY
Recording evidence against an obligation nobody declared is how a checklist grows entries nobody asked for. The refusal names what the task does require.
Without a command or an artifact
active task
yes
the task owes tests
yes
Given this repository
# ... and an active task that owes an obligation, with work done inside its scope. The
# obligation is written into the record the way a caller would declare it, because what the
# scenario is about is the discharge, not how the list got there.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" start "narrow the parser" --scope lib >/dev/null
echo work >> lib/a
python3 - <<'PY'
import io
p = '.ai/local/state/current.yaml'
s = io.open(p, encoding='utf-8').read()
io.open(p, 'w', encoding='utf-8').write(s.replace('outcome:', 'requires:\n - tests\noutcome:'))
PY
Run
$ majordomus evidence --covers tests
Output contains
narrative is not evidence
exit2
An assertion that something was done is the thing this command exists to replace. Either a command produced the evidence or an artifact points at it.
With no active task
active task
no
Given this repository
# A repository with Majordomus installed and projections generated, and one commit of work.
"$MJ" init >/dev/null
"$MJ" update >/dev/null
mkdir -p lib docs
echo a > lib/a
echo d > docs/d
git add . && git commit -qm base
A task's scope says where a worker may write; its requires says what the worker owes
before the outcome completed is available. The tokens are declared in
share/obligations.yaml — implementation, tests, docs, generated, rules, commit, push,
target, pages, deploy, verify — each naming the command that discharges it and, where the
fact is local, the pathspecs its evidence is taken over.
Four of them are never recorded here. commit, push, target and pages name facts the
tool can establish — a clean tree, a remote-tracking ref that reaches the head, a trunk that
reaches it, a published site that serves it — and check and finish settle those live at
HEAD instead of asking a worker to transcribe them. Recording one has no effect: an
established obligation discharges by being true and refuses by being false. Where the
checkout cannot settle it (no remote, no default branch recorded, a site that never
answered) the token falls back to the recorded line, and the finding says which it was.
deploy and verify stay hand-recorded, and share/obligations.yaml says in one line why:
a deployment is a fact about a machine this repository never contacts.
--command or --artifact is required: narrative is not evidence. A token the vocabulary
does not declare exits 2; a token the active task never promised exits 15, because
recording evidence for something nobody asked for is how a checklist grows entries nobody
wanted.
Writes: a task.evidence line in the ledger, carrying the obligation, how it was taken,
the command or artifact, and the hash of the tracked files the obligation names. Nothing
else is written; the ledger is already append-only, ordered and integrity-checked, and its
envelope already carries the head, the branch and the session.
That hash is the point. Evidence discharges an obligation only while the recomputed hash of
its inputs equals the recorded one, so a change to any file the obligation names takes the
proof away rather than leaving it behind — the same currency question the site's own
source_hash asks, asked of a test result. An obligation whose fact is remote (a push, an
integration, a publication, a deployment) has no inputs and is bound instead to the commit
it was taken at, judged exact | advanced | diverged | different_context like every other
record here.
check and finish evaluate every obligation on every run through the doctrine
majordomus.obligation-closure, so a stale evidence is visible before someone builds on
it; only an outcome of completed is refused. A worker reporting blocked is being honest,
and refusing that would teach them to claim completed instead.
Evidence
Every case below runs in CI on Linux and macOS. The site refuses to build if a public command has no behavioural case, no negative case, or no demonstration.