feat(board): give --plan a focus cutoff that reports what it held back

--focus "<prose>" narrows the day plan to repos whose STATE.md DECLARES a
matching topic marker. Measured on the real tree: 26 blocks to 6.

The filter alone was never the feature. --plan documents that it takes one
position (the order), hides nothing, and labels what it cannot rank rather
than dropping it, so a silent cutoff would break a property the format had
already written down. The same run prints the slugs the prose resolved to,
how many blocks it removed, the repos that MENTION a resolved slug with no
marker line - named, not counted - and how many STATE.md it searched. Each
surviving block carries the declaration it survived on.

Enumerated rather than counted because the decisive find behind this feature
was invisible to every string measurement until the held-back population was
listed. "nevner", never "dekker": this reports text found, and board.sh has
no grounds for a claim about relevance. The slug vocabulary comes from the
scanned STATE.md themselves, so the "no other file" invariant survives.

Emitted as key=value, not '#' comments: the consumer's parser runs in
paragraph mode and drops any block without tab=, so a comment would reach the
operator on the terminal path and vanish on the driver path - the one case
where the cutoff is applied unseen.

board-selftest 89 -> 113. The narrowing check is comparative, since every
presence-only assertion passes against a no-op filter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186vKCzuUEN5WcJB82kddzF
This commit is contained in:
Kjell Tore Guttormsen 2026-08-02 19:58:25 +02:00
commit f9d2c927ab
4 changed files with 438 additions and 0 deletions

View file

@ -215,6 +215,64 @@ mkrepo "$ROOT/repo-typo"
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-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 ---------------------------------------------------------
@ -638,6 +696,133 @@ 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)" $?
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" $?
# 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" $?
echo ""
echo "board-selftest: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ] || exit 1

View file

@ -73,7 +73,20 @@
# with no declared status) and there is no cutoff, so nothing is hidden.
# Read-only like the rest: --plan writes nothing, in the repo or the mailbox.
#
# --focus "<prose>" narrows --plan to the repos whose STATE.md DECLARES a
# matching topic marker (`<slug>: <status>`), and is the only cutoff this
# format has. It is therefore required to report what it held back: the same
# run prints fokus= (the slugs the prose resolved to), fokus_droppet= (how
# many blocks the cutoff removed), fokus_utenfor= (the repos that MENTION a
# resolved slug with no marker line, named - that class is where the decisive
# find came from), and fokus_rekkevidde= (how many STATE.md were searched;
# board opens no other file). Each surviving block carries fokus_treff=, the
# declaration it survived on. Prose matching no declared slug prints the FULL
# plan plus fokus_ikke_brukt= - never an empty one, since the prose arrives
# verbatim from the operator and a typo must not empty the morning.
#
# Usage: board.sh [--roots <dir>[,<dir>...]] [--plain] [--brief|--plan]
# [--focus "<prose>"]
# Env: CLAUDE_COORD_DIR overrides the mailbox root.
# BOARD_ROOTS overrides the default scan roots.
# ASCII only, bash 3.2 safe.
@ -85,6 +98,7 @@ ROOTS="${BOARD_ROOTS:-$HOME/repos}"
NESTE_WIDTH=38
BRIEF=0
PLAN=0
FOCUS=""
# Sibling calculator, invoked rather than reimplemented: the rubric that turns
# four traits into a model has exactly one copy, and it is route.sh's row
@ -100,6 +114,11 @@ while [ $# -gt 0 ]; do
# Three renderings of one scan, so exactly one may be selected: last wins.
--brief) BRIEF=1; PLAN=0; shift ;;
--plan) PLAN=1; BRIEF=0; shift ;;
# Raw operator prose, forwarded verbatim by the driver: it does not
# tokenize, match or normalize, so every bit of that work is here. Same
# `shift 2` guard as --roots, for the same bash 3.2 reason.
--focus) [ $# -ge 2 ] || { echo "board: --focus requires a value" >&2; exit 2; }
FOCUS="$2"; shift 2 ;;
--plain) shift ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "board: unknown argument: $1 (ignored)" >&2; shift ;;
@ -382,6 +401,107 @@ if [ "$BRIEF" -eq 1 ]; then
exit 0
fi
# --- Focus resolution (--focus) --------------------------------------------
# --focus is the first CUTOFF this format has ever had, and the plan documents
# at length that it has none: it takes one position (the order), it hides
# nothing, and it LABELS what it cannot rank rather than dropping it. A filter
# that stayed silent about what fell outside it would break that property
# outright, so the report is not a refinement of the feature - it is the
# condition the feature was allowed to exist under.
#
# The topic marker grammar belongs to the register, not here. board.sh only
# ever READS a declaration, and reads it from STATE.md alone: the slug
# vocabulary is whatever the scanned STATE.md files themselves declare, so no
# new file is opened and the "STATE.md and nothing else" invariant survives.
# It also means the reader must accept the marker as operators actually write
# it - bold, backticked, bulleted - because the strict form is what the
# register's own grep looks for, and the single most consequential repo in the
# measurement behind this feature was invisible to exactly that grep.
FOCUS_STATUS='planned|in-progress|partial|blocked|deferred|done|not-applicable'
focus_marker_re() {
printf '^[[:space:]]*[-*]?[[:space:]]*\**`?%s`?\**:[[:space:]]+(%s)([[:space:]]|$)' \
"$1" "$FOCUS_STATUS"
}
# Every slug declared anywhere in the scanned tree. Field 10 of RECORDS is the
# repo directory; a repo with no STATE.md simply contributes nothing.
focus_slugs() {
awk -F'|' '{print $10}' "$RECORDS" | while read -r fs_d; do
[ -n "$fs_d" ] && [ -f "$fs_d/STATE.md" ] || continue
grep -hE "$(focus_marker_re '[a-z0-9][a-z0-9-]*')" "$fs_d/STATE.md" 2>/dev/null
done | sed -E 's/^[[:space:]]*[-*]?[[:space:]]*\**`?([a-z0-9][a-z0-9-]*)`?\**:.*/\1/' \
| sort -u
}
# Prose -> slugs. Two normalisations, because both readings occur: the operator
# types a slug ("llm-ingestion-guard") or a bare word out of their own day
# ("guard"). Matching is never narrowed to one winner - an ambiguous phrase
# widens the answer and every slug it resolved to is named in the output,
# because silently picking one would make the cutoff lie about its own size.
focus_resolve() {
fr_words=" $(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9-' ' ') "
fr_parts=" $(printf '%s' "$fr_words" | tr '-' ' ') "
focus_slugs | while read -r fr_s; do
[ -n "$fr_s" ] || continue
case "$fr_words" in
*" $fr_s "*) printf '%s\n' "$fr_s"; continue ;;
esac
for fr_p in $(printf '%s' "$fr_s" | tr '-' ' '); do
# Two-character parts match far too much prose to be evidence of intent.
[ "${#fr_p}" -ge 3 ] || continue
case "$fr_parts" in
*" $fr_p "*) printf '%s\n' "$fr_s"; break ;;
esac
done
done | sort -u
}
# Does this repo DECLARE any of the resolved slugs? (survives the cutoff)
focus_declares() {
for fd_s in $FOCUS_SLUGS; do
grep -qE "$(focus_marker_re "$fd_s")" "$1/STATE.md" 2>/dev/null && return 0
done
return 1
}
# What a surviving block survived ON. This is the per-block evidence that
# closed `topics=`: the need was real, but a field in all 27 blocks on every
# day the operator has no focus is noise, while the same fact inside a focused
# run is the reason the block is there.
focus_evidence() {
for fe_s in $FOCUS_SLUGS; do
fe_line="$(grep -m1 -E "$(focus_marker_re "$fe_s")" "$1/STATE.md" 2>/dev/null)"
if [ -n "$fe_line" ]; then
fe_st="$(printf '%s' "$fe_line" | sed -E "s/.*:[[:space:]]+($FOCUS_STATUS).*/\1/")"
printf '%s: %s\n' "$fe_s" "$fe_st"
return 0
fi
done
return 1
}
# The held-back population: STATE.md MENTIONS a resolved slug and declares no
# marker line for it. The wording is a constraint, not a style choice - this
# is a fact about text found in a file, and board.sh has no grounds whatever
# for a claim about relevance, so it says "nevner" and never "dekker". The
# class is NAMED rather than counted, because in the measurement that produced
# this feature the decisive find - a heavy consumer pinning the library in its
# build file - appeared only once the population was enumerated. Reasoning
# about it had missed it entirely.
focus_heldback() {
awk -F'|' '{print $3 "|" $10}' "$RECORDS" | while IFS='|' read -r fh_n fh_d; do
[ -n "$fh_d" ] && [ -f "$fh_d/STATE.md" ] || continue
focus_declares "$fh_d" && continue
for fh_s in $FOCUS_SLUGS; do
if grep -qF -- "$fh_s" "$fh_d/STATE.md" 2>/dev/null; then
printf '%s\n' "$fh_n"
break
fi
done
done
}
# --- Day-plan rendering (--plan) -------------------------------------------
# A THIRD rendering of the same scan, built on exactly the argument --brief was:
# it is a lookup over data the scan already holds, it costs zero model calls,
@ -449,6 +569,26 @@ plan() {
awk -F'|' -v OFS='|' '$6+0 == 0 && ($4 == "?" || $4 ~ /^MALFORMED:/) {print "uavklart", $0}' "$RECORDS" \
| sort -t'|' -k3,3n >> "$pf"
# The cutoff, and its disclosure, computed together - they are one feature.
FOCUS_SLUGS=""
fp_applied=0
fp_before="$(awk 'END{print NR+0}' "$pf")"
if [ -n "$FOCUS" ]; then
FOCUS_SLUGS="$(focus_resolve "$FOCUS" | tr '\n' ' ')"
[ -n "$(printf '%s' "$FOCUS_SLUGS" | tr -d ' ')" ] && fp_applied=1
fi
if [ "$fp_applied" -eq 1 ]; then
fp_names="${TMPDIR:-/tmp}/board-focusnames.$$"
fp_kept="${TMPDIR:-/tmp}/board-planfocus.$$"
awk -F'|' '{print $3 "|" $10}' "$RECORDS" | while IFS='|' read -r fp_n fp_d; do
[ -n "$fp_d" ] && [ -f "$fp_d/STATE.md" ] || continue
focus_declares "$fp_d" && printf '%s\n' "$fp_n"
done > "$fp_names"
awk -F'|' 'NR==FNR{keep[$0]=1;next} keep[$4]' "$fp_names" "$pf" > "$fp_kept"
/bin/rm -f "$fp_names" 2>/dev/null
mv "$fp_kept" "$pf"
fi
echo "# PLAN $(date '+%Y-%m-%d %H:%M') - en blokk per tab, i den rekkefolgen"
echo "# Kilder: STATE.md (NESTE + route-linje), git, coord-innboks. 0 modellkall."
echo "# Rekkefolge: innboksgjeld (INN desc), sa in-progress, sa planned, sa uavklart."
@ -456,6 +596,36 @@ plan() {
# done or deferred repo that owes mail IS planned, and the real tree has two.
# Read the other way this line calls its own tab 4 a bug.
echo "# Utelatt naar repoet ikke skylder svar: done, deferred, blocked, uten STATE.md."
# Emitted as key=value, not as a '#' comment, because the format's second
# consumer drops every comment line by rule - a disclosure written as a
# comment would reach the operator on the terminal path and vanish on the
# driver path, which is the one case where the cutoff is applied unseen.
if [ -n "$FOCUS" ]; then
fp_state="$(awk -F'|' '{print $10}' "$RECORDS" | while read -r fp_sd; do
[ -n "$fp_sd" ] && [ -f "$fp_sd/STATE.md" ] && echo x
done | wc -l | tr -d ' ')"
if [ "$fp_applied" -eq 1 ]; then
printf 'fokus=%s\n' "$(printf '%s' "$FOCUS_SLUGS" | sed 's/[[:space:]]*$//' | tr ' ' ',')"
printf 'fokus_droppet=%s av %s blokker\n' \
"$((fp_before - $(awk 'END{print NR+0}' "$pf")))" "$fp_before"
fp_hb="$(focus_heldback | sort -u)"
fp_hbn="$(printf '%s' "$fp_hb" | grep -c . | tr -d ' ')"
# "nevner", never "dekker": this states what was found in a file, and
# says which files were searched rather than implying it searched repos.
# One repo in the real measurement carries its strongest evidence in a
# README, which this scan never opens.
printf 'fokus_utenfor=%s repo nevner %s uten markorlinje: %s\n' \
"$fp_hbn" "$(printf '%s' "$FOCUS_SLUGS" | sed 's/[[:space:]]*$//' | tr ' ' ',')" \
"$(printf '%s' "$fp_hb" | tr '\n' ' ' | sed -e 's/[[:space:]]*$//' -e 's/^$/-/')"
printf 'fokus_rekkevidde=sokt i %s STATE.md - board leser ingen andre filer\n' "$fp_state"
else
# No declared slug matched. The full plan is printed: the driver forwards
# operator prose verbatim, so a typo must not silently produce a morning
# with no tabs at all.
printf 'fokus_ikke_brukt=%s traff ingen deklarert slug i %s STATE.md - hele planen vises\n' \
"$FOCUS" "$fp_state"
fi
fi
echo ""
pn=0
@ -469,6 +639,9 @@ plan() {
# look right and point at the wrong repo.
printf 'dir=%s\n' "$dir"
printf 'why=%s\n' "$why"
if [ "$fp_applied" -eq 1 ]; then
fp_ev="$(focus_evidence "$dir")" && printf 'fokus_treff=%s\n' "$fp_ev"
fi
printf 'status=%s\n' "$status"
printf 'neste=%s\n' "$neste"
plan_cmd "$dir" "$cost"