feat(board): nested repos enter on a STATE.md, and the scan reports its nevner

Order 20260903T190201Z-238406410-from-.claude (.claude, operator decision
2026-09-03). A git repo nested under a depth-1 REPO was invisible: discovery
adds a depth-1 repo and stops, and the else-branch container scan - the only
place children are ever looked at - is unreachable for an entry that is itself
a repo. Measured before writing anything: 12 nested repos across the real tree,
exactly 1 with a STATE.md (from-ai-to-chitta/content-sadhguru), which had been
running work and reporting to nobody.

Admission is criterion (a) and nothing wider. add_nested_repos() sits beside
add_dot_repos(), never a widening of the `*` loops - the same argument ordre
20260818T124828Z made for dot repos, and the order made it again before this
repo wrote a line: routing a depth-1 repo into the container branch would admit
every vendored clone under claude-code-100x/. One level only; depth 3 is pinned
as NOT admitted. A dot-prefixed depth-1 repo gets the same nested scan, since
nothing in the criterion distinguishes it.

A nested repo now carries TWO names. The board KEY is <parent>/<child> as the
order specifies. The MAILBOX name is not that key: a mailbox is addressed by
basename(git toplevel), so $COORD/<parent>/<child>/inbox finds no directory and
INN/ORDRE/FLY would print 0 for a repo that may have mail - a failed
measurement wearing the reassuring value, in three columns at once. The record
loop carries `mbox` beside `name`; --voyage's order lookup takes
basename($vy_dir) for the same reason. Which dirs are nested is RECORDED by
discovery (NESTED_LIST), not re-derived from "is my parent a repo?", which
would prefix every depth-1 repo if a scan root were ever a checkout.

The denominator line is independent of all of that and went in regardless:
"undersoekt: N katalog(er) depth 1, M polyrepo-container(e), K nestede repo
(J med STATE.md tatt med)". The header count answers how many were found and
nothing about how many were looked at, so a criterion excluding 11 of 12 was
invisible at the surface built to show it. Real tree 2026-09-04: 43 / 5 / 12
(1 tatt med). A non-repo dot-dir counts in N and never in M - it is a
denominator, not a partition.

Its wording broke an existing check: "polyrepo container itself is not listed
as a repo" grepped the whole output for `polyrepo` and matched the footer's own
`polyrepo-container(e)` - the same class as a grep reading a comment that
EXPLAINS a pattern as an instance of it. Now anchored at column 1, which is
what it always meant.

Verified with board.sh, not from memory: from-ai-to-chitta/content-sadhguru
in-progress, Sonnet 5/high, and --plan gives it a real tab with paste=.
Mutation-verified: reverting the eight $COORD/$mbox reads turns exactly the
three mailbox checks red with the rest of the section green.

Bounded gaps, stated rather than closed: the mailbox-keyed JOINS ($OWED,
brief_orphans, --inbox-plan) still key on the board name - neither created nor
worsened here, since the repo was previously absent from RECORDS entirely; a
34-char key overflows the table's %-32s REPO column (same class as Fable
5.1/xhigh in KOST, and widening moves three cut -c89- helpers); a dot-prefixed
NESTED repo is not looked for.

board-selftest 368 -> 393. Suites: coord 257, board 393, route 73, orders 116,
guard 54 = 893. npm test 11/11.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-04 21:35:55 +02:00
commit cde185979c
10 changed files with 428 additions and 23 deletions

View file

@ -284,13 +284,67 @@ trunc() { printf '%s' "$1" | LC_ALL=en_US.UTF-8 cut -c1-"$2"; }
# --- Discovery: git repos at depth 1, plus depth 2 under polyrepo dirs ------
# A directory that is itself a git repo is one repo; a directory that is not
# but contains git repos is a polyrepo container (the plugin marketplace) and
# contributes its children, never itself.
# contributes its children, never itself. A repo nested under a depth-1 REPO is
# a third case, admitted on criterion (a) only - see add_nested_repos() below.
#
# "Is a repo" tests .git with -e, not -d: a worktree or submodule has .git as a
# FILE. A plain `git worktree add <root>/feature-x` lands a depth-1 sibling that
# can CARRY its own STATE.md - a -d test drops it silently. Kept identical in
# the rollup builder (catalog) on purpose: two readers, one name.
REPOS=""
# Dirs admitted by add_nested_repos(), recorded rather than re-derived. The
# record loop needs to know which entries are nested so it can build the
# <parent>/<child> key, and the obvious re-derivation ("is my parent dir a git
# repo?") answers a slightly different question: it would also fire for every
# depth-1 repo if a SCAN ROOT ever happened to be a git checkout. Discovery
# already knows the answer exactly; storing it cannot drift from the criterion.
NESTED_LIST=""
# --- Denominator counters (order 20260903T190201Z-238406410, .claude) -------
# A repo COUNT alone answers "how many were found" and is silent about how many
# directories were looked at, so an admission criterion that excludes 11 of 12
# nested repos is invisible at the very surface meant to show it - ansikt 4
# turned on the board's own reading. These four are printed as one line under
# the table (see UNDERSOEKT below) and are independent of the nested-repo
# admission itself: the line goes in whether or not anything is admitted.
N_DEPTH1=0 # directories examined at depth 1, dot-entries included
N_CONTAINER=0 # of those, entered as polyrepo containers (not themselves repos)
N_NESTED=0 # git repos found one level under a depth-1 repo
N_NESTED_IN=0 # of those, admitted because they carry a STATE.md
# Admission criterion (a), operator decision 2026-09-03: a git repo nested
# under a directory that is ITSELF a git repo enters the board only when it
# carries a STATE.md. Measured on the real tree that day: 12 nested repos,
# exactly 1 with a STATE.md (from-ai-to-chitta/content-sadhguru). The other 11
# are vendored or experimental checkouts with no declared next step, and they
# stay invisible ON PURPOSE - they do not even reach the UTEN STATE.md bucket,
# which is for repos the operator opens.
#
# A dedicated function beside add_dot_repos(), never a widening of the `*`
# loops below, for the identical reason ordre 20260818T124828Z gave for dot
# repos: routing a depth-1 REPO into the else-branch container scan would admit
# every nested checkout, which is exactly what criterion (a) declines. One
# level only - a repo nested inside a nested repo is a checkout of a checkout,
# and widening past what was ordered is the unmeasured scope creep that order
# flagged.
#
# Bounded gap, stated rather than closed: a DOT-prefixed nested repo is not
# looked for (the `*` glob here has no dotglob, same as everywhere else in this
# file). The combination was not measured and not ordered; add_dot_repos exists
# for the depth-1 and container cases because those were.
add_nested_repos() {
for nested in "$1"/*; do
[ -d "$nested" ] || continue
[ -e "$nested/.git" ] || continue
N_NESTED=$((N_NESTED + 1))
[ -f "$nested/STATE.md" ] || continue
N_NESTED_IN=$((N_NESTED_IN + 1))
REPOS="$REPOS
$nested"
NESTED_LIST="$NESTED_LIST
$nested"
done
}
# Picks up dot-prefixed git repos directly under $1 - the Forgejo/GitHub
# `.profile` org-profile convention, measured invisible to the loops below
@ -304,16 +358,29 @@ REPOS=""
# a bare `*` needs dotglob to see them), so no shopt toggle is needed here.
# Only a dot-entry that IS itself a repo is ever added; one that is not is
# silently skipped, never recursed into as a container.
#
# $2 = "d1" when this is the depth-1 scan of a root. A dot-prefixed depth-1
# repo IS a depth-1 repo, so it gets the same nested scan an ordinary one gets
# - the asymmetry would otherwise be arbitrary, and nothing in the admission
# criterion distinguishes them. Under a polyrepo container the flag is absent:
# those entries are already at depth 2, and their children would be depth 3.
add_dot_repos() {
for dotentry in "$1"/.*; do
dotbase="$(basename "$dotentry")"
[ "$dotbase" = "." ] && continue
[ "$dotbase" = ".." ] && continue
[ -d "$dotentry" ] || continue
# Counted as a depth-1 directory that was LOOKED AT even when it is not a
# repo: the denominator reports what was examined, not what was admitted.
# It is deliberately never counted as a polyrepo container - a dot-dir that
# is not a repo is skipped outright, which is ordre 20260818's decision.
[ "${2:-}" = "d1" ] && N_DEPTH1=$((N_DEPTH1 + 1))
[ -e "$dotentry/.git" ] || continue
REPOS="$REPOS
$dotentry"
[ "${2:-}" = "d1" ] && add_nested_repos "$dotentry"
done
return 0
}
# Split on comma via IFS + `set --` rather than an unquoted $(...) expansion:
@ -336,13 +403,20 @@ for root in "$@"; do
continue
fi
ROOTS_OK=$((ROOTS_OK + 1))
add_dot_repos "$root"
add_dot_repos "$root" d1
for entry in "$root"/*; do
[ -d "$entry" ] || continue
N_DEPTH1=$((N_DEPTH1 + 1))
if [ -e "$entry/.git" ]; then
REPOS="$REPOS
$entry"
# A depth-1 repo used to end the walk here: the else-branch below is the
# only place children are ever looked at, and it is unreachable for an
# entry that is itself a repo. That is what made every nested repo
# invisible.
add_nested_repos "$entry"
else
N_CONTAINER=$((N_CONTAINER + 1))
for child in "$entry"/*; do
[ -e "$child/.git" ] || continue
REPOS="$REPOS
@ -613,7 +687,24 @@ VOYAGE_CELL_EOF
printf '%s\n' "$REPOS" | while IFS= read -r d; do
[ -n "$d" ] || continue
name="$(basename "$d")"
# Two names, deliberately: the KEY the board shows and the MAILBOX the coord
# columns read. For every repo but a nested one they are the same string.
#
# A nested repo is keyed <parent>/<child> (operator decision 2026-09-03): the
# bare basename would render a row that says nothing about where the checkout
# lives, and two repos of the same name - one depth-1, one nested - would
# collide into indistinguishable rows.
#
# The mailbox name is NOT that key. A mailbox is addressed by
# basename(git toplevel), which is coord-send.sh's own rule and the only name
# a session in that repo can hold; reading $COORD/<parent>/<child>/inbox would
# find no directory and print INN 0 - a failed measurement wearing the
# reassuring value, which is the one thing this file refuses everywhere.
mbox="$(basename "$d")"
name="$mbox"
if printf '%s\n' "$NESTED_LIST" | grep -qxF "$d"; then
name="$(basename "$(dirname "$d")")/$mbox"
fi
state="$d/STATE.md"
# F6: `git status | wc -l` yields 0 lines whether the tree is CLEAN or git
@ -640,8 +731,8 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
fi
inbox=0
if [ -d "$COORD/$name/inbox" ]; then
inbox="$(ls "$COORD/$name/inbox"/*.md 2>/dev/null | wc -l | tr -d ' ')"
if [ -d "$COORD/$mbox/inbox" ]; then
inbox="$(ls "$COORD/$mbox/inbox"/*.md 2>/dev/null | wc -l | tr -d ' ')"
[ -n "$inbox" ] || inbox=0
fi
@ -657,8 +748,8 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
# as mail to such a name is invisible in INN. coord-count.sh is the cross-
# check for the mail half; there is deliberately no join built for orders.
orders=0
if [ -d "$COORD/$name/orders" ]; then
orders="$(ls "$COORD/$name/orders"/*.md 2>/dev/null | wc -l | tr -d ' ')"
if [ -d "$COORD/$mbox/orders" ]; then
orders="$(ls "$COORD/$mbox/orders"/*.md 2>/dev/null | wc -l | tr -d ' ')"
[ -n "$orders" ] || orders=0
fi
@ -681,8 +772,8 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
# read as "a session is running here" would be the process axis smuggled in
# as a file count.
claimed=0
if [ -d "$COORD/$name/orders/claimed" ]; then
claimed="$(ls "$COORD/$name/orders/claimed"/*.md 2>/dev/null | wc -l | tr -d ' ')"
if [ -d "$COORD/$mbox/orders/claimed" ]; then
claimed="$(ls "$COORD/$mbox/orders/claimed"/*.md 2>/dev/null | wc -l | tr -d ' ')"
[ -n "$claimed" ] || claimed=0
fi
@ -696,9 +787,9 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
# measured 2026-08-23), so a claim without an age is that non-claim with its
# only counter-evidence removed.
ordersage="-"
[ "$orders" -eq 0 ] || ordersage="$(oldest_pending_age "$COORD/$name/orders")"
[ "$orders" -eq 0 ] || ordersage="$(oldest_pending_age "$COORD/$mbox/orders")"
claimedage="-"
[ "$claimed" -eq 0 ] || claimedage="$(oldest_order_age "$COORD/$name/orders/claimed")"
[ "$claimed" -eq 0 ] || claimedage="$(oldest_order_age "$COORD/$mbox/orders/claimed")"
# Read for EVERY repo, not just the STATE-less ones: a repo whose plan file
# is fresh can still have been silent for a year, and that is precisely the
@ -1944,7 +2035,11 @@ voyage() {
# Order coupling: the repo's PENDING orders (claimed ones are in flight and
# are not what a reader is looking for when a brief has stopped moving).
vy_ord=0; vy_ids=""
for vy_of in "$COORD/$vy_name/orders"/*.md; do
# basename($vy_dir), never $vy_name: a nested repo's board key is
# <parent>/<child> while its mailbox is addressed by the bare basename
# (see the record loop's own note). Reading the compound key here would
# find no directory and report ordre=0 for a repo that has orders.
for vy_of in "$COORD/$(basename "$vy_dir")/orders"/*.md; do
[ -f "$vy_of" ] || continue
vy_ord=$((vy_ord+1))
vy_ids="$vy_ids$(basename "$vy_of" .md)
@ -2050,6 +2145,13 @@ n_nofield="$(awk -F'|' '$4=="?"' "$RECORDS" | wc -l | tr -d ' ')"
n_unmeas="$(awk -F'|' '$7=="?"' "$RECORDS" | wc -l | tr -d ' ')"
printf '\nSUM: %s uhaandterte innboks-meldinger, %s ukommiterte filer.\n' "$tot_in" "$tot_dirty"
# The scan's own denominator (order 20260903T190201Z-238406410, .claude). The
# repo count in the header answers "how many were found"; this answers "how
# many were looked at", which is the only way an admission criterion that
# excludes most nested repos is visible at all. Verifiseringsloven ansikt 4:
# a measurement without its nevner is read as a fact about the world.
printf 'undersoekt: %s katalog(er) depth 1, %s polyrepo-container(e), %s nestede repo (%s med STATE.md tatt med).\n' \
"$N_DEPTH1" "$N_CONTAINER" "$N_NESTED" "$N_NESTED_IN"
[ "${n_mal:-0}" -gt 0 ] && printf 'ADVARSEL: %s repo har MALFORMED status-token (utenfor det lukkede settet).\n' "$n_mal"
[ "${n_nofield:-0}" -gt 0 ] && printf 'MERK: %s repo mangler board-linje - status/kost er ukjent (?), NESTE-utdrag brukes.\n' "$n_nofield"
[ "${n_unmeas:-0}" -gt 0 ] && printf 'MERK: %s repo har umaalbart arbeidstre - git svarte ikke, DRT er ? og IKKE med i summen over.\n' "$n_unmeas"