fix(board): discover dot-prefixed repos (.profile) without dotglob's scope creep

board.sh's discovery loops (for entry in "$root"/*, and the polyrepo
container's child loop) never see dot-prefixed directories - measured with
a known-positive control: two repos in one root, one dot-prefixed, board
found only the other. This makes any dot-repo (e.g. .profile, the
Forgejo/GitHub org-profile convention) permanently invisible: not listed,
and --dispatch --repo .profile refuses outright.

A blanket `shopt -s dotglob` is not the fix: it would also route a
dot-prefixed non-repo dir (e.g. .claude) into the container-scan branch,
silently expanding what counts as a polyrepo container. Instead, add_dot_repos()
picks up only dot-entries that are themselves git repos, at both discovery
depths, leaving non-repo dot-dirs untouched. `.*` as a literal glob pattern
already matches dot-entries without dotglob, so no shopt toggle is needed.

Closes ordre 20260818T124828Z-136209036-from-.claude.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qMr8vZZFwa4dBrheNgAhj
This commit is contained in:
Kjell Tore Guttormsen 2026-08-18 15:01:00 +02:00
commit 3e5add0aee
2 changed files with 94 additions and 0 deletions

View file

@ -254,6 +254,31 @@ trunc() { printf '%s' "$1" | LC_ALL=en_US.UTF-8 cut -c1-"$2"; }
# 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=""
# Picks up dot-prefixed git repos directly under $1 - the Forgejo/GitHub
# `.profile` org-profile convention, measured invisible to the loops below
# (ordre 20260818T124828Z-136209036-from-.claude: `for entry in "$root"/*`
# has no dotglob, so a dot-prefixed repo is never seen at all). A blanket
# `shopt -s dotglob` on the loops below is deliberately NOT the fix: it
# would also route a dot-prefixed NON-repo dir (e.g. .claude) into the
# else-branch container-scan, silently expanding what counts as a polyrepo
# container - unmeasured scope creep the order explicitly flagged. `.* ` as
# a literal glob pattern already matches dot-entries without dotglob (only
# 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.
add_dot_repos() {
for dotentry in "$1"/.*; do
dotbase="$(basename "$dotentry")"
[ "$dotbase" = "." ] && continue
[ "$dotbase" = ".." ] && continue
[ -d "$dotentry" ] || continue
[ -e "$dotentry/.git" ] || continue
REPOS="$REPOS
$dotentry"
done
}
# Split on comma via IFS + `set --` rather than an unquoted $(...) expansion:
# unquoted word-splitting would also split roots containing spaces. Arg parsing
# is finished above, so clobbering the positional parameters is safe here.
@ -262,6 +287,7 @@ set -- $ROOTS
IFS="$OLD_IFS"
for root in "$@"; do
[ -d "$root" ] || continue
add_dot_repos "$root"
for entry in "$root"/*; do
[ -d "$entry" ] || continue
if [ -e "$entry/.git" ]; then
@ -273,6 +299,9 @@ $entry"
REPOS="$REPOS
$child"
done
# Same glob, same gap, one level down (board.sh:271 in the order's
# numbering) - a dot-prefixed repo nested under a polyrepo container.
add_dot_repos "$entry"
fi
done
done