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:
parent
cb77f2889d
commit
f9d2c927ab
4 changed files with 438 additions and 0 deletions
173
scripts/board.sh
173
scripts/board.sh
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue