repo-mailbox/scripts/board-selftest.sh
Kjell Tore Guttormsen d8fdeaa991 fix(infra): a failed measurement must never render as a reassuring value
Tier 3, all five the same defect class (Verifiseringsloven ansikt 4): a
broken or uninstrumented query returning a positive-looking null, consumed
as a fact about the world.

F5  coord-count.sh: a mailbox root that does not exist was byte-identical
    to one where nobody has pending mail - zero lines, exit 0, silent
    stderr. Now exit 3 + a named stderr line; an existing-but-empty root
    stays a silent, clean 0. 3 rather than 2 because 2 already means "you
    called me wrong" and this means "the world you named is not there".
F14 coord-count.sh: the header promised exit 0 unconditionally while
    --exclude with no value already exited 2. Contract restated as
    0/2/3 and pinned as a check on the help TEXT.
F6  board.sh: `git status | wc -l` yields 0 lines whether the tree is
    clean or git refused to answer, so a failure printed DRT=0. Now "?",
    and BOTH awk consumers handle it - --plan's free-capacity test
    compares the field as a string against "0" (a "?" coerces to 0 in
    arithmetic and would certify an unmeasured tree as free), and the SUM
    roll-up names what it could not add.
F10 board.sh: a scan root that does not exist was skipped in silence and
    the empty scan exited 0. Bad roots are now named on stderr; exit 3
    only when NO root was scanned. A mix still exits 0 and prints the
    board. Replaces an assertion that encoded this defect as a pass.
F13 pre-state-line-guard.mjs: MAX_LINES is overridable via
    CLAUDE_STATE_MAX_LINES so the boundary is testable without hardcoding
    120 twice. An unusable value denies by name rather than falling back
    to the default - a limit that silently did not take effect is the
    same defect one layer up.

Every design choice mutation-tested; every negative check carries a
known-positive control. Section 11's first cut was vacuously green (wrong
basename + unexported fixture path) - recorded in CLAUDE.md rather than
quietly fixed, and the section now asserts its own ground truth.

Denominator measured, not estimated: coord-inbox.sh:57 and
coord-order-inbox.sh:60/64 carry the same `|| exit 0` shape and are
deliberately left alone (injection path, prose output, must never fail a
SessionStart) - stated in CLAUDE.md as a bounded gap.

Suites: coord 230->242, board 281->300, guard 40->54, route 69, orders
110, npm 11/11. Verified under system bash 3.2, not just Homebrew 5.3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 12:15:05 +02:00

2452 lines
132 KiB
Bash
Executable file

#!/bin/bash
# board-selftest.sh - prove board.sh end-to-end against a throwaway repo tree
# and a throwaway mailbox (never touches ~/repos or ~/.claude/coord). Re-run
# after any edit to board.sh. ASCII only, bash 3.2 safe.
#
# Multibyte STATE.md content (em-dash, the NESTE pointing-hand) is generated
# with printf octal escapes so this script's own source stays pure ASCII - a
# literal em-dash in shell source has crashed bash 3.2 under `set -u` before.
set -u
export LC_ALL=C
DIR="$(cd "$(dirname "$0")" && pwd)"
BOARD="$DIR/board.sh"
ROOT="$(mktemp -d)"
CLAUDE_COORD_DIR="$(mktemp -d)"
export CLAUDE_COORD_DIR
cleanup() { /bin/rm -rf "$ROOT" "$CLAUDE_COORD_DIR" 2>/dev/null; }
trap cleanup EXIT
PASS=0; FAIL=0
check() { if [ "$2" -eq 0 ]; then PASS=$((PASS+1)); echo " ok - $1"; else FAIL=$((FAIL+1)); echo " FAIL - $1"; fi; }
# Multibyte building blocks (octal escapes keep this source ASCII).
EMDASH="$(printf '\342\200\224')"
HAND="$(printf '\360\237\221\211')"
OSLASH="$(printf '\303\270')"
mkrepo() { mkdir -p "$1" && git -C "$1" init -q 2>/dev/null; }
echo "board-selftest (root: $ROOT, mailbox: $CLAUDE_COORD_DIR)"
# --- 0. Empty root: no repos, still exits cleanly. ---
out0="$("$BOARD" --roots "$ROOT" 2>/dev/null)"; rc=$?
[ "$rc" -eq 0 ]; check "empty root exits 0" $?
# --- Fixture tree ---------------------------------------------------------
# repo-a: full board line, in-progress, cheap next step, unhandled inbox.
mkrepo "$ROOT/repo-a"
{
echo "# STATE - repo-a"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=sonnet/xhigh -->"
printf '**Lukk to MAJOR fra reviewen** %s deretter S3.3 concurrent fan-out.\n' "$EMDASH"
} > "$ROOT/repo-a/STATE.md"
# repo-b: STATE + NESTE prose but NO board line (the un-backfilled majority).
mkrepo "$ROOT/repo-b"
{
echo "# STATE - repo-b"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo ""
printf '> Kj%sr forskningstema 1 headless %s hard gate for motorens arkitektur.\n' "$OSLASH" "$EMDASH"
} > "$ROOT/repo-b/STATE.md"
# repo-c: no STATE.md at all (dormant class).
mkrepo "$ROOT/repo-c"
# repo-d: dirty working tree.
mkrepo "$ROOT/repo-d"
{
echo "# STATE - repo-d"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=deferred; blocked-on=-; next-cost=sonnet/high -->"
echo "Parkert med vilje."
} > "$ROOT/repo-d/STATE.md"
# Commit STATE.md first, so the dirty count proves board counts UNCOMMITTED
# files only (2 junk files) rather than every file in a fresh tree.
git -C "$ROOT/repo-d" add STATE.md >/dev/null 2>&1
git -C "$ROOT/repo-d" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
: > "$ROOT/repo-d/junk1.txt"
: > "$ROOT/repo-d/junk2.txt"
# repo-e: malformed status token (must be flagged, never silently accepted).
mkrepo "$ROOT/repo-e"
{
echo "# STATE - repo-e"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=aktiv; blocked-on=-; next-cost=opus/high -->"
echo "Ugyldig token."
} > "$ROOT/repo-e/STATE.md"
# repo-status-prefix: F3 repro. status=done2 - a valid vocab word ("done") with
# a trailing byte the old [a-z-]* capture class does not match, so the old sed
# stopped at "done" and silently classified this as done (excluded from --plan
# when it owes nothing, table shows plain "done"). The correct read is
# MALFORMED - the token is out-of-vocabulary, and being one prefix-edit from a
# real token makes it MORE dangerous, not less: it must never disappear from
# the plan the way a genuine done repo does.
mkrepo "$ROOT/repo-status-prefix"
{
echo "# STATE - repo-status-prefix"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done2; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Ugyldig token, ett tegn forbi et gyldig ett."
} > "$ROOT/repo-status-prefix/STATE.md"
# repo-status-case: F3 repro. status=Planned (capital P) - the old [a-z-]*
# class does not match the leading uppercase byte at all, so the capture was
# EMPTY and the repo was reported as "?" (no board line), feeding the MERK
# footer with a false "mangler board-linje" count for a repo that has one. The
# correct read is MALFORMED, not "no board line at all".
mkrepo "$ROOT/repo-status-case"
{
echo "# STATE - repo-status-case"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=Planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Feil case, ikke fravaer av board-linje."
} > "$ROOT/repo-status-case/STATE.md"
# repo-trait-prefix: F4 repro, the exact example from the order. path=known2 -
# the old [a-z-]* capture on route_cmd_for's four traits silently truncated to
# "known", which route.sh's exact-match case statement then ACCEPTS - producing
# a safely-worded but WRONG startup command instead of a refusal. This is
# worse than repo-typo's `knwon` (a whole different word, already rejected
# correctly): a one-byte-longer valid-looking token is the case an
# exact-match, not prefix-match, extraction is required to catch.
mkrepo "$ROOT/repo-trait-prefix"
{
echo "# STATE - repo-trait-prefix"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
echo "<!-- route: path=known2; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Neste steg for repo-trait-prefix."
} > "$ROOT/repo-trait-prefix/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-trait-prefix/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-trait-prefix/inbox/2026-msg1-from-y.md"
# repo-revers-prefix: same defect class on a DIFFERENT one of the four traits
# (reversibility), proving the fix covers all four sed lines in route_cmd_for,
# not just the path field the order's example happened to name.
mkrepo "$ROOT/repo-revers-prefix"
{
echo "# STATE - repo-revers-prefix"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap2; scope=local; rationale=x -->"
echo "Neste steg for repo-revers-prefix."
} > "$ROOT/repo-revers-prefix/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-revers-prefix/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-revers-prefix/inbox/2026-msg1-from-y.md"
# repo-g: prose containing a 'board:'-lookalike ABOVE the real board line.
# An unanchored substring grep would match 'dashboard:' first and mis-parse the
# whole repo; the board line is defined as living under the NESTE heading.
mkrepo "$ROOT/repo-g"
{
echo "# STATE - repo-g"
echo "Vi bygde et dashboard: status=done ble diskutert i forrige runde."
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=opus/xhigh -->"
echo "Ekte neste steg her."
} > "$ROOT/repo-g/STATE.md"
# repo-h: next-cost written the way the model rubric actually names the models,
# with a space and capitals ("Sonnet 5/xhigh"). This is spec-conformant
# (<modell>/<effort>) and must parse - a lowercase-only pattern silently drops
# it to "?" and hides the cost column exactly where it is needed.
mkrepo "$ROOT/repo-h"
{
echo "# STATE - repo-h"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Sonnet 5/xhigh -->"
echo "Neste steg her."
} > "$ROOT/repo-h/STATE.md"
# polyrepo/: NOT a git repo itself, but holds git repos one level down.
mkdir -p "$ROOT/polyrepo"
mkrepo "$ROOT/polyrepo/plug-x"
{
echo "# STATE - plug-x"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=repo-a; next-cost=opus/high -->"
printf 'Venter p%s amendment-pakken.\n' "$EMDASH"
} > "$ROOT/polyrepo/plug-x/STATE.md"
# repo-wt + wt-feature: a git WORKTREE (and a submodule) has .git as a FILE,
# not a directory. A `git worktree add <root>/feature-x` yields a sibling
# directory that can CARRY its own STATE.md. Testing discovery for a .git
# DIRECTORY only drops it silently - the same silent-loss class as the V6
# marker fix.
mkrepo "$ROOT/repo-wt"
{
echo "# STATE - repo-wt"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=sonnet/high -->"
printf 'Hovedtreet %s ferdig.\n' "$EMDASH"
} > "$ROOT/repo-wt/STATE.md"
git -C "$ROOT/repo-wt" add STATE.md >/dev/null 2>&1
git -C "$ROOT/repo-wt" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
git -C "$ROOT/repo-wt" -c user.email=t@t -c user.name=t \
worktree add -q -b feature-x "$ROOT/wt-feature" >/dev/null 2>&1
# Distinct board line, so the check proves board read the STATE INSIDE the
# worktree rather than matching the source repo's row by accident.
{
echo "# STATE - wt-feature"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=fable/xhigh -->"
printf 'Arbeid i worktree %s eget neste steg.\n' "$EMDASH"
} > "$ROOT/wt-feature/STATE.md"
# repo-old: fresh STATE.md, last COMMIT 400 days old. This is the case the
# fixture tree was missing entirely: with age read off STATE.md's mtime, a repo
# whose work stopped long ago looks exactly as alive as one touched this
# morning, and no column contradicts it.
mkrepo "$ROOT/repo-old"
{
echo "# STATE - repo-old"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Opus 5/high -->"
echo "Ser levende ut, men ingen commit paa lenge."
} > "$ROOT/repo-old/STATE.md"
OLD_EPOCH=$(( $(date +%s) - 400 * 86400 ))
git -C "$ROOT/repo-old" add STATE.md >/dev/null 2>&1
# %ct is the COMMITTER date. `--date=` sets the AUTHOR date only and would
# leave %ct at now, so the fixture would be backdated in name only.
GIT_AUTHOR_DATE="@$OLD_EPOCH +0000" GIT_COMMITTER_DATE="@$OLD_EPOCH +0000" \
git -C "$ROOT/repo-old" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
# repo-stale: the mirror image - STATE.md untouched since a fixed past date,
# last commit today. The pair pins that the two ages are independent readings
# and that neither of them silently became the sort key.
mkrepo "$ROOT/repo-stale"
{
echo "# STATE - repo-stale"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Opus 5/high -->"
echo "Gammel STATE, fersk commit."
} > "$ROOT/repo-stale/STATE.md"
git -C "$ROOT/repo-stale" add STATE.md >/dev/null 2>&1
git -C "$ROOT/repo-stale" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
touch -t 202601010000 "$ROOT/repo-stale/STATE.md"
# plain-dir/: no git repo anywhere under it - must be ignored entirely.
mkdir -p "$ROOT/plain-dir/sub"
echo "hei" > "$ROOT/plain-dir/sub/file.txt"
# Coord fixture: 3 unhandled for repo-a, 1 archived (must not be counted).
mkdir -p "$CLAUDE_COORD_DIR/repo-a/inbox" "$CLAUDE_COORD_DIR/repo-a/archive"
for n in 1 2 3; do echo "msg" > "$CLAUDE_COORD_DIR/repo-a/inbox/2026-msg$n-from-x.md"; done
echo "old" > "$CLAUDE_COORD_DIR/repo-a/archive/2026-old-from-x.md"
# repo-owes: unhandled inbox AND a route line, so the briefing can derive the
# EXACT startup command - advisor flag included - from the repo's own four
# traits instead of guessing from next-cost alone. Its NESTE runs deliberately
# past the table's 38-character column: carrying that line whole is the reason
# the briefing exists at all.
mkrepo "$ROOT/repo-owes"
{
echo "# STATE - repo-owes"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Svar org-ops om badge-formatet, deretter bump katalogens ref og verifiser check-versions."
} > "$ROOT/repo-owes/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-owes/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-owes/inbox/2026-msg1-from-y.md"
# repo-typo: a route line that EXISTS but carries a value outside route.sh's
# closed set. This is the case that actually occurs as route lines are written
# by hand across repos, and it is distinct from having no route line at all:
# route.sh exits 2, the command comes back empty, and the briefing must say so
# rather than print a bare "$ " that reads as a runnable command.
mkrepo "$ROOT/repo-typo"
{
echo "# STATE - repo-typo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
echo "<!-- route: path=knwon; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Neste steg for repo-typo."
} > "$ROOT/repo-typo/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-typo/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-typo/inbox/2026-msg1-from-y.md"
# --- Focus fixtures --------------------------------------------------------
# The topic marker grammar is the register's, not this repo's: a STATE.md line
# of the form `<slug>: <status-token> <emdash> prose`. board.sh only ever READS
# it, and reads it from STATE.md alone - it must never start opening
# register.md to learn the vocabulary, so the slug set is whatever the scanned
# STATE.md files declare.
#
# repo-focus-plain declares the slug in the bare form.
mkrepo "$ROOT/repo-focus-plain"
{
echo "# STATE - repo-focus-plain"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Opus 5/high -->"
echo "Neste steg for repo-focus-plain."
echo ""
printf -- '- demo-topic: in-progress %s wired at the boundary, ingen apen trad\n' "$EMDASH"
} > "$ROOT/repo-focus-plain/STATE.md"
# repo-focus-bold: the SAME declaration wrapped in bold and backticks. This is
# the class the register's own grep loses, and it was the most consequential
# find in the measurement that produced the decision - a heavy consumer made
# invisible by two asterisks. A reader that only accepts the bare form
# reproduces that defect.
mkrepo "$ROOT/repo-focus-bold"
{
echo "# STATE - repo-focus-bold"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Neste steg for repo-focus-bold."
echo ""
printf -- '- **`demo-topic`**: planned %s pin bumpet, ikke startet\n' "$EMDASH"
} > "$ROOT/repo-focus-bold/STATE.md"
# repo-focus-boldstatus: the bold is on the STATUS token, not the slug. Found in
# the real tree AFTER the first release, which is the point: accepting bold on
# one half of the line and not the other is not a rule, it is an accident of
# which example was in front of us. The register's own grep loses this form too,
# so the repo writing it looks silent while having declared.
mkrepo "$ROOT/repo-focus-boldstatus"
{
echo "# STATE - repo-focus-boldstatus"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Neste steg for repo-focus-boldstatus."
echo ""
echo "demo-topic: **done** (1.8.1). akse-B naadd, ingen apen trad"
} > "$ROOT/repo-focus-boldstatus/STATE.md"
# repo-focus-mentions: names the slug in prose and declares NOTHING. This is
# the held-back class the report exists for. It is in-progress with a live
# next step, so the cutoff genuinely removes a repo that would otherwise be a
# tab - which is what makes silence about it a lie rather than a rounding.
mkrepo "$ROOT/repo-focus-mentions"
{
echo "# STATE - repo-focus-mentions"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Opus 5/high -->"
echo "Vi pinner demo-topic i byggefila, men har aldri skrevet en markorlinje."
} > "$ROOT/repo-focus-mentions/STATE.md"
# repo-focus-other: declares a DIFFERENT slug sharing one hyphen-part, so
# "topic" resolves to two slugs and "demo" to one. Ambiguity must widen the
# answer and say so, never silently pick a winner.
mkrepo "$ROOT/repo-focus-other"
{
echo "# STATE - repo-focus-other"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Neste steg for repo-focus-other."
echo ""
printf -- '- other-topic: planned %s ikke startet\n' "$EMDASH"
} > "$ROOT/repo-focus-other/STATE.md"
OUT="$("$BOARD" --roots "$ROOT" 2>/dev/null)"
# --- 1. Discovery ---------------------------------------------------------
printf '%s' "$OUT" | grep -q 'repo-a'; check "discovers top-level git repo" $?
printf '%s' "$OUT" | grep -q 'plug-x'; check "discovers nested polyrepo git repo (depth 2)" $?
printf '%s' "$OUT" | grep -q 'repo-c'; check "lists git repo without STATE.md" $?
printf '%s' "$OUT" | grep -q 'plain-dir'; [ $? -ne 0 ]; check "ignores non-git directory tree" $?
printf '%s' "$OUT" | grep -q 'polyrepo'; [ $? -ne 0 ]; check "polyrepo container itself is not listed as a repo" $?
# Guard the fixture itself: if git ever stops writing a .git FILE for
# worktrees, the next two checks would pass for the wrong reason.
[ -f "$ROOT/wt-feature/.git" ]; check "fixture: worktree .git is a FILE, not a dir" $?
printf '%s' "$OUT" | grep -q 'wt-feature'; check "discovers git worktree (.git is a file)" $?
printf '%s' "$OUT" | grep -qE 'wt-feature.*fable/xhigh'
check "reads STATE.md from inside the worktree, not the source repo" $?
# --- 2. Board line parsing (the B field) ----------------------------------
printf '%s' "$OUT" | grep -q 'in-progress'; check "parses status token from board line" $?
printf '%s' "$OUT" | grep -q 'sonnet/xhigh'; check "parses next-cost from board line" $?
printf '%s' "$OUT" | grep -qE 'repo-h.*Sonnet 5/xhigh'
check "next-cost accepts spaces and capitals (rubric model names)" $?
printf '%s' "$OUT" | grep -qE 'plug-x.*repo-a'
check "blocked repo names its blocker on its own row" $?
printf '%s' "$OUT" | grep -q 'deferred'; check "distinguishes deferred from blocked" $?
# --- 3. Malformed input is flagged, not swallowed -------------------------
printf '%s' "$OUT" | grep -qi 'malformed\|ugyldig\|invalid'; check "malformed status token is flagged" $?
# F3: a prefix-of-a-valid-token status (status=done2) must be MALFORMED, never
# silently classified as the valid token it happens to start with.
printf '%s' "$OUT" | grep -qE 'repo-status-prefix.*MALFORMED:done2'
check "prefix-match status token (done2) is flagged, not silently read as done" $?
printf '%s' "$OUT" | grep -E '^repo-status-prefix ' | grep -qE '[[:space:]]done[[:space:]]'
[ $? -ne 0 ]
check "prefix-match status token (done2) never displays as bare done" $?
# F3: a case-variant status (status=Planned) must be MALFORMED, never emptied
# to "?" - "?" means no board line at all, and this repo has one.
printf '%s' "$OUT" | grep -qE 'repo-status-case.*MALFORMED:Planned'
check "case-variant status token (Planned) is flagged, not emptied to ?" $?
printf '%s' "$OUT" | grep -E '^repo-status-case ' | grep -qE '[[:space:]][?][[:space:]]'
[ $? -ne 0 ]
check "case-variant status token (Planned) never reads as a missing board line" $?
# Known-positive control: a genuinely absent board line still reads as "?",
# proving the fix narrowed the match, it did not just stop matching "?".
printf '%s' "$OUT" | grep -E '^repo-b ' | grep -qE '[[:space:]][?][[:space:]]'
check "known-positive: repo truly missing a board line still reads as ?" $?
# A 'dashboard:' lookalike earlier in the file must not win over the real line.
printf '%s' "$OUT" | grep -qE 'repo-g.*planned.*opus/xhigh'
check "board-line parse ignores 'board:' lookalikes in prose" $?
# --- 4. Heuristic fallback when board line is absent -----------------------
printf '%s' "$OUT" | grep -q 'repo-b'; check "repo without board line still listed" $?
printf '%s' "$OUT" | grep -qi 'forskningstema\|headless'; check "shows NESTE excerpt when board line absent" $?
# Markdown noise must be stripped: a blockquoted NESTE line renders as prose.
printf '%s' "$OUT" | grep -qE 'repo-b.*[[:space:]]>'; [ $? -ne 0 ]
check "blockquote marker stripped from NESTE excerpt" $?
# --- 5. Git + coord signals ------------------------------------------------
printf '%s' "$OUT" | grep -qE 'repo-d.*[^0-9]2([^0-9]|$)'; check "reports dirty file count" $?
printf '%s' "$OUT" | grep -qE 'repo-a.*[^0-9]3([^0-9]|$)'; check "reports unhandled coord inbox count (archive excluded)" $?
# --- 6. Bucketing ----------------------------------------------------------
printf '%s' "$OUT" | grep -qi 'blocked'; check "blocked repo surfaced" $?
printf '%s' "$OUT" | grep -qiE 'dormant|sovende|uten STATE'; check "STATE-less repos bucketed separately" $?
# --- 7. Robustness ---------------------------------------------------------
# Multibyte prose must not crash the reader nor emit split-character garbage.
[ -n "$OUT" ]; check "produces output over multibyte STATE prose" $?
printf '%s' "$OUT" | iconv -f UTF-8 -t UTF-8 >/dev/null 2>&1
check "output is valid UTF-8 (no split multibyte truncation)" $?
# A STATE.md with a NESTE heading and nothing after it must not hang or crash.
mkrepo "$ROOT/repo-f"
{ echo "# STATE - repo-f"; printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"; } > "$ROOT/repo-f/STATE.md"
"$BOARD" --roots "$ROOT" >/dev/null 2>&1; check "empty NESTE block does not crash" $?
# The NESTE marker must be anchored to the heading form, not any line
# containing the word. A prose line mentioning "NESTE" earlier in the file
# must not be mistaken for the marker - that would make the excerpt the line
# AFTER the false match instead of the real next step under the real heading.
mkrepo "$ROOT/repo-neste-lookalike"
{
echo "# STATE - repo-neste-lookalike"
echo "## Fakta"
echo "Noe forklaring om NESTE-formen som ble diskutert i gaar."
echo "Dette er en tilfeldig linje som IKKE er det ekte neste steget."
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=sonnet/xhigh -->"
echo "Det ekte neste steget er aa fikse boardskriptet."
} > "$ROOT/repo-neste-lookalike/STATE.md"
NESTE_OUT="$("$BOARD" --roots "$ROOT" 2>/dev/null)"
printf '%s' "$NESTE_OUT" | grep -qE 'repo-neste-lookalike.*ekte neste steget'
check "NESTE marker anchored to heading, not any content line mentioning it" $?
printf '%s' "$NESTE_OUT" | grep -qE 'repo-neste-lookalike.*tilfeldig linje'
[ $? -ne 0 ]; check "content line mentioning NESTE is not mistaken for the marker" $?
# A MULTI-LINE HTML comment under NESTE must be skipped THROUGH TO ITS CLOSER,
# not just on its opening line. Skipping only lines that START with the opener
# leaves every continuation line looking like prose, so the excerpt becomes
# comment internals - measured on the real tree, this repo was 1 of 28 affected
# and held the symptom down by keeping its comments one-line.
# The fixture is the REAL shape deliberately: one-line, multi-line, one-line,
# prose. A lone multi-line comment would prove enter-and-exit but not that the
# open-comment flag RESETS - a flag stuck on would still pass that weaker
# fixture by falling through to the same prose.
# NOTE: an HTML comment body cannot contain '-->' at all (that is the format,
# not a board.sh limit), so a rationale that quotes the closer still ends the
# comment early. That constraint survives this fix by construction.
mkrepo "$ROOT/repo-multiline-comment"
{
echo "# STATE - repo-multiline-comment"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
# The marker sits at the START of the continuation line on purpose: the table
# cuts the excerpt at 38 characters, so a marker further in would be truncated
# away and the check would pass against the BROKEN code too.
echo "<!-- route: path=known; verification=strong; reversibility=cheap;"
echo " FORTSETTELSESLINJE som ikke er noe neste steg;"
echo " scope=local; rationale=brer seg over flere linjer. -->"
echo "<!-- route-last: model=Opus 5; effort=high; completed=yes -->"
echo "Det ekte neste steget staar under kommentarblokken."
} > "$ROOT/repo-multiline-comment/STATE.md"
ML_OUT="$("$BOARD" --roots "$ROOT" 2>/dev/null)"
printf '%s' "$ML_OUT" | grep -qE 'repo-multiline-comment.*ekte neste steget'
check "multi-line HTML comment skipped through to its closer" $?
printf '%s' "$ML_OUT" | grep -q 'FORTSETTELSESLINJE'
[ $? -ne 0 ]; check "comment continuation line never becomes the NESTE excerpt" $?
# The board line still parses: it is read by its own anchored grep, so the
# excerpt fix must not disturb it.
printf '%s' "$ML_OUT" | grep -qE 'repo-multiline-comment.*planned'
check "board line still parsed alongside a wrapped route comment" $?
# A NESTE block that is NOTHING BUT a multi-line comment has no next step, and
# must say so rather than promote comment internals to the excerpt.
mkrepo "$ROOT/repo-comment-only"
{
echo "# STATE - repo-comment-only"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- route: path=known; verification=strong;"
echo " scope=local; rationale=BARE EN KOMMENTAR her. -->"
} > "$ROOT/repo-comment-only/STATE.md"
CO_OUT="$("$BOARD" --roots "$ROOT" 2>/dev/null)"
printf '%s' "$CO_OUT" | grep -qE 'repo-comment-only.*tom NESTE-blokk'
check "NESTE block of only a multi-line comment reports an empty block" $?
"$BOARD" --help >/dev/null 2>&1; check "--help exits 0" $?
# A root that does not exist is NOT a clean no-op - it is an unmeasured scan,
# and it used to be indistinguishable from an empty tree. Pinned in full by
# section 26 below (F10); asserted here only as "it does not crash".
mr_rc=0
"$BOARD" --roots "$ROOT/does-not-exist" >/dev/null 2>&1 || mr_rc=$?
[ "$mr_rc" -eq 3 ]
check "missing root exits nonzero (3) without crashing" $?
# --- 8. The documented next-cost form IS the convention --------------------
# The cost field is free text on purpose: the parser reads to ';' or '-->' so
# the rubric's spacing survives, and the fixtures above deliberately vary the
# spelling to pin that leniency. But leniency on the read side means the ONLY
# thing holding the field uniform is what --help prescribes, and --help once
# prescribed a versionless `sonnet/xhigh` while the global rubric spelled
# `Sonnet 5 / xhigh`. Two specs for one field: measured across the real tree,
# not one board line used ours, and eight distinct strings were in circulation.
# Pinned here because cleaning the DATA cannot fix that - a spec that
# contradicts the rubric regenerates the divergence every session.
HELP="$("$BOARD" --help 2>/dev/null)"
printf '%s' "$HELP" | grep -q 'next-cost=Sonnet 5/xhigh'
check "--help prescribes the canonical next-cost form" $?
# The versionless form is what the rubric does NOT use; no example may show it.
if printf '%s' "$HELP" | grep -qE '(sonnet|opus|fable)/(high|xhigh)'; then rc=1; else rc=0; fi
check "--help shows no versionless model example" "$rc"
# --- 9. SISTE: last commit, read for EVERY repo ----------------------------
# One column, one meaning. ALDER answers "when was the plan last touched" and
# is blank where there is no plan; SISTE answers "when did anything last land"
# and is read for every repo. Before this, a single ALDER column carried both
# readings depending on which branch a repo fell into, so a repo with a STATE.md
# could go a year without a commit and show nothing at all.
[ "$(git -C "$ROOT/repo-old" log -1 --format=%ct 2>/dev/null)" = "$OLD_EPOCH" ]
check "fixture: repo-old's COMMITTER date is actually backdated" $?
printf '%s' "$OUT" | grep -q 'SISTE'; check "table has a SISTE column" $?
printf '%s\n' "$OUT" | grep -qE '^repo-old .*[[:space:]]0d[[:space:]]+40[01]d[[:space:]]'
check "fresh STATE.md + old commit: ALDER stays 0d, SISTE shows the 400 days" $?
printf '%s\n' "$OUT" | grep -qE '^repo-stale .*[[:space:]][1-9][0-9]*d[[:space:]]+0d[[:space:]]'
check "old STATE.md + fresh commit: the two ages read independently" $?
# A repo with no commits has no last commit to report. A day count there would
# be a fabricated reading, and the pre-existing -1d was exactly that.
# The -n guard is load-bearing: an absent row would leave crow empty, and an
# empty string trivially contains no day count - the check would pass by
# finding nothing rather than by reading the row.
crow="$(printf '%s\n' "$OUT" | grep '^repo-c ')"
if [ -n "$crow" ] && ! printf '%s' "$crow" | grep -qE '[0-9]+d'; then rc=0; else rc=1; fi
check "repo with no commits reports no day count in either age column" "$rc"
# The four ranking rules stay four: SISTE is evidence the operator reads, never
# an input to the order. If it had become the sort key, repo-old (400d) would
# fall behind repo-stale (0d) instead of ahead of it.
n_old="$(printf '%s\n' "$OUT" | grep -n '^repo-old ' | cut -d: -f1)"
n_stale="$(printf '%s\n' "$OUT" | grep -n '^repo-stale ' | cut -d: -f1)"
[ -n "$n_old" ] && [ -n "$n_stale" ] && [ "$n_old" -lt "$n_stale" ]
check "SISTE is evidence, not a ranking input (order still follows ALDER)" $?
# --- 8. Briefing rendering (--brief) --------------------------------------
# A second rendering of the SAME scan, never a second scan: the briefing
# answers "who is waiting on me and what does answering cost", where the table
# answers "what is the state of every repo".
BRIEF="$("$BOARD" --roots "$ROOT" --brief 2>/dev/null)"
printf '%s' "$BRIEF" | grep -q 'repo-owes'
check "brief includes a repo with an unhandled inbox" $?
printf '%s' "$BRIEF" | grep -q 'repo-b'; [ $? -ne 0 ]
check "brief excludes a repo that owes nothing" $?
# The table cuts NESTE at 38 characters. The briefing carries the whole line,
# so the tail past the cut is the thing being proved here.
printf '%s' "$BRIEF" | grep -q 'check-versions'
check "brief prints the full NESTE line, not the 38-char table excerpt" $?
# Derived by CALLING route.sh with the repo's own four traits - deliberately
# not spelled out in board.sh - so the rubric keeps exactly one copy. Row 1
# carries the advisor, which is what makes the quota fallback safe to take.
printf '%s' "$BRIEF" | grep -q 'claude --model sonnet --effort high --advisor opus'
check "brief derives the exact startup command from the repo's route line" $?
# The command must start its OWN line. `fold` copies its input's missing
# trailing newline, which ran the command onto the tail of the NESTE prose and
# produced a briefing whose commands could not be copied - caught by eye
# against the real tree, which is exactly what a check is for.
printf '%s' "$BRIEF" | grep -qE '^ \$ claude --model'
check "startup command starts on its own line, not appended to NESTE prose" $?
# A route line that parses to a value route.sh rejects must degrade the same
# way a missing one does. Silence here would print a bare '$ ' - the shape of a
# runnable command, carrying nothing - which is worse than an absent command
# because it looks copied-and-pasteable.
printf '%s' "$BRIEF" | grep -A4 'repo-typo' | grep -qi 'route'
check "unparseable route line degrades to a marker, not to an empty command" $?
printf '%s' "$BRIEF" | grep -A4 'repo-typo' | grep -qE '^ \$ claude'; [ $? -ne 0 ]
check "unparseable route line never emits a command line at all" $?
# F4: path=known2 - a prefix-of-a-valid-token route trait. Silently trimmed to
# "known" by the old [a-z-]* capture, route.sh would accept it and hand back a
# safely-worded but WRONG command (row 1: known/strong/cheap/local). The fix
# must produce the SAME degrade-to-marker outcome as repo-typo's whole-word
# typo, never a plausible command built on a truncated value.
printf '%s' "$BRIEF" | grep -A4 'repo-trait-prefix' | grep -qi 'route'
check "prefix-match route trait (known2) degrades to a marker, not a guessed command" $?
printf '%s' "$BRIEF" | grep -A4 'repo-trait-prefix' | grep -qE '^ \$ claude'; [ $? -ne 0 ]
check "prefix-match route trait (known2) never emits a command line at all" $?
# F4 on a different one of the four traits (reversibility=cheap2), proving the
# fix is not path-specific.
printf '%s' "$BRIEF" | grep -A4 'repo-revers-prefix' | grep -qi 'route'
check "prefix-match route trait (cheap2) degrades to a marker, not a guessed command" $?
printf '%s' "$BRIEF" | grep -A4 'repo-revers-prefix' | grep -qE '^ \$ claude'; [ $? -ne 0 ]
check "prefix-match route trait (cheap2) never emits a command line at all" $?
# repo-a owes 3 messages and has no route line. A fabricated command would be
# worse than none: it would read as authoritative while being a guess.
printf '%s' "$BRIEF" | grep -A4 'repo-a' | grep -qi 'route'
check "repo owing mail but lacking a route line is marked, never guessed at" $?
# Read-only by construction, and the briefing must not erode it. Reading IS
# delivering in this engine, so a survey that consumed a backlog would be
# precisely the defect the whole design forbids.
snap() { find "$1" -type f -exec stat -f '%N %m %z' {} \; 2>/dev/null | sort; }
b4="$(snap "$CLAUDE_COORD_DIR")"
"$BOARD" --roots "$ROOT" --brief >/dev/null 2>&1
[ "$b4" = "$(snap "$CLAUDE_COORD_DIR")" ]
check "brief writes nothing to the mailbox (reading is delivering)" $?
# A mailbox can carry a name the repo scan will NEVER produce: a declared
# non-git surface (CLAUDE_COORD_REPO, e.g. ~/repos itself) or a checkout
# outside the scan roots. board.sh discovers git repos, so such a mailbox is
# invisible to every column it prints - and the briefing exists to answer "who
# is waiting on you", where dropping one silently is the loss-wearing-the-
# shape-of-normal class this engine keeps naming. Measured against the real
# mailbox before this check existed: 11 repos / 21 messages in the briefing
# against 12 mailboxes / 22 pending in coord-count.
mkdir -p "$CLAUDE_COORD_DIR/orphan-surface/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/orphan-surface/inbox/2026-msg1-from-z.md"
BRIEF2="$("$BOARD" --roots "$ROOT" --brief 2>/dev/null)"
printf '%s' "$BRIEF2" | grep -q 'orphan-surface'
check "brief surfaces a pending mailbox that has no repo in the scan tree" $?
# It must be reported as its own class, not silently folded in among repos the
# scan actually found - there is no STATE.md behind it and so no next step.
printf '%s' "$BRIEF2" | grep -qi 'utenfor repo-skannen\|uten repo'
check "orphan mailbox is reported as its own class, not as a scanned repo" $?
# --- 9. brief-nightly.sh: the only writer, and it writes atomically -------
# board.sh stays read-only, so the file write lives in a separate wrapper.
# Unattended overwrite must never expose a half-written briefing: the wrapper
# renders to a temp file in the same directory and renames it into place.
NIGHTLY="$DIR/brief-nightly.sh"
OUTFILE="$ROOT/briefing.md"
CLAUDE_BRIEF_FILE="$OUTFILE" BOARD_ROOTS="$ROOT" bash "$NIGHTLY" >/dev/null 2>&1
check "brief-nightly exits 0" $?
[ -f "$OUTFILE" ] && grep -q 'repo-owes' "$OUTFILE"
check "brief-nightly writes the briefing to CLAUDE_BRIEF_FILE" $?
ls "$OUTFILE".tmp.* >/dev/null 2>&1; [ $? -ne 0 ]
check "brief-nightly leaves no temp file behind" $?
# An EMPTY render is a failed render, and must leave the previous briefing
# standing rather than truncating it to nothing - the failure mode a plain
# `> file` redirect has, and the reason the temp-then-rename exists. A repo
# tree where nobody owes anything is NOT this case: that renders a valid,
# non-empty briefing saying so, and is written normally.
echo "FORRIGE BRIEFING" > "$OUTFILE"
CLAUDE_BRIEF_FILE="$OUTFILE" BOARD_ROOTS="$ROOT/does-not-exist" \
bash "$NIGHTLY" >/dev/null 2>&1
grep -q 'FORRIGE BRIEFING' "$OUTFILE"
check "empty render never overwrites the previous briefing" $?
# --- 10. Day-plan rendering (--plan) ---------------------------------------
# A THIRD rendering of the same scan, on exactly the argument --brief was built
# on. The table answers "what is the state of every repo"; the briefing answers
# "who is waiting on me"; the plan answers "which repos do I open a tab for
# today, in what order, with which command". It has TWO consumers - the operator
# pasting commands, and a separate driver repo consuming the plan - which is why
# it renders key=value blocks rather than prose: prose would make the FORMAT an
# API that no test in this repo could hold stable.
#
# repo-blocked-owes: blocked AND owing mail. The exclusion of `blocked` is about
# a repo's OWN next step, which by definition cannot be moved; answering a
# message is a different axis, and is often precisely what unblocks it. Without
# this fixture the debt-first rule and the status exclusion never meet, and
# whichever one was written second would silently win.
mkrepo "$ROOT/repo-blocked-owes"
{
echo "# STATE - repo-blocked-owes"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=repo-a; next-cost=Opus 5/high -->"
printf 'Venter p%s repo-a, men skylder to svar.\n' "$EMDASH"
} > "$ROOT/repo-blocked-owes/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-blocked-owes/inbox"
for n in 1 2; do
echo "msg" > "$CLAUDE_COORD_DIR/repo-blocked-owes/inbox/2026-msg$n-from-w.md"
done
# repo-done-owes: done AND owing mail. Same rule as repo-blocked-owes, but this
# is the shape that actually occurs - measured on the real tree at 0.16.0, two
# of the 26 planned repos were `done` with an unhandled inbox, and none were
# blocked-with-debt. A repo whose own work is finished can still owe an answer.
mkrepo "$ROOT/repo-done-owes"
{
echo "# STATE - repo-done-owes"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/high -->"
printf 'Arbeidet er ferdig %s men innboksen er ikke gjort opp.\n' "$EMDASH"
} > "$ROOT/repo-done-owes/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-done-owes/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-done-owes/inbox/2026-msg1-from-w.md"
# repo-done-fyi: done, with pending mail, but every message declares
# reply-expected: no (a notice, not a request). Every OTHER fixture message in
# this suite is written with no frontmatter at all, which owes_reply() in
# coord-count.sh treats as owing by default - so pending and owed have been
# equal in every prior fixture, and a raw-pending-as-debt bug is invisible to
# this suite without a genuine FYI-only mailbox. Measured on the live mailbox
# 2026-08-11 by morning-driver: 14 of 22 unhandled messages were notices.
mkrepo "$ROOT/repo-done-fyi"
{
echo "# STATE - repo-done-fyi"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/high -->"
printf 'Ferdig %s to varsler ligger i innboksen, ingen skylder svar.\n' "$EMDASH"
} > "$ROOT/repo-done-fyi/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-done-fyi/inbox"
for n in 1 2; do
{
echo "---"
echo "from: w"
echo "to: repo-done-fyi"
echo "reply-expected: no"
echo "---"
echo "fyi only"
} > "$CLAUDE_COORD_DIR/repo-done-fyi/inbox/2026-msg$n-from-w.md"
done
# repo-blocked-mixed: blocked, 3 pending messages but only 2 owe a reply - the
# third declares reply-expected: no. repo-blocked-owes (above) cannot prove
# ranking uses OWED rather than raw pending, because every one of its messages
# happens to owe; this fixture separates the two counts (3 pending, 2 owed).
mkrepo "$ROOT/repo-blocked-mixed"
{
echo "# STATE - repo-blocked-mixed"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=-; next-cost=Opus 5/high -->"
printf 'Blokkert %s tre meldinger, bare to skylder svar.\n' "$EMDASH"
} > "$ROOT/repo-blocked-mixed/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/repo-blocked-mixed/inbox"
echo "msg" > "$CLAUDE_COORD_DIR/repo-blocked-mixed/inbox/2026-msg1-from-w.md"
echo "msg" > "$CLAUDE_COORD_DIR/repo-blocked-mixed/inbox/2026-msg2-from-w.md"
{
echo "---"
echo "from: w"
echo "to: repo-blocked-mixed"
echo "reply-expected: no"
echo "---"
echo "fyi only"
} > "$CLAUDE_COORD_DIR/repo-blocked-mixed/inbox/2026-msg3-from-w.md"
# A fresh --brief, taken after repo-done-fyi and repo-blocked-mixed exist:
# BRIEF (above) predates both fixtures, so it cannot exercise them.
BRIEF3="$("$BOARD" --roots "$ROOT" --brief 2>/dev/null)"
printf '%s' "$BRIEF3" | grep -q 'repo-done-fyi'; [ $? -ne 0 ]
check "brief excludes a repo whose pending mail is all FYI (no debt)" $?
printf '%s' "$BRIEF3" | grep -q 'repo-blocked-mixed'
check "brief includes a repo with mixed mail (it has 2 owed)" $?
printf '%s' "$BRIEF3" | grep -qE 'repo-blocked-mixed[[:space:]]+INN[[:space:]]+2([[:space:]]|$)'
check "brief's INN count is owed messages, not raw pending (3 pending, 2 owed)" $?
PLAN="$("$BOARD" --roots "$ROOT" --plan 2>/dev/null)"; rc=$?
check "--plan exits 0" "$rc"
printf '%s' "$PLAN" | grep -q '^# PLAN '
check "plan carries a header naming what it is" $?
# Machine-readable by construction: the driver repo reads these keys.
printf '%s' "$PLAN" | grep -q '^tab=1$'
check "plan numbers tabs starting at 1" $?
# Debt outranks everything, most-owed first. repo-a owes 3, repo-blocked-owes 2,
# repo-owes and repo-typo 1 each.
[ "$(printf '%s\n' "$PLAN" | grep -A1 '^tab=1$' | grep '^repo=' | cut -d= -f2)" = "repo-a" ]
check "the repo owing the most messages is tab 1" $?
n_a="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-a$' | cut -d: -f1)"
n_bo="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-blocked-owes$' | cut -d: -f1)"
n_ow="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-owes$' | cut -d: -f1)"
[ -n "$n_a" ] && [ -n "$n_bo" ] && [ -n "$n_ow" ] \
&& [ "$n_a" -lt "$n_bo" ] && [ "$n_bo" -lt "$n_ow" ]
check "debt group is ordered by message count, descending" $?
# The status exclusion is about a repo's own next step, never about its debt.
printf '%s' "$PLAN" | grep -q '^repo=repo-blocked-owes$'
check "a BLOCKED repo that owes mail is still planned (debt is the other axis)" $?
printf '%s\n' "$PLAN" | grep -A4 '^repo=repo-blocked-owes$' | grep -q '^why=inbox:2$'
check "a blocked repo in the plan says debt, not status, is why it is there" $?
# Debt before live work: repo-h is in-progress and owes nothing. Stated as
# group 2 over group 4, NOT as "before any that owes none" - since 0.20.0 the
# chain-root group sits above debt, so a repo owing nothing CAN outrank one that
# does. Section 12 pins that half on the fixture that shows it cleanly.
n_h="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-h$' | cut -d: -f1)"
[ -n "$n_h" ] && [ "$n_ow" -lt "$n_h" ]
check "a repo owing mail is planned before live work that owes and releases nothing" $?
# Group 2 over group 3: repo-g is planned and owes nothing.
n_g="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-g$' | cut -d: -f1)"
[ -n "$n_g" ] && [ "$n_ow" -lt "$n_g" ]
check "a repo owing mail is planned before a repo that merely has a plan" $?
# repo-a is BOTH in-progress and owing. It must appear exactly once - a repo
# listed twice is two tabs for one repo, which is the plan failing at its job.
[ "$(printf '%s\n' "$PLAN" | grep -c '^repo=repo-a$')" -eq 1 ]
check "a repo qualifying under two rules is planned exactly once" $?
# repo-a owes 3 messages AND is the blocker plug-x and repo-blocked-owes both
# name. Under the group form why= names the GROUP that put the repo in the plan,
# and the chain-root group is the first one tested - so it reports what a session
# there would release rather than what it owes. Between 0.19.0 and 0.20.0 the
# same assertion held for a different reason (the dominant term of a score);
# the reason is written down because the check passes either way and only the
# reason says which form is running.
printf '%s\n' "$PLAN" | grep -A3 '^repo=repo-a$' | grep -q '^why=unblocks:2$'
check "why= names the group that planned the repo, releasing over owing" $?
# planned outranks in-progress among the repos that neither owe nor release.
# INVERTED at 0.20.0 by operator decision: a decided-but-unstarted next step is
# the step that converts a decision into motion, and live work is already moving.
# This is a policy call, not a preference - it is recorded here and in board.sh
# so a later session cannot read it as a sort that drifted.
[ -n "$n_g" ] && [ "$n_g" -lt "$n_h" ]
check "planned work is planned before live in-progress work (operator inversion)" $?
# Group 4 over group 5: repo-e declares an out-of-set status token and lands in
# the undeclared group, which is planned LAST and never dropped.
n_e="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-e$' | cut -d: -f1)"
[ -n "$n_e" ] && [ "$n_h" -lt "$n_e" ]
check "a repo with no declared status is planned after live work, not dropped" $?
# Excluded classes. A tab for a done or deferred repo is noise; a tab for a
# blocked repo that owes nothing cannot be moved at all.
printf '%s' "$PLAN" | grep -q '^repo=repo-wt$'; [ $? -ne 0 ]
check "plan excludes a done repo that owes nothing" $?
# ...but the exclusion is conditional on owing nothing, and the header says so.
# Read the other way, the plan's own header would call these entries a bug.
printf '%s' "$PLAN" | grep -q '^repo=repo-done-owes$'
check "a DONE repo that owes mail is still planned" $?
printf '%s\n' "$PLAN" | grep -A4 '^repo=repo-done-owes$' | grep -q '^status=done$'
check "a done repo in the plan still reports its real status" $?
printf '%s\n' "$PLAN" | grep -m1 '^# Utelatt' | grep -q 'skylder svar'
check "the header states the exclusions are conditional on owing nothing" $?
# The header above already says "skylder svar" (owes a reply) - a done repo
# whose pending mail is 100% notices does not owe a reply, so it is excluded
# on the SAME rule as repo-wt, not a new one. Pending (2) must not stand in
# for owed (0).
printf '%s' "$PLAN" | grep -q '^repo=repo-done-fyi$'; [ $? -ne 0 ]
check "plan excludes a done repo whose pending mail is all FYI (owed 0, pending 2)" $?
# blocked-with-debt (repo-blocked-owes, above) stays planned on its debt; this
# fixture proves the COUNT that seats and ranks it is the owed count, not the
# raw pending count - 3 pending, 2 owed.
printf '%s' "$PLAN" | grep -q '^repo=repo-blocked-mixed$'
check "a blocked repo with mixed mail is still planned on its owed messages" $?
printf '%s\n' "$PLAN" | grep -A4 '^repo=repo-blocked-mixed$' | grep -q '^why=inbox:2$'
check "why=inbox:N counts owed messages, not raw pending (3 pending, 2 owed)" $?
printf '%s' "$PLAN" | grep -q '^repo=repo-d$'; [ $? -ne 0 ]
check "plan excludes a deferred repo" $?
printf '%s' "$PLAN" | grep -q '^repo=plug-x$'; [ $? -ne 0 ]
check "plan excludes a blocked repo that owes nothing" $?
printf '%s' "$PLAN" | grep -q '^repo=repo-c$'; [ $? -ne 0 ]
check "plan excludes a repo with no STATE.md and no debt" $?
# A repo with no board line has no declared next step, but dropping it SILENTLY
# is what the table's own MERK line exists to prevent. It is planned last and
# labelled, never omitted.
printf '%s' "$PLAN" | grep -q '^repo=repo-b$'
check "a repo lacking a board line is planned, not silently dropped" $?
printf '%s\n' "$PLAN" | grep -A3 '^repo=repo-b$' | grep -q '^why=uavklart$'
check "a repo with unknown status is labelled uavklart, not guessed into a rule" $?
n_b="$(printf '%s\n' "$PLAN" | grep -n '^repo=repo-b$' | cut -d: -f1)"
[ -n "$n_b" ] && [ "$n_g" -lt "$n_b" ]
check "uavklart repos rank below every repo that declared a status" $?
# The command comes from route.sh, same single copy of the rubric the briefing
# uses - advisor flag included, since that is a property of the ROW.
printf '%s' "$PLAN" | grep -q '^command=claude --model sonnet --effort high --advisor opus$'
check "plan derives the exact startup command from the repo's route line" $?
# Both no-command causes must degrade to a marker. A bare `command=` would be
# the shape of a runnable command carrying nothing - worse than none, because a
# driver reading `^command=` would type an empty line into a live pane.
printf '%s' "$PLAN" | grep -q '^command=$'; [ $? -ne 0 ]
check "plan never emits an empty command= line" $?
printf '%s\n' "$PLAN" | grep -A6 '^repo=repo-typo$' | grep -q '^command_missing='
check "unparseable route line degrades to command_missing=, not to a guess" $?
printf '%s\n' "$PLAN" | grep -A6 '^repo=repo-a$' | grep -q '^command_missing='
check "repo owing mail but lacking a route line is marked, never guessed at" $?
# F4: path=known2 must degrade to command_missing=, exactly like repo-typo's
# whole-word typo - never to a command= built on a truncated "known".
printf '%s\n' "$PLAN" | grep -A6 '^repo=repo-trait-prefix$' | grep -q '^command_missing='
check "F4: prefix-match route trait (known2) degrades to command_missing=" $?
printf '%s\n' "$PLAN" | grep -A7 '^repo=repo-trait-prefix$' | grep -q '^paste='; [ $? -ne 0 ]
check "F4: prefix-match route trait (known2) gets no paste line either" $?
printf '%s\n' "$PLAN" | grep -A6 '^repo=repo-revers-prefix$' | grep -q '^command_missing='
check "F4: prefix-match route trait (cheap2) degrades to command_missing=" $?
# Same argument as the briefing: the 38-char cut is the TABLE column's property.
printf '%s' "$PLAN" | grep -q '^neste=.*check-versions'
check "plan prints the full NESTE line, not the 38-char table excerpt" $?
# paste= is the operator's line and command= is the driver's. Both are kept
# because they answer different questions: a driver cd's the pane itself and
# would choke on a compound line, while the operator needs ONE thing to copy.
# Assembling it by hand from two fields is where a tab lands in the wrong repo.
printf '%s' "$PLAN" | grep -q "^paste=cd $ROOT/repo-owes && claude --model sonnet --effort high --advisor opus\$"
check "paste= is the whole line: cd into the repo, then the startup command" $?
printf '%s\n' "$PLAN" | grep -A7 '^repo=repo-typo$' | grep -q '^paste='; [ $? -ne 0 ]
check "a repo with no usable route line gets no paste line either" $?
# The driver cds into this, so a relative or missing path lands a session in the
# wrong repo - constraint 2 of the Ghostty measurement, in field form.
pdir="$(printf '%s\n' "$PLAN" | grep -m1 '^dir=' | cut -d= -f2-)"
[ -n "$pdir" ] && [ -d "$pdir" ] && [ "${pdir#/}" != "$pdir" ]
check "dir= is an absolute path that exists" $?
# Every block must be complete: a driver that reads a block missing dir= or
# command= has no safe default, and guessing one types into a live pane.
n_tab="$(printf '%s\n' "$PLAN" | grep -c '^tab=')"
n_rep="$(printf '%s\n' "$PLAN" | grep -c '^repo=')"
n_dir="$(printf '%s\n' "$PLAN" | grep -c '^dir=')"
n_why="$(printf '%s\n' "$PLAN" | grep -c '^why=')"
n_sta="$(printf '%s\n' "$PLAN" | grep -c '^status=')"
n_nes="$(printf '%s\n' "$PLAN" | grep -c '^neste=')"
n_cmd="$(printf '%s\n' "$PLAN" | grep -c '^command=')"
n_cms="$(printf '%s\n' "$PLAN" | grep -c '^command_missing=')"
[ "$n_tab" -gt 0 ] && [ "$n_rep" -eq "$n_tab" ] && [ "$n_dir" -eq "$n_tab" ] \
&& [ "$n_why" -eq "$n_tab" ] && [ "$n_sta" -eq "$n_tab" ] \
&& [ "$n_nes" -eq "$n_tab" ] && [ $(( n_cmd + n_cms )) -eq "$n_tab" ]
check "every planned block carries every field exactly once" $?
# paste= is one per command=, never one per block: a repo with no command has
# nothing to paste, and `paste=cd X && ` would run the cd and then a bare
# newline - putting the operator in the right repo with no session started.
n_pst="$(printf '%s\n' "$PLAN" | grep -c '^paste=')"
[ "$n_pst" -eq "$n_cmd" ]
check "paste= appears exactly where command= does, never beside command_missing" $?
# Numbering must be dense: a driver opening tab 4 of 3 is a real failure mode.
seq_ok=0
printf '%s\n' "$PLAN" | grep '^tab=' | cut -d= -f2 > "$ROOT/tabs.txt"
# An empty tab list satisfies "every number is its index" vacuously, which is
# the check passing by finding nothing rather than by reading the numbering.
[ -s "$ROOT/tabs.txt" ] || seq_ok=1
i=0; while read -r t; do i=$((i+1)); [ "$t" = "$i" ] || seq_ok=1; done < "$ROOT/tabs.txt"
check "tab numbers are dense and consecutive" "$seq_ok"
# Read-only, same as every other rendering. Reading IS delivering in this
# engine, so a plan that consumed a backlog would be the core defect.
p4="$(snap "$CLAUDE_COORD_DIR")"
"$BOARD" --roots "$ROOT" --plan >/dev/null 2>&1
[ "$p4" = "$(snap "$CLAUDE_COORD_DIR")" ]
check "plan writes nothing to the mailbox (reading is delivering)" $?
# The scan and the mailbox are two populations. An orphan mailbox has no repo to
# cd into, so it cannot BE a tab - but dropping it makes the plan claim a
# completeness it knows it lacks. It is reported as commentary.
printf '%s' "$PLAN" | grep -q 'orphan-surface'
check "plan surfaces a pending mailbox with no repo in the scan tree" $?
printf '%s' "$PLAN" | grep -q '^repo=orphan-surface$'; [ $? -ne 0 ]
check "orphan mailbox is commentary, never a tab block (there is no dir to cd to)" $?
# Comment lines are '#'-prefixed so a consumer can drop them with one rule.
printf '%s\n' "$PLAN" | grep -vE '^#|^$|^[a-z_]+=' | grep -q .; [ $? -ne 0 ]
check "every plan line is a comment, a blank, or a key=value pair" $?
printf '%s' "$PLAN" | iconv -f UTF-8 -t UTF-8 >/dev/null 2>&1
check "plan output is valid UTF-8" $?
"$BOARD" --help 2>/dev/null | grep -q '\-\-plan'
check "--help documents --plan" $?
# --- 11. Focused day plan (--focus) ---------------------------------------
# --focus is the first CUTOFF the plan has ever had, and every check here
# exists because a cutoff is exactly what the plan format promised it was not.
# The filter alone is half the feature; the other half is the run saying what
# it held back, and they ship together or not at all.
FPLAIN="$("$BOARD" --roots "$ROOT" --plan 2>/dev/null)"
FDEMO="$("$BOARD" --roots "$ROOT" --plan --focus demo 2>/dev/null)"
n_all="$(printf '%s\n' "$FPLAIN" | grep -c '^repo=')"
n_focus="$(printf '%s\n' "$FDEMO" | grep -c '^repo=')"
# The operator's instruction, as a test: prove it NARROWS. Every other check
# in this section passes trivially against a no-op filter, which is precisely
# the state the argument was in before this feature - swallowed by the unknown
# argument fallback, full plan returned, no crash. "It did not crash" is not
# evidence of a filter.
[ "$n_focus" -lt "$n_all" ] && [ "$n_focus" -gt 0 ]
check "focused plan is strictly smaller than the full plan, and not empty" $?
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-focus-plain$'
check "a repo declaring the slug survives the focus" $?
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-focus-bold$'
check "a bold/backtick declaration counts as declared (the register's grep loses it)" $?
# Bold around the STATUS rather than the slug. Accepting one and not the other
# is not a rule, just whichever example was in front of us first.
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-focus-boldstatus$'
check "bold on the status token counts as declared, same as bold on the slug" $?
printf '%s\n' "$FDEMO" | grep '^fokus_treff=' | grep -q 'demo-topic: done'
check "the evidence reports the status unwrapped, never '**done**'" $?
printf '%s\n' "$FPLAIN" | grep -q '^repo=repo-a$'
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-a$'; [ $? -ne 0 ]
check "an off-topic repo is in the full plan and gone from the focused one" $?
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-focus-other$'; [ $? -ne 0 ]
check "a repo declaring a DIFFERENT slug is not swept in" $?
# The precondition. A repo that mentions the slug without declaring it is
# neither kept nor dropped silently: it is named. Enumerating this class - not
# reasoning about it - is what found the heaviest consumer in the real tree.
printf '%s\n' "$FDEMO" | grep -q '^fokus_utenfor='
check "the run reports the repos it held back" $?
printf '%s\n' "$FDEMO" | grep '^fokus_utenfor=' | grep -q 'repo-focus-mentions'
check "the held-back report NAMES the repo, not just a count" $?
printf '%s\n' "$FDEMO" | grep -q '^repo=repo-focus-mentions$'; [ $? -ne 0 ]
check "a mention without a marker line does not become a tab" $?
# Wording is load-bearing: board.sh reads text, and has no grounds whatever
# for a claim about relevance. It says what it FOUND.
printf '%s\n' "$FDEMO" | grep '^fokus_utenfor=' | grep -q 'nevner'
check "the held-back line says 'nevner' (a fact about text found)" $?
printf '%s\n' "$FDEMO" | grep '^fokus_utenfor=' | grep -qi 'dekker'; [ $? -ne 0 ]
check "the held-back line never claims a repo 'dekker' the topic" $?
# It states its own reach: 27 STATE.md, not "the tree". One repo in the real
# measurement has its strongest evidence in a README the scan never opens.
printf '%s\n' "$FDEMO" | grep -q '^fokus_rekkevidde=.*STATE.md'
check "the run states its reach (N STATE.md searched, live-counted)" $?
n_state="$(printf '%s\n' "$FDEMO" | sed -n 's/^fokus_rekkevidde=sokt i \([0-9]*\) STATE.md.*/\1/p')"
# Both depths, because that is what board SCANS. The register's own roll-up
# greps ~/repos/*/STATE.md and so cannot see a polyrepo child; the reach line
# must state the population board actually searched, not the register's.
real_state="$(ls "$ROOT"/*/STATE.md "$ROOT"/*/*/STATE.md 2>/dev/null | wc -l | tr -d ' ')"
[ -n "$n_state" ] && [ "$n_state" = "$real_state" ]
check "the reach count is measured, never a constant" $?
printf '%s\n' "$FDEMO" | grep -q '^fokus=demo-topic$'
check "the run names the slug the prose resolved to" $?
# Per-block evidence: a focused run must say why each surviving block survived.
# This is the need that closed topics= - relocated from all 27 blocks every
# day into the focused run, where it is actually evidence.
n_blocks="$(printf '%s\n' "$FDEMO" | grep -c '^repo=')"
n_ev="$(printf '%s\n' "$FDEMO" | grep -c '^fokus_treff=')"
[ "$n_ev" -eq "$n_blocks" ] && ev_ok=0 || ev_ok=1
check "every surviving block carries its own evidence (fokus_treff=)" "$ev_ok"
printf '%s\n' "$FDEMO" | grep '^fokus_treff=' | grep -q 'demo-topic'
check "the per-block evidence names the slug and its declared status" $?
# Zero held back is a real answer and must LOOK like one. A trailing ": " with
# nothing after it is the same defect class the format already legislated
# against for command=: the shape of a value carrying nothing. Reached via a
# slug that nobody mentions without declaring.
FOTHER="$("$BOARD" --roots "$ROOT" --plan --focus other 2>/dev/null)"
printf '%s\n' "$FOTHER" | grep '^fokus_utenfor=' | grep -qE ':[[:space:]]*$'; [ $? -ne 0 ]
check "an empty held-back set renders a value, never a dangling colon" $?
# Ambiguity widens and is named. "topic" is a hyphen-part of two declared
# slugs; picking one silently would be the cutoff lying about its own size.
FBOTH="$("$BOARD" --roots "$ROOT" --plan --focus topic 2>/dev/null)"
printf '%s\n' "$FBOTH" | grep '^fokus=' | grep -q 'demo-topic'
printf '%s\n' "$FBOTH" | grep '^fokus=' | grep -q 'other-topic'
check "ambiguous prose resolves to the union, with every slug named" $?
printf '%s\n' "$FBOTH" | grep -q '^repo=repo-focus-other$'
check "the union actually includes the second slug's repo" $?
# No match: the full plan, plus a line saying the focus was not applied. An
# empty plan would be the worst outcome of all - the driver forwards operator
# prose verbatim, so a typo would silently produce a morning with no tabs.
FNONE="$("$BOARD" --roots "$ROOT" --plan --focus kaffe 2>/dev/null)"
n_none="$(printf '%s\n' "$FNONE" | grep -c '^repo=')"
[ "$n_none" -eq "$n_all" ]
check "prose matching no declared slug returns the FULL plan, never an empty one" $?
printf '%s\n' "$FNONE" | grep -q '^fokus_ikke_brukt='
check "a focus that was not applied says so" $?
# Format invariant: --focus adds fields, it does not change the shape two
# declared consumers parse.
printf '%s\n' "$FDEMO" | grep -vE '^#|^$|^[a-z_]+=' | grep -q .; [ $? -ne 0 ]
check "focused plan is still comments, blanks and key=value only" $?
printf '%s' "$FDEMO" | iconv -f UTF-8 -t UTF-8 >/dev/null 2>&1
check "focused plan output is valid UTF-8" $?
# The read-only invariant holds for the new path too: reading is delivering,
# and a plan that consumed a backlog would be the core defect of the engine.
before_inbox="$(ls "$CLAUDE_COORD_DIR/repo-a/inbox" 2>/dev/null | wc -l | tr -d ' ')"
"$BOARD" --roots "$ROOT" --plan --focus demo >/dev/null 2>&1
after_inbox="$(ls "$CLAUDE_COORD_DIR/repo-a/inbox" 2>/dev/null | wc -l | tr -d ' ')"
[ "$before_inbox" = "$after_inbox" ]
check "--focus writes nothing to the mailbox" $?
# bash 3.2: `shift 2` past the end loops forever. A flag whose value is missing
# must not hang the driver that forwards it - and it refuses loudly, exactly as
# --roots does, rather than degrading into "no focus" and printing a full plan
# that looks like a focused one.
"$BOARD" --roots "$ROOT" --plan --focus >/dev/null 2>&1
[ $? -eq 2 ]
check "--focus with no value exits 2, like every other flag missing its value" $?
"$BOARD" --help 2>/dev/null | grep -q '\-\-focus'
check "--help documents --focus" $?
# --- 12. Chain-root credit in --plan --------------------------------------
# Ordered by what a repo OWES, the plan could never say what OPENING it would
# RELEASE. blocked-on was scanned and then used for one display string only.
#
# The credit goes to the ROOT of the chain and to nothing else, and that is the
# whole rule: opening a blocked repo moves nothing, because its own next step is
# by definition waiting on someone. Opening the root moves everything behind it.
# So the walk is transitive - crediting only the direct blocker would leave a
# two-hop chain with its root uncredited, which is the shape the real tree
# actually had when this was ordered.
#
# Three fixtures, one chain: leaf -> mid -> root.
mkrepo "$ROOT/chain-root"
{
echo "# STATE - chain-root"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
# Deliberately `planned`, not `in-progress`: the root must earn its position
# from the chain-root group alone, never from the status group, so the ranking
# checks below fail for the right reason instead of passing on fixture order.
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
printf 'Roten %s ingen gjeld, men holder to repo oppe.\n' "$EMDASH"
} > "$ROOT/chain-root/STATE.md"
mkrepo "$ROOT/chain-mid"
{
echo "# STATE - chain-mid"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=chain-root; next-cost=Opus 5/high -->"
printf 'Venter p%s chain-root.\n' "$EMDASH"
} > "$ROOT/chain-mid/STATE.md"
mkrepo "$ROOT/chain-leaf"
{
echo "# STATE - chain-leaf"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=chain-mid; next-cost=Opus 5/high -->"
printf 'Venter p%s chain-mid, som venter p%s roten.\n' "$EMDASH" "$EMDASH"
} > "$ROOT/chain-leaf/STATE.md"
# A cycle is not hypothetical: two repos can each declare they wait on the other
# after a miscommunication, and nobody would notice until the board hung. The
# walk must terminate and credit NOBODY - a cycle has no root by definition.
mkrepo "$ROOT/cyc-a"
{
echo "# STATE - cyc-a"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=cyc-b; next-cost=Opus 5/high -->"
echo "Venter paa cyc-b."
} > "$ROOT/cyc-a/STATE.md"
mkrepo "$ROOT/cyc-b"
{
echo "# STATE - cyc-b"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=cyc-a; next-cost=Opus 5/high -->"
echo "Venter paa cyc-a."
} > "$ROOT/cyc-b/STATE.md"
# blocked-on names a repo the scan never produced. Nothing validates that field,
# so a typo is the expected case, not the exotic one - and it must credit
# nothing rather than credit a name that has no directory to open.
mkrepo "$ROOT/dangle"
{
echo "# STATE - dangle"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=no-such-repo; next-cost=Opus 5/high -->"
echo "Venter paa noe som ikke finnes."
} > "$ROOT/dangle/STATE.md"
# THE DISCRIMINATING PAIR for the 0.20.0 group form. Every other ordering check
# in this section passes under BOTH the 0.19.0 score and the group form, because
# chain-root releases two repos and 40*2 beats any debt in this tree - it would
# have gone green while the operator's decision quietly failed to ship.
#
# These two are built so the forms DISAGREE. solo-root releases exactly one repo
# and owes nothing (score: 40 + 5 planned = 45). heavy-debtor owes four (score:
# 60 + 10 in-progress = 70). The score ranks the debtor first; the group form
# ranks the root first, because releasing is group 1 and debt is group 2.
mkrepo "$ROOT/solo-root"
{
echo "# STATE - solo-root"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Opus 5/high -->"
printf 'Losner ett repo, skylder ingenting.\n'
} > "$ROOT/solo-root/STATE.md"
mkrepo "$ROOT/solo-leaf"
{
echo "# STATE - solo-leaf"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=blocked; blocked-on=solo-root; next-cost=Opus 5/high -->"
printf 'Venter p%s solo-root.\n' "$EMDASH"
} > "$ROOT/solo-leaf/STATE.md"
mkrepo "$ROOT/heavy-debtor"
{
echo "# STATE - heavy-debtor"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Opus 5/high -->"
printf 'Skylder fire svar, losner ingen.\n'
} > "$ROOT/heavy-debtor/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/heavy-debtor/inbox"
for n in 1 2 3 4; do
echo "msg" > "$CLAUDE_COORD_DIR/heavy-debtor/inbox/2026-msg$n-from-v.md"
done
P2="$("$BOARD" --roots "$ROOT" --plan 2>/dev/null)"; rc=$?
check "--plan still exits 0 with chain, cycle and dangling fixtures present" "$rc"
printf '%s' "$P2" | grep -q '^repo=chain-root$'
check "the root of a blocked chain is planned even though it owes no mail" $?
printf '%s\n' "$P2" | grep -A3 '^repo=chain-root$' | grep -q '^why=unblocks:2$'
check "the root is credited with the WHOLE subtree it holds up, not one edge" $?
# The exclusion these fixtures must not break: a blocked repo with no debt still
# gets no tab. The credit goes to the root precisely so the blocked repos do not
# need one - crediting them instead would open two tabs that cannot move.
printf '%s' "$P2" | grep -q '^repo=chain-mid$'; [ $? -ne 0 ]
check "a blocked middle link with no debt is still not planned" $?
printf '%s' "$P2" | grep -q '^repo=chain-leaf$'; [ $? -ne 0 ]
check "a blocked leaf with no debt is still not planned" $?
# Unblocking outranks work that neither owes nor releases anything. This is the
# point of the change: repo-h is in-progress and idle, chain-root is in-progress
# and holds two repos up.
n2_cr="$(printf '%s\n' "$P2" | grep -n '^repo=chain-root$' | cut -d: -f1)"
n2_h="$(printf '%s\n' "$P2" | grep -n '^repo=repo-h$' | cut -d: -f1)"
[ -n "$n2_cr" ] && [ -n "$n2_h" ] && [ "$n2_cr" -lt "$n2_h" ]
check "a chain root ranks above live work that releases nothing" $?
# THE decisive check for the 0.20.0 group form - the discriminating pair built
# above. solo-root releases ONE and owes nothing; heavy-debtor owes FOUR. This is
# the only ordering assertion in the file that the 0.19.0 score would fail, so it
# is the one that proves which form is actually running. Debt is still neither
# capped nor excluded here - it is one group lower, not down-weighted.
n2_sr="$(printf '%s\n' "$P2" | grep -n '^repo=solo-root$' | cut -d: -f1)"
n2_hd="$(printf '%s\n' "$P2" | grep -n '^repo=heavy-debtor$' | cut -d: -f1)"
[ -n "$n2_sr" ] && [ -n "$n2_hd" ] && [ "$n2_sr" -lt "$n2_hd" ]
check "releasing ONE repo outranks owing FOUR (group form, not the score)" $?
# The other half of the same rule: the debtor is still IN the plan, and still
# says debt is why. A group form that ranked debt lower by dropping it would be
# the excluded-debt defect wearing the operator's decision as a disguise.
printf '%s\n' "$P2" | grep -A3 '^repo=heavy-debtor$' | grep -q '^why=inbox:4$'
check "a repo outranked by a chain root still keeps its tab and its why=" $?
# A cycle terminates and credits nobody. Both halves matter: hanging is the
# failure everyone imagines, but silently inventing a root is the one that would
# ship - it looks like a working plan.
printf '%s' "$P2" | grep -q '^repo=cyc-a$'; [ $? -ne 0 ]
check "a cyclic blocked-on chain credits nobody (cyc-a not planned)" $?
printf '%s' "$P2" | grep -q '^repo=cyc-b$'; [ $? -ne 0 ]
check "a cyclic blocked-on chain credits nobody (cyc-b not planned)" $?
printf '%s' "$P2" | grep -q '^why=unblocks:0$'; [ $? -ne 0 ]
check "no repo is ever credited with an empty unblock count" $?
# A dangling blocked-on must not conjure a tab for a name with no directory.
printf '%s' "$P2" | grep -q '^repo=no-such-repo$'; [ $? -ne 0 ]
check "a dangling blocked-on target is never planned into existence" $?
printf '%s' "$P2" | grep -q '^repo=dangle$'; [ $? -ne 0 ]
check "the repo carrying a dangling blocked-on is itself still excluded" $?
# The format is the API. Changing the ranking form must not move, rename or drop
# a single field - the driver parses these keys positionally-independently, but
# it parses THESE keys.
n2_tab="$(printf '%s\n' "$P2" | grep -c '^tab=')"
n2_rep="$(printf '%s\n' "$P2" | grep -c '^repo=')"
n2_dir="$(printf '%s\n' "$P2" | grep -c '^dir=')"
n2_why="$(printf '%s\n' "$P2" | grep -c '^why=')"
n2_sta="$(printf '%s\n' "$P2" | grep -c '^status=')"
n2_nes="$(printf '%s\n' "$P2" | grep -c '^neste=')"
n2_cmd="$(printf '%s\n' "$P2" | grep -c '^command=')"
n2_cms="$(printf '%s\n' "$P2" | grep -c '^command_missing=')"
[ "$n2_tab" -gt 0 ] && [ "$n2_rep" -eq "$n2_tab" ] && [ "$n2_dir" -eq "$n2_tab" ] \
&& [ "$n2_why" -eq "$n2_tab" ] && [ "$n2_sta" -eq "$n2_tab" ] \
&& [ "$n2_nes" -eq "$n2_tab" ] && [ $(( n2_cmd + n2_cms )) -eq "$n2_tab" ]
check "ranked plan still carries every documented field exactly once per block" $?
printf '%s' "$P2" | grep -q '^command=$'; [ $? -ne 0 ]
check "ranked plan never emits an empty command= line" $?
# Debt still puts a repo in the plan and still names itself when it is the
# dominant reason. Rejecting the proposed cap on debt was a deliberate call:
# owing a reply is the other axis, and answering is often what unblocks a chain.
printf '%s\n' "$P2" | grep -A3 '^repo=repo-blocked-owes$' | grep -q '^why=inbox:2$'
check "debt still names itself in why= when it is the dominant reason" $?
# --brief is a second RENDERING of the same scan and must survive the change.
"$BOARD" --roots "$ROOT" --brief >/dev/null 2>&1
check "--brief still exits 0 after the ranking change" $?
# The plan must still print the scan whole. There is no cutoff by design, so a
# consumer's own tab cap is the only thing that ever hides a repo.
[ "$n2_tab" -ge "$n_tab" ]
check "the grouped plan hides nothing an earlier ordering showed" $?
# --- 13. Zero blocked repos does not empty the plan (NR==FNR regression) ---
# Isolated root, not the shared fixture tree above: that tree has carried a
# blocked repo (repo-blocked-owes, plug-x, ...) since the chain-root feature
# shipped, which is exactly the state that kept this bug invisible to every
# check above it. $UNBLOCKS is empty only when NO repo in the scan is blocked
# - an ordinary tree state, reproduced here with a root that has none at all.
# Verified against the shipped 0.21.0 script before this fix existed: this
# exact fixture produced "0 tabber" - solo-repo, with an unhandled inbox
# message and nothing blocking anything, vanished from its own plan.
NOBLOCK_ROOT="$(mktemp -d)"
NOBLOCK_COORD="$(mktemp -d)"
mkrepo "$NOBLOCK_ROOT/solo-repo"
{
echo "# STATE - solo-repo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Ordinary work, nothing blocked anywhere in this tree."
} > "$NOBLOCK_ROOT/solo-repo/STATE.md"
mkdir -p "$NOBLOCK_COORD/solo-repo/inbox"
echo "msg" > "$NOBLOCK_COORD/solo-repo/inbox/2026-msg1-from-w.md"
NOBLOCK_PLAN="$(CLAUDE_COORD_DIR="$NOBLOCK_COORD" "$BOARD" --roots "$NOBLOCK_ROOT" --plan 2>/dev/null)"
printf '%s' "$NOBLOCK_PLAN" | grep -q '^repo=solo-repo$'
check "zero blocked repos in the tree does not empty the plan (NR==FNR regression)" $?
printf '%s\n' "$NOBLOCK_PLAN" | grep -A3 '^repo=solo-repo$' | grep -q '^why=inbox:1$'
check "the surviving repo still ranks correctly with an empty chain-root lookup" $?
/bin/rm -rf "$NOBLOCK_ROOT" "$NOBLOCK_COORD" 2>/dev/null
# --- 14. Zero-debt briefing must not claim zero pending mail ---------------
# n_owe now counts OWED repos (section 8's fix), so its ==0 branch can fire
# while a repo still holds FYI-only mail - a real, re-injected message the
# operator has not seen answered here. The branch's own first sentence used
# to say "Ingen repo har uhaandtert innboks" (no repo has unhandled inbox),
# which becomes FALSE the moment that happens; its second sentence ("ingen
# skylder svar") stays true. Isolated root: the shared fixture tree never
# reaches n_owe==0 (repo-a and friends always owe something), so this branch
# is otherwise never exercised by this suite.
NODEBT_ROOT="$(mktemp -d)"
NODEBT_COORD="$(mktemp -d)"
mkrepo "$NODEBT_ROOT/fyi-only-repo"
{
echo "# STATE - fyi-only-repo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Ferdig, ett varsel ligger i innboksen."
} > "$NODEBT_ROOT/fyi-only-repo/STATE.md"
mkdir -p "$NODEBT_COORD/fyi-only-repo/inbox"
{
echo "---"
echo "from: w"
echo "to: fyi-only-repo"
echo "reply-expected: no"
echo "---"
echo "fyi only"
} > "$NODEBT_COORD/fyi-only-repo/inbox/2026-msg1-from-w.md"
NODEBT_BRIEF="$(CLAUDE_COORD_DIR="$NODEBT_COORD" "$BOARD" --roots "$NODEBT_ROOT" --brief 2>/dev/null)"
printf '%s' "$NODEBT_BRIEF" | grep -qi 'ingen.*uhaandtert innboks'; [ $? -ne 0 ]
check "zero-debt briefing never claims no mail is pending when FYI mail exists" $?
printf '%s' "$NODEBT_BRIEF" | grep -q 'Ingen repo skylder'
check "zero-debt briefing still states the true claim: nobody owes a reply" $?
/bin/rm -rf "$NODEBT_ROOT" "$NODEBT_COORD" 2>/dev/null
# --- 15. Inbox-plan rendering (--inbox-plan) --------------------------------
# A FOURTH rendering, ordered by morning-driver (20260814T175317Z, corrected
# 20260814T180854Z): --plan answers "which repos deserve a tab today"
# (admission, ranking, a cap); --innboks (in the driver) answers "which repos
# have unhandled post" (population, no judgement) - and deriving the second
# from the first was always a shortcut, since --plan's admission gate can and
# does exclude repos that still hold real, unhandled mail (done/deferred with
# FYI-only mail, for instance). --inbox-plan is the population question,
# answered directly: one block per NAME with pending>0 in the mailbox,
# independent of --plan's admission gate entirely - admitted or not.
#
# Isolated root+mailbox, not the shared fixture tree: this section needs a
# repo with pending mail that --plan would EXCLUDE (done + FYI-only), a repo
# with NO STATE.md at all that still has mail, and a mailbox with no matching
# repo directory anywhere in the scan - three distinct "why can't I open this"
# reasons the work order says must never collapse into one undifferentiated
# "kan ikke aapnes".
IP_ROOT="$(mktemp -d)"
IP_COORD="$(mktemp -d)"
# ip-repo-done-fyi: real repo, STATE.md + route line present, status=done with
# 2 pending messages that are BOTH FYI (reply-expected: no). --plan excludes
# this repo entirely (owed=0, status=done) - it is exactly one of the "7 ekte
# repo" the work order measured as invisible. class=repo, pending=2, owed=0.
mkrepo "$IP_ROOT/ip-repo-done-fyi"
{
echo "# STATE - ip-repo-done-fyi"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Ferdig, men to FYI-varsler ligger fortsatt i innboksen."
} > "$IP_ROOT/ip-repo-done-fyi/STATE.md"
mkdir -p "$IP_COORD/ip-repo-done-fyi/inbox"
for n in 1 2; do
{
echo "---"
echo "from: w"
echo "to: ip-repo-done-fyi"
echo "reply-expected: no"
echo "---"
echo "fyi only"
} > "$IP_COORD/ip-repo-done-fyi/inbox/2026-msg$n-from-w.md"
done
# ip-repo-instate-owes: already admitted by --plan (in-progress + owed). Must
# STILL appear in --inbox-plan: the mode is independent of admission, not a
# complement of it - a superset, not "only what --plan dropped".
mkrepo "$IP_ROOT/ip-repo-instate-owes"
{
echo "# STATE - ip-repo-instate-owes"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Skylder ett svar."
} > "$IP_ROOT/ip-repo-instate-owes/STATE.md"
mkdir -p "$IP_COORD/ip-repo-instate-owes/inbox"
echo "msg" > "$IP_COORD/ip-repo-instate-owes/inbox/2026-msg1-from-w.md"
# ip-repo-no-state: a real, scanned git repo (dir + .git) with NO STATE.md at
# all, holding one unhandled (owed-by-default) message. This is the
# content-sadhguru case: a repo the scan finds but that has no plan file, so
# no NESTE and no route line can ever exist for it - class=no-state.
mkrepo "$IP_ROOT/ip-repo-no-state"
mkdir -p "$IP_COORD/ip-repo-no-state/inbox"
echo "msg" > "$IP_COORD/ip-repo-no-state/inbox/2026-msg1-from-w.md"
# ip-repo-clean: real repo, real STATE.md, but NO pending mail at all. Proves
# the population is exactly "has pending mail" - nothing else earns a block.
mkrepo "$IP_ROOT/ip-repo-clean"
{
echo "# STATE - ip-repo-clean"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Ingenting i innboksen."
} > "$IP_ROOT/ip-repo-clean/STATE.md"
# ip-orphan: a mailbox with pending mail but NO matching repo directory
# anywhere under the scanned roots (the ktg-plugin-marketplace / svv /
# llm-ingestion-guard case: "ingen katalog", never opened as a tab).
mkdir -p "$IP_COORD/ip-orphan/inbox"
echo "msg" > "$IP_COORD/ip-orphan/inbox/2026-msg1-from-w.md"
IPLAN="$(CLAUDE_COORD_DIR="$IP_COORD" "$BOARD" --roots "$IP_ROOT" --inbox-plan 2>/dev/null)"; rc=$?
check "--inbox-plan exits 0" "$rc"
printf '%s' "$IPLAN" | grep -q '^# INBOX-PLAN '
check "inbox-plan carries a header naming what it is" $?
# The class the work order asks to be distinguished, never collapsed.
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-done-fyi$' | grep -q '^class=repo$'
check "a real repo with STATE.md is class=repo" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-no-state$' | grep -q '^class=no-state$'
check "a scanned repo with no STATE.md is class=no-state" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-orphan$' | grep -q '^class=orphan-mailbox$'
check "a mailbox with no matching repo directory is class=orphan-mailbox" $?
# Independence from --plan's admission gate: a done+FYI-only repo --plan would
# never seat still gets a block here.
IPLAN_PLAN="$(CLAUDE_COORD_DIR="$IP_COORD" "$BOARD" --roots "$IP_ROOT" --plan 2>/dev/null)"
printf '%s' "$IPLAN_PLAN" | grep -q '^repo=ip-repo-done-fyi$'; [ $? -ne 0 ]
check "fixture check: --plan itself excludes the done+FYI-only repo" $?
printf '%s' "$IPLAN" | grep -q '^repo=ip-repo-done-fyi$'
check "--inbox-plan includes a repo --plan's admission gate would exclude" $?
# Superset, not a complement: an already-admitted repo still gets a block.
printf '%s' "$IPLAN" | grep -q '^repo=ip-repo-instate-owes$'
check "--inbox-plan also includes a repo --plan already admits" $?
# A repo with zero pending mail earns no block at all.
printf '%s' "$IPLAN" | grep -q '^repo=ip-repo-clean$'; [ $? -ne 0 ]
check "--inbox-plan excludes a repo with no pending mail" $?
# Owed vs FYI (ask #2 of the work order): coord-count's debt field, surfaced
# directly rather than re-derived.
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-done-fyi$' | grep -q '^pending=2$'
check "ip-repo-done-fyi reports 2 pending messages" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-done-fyi$' | grep -q '^owed=0$'
check "ip-repo-done-fyi reports 0 owed (both messages are FYI)" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-no-state$' | grep -q '^pending=1$'
check "ip-repo-no-state reports 1 pending message" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-no-state$' | grep -q '^owed=1$'
check "ip-repo-no-state reports 1 owed (no reply-expected: no declared)" $?
# class=repo still derives the exact startup command from the repo's own
# route line - same single copy of the rubric every other rendering uses.
printf '%s\n' "$IPLAN" | grep -A8 '^repo=ip-repo-done-fyi$' \
| grep -q '^command=claude --model sonnet --effort high --advisor opus$'
check "class=repo block derives its command from the repo's own route line" $?
# class=no-state and class=orphan-mailbox can never fabricate a command - ask
# #1 requires an accurate reason, not an undifferentiated "kan ikke aapnes".
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-repo-no-state$' | grep -q '^command=$'; [ $? -ne 0 ]
check "class=no-state never emits an empty command= line" $?
printf '%s\n' "$IPLAN" | grep -A8 '^repo=ip-repo-no-state$' | grep -q '^command_missing=.*STATE.md'
check "class=no-state names the missing STATE.md as the reason, not a guess" $?
printf '%s\n' "$IPLAN" | grep -A8 '^repo=ip-orphan$' | grep -q '^command_missing=.*katalog'
check "class=orphan-mailbox names the missing directory as the reason" $?
printf '%s\n' "$IPLAN" | grep -A6 '^repo=ip-orphan$' | grep -q '^dir=-$'
check "class=orphan-mailbox has no directory to cd into" $?
# Every block is complete: a driver reading a partial block has no safe
# default. Same invariant section 10 pins for --plan.
n_ip_tab="$(printf '%s\n' "$IPLAN" | grep -c '^tab=')"
n_ip_rep="$(printf '%s\n' "$IPLAN" | grep -c '^repo=')"
n_ip_dir="$(printf '%s\n' "$IPLAN" | grep -c '^dir=')"
n_ip_cls="$(printf '%s\n' "$IPLAN" | grep -c '^class=')"
n_ip_pnd="$(printf '%s\n' "$IPLAN" | grep -c '^pending=')"
n_ip_owe="$(printf '%s\n' "$IPLAN" | grep -c '^owed=')"
n_ip_sta="$(printf '%s\n' "$IPLAN" | grep -c '^status=')"
n_ip_nes="$(printf '%s\n' "$IPLAN" | grep -c '^neste=')"
n_ip_cmd="$(printf '%s\n' "$IPLAN" | grep -c '^command=')"
n_ip_cms="$(printf '%s\n' "$IPLAN" | grep -c '^command_missing=')"
[ "$n_ip_tab" -gt 0 ] && [ "$n_ip_rep" -eq "$n_ip_tab" ] && [ "$n_ip_dir" -eq "$n_ip_tab" ] \
&& [ "$n_ip_cls" -eq "$n_ip_tab" ] && [ "$n_ip_pnd" -eq "$n_ip_tab" ] \
&& [ "$n_ip_owe" -eq "$n_ip_tab" ] && [ "$n_ip_sta" -eq "$n_ip_tab" ] \
&& [ "$n_ip_nes" -eq "$n_ip_tab" ] && [ $(( n_ip_cmd + n_ip_cms )) -eq "$n_ip_tab" ]
check "every inbox-plan block carries every field exactly once" $?
# Dense, consecutive numbering - a driver opening tab 4 of 3 is a real failure.
seq_ok=0
printf '%s\n' "$IPLAN" | grep '^tab=' | cut -d= -f2 > "$IP_ROOT/tabs.txt"
[ -s "$IP_ROOT/tabs.txt" ] || seq_ok=1
i=0; while read -r t; do i=$((i+1)); [ "$t" = "$i" ] || seq_ok=1; done < "$IP_ROOT/tabs.txt"
check "inbox-plan tab numbers are dense and consecutive" "$seq_ok"
# Read-only, same invariant as every other rendering.
p5="$(snap "$IP_COORD")"
CLAUDE_COORD_DIR="$IP_COORD" "$BOARD" --roots "$IP_ROOT" --inbox-plan >/dev/null 2>&1
[ "$p5" = "$(snap "$IP_COORD")" ]
check "inbox-plan writes nothing to the mailbox (reading is delivering)" $?
printf '%s' "$IPLAN" | iconv -f UTF-8 -t UTF-8 >/dev/null 2>&1
check "inbox-plan output is valid UTF-8" $?
"$BOARD" --help 2>/dev/null | grep -q '\-\-inbox-plan'
check "--help documents --inbox-plan" $?
/bin/rm -rf "$IP_ROOT" "$IP_COORD" 2>/dev/null
# --- 16. Dead-letter flagging in --brief (.origin-age, coord-count.sh col 4) -
# WP1d (.claude, 2026-08-14): a census of the real mailbox found unhandled mail
# sitting in mailboxes no session has ever read - .origin is written only by
# coord-inbox.sh's real (non --repo) SessionStart path, so a mailbox lacking it
# is never reached by the normal injection at all. This is the detection half
# of WP1d only: coord-count.sh's fourth column reports the age in days of the
# OLDEST pending message when .origin is absent (coord-selftest.sh section 31);
# --brief surfaces mailboxes past the 3-day threshold as their own class,
# mirroring how it already surfaces orphan mailboxes with no matching repo.
# The action half (report to sender / retract) is unapproved design and is
# deliberately not built here.
DL_ROOT="$(mktemp -d)"
DL_COORD="$(mktemp -d)"
mkrepo "$DL_ROOT/dead-letter-repo"
{
echo "# STATE - dead-letter-repo"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=sonnet/high -->"
echo "Noe a gjore."
} > "$DL_ROOT/dead-letter-repo/STATE.md"
mkdir -p "$DL_COORD/dead-letter-repo/inbox"
cat > "$DL_COORD/dead-letter-repo/inbox/$(date -u -v-10d +%Y%m%dT%H%M%SZ)-1-from-somebody.md" <<'EOF'
---
from: somebody
to: dead-letter-repo
subject: rotting notice
date: 2026-08-01T00:00:00Z
reply-expected: no
---
Nobody has ever read this mailbox.
EOF
# A mailbox WITH .origin must never be flagged, no matter how old its mail is -
# .origin means a real session claims and reads it regularly.
mkrepo "$DL_ROOT/claimed-repo"
{
echo "# STATE - claimed-repo"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=sonnet/high -->"
echo "Noe annet."
} > "$DL_ROOT/claimed-repo/STATE.md"
mkdir -p "$DL_COORD/claimed-repo/inbox"
printf '%s\n' "/tmp/claimed-repo" > "$DL_COORD/claimed-repo/.origin"
cat > "$DL_COORD/claimed-repo/inbox/$(date -u -v-10d +%Y%m%dT%H%M%SZ)-1-from-somebody.md" <<'EOF'
---
from: somebody
to: claimed-repo
subject: old but claimed
date: 2026-08-01T00:00:00Z
reply-expected: no
---
This mailbox is claimed - never flagged.
EOF
DLBRIEF="$(CLAUDE_COORD_DIR="$DL_COORD" "$BOARD" --roots "$DL_ROOT" --brief 2>/dev/null)"
printf '%s' "$DLBRIEF" | grep -qi 'dead-letter-repo'
check "brief flags a mailbox with no .origin and mail older than the threshold" $?
printf '%s' "$DLBRIEF" | grep -qi 'aldri lest\|never read\|\.origin'
check "the flag names why the mailbox is flagged, not just its name" $?
printf '%s' "$DLBRIEF" | grep -A3 -i 'aldri lest' | grep -qi 'claimed-repo'; [ $? -ne 0 ]
check "a mailbox WITH .origin is never flagged, regardless of message age" $?
/bin/rm -rf "$DL_ROOT" "$DL_COORD" 2>/dev/null
# --- 17. Missing coord-count.sh sibling never reads as "checked, zero debt" -
# Review finding 1 (2026-08-14), reproduced exactly as measured: copy board.sh
# + route.sh to a scratch dir WITHOUT coord-count.sh (the 0.12.1 deployed-copy
# incident shape), point it at a fixture mailbox where one repo holds a
# reply-owing message. Before the fix, the copy's --brief claimed "Ingen repo
# skylder noen et svar i dag." and then actively mislabeled the reply-owing
# repo as "bare FYI-post" - a false statement, not merely an absent one - and
# --inbox-plan silently rendered 0 blocks instead of 1. This section pins the
# fix's actual claim: a warning, never a confident zero or a mislabel.
SIB_ROOT="$(mktemp -d)"
SIB_COORD="$(mktemp -d)"
SIB_SCRATCH="$(mktemp -d)"
cp "$DIR/board.sh" "$SIB_SCRATCH/board.sh"
cp "$DIR/route.sh" "$SIB_SCRATCH/route.sh"
chmod +x "$SIB_SCRATCH/board.sh" "$SIB_SCRATCH/route.sh"
# coord-count.sh deliberately not copied here.
mkrepo "$SIB_ROOT/repo-a"
{
echo "# STATE - repo-a"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=sonnet/high -->"
echo "Noe a gjore."
} > "$SIB_ROOT/repo-a/STATE.md"
mkdir -p "$SIB_COORD/repo-a/inbox"
cat > "$SIB_COORD/repo-a/inbox/20260101T000000Z-1-from-somebody.md" <<'EOF'
---
from: somebody
to: repo-a
subject: needs an answer
date: 2026-01-01T00:00:00Z
reply-expected: yes
---
Please respond.
EOF
SIBBRIEF="$(CLAUDE_COORD_DIR="$SIB_COORD" "$SIB_SCRATCH/board.sh" --roots "$SIB_ROOT" --brief 2>/dev/null)"
printf '%s' "$SIBBRIEF" | grep -qi 'bare FYI-post'; [ $? -ne 0 ]
check "missing sibling: --brief never mislabels a reply-owing repo as FYI-only" $?
printf '%s' "$SIBBRIEF" | grep -qi 'coord-count.sh mangler'
check "missing sibling: --brief surfaces a warning instead of a confident zero" $?
printf '%s' "$SIBBRIEF" | grep -qi '^Ingen repo skylder noen et svar i dag\.$'; [ $? -ne 0 ]
check "missing sibling: --brief does not print the debt-free claim it could not verify" $?
SIBPLAN="$(CLAUDE_COORD_DIR="$SIB_COORD" "$SIB_SCRATCH/board.sh" --roots "$SIB_ROOT" --plan 2>/dev/null)"
printf '%s' "$SIBPLAN" | grep -q '^advarsel=coord-count.sh mangler'
check "missing sibling: --plan carries a machine-readable warning key" $?
SIBIP="$(CLAUDE_COORD_DIR="$SIB_COORD" "$SIB_SCRATCH/board.sh" --roots "$SIB_ROOT" --inbox-plan 2>/dev/null)"
printf '%s' "$SIBIP" | grep -q '^advarsel=coord-count.sh mangler'
check "missing sibling: --inbox-plan carries a machine-readable warning key, not a silent 0 blocks" $?
/bin/rm -rf "$SIB_ROOT" "$SIB_COORD" "$SIB_SCRATCH" 2>/dev/null
# --- 18. Dispatch rendering (--dispatch) ------------------------------------
# The FOURTH rendering of the same scan, and the one that carries a task INTO
# another repo. It exists here rather than in a new script for one reason: the
# block format has exactly one generator, and board.sh already owns it
# (tab=/repo=/dir=/command=/paste=, consumed by morning's plan_parse). A second
# emitter of the same file format is the drift defect this repo's CLAUDE.md
# warns about, and it would be a second place to get `paste=` wrong.
#
# Read-only holds: every check here is a read (test -s on the prompt file, the
# path grammar, the scan), and the FILE WRITES - the prompt file and the plan
# file - stay with the caller. That is the brief-nightly.sh split, unchanged.
DSP="$ROOT/dispatch.prompt"
printf 'ORDRE X - do the thing.\nWith $(whoami) and `id` and "quotes" in the body.\n' > "$DSP"
DSPEMPTY="$ROOT/empty.prompt"
: > "$DSPEMPTY"
DSPTRAITS='--path known --verification strong --reversibility cheap --scope local --rationale t'
# --target-pane has NO DEFAULT, and that is the same rule route.sh's
# --last-effort carries: the answer is a MEASUREMENT of the world (does the
# target repo already have a Ghostty pane), and a calculator that guesses it
# produces a dispatch that verifies green and opens nothing. Defaulting to
# "no" would be worst: that is the plan-file form, which morning's
# plan_drop_open (morning:1788) silently drops for a repo that already has a
# pane - measured four times in one day, 2026-08-16, and read every time as a
# broken plan file rather than as the filter doing its job.
d1="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses without --target-pane (no default, it is a measurement)" $?
printf '%s' "$d1" | grep -q 'command='; [ $? -ne 0 ]; check "dispatch: emits no command when it refuses for a missing --target-pane" $?
d2="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane maybe $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses a --target-pane value outside yes|no" $?
# The prompt file is the whole payload: an empty one produces a session that
# is started and then told nothing, which is indistinguishable from a session
# waiting for Go - and the operator has to diagnose it from the far end.
d3="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$ROOT/nope.prompt" --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses a prompt file that does not exist" $?
d4="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSPEMPTY" --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses an EMPTY prompt file (test -s, not test -e)" $?
# The PATH is what has to be shell-clean, not the prompt CONTENT. Verified
# directly (2026-08-16): `"$(cat f)"` passes the file's bytes as ONE argv
# element with no re-evaluation, so $(...), backticks, quotes and UTF-8 in the
# BODY are inert - that is precisely why the dispatch form puts the prompt in
# argv instead of inlining it. The path, though, sits inside those quotes and
# IS evaluated, so a space or a quote in it splits the command.
mkdir -p "$ROOT/dir with space"
cp "$DSP" "$ROOT/dir with space/p.prompt"
d5="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$ROOT/dir with space/p.prompt" --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses a prompt PATH that is not shell-clean" $?
# A relative path resolves against whatever directory the pane is in, which
# for the paste-only form is a repo this script never sees - so the command
# would read a different file, or none, with no error anywhere near the
# dispatch.
d5b="$(cd "$ROOT" && "$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file dispatch.prompt --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses a RELATIVE prompt path (it resolves in the pane, not here)" $?
d6="$("$BOARD" --roots "$ROOT" --dispatch --repo no-such-repo --prompt-file "$DSP" --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses a repo the scan does not know" $?
# Invalid traits must refuse, never degrade to a command without them: a
# command missing --advisor reads exactly like a row that legitimately has no
# advisor.
d7="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane no \
--path bogus --verification strong --reversibility cheap --scope local --rationale t 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch: refuses trait values route.sh rejects, rather than emitting a partial command" $?
# --- The plan-file form (target has NO pane) ---
d8="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane no $DSPTRAITS 2>/dev/null)"; rc=$?
[ "$rc" -eq 0 ]; check "dispatch: the plan-file form exits 0" $?
printf '%s\n' "$d8" | grep -q '^form=plan-file'; check "dispatch: names its output form machine-readably" $?
# The four keys morning's plan_parse requires (lib/plan.sh:30-46). Named here
# rather than by sourcing that library: it lives in another repo, and this
# selftest pins OUR side of the contract.
printf '%s\n' "$d8" | grep -q '^tab=1$'; check "dispatch: plan block carries tab= (plan_parse discards a block without it)" $?
printf '%s\n' "$d8" | grep -q '^repo=repo-a$'; check "dispatch: plan block carries repo=" $?
printf '%s\n' "$d8" | grep -q "^dir=$ROOT/repo-a\$"; check "dispatch: plan block carries dir=" $?
printf '%s\n' "$d8" | grep -q '^paste=cd '; check "dispatch: plan block carries a paste= that cds first" $?
# The prompt reaches the session through argv. A bare model+effort command
# forces the operator to type Go, and the session must then GUESS the task out
# of STATE instead of being handed it - measured twice on 2026-08-16.
printf '%s\n' "$d8" | grep -q "command=.*\"\$(cat $DSP)\""; check "dispatch: the command carries the prompt in argv, never bare model+effort" $?
printf '%s\n' "$d8" | grep -q "^paste=cd $ROOT/repo-a && claude .*\"\$(cat $DSP)\""; check "dispatch: paste= is the complete one-string form, prompt included" $?
# The cost comes from route.sh's row table and nowhere else, so --advisor is a
# property of the ROW. These two differ ONLY in reversibility: both land on
# row 3 (Opus 5/high), and only the costly one carries the advisor. A dispatch
# that took --model/--effort directly would have no source for that flag at
# all, and forwarding it blindly is how a session ends up looking peer-reviewed
# without being.
d9="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane no \
--path known --verification strong --reversibility cheap --scope multi-file --rationale t 2>/dev/null)"
printf '%s\n' "$d9" | grep -q '^command=claude --model opus --effort high "'; check "dispatch: model+effort come from the route row (row 3, no advisor at cheap)" $?
d10="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane no \
--path known --verification strong --reversibility costly --scope local --rationale t 2>/dev/null)"
printf '%s\n' "$d10" | grep -q '^command=claude --model opus --effort high --advisor opus "'; check "dispatch: the advisor flag follows the ROW (costly -> row 3 with advisor)" $?
printf '%s\n' "$d8" | grep -q '^next-cost=Sonnet 5/high$'; check "dispatch: the row's next-cost is reported alongside the command" $?
# --no-go stops the Go MESSAGE, not the work: the startup command - prompt in
# argv and all - is typed regardless (morning:806). An operator decided on the
# opposite premise once already, and it had to be corrected before the run.
printf '%s\n' "$d8" | grep -qi 'no-go'; check "dispatch: the plan-file form states what --no-go does and does not stop" $?
# The dry-run is NOT the pane gate, and the output must not imply it is.
# Measured 2026-08-16 against the real morning: run without a tty (which is
# every Claude session) it prints "window: unknown ... assuming an empty
# window" and plan_drop_open never fires, so a dry-run gate would pass the
# self-dispatch case every time - the one case it would exist to catch.
printf '%s\n' "$d8" | grep -q 'probe-panes'; check "dispatch: points at the measurement that CAN answer the pane question" $?
# --- The paste-only form (target ALREADY has a pane) ---
d11="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --prompt-file "$DSP" --target-pane yes $DSPTRAITS 2>/dev/null)"; rc=$?
[ "$rc" -eq 0 ]; check "dispatch: the paste-only form exits 0" $?
printf '%s\n' "$d11" | grep -q '^form=paste-only'; check "dispatch: names the paste-only form machine-readably" $?
# No tab= is the load-bearing half: a block with tab= is a plan block, and a
# plan block for a repo that already has a pane is the one morning drops in
# silence. Withholding the key makes the wrong use impossible rather than
# merely discouraged.
printf '%s\n' "$d11" | grep -q '^tab='; [ $? -ne 0 ]; check "dispatch: the paste-only form emits NO tab= (it must never be fed to morning as a plan)" $?
printf '%s\n' "$d11" | grep -q '^paste=claude '; check "dispatch: paste-only starts the session directly" $?
# One repo per terminal tab: the operator is already standing in that repo, so
# a cd is at best noise and at worst a session started in the wrong directory.
printf '%s\n' "$d11" | grep -q '^paste=cd '; [ $? -ne 0 ]; check "dispatch: paste-only carries NO cd (the operator is already in that tab)" $?
printf '%s\n' "$d11" | grep -q "^paste=claude .*\"\$(cat $DSP)\""; check "dispatch: paste-only also carries the prompt in argv" $?
printf '%s\n' "$d11" | grep -qi 'exit'; check "dispatch: paste-only says the existing session must be exited first" $?
printf '%s\n' "$d11" | grep -q 'plan_drop_open'; check "dispatch: paste-only names the filter that made this form necessary" $?
# --- The --order-id thin starter must call the verbs by an executable path ---
# ORDRE 65 (.claude, 2026-08-17): the starter text told a dispatched session to
# run `coord-order-claim <id>` and `coord-order-done <id> ...` as bare command
# names. Neither is on PATH (only coord-send.sh/coord-inbox.sh/coord-done.sh
# have ever been documented as bare names, and only in prose a human reads -
# this string lands in argv and a SESSION executes it literally). The absolute
# path is derived from where board.sh itself is running FROM ($0's directory,
# the same $SELFDIR variable ROUTE already uses), not a literal "0.27.0" - so
# it is correct at EMISSION time for whichever cache path is actually live
# then. It does not survive a version bump landing between generation and
# paste - a plan-file form held across a release can still go stale.
mkdir -p "$CLAUDE_COORD_DIR/repo-a/orders"
echo "order body" > "$CLAUDE_COORD_DIR/repo-a/orders/testorder1.md"
d12="$("$BOARD" --roots "$ROOT" --dispatch --repo repo-a --order-id testorder1 --target-pane no $DSPTRAITS 2>/dev/null)"; rc=$?
[ "$rc" -eq 0 ]; check "dispatch --order-id: exits 0 for a pending order" $?
# Anchored to `bash /` (not just `/scripts/...`) so a RELATIVE path (which
# would also contain the substring "/scripts/coord-order-claim.sh") cannot
# pass this check - the property being tested is "absolute", not "has slashes".
printf '%s\n' "$d12" | grep -Eq 'command=.*bash /.*/scripts/coord-order-claim\.sh testorder1'; check "dispatch --order-id: starter calls coord-order-claim.sh by an ABSOLUTE script path, not a bare PATH name" $?
printf '%s\n' "$d12" | grep -Eq 'command=.*bash /.*/scripts/coord-order-done\.sh testorder1 --commit'; check "dispatch --order-id: starter calls coord-order-done.sh by an ABSOLUTE script path, not a bare PATH name" $?
printf '%s\n' "$d12" | grep -Eq '(^|[^./])coord-order-claim testorder1'; [ $? -ne 0 ]; check "dispatch --order-id: no bare, un-pathed coord-order-claim invocation survives in the starter" $?
printf '%s\n' "$d12" | grep -Eq '(^|[^./])coord-order-done testorder1'; [ $? -ne 0 ]; check "dispatch --order-id: no bare, un-pathed coord-order-done invocation survives in the starter" $?
# --- The $SELFDIR interpolation is shell-clean-guarded like $D_PROMPT/$D_ORDER ---
# It is install-location-derived, not operator input, but it lands in the
# EXACT SAME double-quoted position in $d_full as those two - so a mis-
# installed path containing a space would silently break the pasted command
# the same way an unchecked --prompt-file would. Verified REACHABLE (not
# speculative): copy board.sh + route.sh into a directory whose path contains
# a space and invoke the COPY, so $0's own directory is genuinely unclean.
SPACEDIR="$ROOT/dir with space/scripts"
mkdir -p "$SPACEDIR"
cp "$BOARD" "$DIR/route.sh" "$SPACEDIR/" && chmod +x "$SPACEDIR/board.sh" "$SPACEDIR/route.sh"
d12b="$("$SPACEDIR/board.sh" --roots "$ROOT" --dispatch --repo repo-a --order-id testorder1 --target-pane no $DSPTRAITS 2>&1)"; rc=$?
[ "$rc" -eq 2 ]; check "dispatch --order-id: refuses when board.sh's OWN directory is not shell-clean (a mis-installed path with a space)" $?
printf '%s' "$d12b" | grep -q 'command='; [ $? -ne 0 ]; check "dispatch --order-id: emits no command when its own directory is not shell-clean" $?
/bin/rm -rf "$ROOT/dir with space" 2>/dev/null
# --- 19. The dispatch skill's own engine line ------------------------------
# Same defect class coord-selftest section 28 pins for coord-send/SKILL.md: a
# Bash tool call never has CLAUDE_PLUGIN_ROOT set, so a `:-` fallback wins
# every time the line is actually executed and routes through some other copy.
# Fail loud (empty path) rather than silently running the wrong script.
DSKILL="$DIR/../skills/dispatch/SKILL.md"
[ -f "$DSKILL" ]; check "dispatch SKILL.md is where the selftest expects it" $?
grep -q 'BOARD="\${CLAUDE_PLUGIN_ROOT}/scripts/board.sh"' "$DSKILL"
check "dispatch SKILL.md's engine line has no fallback path" $?
if grep -q 'BOARD=.*CLAUDE_PLUGIN_ROOT:-' "$DSKILL"; then rc=1; else rc=0; fi
check "dispatch SKILL.md's BOARD assignment carries no fallback" "$rc"
# The pane question has exactly one measurement, and the skill must send the
# caller to it rather than to the dry-run, which cannot answer it from a
# session (no tty -> morning assumes an empty window).
grep -q 'probe-panes' "$DSKILL"
check "dispatch SKILL.md names --probe-panes as the pane measurement" $?
# The order engine is the second engine line in the same skill, and it carries
# the identical fallback hazard for the identical reason.
grep -q 'ORDER="\${CLAUDE_PLUGIN_ROOT}/scripts/coord-order-send.sh"' "$DSKILL"
check "dispatch SKILL.md's order engine line has no fallback path" $?
if grep -q 'ORDER=.*CLAUDE_PLUGIN_ROOT:-' "$DSKILL"; then rc=1; else rc=0; fi
check "dispatch SKILL.md's ORDER assignment carries no fallback" "$rc"
# The queue is the canonical home of the order text; a skill that still told
# the caller to inline the prompt would reopen the scratch-only defect.
grep -q -- '--order-id' "$DSKILL"
check "dispatch SKILL.md dispatches on --order-id" $?
# --- 20. The ORDRE column ---------------------------------------------------
# Two mailbox-derived columns, never summed and never merged: INN is "others
# are waiting on YOU", ORDRE is "authorized work is waiting on this REPO".
# Own root, so the two counts can be set independently of the shared fixture
# tree and read off one rendered row.
ORD_ROOT="$(mktemp -d)"
mkrepo "$ORD_ROOT/ord-both"
{
echo "# STATE - ord-both"
echo ""
printf '## %s NESTE\n' "$HAND"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Do the planned thing."
} > "$ORD_ROOT/ord-both/STATE.md"
mkrepo "$ORD_ROOT/ord-none"
{
echo "# STATE - ord-none"
echo ""
printf '## %s NESTE\n' "$HAND"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Nothing waiting here."
} > "$ORD_ROOT/ord-none/STATE.md"
mkdir -p "$CLAUDE_COORD_DIR/ord-both/inbox" "$CLAUDE_COORD_DIR/ord-both/orders" \
"$CLAUDE_COORD_DIR/ord-both/orders/claimed"
for i in 1 2 3; do
printf -- '---\nfrom: x\nto: ord-both\nsubject: m%s\n---\nbody\n' "$i" \
> "$CLAUDE_COORD_DIR/ord-both/inbox/2026010${i}T000000Z-${i}-from-x.md"
done
for i in 1 2; do
printf -- '---\nfrom: d\nto: ord-both\norder-id: o%s\nsubject: order %s\n---\nbody\n' "$i" "$i" \
> "$CLAUDE_COORD_DIR/ord-both/orders/2026010${i}T000000Z-${i}-from-d.md"
done
# A CLAIMED order is deliberately NOT counted: the column answers "what can a
# session pick up here", and one already in flight cannot be. Counting it would
# open a tab for work someone else holds.
printf -- '---\nfrom: d\nto: ord-both\norder-id: o9\nsubject: in flight\n---\nbody\n' \
> "$CLAUDE_COORD_DIR/ord-both/orders/claimed/20260109T000000Z-9-from-d.md"
ORD_OUT="$("$BOARD" --roots "$ORD_ROOT" 2>/dev/null)"
printf '%s' "$ORD_OUT" | grep -q 'ORDRE'; check "table header carries an ORDRE column" $?
# Matched on the rendered row, not by awk field index: KOST is "Sonnet 5/high"
# and contains a space, so a field number would be counting other columns and
# would keep passing if the layout shifted.
printf '%s' "$ORD_OUT" | grep -qE '^ord-both[[:space:]]+planned[[:space:]]+Sonnet 5/high[[:space:]]+3[[:space:]]+2[[:space:]]'
check "INN 3 and ORDRE 2 are printed side by side, never summed" $?
printf '%s' "$ORD_OUT" | grep -qE '^ord-none[[:space:]]+planned[[:space:]]+Sonnet 5/high[[:space:]]+0[[:space:]]+0[[:space:]]'
check "a repo with no mail and no orders reads 0 in both columns" $?
# neste is the LAST field of the record and may contain a literal '|' from a
# markdown table, which is why orders was inserted before it and not after.
printf '%s' "$ORD_OUT" | grep -q 'Do the planned thing'
check "NESTE still renders after the field insertion" $?
printf '%s' "$ORD_OUT" | grep -q 'summeres ALDRI'
check "the legend states that INN and ORDRE are never summed" $?
/bin/rm -rf "$ORD_ROOT" 2>/dev/null
# --- 21. board.sh contains no live NR==FNR (structural invariant) ----------
# F12: a third NR==FNR survived at the focus-filter join in plan() (fp_names x
# pf), next to two comments (1131-1138, 1294) that state the file's own rule -
# "never by NR==FNR" - as prose. Measured before writing this section (not
# assumed): for a plain two-file keep-set join with no third file whose lookup
# table a misroute could corrupt, an empty fp_names produces the SAME output
# (0 kept) under NR==FNR and under FILENAME== alike, because when fp_names is
# genuinely empty (0 repos anywhere declare the resolved focus slug) 0 kept
# IS the correct answer - unlike the two prior instances in this file, where
# an empty first file silently dropped a lookup table (ub[]/ow[]) consumed by
# a THIRD file. FOCUS_SLUGS is provably a subset of what focus_slugs() finds
# in $RECORDS, and focus_declares() re-checks the identical regex against the
# identical $RECORDS, so fp_names cannot be empty while fp_applied=1 in normal
# use - there is no reachable, observable defect here to pin behaviourally,
# and a --focus fixture asserting one would pass identically before and after
# this fix (verified with a standalone awk run, both forms, both empty and
# non-empty first files: identical output every time). The fix is therefore
# structural, not behavioural: line 1195 is a live counter-example to a rule
# this file states about itself, which is a trap for the next session that
# greps NR==FNR expecting every hit to be a bug and finds one that works.
grep -v '^[[:space:]]*#' "$BOARD" | grep -c 'NR==FNR' | grep -q '^0$'
check "board.sh has no live NR==FNR outside comments (the file's own stated rule)" $?
# Known-positive control: without this, the check above could be finding
# nothing because the filter is broken, not because the file is clean.
NRFNR_FIXTURE="${TMPDIR:-/tmp}/board-nrfnr-fixture.$$"
printf ' awk NR==FNR live code, not a comment\n' > "$NRFNR_FIXTURE"
grep -v '^[[:space:]]*#' "$NRFNR_FIXTURE" | grep -q 'NR==FNR'
check "the same filter+grep DOES find a live NR==FNR in a known-positive fixture" $?
/bin/rm -f "$NRFNR_FIXTURE" 2>/dev/null
# --- 22. Dot-prefixed repo discovery (board.sh:265/271 dotglob gap) --------
# Ordre 20260818T124828Z-136209036-from-.claude, measured: `for entry in
# "$root"/*` has no dotglob, so a dot-prefixed repo directory (the Forgejo/
# GitHub `.profile` org-profile convention) is never seen by board at all -
# not listed, not dispatchable ("no repo named '.profile' in the scanned
# roots"). Known-positive control per the order: two repos in one isolated
# root, one dot-prefixed, one not - board must find BOTH, not just the dot
# one (a test that only checked the dot-repo would pass even if the fix
# broke the ordinary case).
DOT_ROOT="$(mktemp -d)"
mkrepo "$DOT_ROOT/.dotrepo"
{
echo "# STATE - .dotrepo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Dot-prefixed repo, e.g. the .profile org-profile convention."
} > "$DOT_ROOT/.dotrepo/STATE.md"
mkrepo "$DOT_ROOT/regularrepo"
{
echo "# STATE - regularrepo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Ordinary repo, no leading dot."
} > "$DOT_ROOT/regularrepo/STATE.md"
DOT_OUT="$("$BOARD" --roots "$DOT_ROOT" --plain 2>/dev/null)"
printf '%s' "$DOT_OUT" | grep -q '\.dotrepo'
check "board finds a dot-prefixed repo" $?
printf '%s' "$DOT_OUT" | grep -q 'regularrepo'
check "board still finds the ordinary repo alongside it (known-positive)" $?
printf '%s' "$DOT_OUT" | grep -q '(2 repo'
check "board reports both repos, not just one" $?
# A dot-prefixed directory that is NOT itself a repo must never become a
# polyrepo container: a naive `shopt -s dotglob` on the existing else-branch
# (board.sh:270-275) would route a dir like .claude there, silently
# expanding what counts as a container - unmeasured scope creep the order
# explicitly flagged. Its child repo must stay invisible.
mkdir -p "$DOT_ROOT/.nonrepo-dotdir"
mkrepo "$DOT_ROOT/.nonrepo-dotdir/child-repo"
DOT_OUT2="$("$BOARD" --roots "$DOT_ROOT" --plain 2>/dev/null)"
printf '%s' "$DOT_OUT2" | grep -q 'child-repo'
[ $? -ne 0 ]
check "a dot-prefixed NON-repo dir is not turned into a polyrepo container" $?
printf '%s' "$DOT_OUT2" | grep -q '(2 repo'
check "the non-repo dot-dir does not change the repo count" $?
# Same glob, second place (board.sh:271): a dot-prefixed repo nested under a
# polyrepo container (depth 2) must also be found, for the identical reason
# - the order flags this as the same defect class, unmeasured but present in
# the code.
mkdir -p "$DOT_ROOT/polyrepo-dir"
mkrepo "$DOT_ROOT/polyrepo-dir/.dotchild"
{
echo "# STATE - .dotchild"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Dot-prefixed repo nested under a polyrepo container."
} > "$DOT_ROOT/polyrepo-dir/.dotchild/STATE.md"
DOT_OUT3="$("$BOARD" --roots "$DOT_ROOT" --plain 2>/dev/null)"
printf '%s' "$DOT_OUT3" | grep -q '\.dotchild'
check "board finds a dot-prefixed repo nested under a polyrepo container (depth 2)" $?
/bin/rm -rf "$DOT_ROOT" 2>/dev/null
# --- 23. Greedy .*trait= reads the rationale, not the field ----------------
# Order 20260820T204409Z-8157821110-from-.claude, measured on four real
# STATE.md files: route_cmd_for's four extractions use `sed -n
# 's/.*path=\([^;>]*\).*/\1/p'`, and the `.*` prefix is GREEDY. route.sh
# --help asks for a rationale per score, so the rationale routinely NAMES the
# traits - and then `.*path=` matches the LAST occurrence, inside the free
# text, instead of the field. route.sh correctly rejects the prose, the
# command degrades to command_missing=, and the operator reads a broken
# PARSER as "that repo has no route line" - Verifiseringsloven ansikt 4,
# pointed at our own tooling. Denominator at the time: 5 of 27 tabs in the
# day plan had no command, all five from this one defect.
#
# The board line needs no equivalent fix and this was measured, not assumed:
# its grammar (status / blocked-on / next-cost) carries no free-text field,
# so no trait token can occur twice on it. `grep -n 's/\.\*' scripts/board.sh`
# is the denominator - the four route traits are the only extractions whose
# search space contains prose.
RG_ROOT="$(mktemp -d)"
# The defect itself: every field is valid, and the rationale names all four
# traits the way a real one does. A fixture whose rationale named only SOME
# traits would still pass through the wrong extraction path for the others
# and go green having proven nothing.
mkrepo "$RG_ROOT/repo-greedy-rationale"
{
echo "# STATE - repo-greedy-rationale"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
printf '%s%s\n' "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; " \
"rationale=path=known fordi filene er kjent; verification=strong via selftest; reversibility=cheap; scope=local -->"
echo "Neste steg for repo-greedy-rationale."
} > "$RG_ROOT/repo-greedy-rationale/STATE.md"
# --brief lists only repos that OWE a reply, so this fixture needs mail to be
# reachable by that check at all. Without it the --brief assertion below could
# never pass no matter what route_cmd_for did - a check that measures the
# fixture's eligibility instead of the code under test.
mkdir -p "$CLAUDE_COORD_DIR/repo-greedy-rationale/inbox"
printf -- '---\nfrom: y\nto: repo-greedy-rationale\nsubject: s\n---\nbody\n' \
> "$CLAUDE_COORD_DIR/repo-greedy-rationale/inbox/2026-msg1-from-y.md"
# Known-positive control: a rationale that names no trait at all must keep
# producing the same command. This is what isolates the defect - the parser
# already WORKS here, and a fix that truncated too much would break it.
mkrepo "$RG_ROOT/repo-clean-rationale"
{
echo "# STATE - repo-clean-rationale"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; rationale=ren mekanisk endring -->"
echo "Neste steg for repo-clean-rationale."
} > "$RG_ROOT/repo-clean-rationale/STATE.md"
# A route line with NO rationale field at all: truncating at '; rationale='
# must be a no-op here, never eat the line.
mkrepo "$RG_ROOT/repo-no-rationale"
{
echo "# STATE - repo-no-rationale"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local -->"
echo "Neste steg for repo-no-rationale."
} > "$RG_ROOT/repo-no-rationale/STATE.md"
# The sharp case, and the only one that fails in the OPPOSITE direction: the
# real field is invalid (known2, the F4 token) while the rationale contains a
# VALID one. Greedy extraction reads the rationale, route.sh's exact match
# ACCEPTS it, and the plan emits a confident command built on a value the
# STATE line never declared. A fix that merely made the refusal more likely
# would not catch this - only reading the FIELD does.
mkrepo "$RG_ROOT/repo-rationale-overrides"
{
echo "# STATE - repo-rationale-overrides"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known2; verification=strong; reversibility=cheap; scope=local; rationale=path=known; feltet over er feil -->"
echo "Neste steg for repo-rationale-overrides."
} > "$RG_ROOT/repo-rationale-overrides/STATE.md"
RG_PLAN="$("$BOARD" --roots "$RG_ROOT" --plan 2>/dev/null)"
RG_CMD='^command=claude --model sonnet --effort high --advisor opus$'
printf '%s\n' "$RG_PLAN" | grep -A6 '^repo=repo-greedy-rationale$' | grep -q "$RG_CMD"
check "route line whose rationale names all four traits still yields a command" $?
printf '%s\n' "$RG_PLAN" | grep -A6 '^repo=repo-greedy-rationale$' | grep -q '^command_missing='; [ $? -ne 0 ]
check "greedy-rationale repo is never reported as an unparseable route line" $?
printf '%s\n' "$RG_PLAN" | grep -A6 '^repo=repo-clean-rationale$' | grep -q "$RG_CMD"
check "known-positive: a trait-free rationale keeps producing the same command" $?
printf '%s\n' "$RG_PLAN" | grep -A6 '^repo=repo-no-rationale$' | grep -q "$RG_CMD"
check "known-positive: a route line with no rationale field at all still parses" $?
printf '%s\n' "$RG_PLAN" | grep -A6 '^repo=repo-rationale-overrides$' | grep -q '^command_missing='
check "an invalid FIELD is refused even when the rationale holds a valid value" $?
printf '%s\n' "$RG_PLAN" | grep -A7 '^repo=repo-rationale-overrides$' | grep -q '^paste='; [ $? -ne 0 ]
check "the rationale-overrides repo gets no paste line either" $?
# --brief shares route_cmd_for, so it must recover the same command.
RG_BRIEF="$("$BOARD" --roots "$RG_ROOT" --brief 2>/dev/null)"
printf '%s' "$RG_BRIEF" | grep -A4 'repo-greedy-rationale' | grep -qE '\$ claude --model sonnet'
check "--brief recovers the command too (route_cmd_for has one reader)" $?
/bin/rm -rf "$RG_ROOT" 2>/dev/null
# --- 24. FLY (claimed orders) and --plan's free-capacity reading ------------
# Order 20260823T162951Z (.claude, 2026-08-23): ORDRE counted PENDING orders
# only, so a repo with one order IN FLIGHT and a repo with no orders at all
# both printed 0 - the same digit for two opposite facts ("work is happening
# here" vs "nothing is waiting here"). Measured on the live tree the day the
# order was written: two tabs stood open and idle for 45 hours holding
# finished orders while no column on the board reported it.
#
# FLY is NOT a fourth axis and never claims a session is alive. It counts
# files in orders/claimed/ - the same order queue ORDRE already reads, in its
# other state. Measured counter-example, live mailbox 2026-08-23: wiki-advise
# held an order claimed for 117 hours. A claim is evidence that a session took
# the order, never proof one is still working it, and the legend says so.
FLY_ROOT="$(mktemp -d)"
mkfly() { # name status
mkrepo "$FLY_ROOT/$1"
{
echo "# STATE - $1"
echo ""
printf '## %s NESTE\n' "$HAND"
echo "<!-- board: status=$2; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "<!-- route: path=known; verification=strong; reversibility=cheap; scope=local; rationale=x -->"
echo "Next step for $1."
} > "$FLY_ROOT/$1/STATE.md"
# COMMITTED, deliberately: `mkrepo` alone leaves STATE.md untracked, so every
# fixture repo would read DRT=1 - which silently satisfied the FLY column
# assertions below before the column existed (the regex matched DRT's 1 where
# it expected FLY's), and would make every repo permanently un-free under the
# clean-tree condition. A dirty fixture is created explicitly where one is
# wanted, never inherited.
git -C "$FLY_ROOT/$1" add -A >/dev/null 2>&1
git -C "$FLY_ROOT/$1" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
}
mkorder() { # mailbox state(pending|claimed) id
mkdir -p "$CLAUDE_COORD_DIR/$1/orders/claimed"
if [ "$2" = claimed ]; then f="$CLAUDE_COORD_DIR/$1/orders/claimed/$3.md"
else f="$CLAUDE_COORD_DIR/$1/orders/$3.md"; fi
printf -- '---\nfrom: d\nto: %s\norder-id: %s\nsubject: s\n---\nbody\n' "$1" "$3" > "$f"
}
# THE defect, isolated: identical ORDRE, opposite meanings.
mkfly fly-inflight planned; mkorder fly-inflight claimed 20260101T000000Z-1-from-d
mkfly fly-empty planned
# Both states at once, so the two counts are provably read from different dirs.
mkfly fly-mixed planned
mkorder fly-mixed pending 20260102T000000Z-2-from-d
mkorder fly-mixed pending 20260103T000000Z-3-from-d
mkorder fly-mixed claimed 20260104T000000Z-4-from-d
FLY_OUT="$("$BOARD" --roots "$FLY_ROOT" 2>/dev/null)"
printf '%s' "$FLY_OUT" | grep -q 'FLY'; check "table header carries a FLY column" $?
printf '%s' "$FLY_OUT" | grep -qE '^fly-mixed[[:space:]]+planned[[:space:]]+Sonnet 5/high[[:space:]]+0[[:space:]]+2[[:space:]]+1[[:space:]]'
check "ORDRE 2 and FLY 1 print side by side, never summed into 3" $?
printf '%s' "$FLY_OUT" | grep -qE '^fly-inflight[[:space:]]+planned[[:space:]]+Sonnet 5/high[[:space:]]+0[[:space:]]+0[[:space:]]+1[[:space:]]'
check "an order in flight reads ORDRE 0 / FLY 1, not ORDRE 0 alone" $?
printf '%s' "$FLY_OUT" | grep -qE '^fly-empty[[:space:]]+planned[[:space:]]+Sonnet 5/high[[:space:]]+0[[:space:]]+0[[:space:]]+0[[:space:]]'
check "known-positive: a repo with no orders at all still reads 0 in both" $?
printf '%s' "$FLY_OUT" | grep -q 'Next step for fly-mixed'
check "NESTE still renders after the second field insertion" $?
# The legend must refuse the liveness reading outright - a column that looked
# like "a session is running here" would be the process axis smuggled in as a
# file count, and wiki-advise's 117-hour claim is why that reading is false.
printf '%s' "$FLY_OUT" | grep -qi 'FLY = '
check "the legend defines FLY" $?
printf '%s' "$FLY_OUT" | grep -qiE 'FLY.*(ikke|aldri).*(lever|kj[^ ]*r|aktiv)'
check "the legend denies that FLY proves a session is alive" $?
# --- --plan: free capacity is NAMED, never turned into a tab ---------------
# The operator's actual question ("which repos are finished and can take more
# work") has an answer in fields the scan already reads, and it is not
# status=done alone: measured on the real tree 2026-08-23, 4 of 17 done/
# deferred repos were NOT free (2 held a pending order, 1 owed a reply, 1 had
# an uncommitted tree). All four conditions are required.
mkfly fly-free done
mkfly fly-busy-order done; mkorder fly-busy-order pending 20260105T000000Z-5-from-d
mkfly fly-busy-fly done; mkorder fly-busy-fly claimed 20260106T000000Z-6-from-d
mkfly fly-busy-mail done
mkdir -p "$CLAUDE_COORD_DIR/fly-busy-mail/inbox"
printf -- '---\nfrom: x\nto: fly-busy-mail\nsubject: m\nreply-expected: yes\n---\nbody\n' \
> "$CLAUDE_COORD_DIR/fly-busy-mail/inbox/20260107T000000Z-7-from-x.md"
mkfly fly-busy-dirty done
echo "uncommitted" > "$FLY_ROOT/fly-busy-dirty/scratch.txt"
mkfly fly-free-def deferred
FLY_PLAN="$("$BOARD" --roots "$FLY_ROOT" --plan 2>/dev/null)"
printf '%s\n' "$FLY_PLAN" | grep -qE '^ledig=fly-free \(done\)$'
check "plan names a genuinely free repo with its status" $?
printf '%s\n' "$FLY_PLAN" | grep -qE '^ledig=fly-free-def \(deferred\)$'
check "plan names a deferred repo as free, labelled deferred rather than merged into done" $?
printf '%s\n' "$FLY_PLAN" | grep -q '^ledig=fly-busy-order'; [ $? -ne 0 ]
check "a done repo holding a pending order is not free" $?
printf '%s\n' "$FLY_PLAN" | grep -q '^ledig=fly-busy-fly'; [ $? -ne 0 ]
check "a done repo with an order in flight is not free" $?
printf '%s\n' "$FLY_PLAN" | grep -q '^ledig=fly-busy-mail'; [ $? -ne 0 ]
check "a done repo owing a reply is not free" $?
printf '%s\n' "$FLY_PLAN" | grep -q '^ledig=fly-busy-dirty'; [ $? -ne 0 ]
check "a done repo with an uncommitted tree is not free" $?
# A count, so zero is an ANSWER and not an absence - the same rule fokus_utenfor
# already follows with its "(ingen)" placeholder.
printf '%s\n' "$FLY_PLAN" | grep -qE '^ledig_antall=2$'
check "plan states how many free repos it found" $?
# The plan's second consumer opens a tab per block; plan_parse discards a block
# with no tab=, so a free repo emitted as a BLOCK would be invisible to the
# driver. A single key=value line is visible to both and can never be opened.
printf '%s\n' "$FLY_PLAN" | grep -A2 '^ledig=fly-free ' | grep -q '^tab='; [ $? -ne 0 ]
check "a free repo is never emitted as a tab block" $?
printf '%s\n' "$FLY_PLAN" | grep -q '^repo=fly-free$'; [ $? -ne 0 ]
check "a free repo does not enter the tab list at all" $?
# A repo the plan DOES open a tab for may already hold a claimed order: the
# driver must be able to see that before typing into a live pane.
printf '%s\n' "$FLY_PLAN" | grep -A6 '^repo=fly-inflight$' | grep -qE '^fly=1$'
check "a planned repo with an order in flight carries fly=1 in its block" $?
printf '%s\n' "$FLY_PLAN" | grep -A6 '^repo=fly-empty$' | grep -q '^fly='; [ $? -ne 0 ]
check "known-positive: a planned repo with nothing in flight carries no fly= line" $?
# Zero free repos must still print the count line, or "none found" and "not
# computed" become the same output - Verifiseringslovens ansikt 4.
FLY_ROOT2="$(mktemp -d)"
FLY_SAVE="$FLY_ROOT"; FLY_ROOT="$FLY_ROOT2"
mkfly fly-only-planned planned
FLY_ROOT="$FLY_SAVE"
FLY_PLAN2="$("$BOARD" --roots "$FLY_ROOT2" --plan 2>/dev/null)"
printf '%s\n' "$FLY_PLAN2" | grep -qE '^ledig_antall=0$'
check "a tree with no free repo still states the count (zero is an answer)" $?
printf '%s\n' "$FLY_PLAN2" | grep -q '^ledig='; [ $? -ne 0 ]
check "a tree with no free repo emits no ledig= line" $?
/bin/rm -rf "$FLY_ROOT2" 2>/dev/null
# board.sh must not have grown a process-inspection path. The three axes are
# durable filesystem facts reproducible in this fixture tree; a pgrep/ps/lsof
# column would measure the operator's machine at one instant, could not be
# pinned here at all, and would make the engine decide a session is dead -
# which CLAUDE.md already forbids the order queue from doing.
grep -nE '(^|[^-[:alnum:]_])(pgrep|pkill|lsof)([^-[:alnum:]_]|$)' "$DIR/board.sh" | grep -qv '^[0-9]*:#'; [ $? -ne 0 ]
check "board.sh inspects no processes (no live pgrep/pkill/lsof)" $?
printf 'x\npgrep claude\n' > "$FLY_ROOT/known-positive.txt"
grep -qE '(^|[^-[:alnum:]_])pgrep([^-[:alnum:]_]|$)' "$FLY_ROOT/known-positive.txt"
check "known-positive: the process-inspection grep can find a planted pgrep call" $?
/bin/rm -rf "$FLY_ROOT" 2>/dev/null
# --- 25. F6: a git FAILURE must not read as a clean tree -------------------
# `git -C "$d" status --porcelain 2>/dev/null | wc -l` yields 0 lines whether
# the tree is clean or git refused to answer at all, so DRT printed 0 and every
# reader - the table, the SUM, and --plan's free-capacity test - took that as
# "nothing uncommitted here". Verifiseringsloven ansikt 4 on our own tooling.
#
# The fixture is a REAL reachable shape, not a contrived one: a `.git` FILE
# pointing at a worktree parent that no longer exists. Discovery tests `.git`
# with -e precisely so worktrees are found (see board.sh's own comment), so
# this directory IS scanned as a repo and `git status` exits 128 on it.
# Measured before the fixture was written: rc=128, zero lines on stdout.
F6ROOT="$(mktemp -d)"
F6COORD="$(mktemp -d)"
# The known-positive controls come first and are the reason this section can
# fail in both directions: if the fix widened "unknown" to cover healthy repos,
# these go red while every negative check below stays green.
mkrepo "$F6ROOT/f6-clean"
{
echo "# STATE - f6-clean"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/low -->"
echo "Ingenting."
} > "$F6ROOT/f6-clean/STATE.md"
git -C "$F6ROOT/f6-clean" add -A >/dev/null 2>&1
git -C "$F6ROOT/f6-clean" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
mkrepo "$F6ROOT/f6-dirty"
{
echo "# STATE - f6-dirty"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/low -->"
echo "Ingenting."
} > "$F6ROOT/f6-dirty/STATE.md"
git -C "$F6ROOT/f6-dirty" add -A >/dev/null 2>&1
git -C "$F6ROOT/f6-dirty" -c user.email=t@t -c user.name=t commit -qm init >/dev/null 2>&1
echo "uncommitted" > "$F6ROOT/f6-dirty/scratch.txt"
# The defect case: scanned as a repo, but git cannot answer.
mkdir -p "$F6ROOT/f6-broken"
echo "gitdir: $F6ROOT/f6-broken-parent-that-does-not-exist/.git/worktrees/x" \
> "$F6ROOT/f6-broken/.git"
{
echo "# STATE - f6-broken"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=done; blocked-on=-; next-cost=Sonnet 5/low -->"
echo "Ingenting."
} > "$F6ROOT/f6-broken/STATE.md"
# Ground truth for the fixture itself, so a later git version that starts
# answering here fails THIS check rather than silently disarming the section.
git -C "$F6ROOT/f6-broken" status --porcelain >/dev/null 2>&1
[ $? -ne 0 ]
check "F6: fixture ground truth - git really does fail on the broken worktree" $?
F6TBL="$(CLAUDE_COORD_DIR="$F6COORD" "$BOARD" --roots "$F6ROOT" 2>/dev/null)"
# DRT is counted from the RIGHT (NF-3: DRT ALDER SISTE NESTE), never from the
# left: the KOST field is free text and its realistic spelling ("Sonnet 5/low")
# contains a space, so $7 reads FLY instead. Measured, not assumed - the first
# cut of this section passed its clean-tree control by accident that way.
printf '%s' "$F6TBL" | grep -E '^f6-clean[[:space:]]' | awk '{print $(NF-3)}' | grep -qx '0'
check "F6: control - a healthy CLEAN tree still reads DRT 0" $?
printf '%s' "$F6TBL" | grep -E '^f6-dirty[[:space:]]' | awk '{print $(NF-3)}' | grep -qx '1'
check "F6: control - a healthy DIRTY tree still reads DRT 1" $?
printf '%s' "$F6TBL" | grep -E '^f6-broken[[:space:]]' | awk '{print $(NF-3)}' | grep -qx '0'
[ $? -ne 0 ]
check "F6: a git failure does NOT read as DRT 0 (clean tree)" $?
printf '%s' "$F6TBL" | grep -E '^f6-broken[[:space:]]' | awk '{print $(NF-3)}' | grep -qx '?'
check "F6: a git failure reads as ? (not measured), the same token coord-count uses" $?
# The load-bearing consequence. All three fixtures are status=done with no mail
# and no orders, so the ONLY thing separating them is the tree reading. A repo
# whose tree could not be measured is not provably free, and certifying it free
# is how an unmeasured null becomes a fact about the world.
F6PLAN="$(CLAUDE_COORD_DIR="$F6COORD" "$BOARD" --roots "$F6ROOT" --plan 2>/dev/null)"
printf '%s' "$F6PLAN" | grep -q '^ledig=f6-clean '
check "F6: control - the clean done repo IS still reported as free capacity" $?
printf '%s' "$F6PLAN" | grep -q '^ledig=f6-dirty '
[ $? -ne 0 ]
check "F6: control - the dirty done repo is still NOT free capacity" $?
printf '%s' "$F6PLAN" | grep -q '^ledig=f6-broken '
[ $? -ne 0 ]
check "F6: an unmeasurable tree is NOT certified as free capacity" $?
# The SUM line adds field 7 across every repo. An unknown adds 0 there, which
# silently understates the total under a heading the operator reads as counted.
# It must be NAMED, on the same principle --plan already applies to repos with
# no board line: labelled, never silently dropped.
printf '%s' "$F6TBL" | grep -q 'MERK: 1 repo har umaalbart arbeidstre'
check "F6: the SUM roll-up names the repo whose tree could not be measured" $?
printf '%s' "$F6TBL" | grep -qE 'SUM: [0-9]+ uhaandterte innboks-meldinger, 1 ukommiterte filer'
check "F6: control - the SUM still counts the one real uncommitted file" $?
/bin/rm -rf "$F6ROOT" "$F6COORD" 2>/dev/null
# --- 26. F10: a scan root that does not exist is not an empty tree ----------
# `[ -d "$root" ] || continue` skipped a bad root silently, and a scan that
# found no repo at all then exited 0 printing nothing - so a typo in --roots,
# a moved home directory and a genuinely empty tree were one single output.
# This section REPLACES the older "missing root is a clean no-op" assertion,
# which encoded exactly this defect as a passing test.
F10ROOT="$(mktemp -d)"
F10COORD="$(mktemp -d)"
mkrepo "$F10ROOT/f10-repo"
{
echo "# STATE - f10-repo"
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=planned; blocked-on=-; next-cost=Sonnet 5/low -->"
echo "Et steg."
} > "$F10ROOT/f10-repo/STATE.md"
# Known-positive control FIRST: a valid root still scans, still exits 0, and -
# critically - still says NOTHING on stderr. A warning on the ordinary path
# would train every reader to ignore the channel the defect case needs.
f10a_err="${TMPDIR:-/tmp}/f10a.err.$$"
f10a_out="$(CLAUDE_COORD_DIR="$F10COORD" "$BOARD" --roots "$F10ROOT" 2>"$f10a_err")"; f10a_rc=$?
[ "$f10a_rc" -eq 0 ] && printf '%s' "$f10a_out" | grep -q 'f10-repo' && [ ! -s "$f10a_err" ]
check "F10: control - a valid root scans, exits 0, and warns about nothing" $?
# An EXISTING but empty root is the genuine "no repos here" answer and must
# stay a silent, clean 0 - it is the reading the defect case used to be
# indistinguishable from.
F10EMPTY="$(mktemp -d)"
f10b_err="${TMPDIR:-/tmp}/f10b.err.$$"
f10b_out="$(CLAUDE_COORD_DIR="$F10COORD" "$BOARD" --roots "$F10EMPTY" 2>"$f10b_err")"; f10b_rc=$?
[ "$f10b_rc" -eq 0 ] && [ -z "$f10b_out" ] && [ ! -s "$f10b_err" ]
check "F10: control - an existing but EMPTY root is a silent, clean 0" $?
# The defect: the root is not there at all.
f10c_err="${TMPDIR:-/tmp}/f10c.err.$$"
f10c_out="$(CLAUDE_COORD_DIR="$F10COORD" "$BOARD" --roots "$F10ROOT/no-such-dir" 2>"$f10c_err")"; f10c_rc=$?
[ "$f10c_rc" -eq 3 ]
check "F10: a scan root that does not exist exits 3, not 0" $?
[ -z "$f10c_out" ]
check "F10: a missing root prints no board (3 is not an empty board)" $?
grep -q 'no-such-dir' "$f10c_err"
check "F10: the missing root is NAMED on stderr, not merely counted" $?
[ "$f10b_rc" -ne "$f10c_rc" ]
check "F10: empty root and missing root no longer report the same status" $?
# A MIX is the case that decides whether this is a warning or a failure: some
# repos really were scanned, so the board is real and must be printed - but the
# reader must still learn that one root contributed nothing because it is not
# there, rather than because it is empty.
f10d_err="${TMPDIR:-/tmp}/f10d.err.$$"
f10d_out="$(CLAUDE_COORD_DIR="$F10COORD" "$BOARD" --roots "$F10ROOT,$F10ROOT/no-such-dir" 2>"$f10d_err")"; f10d_rc=$?
[ "$f10d_rc" -eq 0 ]
check "F10: one good root among bad ones still exits 0 - the board is real" $?
printf '%s' "$f10d_out" | grep -q 'f10-repo'
check "F10: the good root's repos are still scanned when a sibling root is bad" $?
grep -q 'no-such-dir' "$f10d_err"
check "F10: the bad root is still named on stderr in the mixed case" $?
/bin/rm -rf "$F10ROOT" "$F10COORD" "$F10EMPTY" "$f10a_err" "$f10b_err" \
"$f10c_err" "$f10d_err" 2>/dev/null
echo ""
echo "board-selftest: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ] || exit 1
exit 0