A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
test/cases/04_start_check.sh
An object of kind test
What it is
- URI
majordomus://test/test/cases/04_start_check.sh- Kind
test- Identity
test/cases/04_start_check.sh- Path
test/cases/04_start_check.sh- Provenance
- declared
- Media type
text/plain- As a capability
- test.test/cases/04_start_check.sh
Front matter
{}Content
# majordomus-covers: start check
# majordomus-negative: start check
# claims: consistency-check, divergence-label, git-identity, overlap-report, scope-enforcement, scoped-task
. "$ROOT/test/lib.sh"
"$MJ" init >/dev/null; "$MJ" update >/dev/null
mkdir -p lib/auth lib/other && echo x > lib/auth/a.txt && echo y > lib/other/b.txt && git add . && git commit -qm base
expect_exit 12 "$MJ" check
expect_grep 'no active task'
expect_exit 2 "$MJ" start "no scope"
expect_exit 2 "$MJ" start "escape" --scope ../x
expect_exit 12 "$MJ" start "bad profile" --scope lib/auth --profile nosuch
expect_exit 0 "$MJ" start "fix auth" --scope lib/auth/,./lib/auth/sub --profile debugging --owner alice
expect_grep 'started t-[0-9]+-[0-9a-f]{4} profile=debugging scope=lib/auth,lib/auth/sub'
expect_grep '^head: '"$(git rev-parse HEAD)"'$' .ai/local/state/current.yaml
expect_grep '^branch: '"$(git branch --show-current)"'$' .ai/local/state/current.yaml
expect_grep '^ - lib/auth$' .ai/local/state/current.yaml
expect_grep '"event":"task.started"' .ai/local/state/ledger.jsonl
# git-identity: a body that authors an identity field is refused, and the record keeps git's value
expect_exit 10 bash -c "printf '# Objective\no\nhead: abc\n# Current State\nc\n# Next Action\nn\n' | '$MJ' handover"
expect_grep 'must not contain identity fields; they are computed'
expect_grep '^head: '"$(git rev-parse HEAD)"'$' .ai/local/state/current.yaml
# repeated --scope accumulates; spaces after commas are tolerated; a hand-edited trailing slash still contains
printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n' | "$MJ" handover --close >/dev/null
expect_exit 0 "$MJ" start "multi" --scope lib/auth --scope="lib/other, ./lib/auth/sub/"
expect_grep 'scope=lib/auth,lib/other,lib/auth/sub$'
sed -i.bak 's#^ - lib/auth$# - lib/auth/#' .ai/local/state/current.yaml; rm -f .ai/local/state/current.yaml.bak
echo z >> lib/auth/a.txt
expect_exit 0 "$MJ" check
expect_grep 'OK +scope'
git checkout -q -- lib/auth/a.txt
printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n' | "$MJ" handover --close >/dev/null
expect_exit 0 "$MJ" start "fix auth" --scope lib/auth/,./lib/auth/sub --profile debugging --owner alice
# one active task per checkout
expect_exit 15 "$MJ" start "second" --scope lib/other
expect_grep 'is active'
# healthy check
expect_exit 0 "$MJ" check
expect_grep 'OK +state .* exact'
expect_grep 'OK +scope'
expect_grep 'OK +blockers'
# --explain merges task, profile, policy
expect_exit 0 "$MJ" check --explain
expect_grep '^# profile debugging'
expect_grep '^ effort=high'
# in-scope edits pass; committed too (advanced)
echo z >> lib/auth/a.txt && git commit -qam inscope
expect_exit 0 "$MJ" check
expect_grep 'OK +state .* advanced'
# divergence-label: a recorded head that is not an ancestor of HEAD is diverged
rec=$(sed -n 's/^head: //p' .ai/local/state/current.yaml)
stray=$(git commit-tree "HEAD^{tree}" -m stray)
sed -i.bak "s/^head: .*/head: $stray/" .ai/local/state/current.yaml; rm -f .ai/local/state/current.yaml.bak
expect_exit 10 "$MJ" check
expect_grep 'FAIL state .* diverged from recorded head'
sed -i.bak "s/^head: .*/head: $rec/" .ai/local/state/current.yaml; rm -f .ai/local/state/current.yaml.bak
# out-of-scope edit fails, names the file
echo z >> lib/other/b.txt
expect_exit 10 "$MJ" check
expect_grep 'FAIL scope +lib/other/b.txt — outside claimed scope'
git checkout -q -- lib/other/b.txt
# state files and projections are always allowed
echo "## note" >> .ai/local/state/decisions.md; echo "" >> CLAUDE.md
expect_exit 0 "$MJ" check
git checkout -q -- CLAUDE.md
# unresolved question blocks
id=$(sed -n 's/^id: //p' .ai/local/state/current.yaml)
printf -- '- [unresolved] %s — refresh window? (2026-09-03)\n' "$id" >> .ai/local/state/open-questions.md
expect_exit 10 "$MJ" check
expect_grep 'FAIL blockers .* refresh window'
sed -i.bak "s/\[unresolved\] $id/[resolved 2026-09-03] $id/" .ai/local/state/open-questions.md; rm -f .ai/local/state/open-questions.md.bak
expect_exit 0 "$MJ" check
# checkpoint updates the record and the ledger
old=$(sed -n 's/^checkpoint_at: //p' .ai/local/state/current.yaml); sleep 1
expect_exit 0 "$MJ" check --checkpoint
[ "$(sed -n 's/^checkpoint_at: //p' .ai/local/state/current.yaml)" != "$old" ]
expect_grep '"event":"task.checkpoint"' .ai/local/state/ledger.jsonl
# stale checkpoint warns but does not fail
sed -i.bak 's/^checkpoint_at: .*/checkpoint_at: 2020-01-01T00:00:00Z/' .ai/local/state/current.yaml; rm -f .ai/local/state/current.yaml.bak
expect_exit 0 "$MJ" check
expect_grep 'WARN checkpoint'
# different branch -> different_context
git checkout -qb elsewhere
expect_exit 10 "$MJ" check
expect_grep 'FAIL state .* recorded on branch'
git checkout -q -
# overlap with another worktree's active task is reported at start
wt="$T-wt-bob"; rm -rf "$wt"
git worktree add -q "$wt" -b bob
( cd "$wt" && "$MJ" start "bob task" --scope lib/auth/sub --owner bob >/dev/null ) # the tracked half is there; the local half is created on first write
expect_exit 0 "$MJ" check --overlap
expect_grep 'INFO overlap +.*wt-bob — claims lib/auth/sub — contained by your lib/auth'
# overlap-report: the other containment direction, a wider claim elsewhere containing ours
( cd "$wt" && printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n' | "$MJ" handover --close >/dev/null \
&& "$MJ" start "bob wide" --scope lib --owner bob >/dev/null )
expect_exit 0 "$MJ" check --overlap
expect_grep 'INFO overlap +.*wt-bob — claims lib — contains your lib/auth'
# ...and only reported: the exit above is 0 with an overlap present. The worker bootstraps once
# told every agent that `check --overlap` refuses a commit; a sentence an agent obeys has to
# match the exit code it will meet, so no template this checkout renders may say otherwise.
for tmpl in "$ROOT"/.ai/repo/providers/*.tmpl "$ROOT"/share/skeleton/ai/repo/providers/*.tmpl; do
[ -f "$tmpl" ] || continue
if tr '\n' ' ' < "$tmpl" | grep -qE 'check --overlap`? (are|is) what refuses?'; then
echo " $tmpl says check --overlap refuses, and it exits 0"; exit 1
fi
done
git worktree remove --force "$wt"
# --- checkpoint freshness is a statement about work in progress, not about a finished task.
# A stale checkpoint on an active task is reported; the same record once the task is
# finished is not, because the reproduce command would record progress on work that is
# done, and under watch it would be drift that never clears.
stale() { sed 's/^checkpoint_at: .*/checkpoint_at: 2026-01-01T00:00:00Z/' .ai/local/state/current.yaml > "$T/.cur" && mv "$T/.cur" .ai/local/state/current.yaml; }
note() { printf '# Objective\no\n# Current State\nc\n# Next Action\nn\n'; }
note | "$MJ" handover >/dev/null # close the task the checks above left active
"$MJ" finish --outcome partial >/dev/null
"$MJ" start "checkpoint freshness" --scope lib/auth >/dev/null
stale
expect_exit 0 "$MJ" check
expect_grep 'WARN +checkpoint .* interval'
expect_exit 11 "$MJ" watch
expect_grep 'DRIFT checkpoint'
note | "$MJ" handover >/dev/null
"$MJ" finish --outcome completed --verify-command "test -d .ai" >/dev/null
stale
expect_exit 0 "$MJ" check
expect_grep 'INFO +checkpoint .* freshness applies while a task is active'
expect_no_grep 'WARN +checkpoint'
# watch still exits 11 here, from the malformed decision this case planted earlier on
# purpose; what matters is that the checkpoint is no longer among its findings
expect_exit 11 "$MJ" watch
expect_no_grep 'DRIFT checkpoint'
expect_grep 'DRIFT records +decisions.md'