feat(board): add --inbox-plan, a fourth rendering independent of --plan's admission
morning-driver's own regression (0.22.0 narrowed --plan's admission gate, and morning --innboks derives its population from --plan, so 21 mailboxes with unhandled post produced only 3 openable tabs): --plan answers "which repos deserve a tab today" (admission, ranking, a cap), --inbox-plan answers "which repos have unhandled post" (population, no judgement, no cap) - a superset of --plan's candidates, not a complement. One block per name with pending>0 in the mailbox, classified against board.sh's own RECORDS scan (no new discovery logic): class=repo (STATE.md present), no-state (scanned repo, no STATE.md), orphan-mailbox (no matching directory at all). pending=/owed= surface coord-count.sh's two counts directly. TDD-first: board-selftest.sh section 15 (6 fixtures, isolated root+mailbox) written and confirmed red before implementation. Accepted work order: morning-driver 20260814T175317Z, corrected 20260814T180854Z. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014mKC7v8gytdsota36tL7oP
This commit is contained in:
parent
bf11cbf89d
commit
09fd4b74fa
2 changed files with 303 additions and 5 deletions
129
scripts/board.sh
129
scripts/board.sh
|
|
@ -125,7 +125,33 @@
|
|||
# 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]
|
||||
# --inbox-plan is a FOURTH rendering, ordered by morning-driver
|
||||
# (20260814T175317Z, corrected 20260814T180854Z) as a fix for its OWN
|
||||
# regression, not a feature request: --plan answers "which repos deserve a
|
||||
# tab today" (admission, ranking, a cap); --inbox-plan answers "which repos
|
||||
# have unhandled post" (population, no judgement, no cap) - and deriving the
|
||||
# second from the first was always a shortcut, one that broke the moment
|
||||
# --plan's admission narrowed in 0.22.0. It is a superset of --plan's
|
||||
# candidates, not a complement: an already-admitted repo still gets a block.
|
||||
#
|
||||
# ONE BLOCK PER NAME WITH PENDING MAIL, independent of --plan's admission
|
||||
# gate entirely. Each block carries `class=` distinguishing the three reasons
|
||||
# a block might be unopenable, per the work order's explicit ask - a repo
|
||||
# without STATE.md and a mailbox without a directory are NOT the same fact
|
||||
# for the operator, and collapsing them into one undifferentiated "kan ikke
|
||||
# aapnes" is the defect this mode exists to fix:
|
||||
# repo - dir, .git and STATE.md all present; may still lack a
|
||||
# route line, in which case command_missing= says so
|
||||
# (same route_cmd_for() every other rendering uses).
|
||||
# no-state - a scanned git repo with no STATE.md at all, so no NESTE
|
||||
# and no route line can ever exist for it.
|
||||
# orphan-mailbox - a mailbox name with no matching directory anywhere in
|
||||
# the scanned roots; there is no dir= to cd into.
|
||||
# `pending=` and `owed=` surface coord-count.sh's two counts directly (its
|
||||
# debt field, not re-derived) so a caller can tell a request from a notice
|
||||
# without recomputing it - the second explicit ask.
|
||||
#
|
||||
# Usage: board.sh [--roots <dir>[,<dir>...]] [--plain] [--brief|--plan|--inbox-plan]
|
||||
# [--focus "<prose>"]
|
||||
# Env: CLAUDE_COORD_DIR overrides the mailbox root.
|
||||
# BOARD_ROOTS overrides the default scan roots.
|
||||
|
|
@ -138,6 +164,7 @@ ROOTS="${BOARD_ROOTS:-$HOME/repos}"
|
|||
NESTE_WIDTH=38
|
||||
BRIEF=0
|
||||
PLAN=0
|
||||
INBOX_PLAN=0
|
||||
FOCUS=""
|
||||
|
||||
# Sibling calculator, invoked rather than reimplemented: the rubric that turns
|
||||
|
|
@ -151,9 +178,10 @@ while [ $# -gt 0 ]; do
|
|||
# bash 3.2: `shift 2` past the end of $# is a no-op -> would loop forever.
|
||||
--roots) [ $# -ge 2 ] || { echo "board: --roots requires a value" >&2; exit 2; }
|
||||
ROOTS="$2"; shift 2 ;;
|
||||
# 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 ;;
|
||||
# Four renderings of one scan, so exactly one may be selected: last wins.
|
||||
--brief) BRIEF=1; PLAN=0; INBOX_PLAN=0; shift ;;
|
||||
--plan) PLAN=1; BRIEF=0; INBOX_PLAN=0; shift ;;
|
||||
--inbox-plan) INBOX_PLAN=1; BRIEF=0; PLAN=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.
|
||||
|
|
@ -328,7 +356,8 @@ done > "${TMPDIR:-/tmp}/board.$$"
|
|||
RECORDS="${TMPDIR:-/tmp}/board.$$"
|
||||
UNBLOCKS="${TMPDIR:-/tmp}/board-unblocks.$$"
|
||||
OWED="${TMPDIR:-/tmp}/board-owed.$$"
|
||||
trap '/bin/rm -f "$RECORDS" "$UNBLOCKS" "$OWED" 2>/dev/null' EXIT
|
||||
ALLMAIL="${TMPDIR:-/tmp}/board-allmail.$$"
|
||||
trap '/bin/rm -f "$RECORDS" "$UNBLOCKS" "$OWED" "$ALLMAIL" 2>/dev/null' EXIT
|
||||
|
||||
# --- Owed lookup (name -> messages that actually owe a reply) --------------
|
||||
# `inbox` (field 6 of RECORDS) is raw pending-file count and stays that way -
|
||||
|
|
@ -354,6 +383,20 @@ if { [ "$BRIEF" -eq 1 ] || [ "$PLAN" -eq 1 ]; } && [ -f "$SELFDIR/coord-count.sh
|
|||
| awk -F"$ow_tab" -v OFS='|' '{print $1, $3}' > "$OWED"
|
||||
fi
|
||||
|
||||
# --- All-mail lookup (name -> pending, owed), --inbox-plan only ------------
|
||||
# --inbox-plan's whole population is "every name coord-count.sh reports", so
|
||||
# unlike $OWED (which only needs the debt column) this keeps BOTH integers -
|
||||
# pending is the population test, owed is the per-block ask #2 marker. Built
|
||||
# only for --inbox-plan, the only consumer, for the same reason $OWED is
|
||||
# gated: an extra coord-count.sh subprocess on every table/plain invocation
|
||||
# would tax a path that never reads it.
|
||||
: > "$ALLMAIL"
|
||||
if [ "$INBOX_PLAN" -eq 1 ] && [ -f "$SELFDIR/coord-count.sh" ]; then
|
||||
am_tab="$(printf '\t')"
|
||||
bash "$SELFDIR/coord-count.sh" 2>/dev/null \
|
||||
| awk -F"$am_tab" -v OFS='|' '{print $1, $2, $3}' > "$ALLMAIL"
|
||||
fi
|
||||
|
||||
# --- Chain-root credit -----------------------------------------------------
|
||||
# For every blocked repo, walk `blocked-on` up to the ROOT of the chain - the
|
||||
# first repo that is not itself blocked - and credit that root with one repo
|
||||
|
|
@ -906,6 +949,82 @@ if [ "$PLAN" -eq 1 ]; then
|
|||
exit 0
|
||||
fi
|
||||
|
||||
# --- Inbox-plan rendering (--inbox-plan) ------------------------------------
|
||||
# See the file-header comment for the full rationale. One block per NAME with
|
||||
# pending>0 in $ALLMAIL, joined against $RECORDS by FILENAME (never NR==FNR -
|
||||
# the plan()'s own regression comment above explains why: the first file being
|
||||
# empty silently misroutes the entire second file's lines, and $RECORDS here
|
||||
# is never empty but the general idiom is worth staying consistent about).
|
||||
#
|
||||
# class is read off $RECORDS' own bucket, not recomputed: bucket 5 is exactly
|
||||
# "no STATE.md" (see the discovery loop's own `printf '5|...'` line above), and
|
||||
# a name absent from $RECORDS entirely never had a directory in the scan.
|
||||
inbox_plan() {
|
||||
ipf="${TMPDIR:-/tmp}/board-inboxplan.$$"
|
||||
awk -F'|' -v OFS='|' -v RCF="$RECORDS" '
|
||||
FILENAME==RCF {
|
||||
name = $3
|
||||
rc_bucket[name] = $1; rc_status[name] = $4; rc_cost[name] = $5
|
||||
rc_dir[name] = $10; rc_neste[name] = $12
|
||||
next
|
||||
}
|
||||
{
|
||||
name = $1; pend = $2 + 0; owed = $3 + 0
|
||||
if (name in rc_bucket) {
|
||||
cls = (rc_bucket[name] == 5) ? "no-state" : "repo"
|
||||
dir = rc_dir[name]; status = rc_status[name]; cost = rc_cost[name]
|
||||
neste = rc_neste[name]
|
||||
} else {
|
||||
cls = "orphan-mailbox"; dir = "-"; status = "-"; cost = "-"; neste = "-"
|
||||
}
|
||||
print owed, pend, name, cls, dir, status, cost, neste
|
||||
}
|
||||
' "$RECORDS" "$ALLMAIL" | sort -t'|' -k1,1nr -k2,2nr -k3,3 > "$ipf"
|
||||
|
||||
echo "# INBOX-PLAN $(date '+%Y-%m-%d %H:%M') - en blokk per repo/mailbox med uhaandtert post"
|
||||
echo "# Kilder: coord-count.sh (pending+owed), STATE.md, git. 0 modellkall."
|
||||
echo "# Populasjon: alt med pending>0, uavhengig av --plan sin admisjon - ingen tak,"
|
||||
echo "# ingen dom. Et repo --plan alt admitterer er fortsatt med (overmengde, ikke komplement)."
|
||||
echo "# class=repo (STATE.md finnes) | no-state (repo finnes, STATE.md mangler) |"
|
||||
echo "# orphan-mailbox (ingen katalog for postkassen i det skannede omraadet)."
|
||||
echo "# pending=meldinger totalt, owed=derav skylder svar (resten er FYI)."
|
||||
echo ""
|
||||
|
||||
ipn=0
|
||||
while IFS='|' read -r owed pend name cls dir status cost neste; do
|
||||
[ -n "$name" ] || continue
|
||||
ipn=$((ipn + 1))
|
||||
printf 'tab=%s\n' "$ipn"
|
||||
printf 'repo=%s\n' "$name"
|
||||
printf 'dir=%s\n' "$dir"
|
||||
printf 'class=%s\n' "$cls"
|
||||
printf 'pending=%s\n' "$pend"
|
||||
printf 'owed=%s\n' "$owed"
|
||||
printf 'status=%s\n' "$status"
|
||||
printf 'neste=%s\n' "$neste"
|
||||
case "$cls" in
|
||||
# Same route_cmd_for()/plan_cmd() every other rendering uses - one copy
|
||||
# of "how a command is derived from a route line", not a second guess.
|
||||
repo) plan_cmd "$dir" "$cost" ;;
|
||||
# No STATE.md means no route line can exist - naming that plainly is
|
||||
# the whole point of a separate class, not a guessed command.
|
||||
no-state) printf 'command_missing=ingen STATE.md - repoet finnes, men har ingen plan\n' ;;
|
||||
orphan-mailbox) printf 'command_missing=ingen katalog for denne postkassen i det skannede omraadet\n' ;;
|
||||
esac
|
||||
echo ""
|
||||
done < "$ipf"
|
||||
/bin/rm -f "$ipf" 2>/dev/null
|
||||
|
||||
printf '# %s blokker.\n' "$ipn"
|
||||
echo "# MERK: INN teller hva ANDRE venter paa fra deg. Hva et repo venter PAA"
|
||||
echo "# staar kun i dets egen board-linje (blocked-on)."
|
||||
}
|
||||
|
||||
if [ "$INBOX_PLAN" -eq 1 ]; then
|
||||
inbox_plan
|
||||
exit 0
|
||||
fi
|
||||
|
||||
count() { awk -F'|' -v b="$1" '$1==b' "$RECORDS" | wc -l | tr -d ' '; }
|
||||
|
||||
echo "BOARD - tverr-repo oppmerksomhetstavle ($(awk 'END{print NR}' "$RECORDS") repo)"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue