Only the codes this command can produce. The full contract is on the commands index.
0ok
2usage
10contract unmet
12missing artifact
15refused
The finish contract
Choose a situation and see whether the outcome is accepted or refused, and for which reasons. Every scenario here is executed against the real binary by test/cases/34_command_fixtures.sh, so this page cannot claim behaviour the tool does not have.
Nothing in place yet
no open blocker
yes
note present
no
scope respected
yes
verification given
no
Given this repository
# ... and an active task scoped to lib, with work done inside that scope.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" start "narrow the parser" --scope lib >/dev/null
echo work >> lib/a
Run
$ majordomus finish --outcome completed
Output contains
FAIL verification
FAIL note
refused
exit10
Two contract lines are unmet and both are named at once. A worker who fixes one and is refused again for the next learns the contract one round trip at a time, so every cause is reported together.
Work outside the claimed scope
no open blocker
yes
note present
yes
scope respected
no
verification given
yes
Given this repository
# An active task scoped to lib, with a change made under docs that it never claimed.
. "$FIXTURE_SETUP/active-task.sh"
echo stray >> docs/d
The task claimed lib. A change under docs is work the task did not claim, and it is refused whatever else is in place.
An unresolved question is open
no open blocker
no
note present
yes
scope respected
yes
verification given
yes
Given this repository
# An active task with an unresolved question open against it.
. "$FIXTURE_SETUP/active-task.sh"
"$MJ" question add "does the parser need to accept tabs?" >/dev/null
An open question refuses completed, and only completed. The same task can be finished as blocked, which is the honest outcome when the answer is not yours to give.
The verification command runs and fails
no open blocker
yes
note present
yes
scope respected
yes
verification given
no
Given this repository
# An active task with the note the outcome requires already written.
. "$FIXTURE_SETUP/active-task.sh"
printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n' | "$MJ" handover >/dev/null
The command is run, not asserted. Its exit code and duration are recorded whatever it returns, so "verification ran" cannot be claimed without something having actually run.
finish --check with no active task
no open blocker
yes
note present
yes
scope respected
yes
verification given
yes
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
Run
$ majordomus finish --check
Output contains
nothing to enforce
exit0
This is why a pre-push hook can run finish --check unconditionally: a repository with no active task is not a failing repository.
Everything in place
no open blocker
yes
note present
yes
scope respected
yes
verification given
yes
Given this repository
# An active task with the note the outcome requires already written.
. "$FIXTURE_SETUP/active-task.sh"
printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n' | "$MJ" handover >/dev/null
Accepted, and the ledger records the outcome together with the verification that earned it.
Reference
Evaluate the finish contract. Refuse if unmet.
Reads: policy, profile, current.yaml, git, ledger.
Writes: on success, current.yaml outcome set to the given value, one
task.finished ledger line carrying the evaluated checklist and the verification
result, and a copy of --note under state/completed/<id>.md when given.
Arguments:--outcome completed|partial|blocked|no_match|failed required.
--verify-command "<cmd>" runs the project's own verification in the repository root
and records its exit code, duration, and command. --note <file> supplies the
completion note; otherwise the newest handover naming this task is used. --check
evaluates scope and state without writing and exits 0 when no task is active or the
task is already finished, so a pre-push hook never blocks a repository with nothing to
enforce.
Profile requirements are also evaluated for completed: regression_test_required
passes when a touched path looks like a test (test/, spec/, _test., .spec.);
decision_record_required passes when decisions.md contains Task: <id>. The
regression check is deliberately crude and says so in its message.
Contract for completed:
scope respected touched files within claimed pathsverification ran --verify-command exited 0, recordedstate updated current.yaml is at HEAD or advanced, not divergedno open blockers open-questions.md has no unresolved entry for this tasknote present newest handover or completion note has required sections
Every line of the contract is evaluated and printed, pass or fail, so that a refusal
says exactly what is missing. partial and blocked require a note with # Next Action; no_match and failed require # Reason; all four skip the verification
line, and blocked skips the blockers line. Nothing is written when any line fails.
Finishing an already finished task is refused (15).
$ majordomus finish --outcome completed --verify-command "make test"OK scope 12 files, all within lib/authOK verification make test — exit 0, 41sOK state exact (head 9b1e2d4)FAIL blockers open-questions.md: "token refresh window — needs product decision" unresolved [reproduce: grep -n 'unresolved' .ai/local/state/open-questions.md]OK note handover 20260903T201455Z--main--9b1e2d4--c0ffee.mdfinish: refused, 1 unmetblocking doctrines:- majordomus.blocker-resolution$ echo $?10
The contract is not a list inside finish. It is the set of doctrines whose
enforced_by names finish, selected by this repository's
verification.finish_requires. A requirement in the policy that no doctrine defines is
reported and refuses, rather than being ignored. See
DOCTRINE.md.
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.