The machine now carries its own manual for AI hands

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-25 10:09:38 -04:00
parent beed44dd87
commit 045a774847
16 changed files with 1321 additions and 30 deletions
+184 -13
View File
@@ -5,16 +5,17 @@
# Author: Gabriel Brown
#
# Commands:
# update Bring this machine up to date: pull, then install --upgrade
# sync Review, commit & push local changes to this repo
# edit Open the Panama repo in Neovim
# doctor Report what is actually running on this machine
# test Run every contract under tests/
# upgrade Re-run the installer from anywhere, interview included
# migrate Apply repairs this machine has not had yet
# apps Choose applications to install, by category
# app Build and install an application that no repository packages
# help Show this help
# update Bring this machine up to date: pull, then install --upgrade
# sync Review, commit & push local changes to this repo
# edit Open the Panama repo in Neovim
# doctor Report what is actually running on this machine
# test Run every contract under tests/ (--safe skips the hijacking ones)
# contracts Name the contracts that mention a given file
# upgrade Re-run the installer from anywhere, interview included
# migrate Apply repairs this machine has not had yet
# apps Choose applications to install, by category
# app Build and install an application that no repository packages
# help Show this help
#
# update and sync are deliberately separate verbs. One acts on the machine, the
# other on the repository, and a single command that guessed between them by
@@ -82,6 +83,11 @@ ${BOLD}Commands:${RESET}
than what was installed. Takes --summary for one line per check.
${GREEN}test${RESET} Run every contract under tests/. Give it a pattern to run
a subset: 'panama test dock' runs the ones matching 'dock'.
--safe skips the ones that take over the live desktop; what
they are and why is tests/desktop-hijacking.
${GREEN}contracts${RESET} Name the contracts that mention a given file, each marked
safe or desktop. A heuristic over the text of tests/, so it
answers "what should I run" rather than "what covers this".
${GREEN}upgrade${RESET} Re-run ./install from anywhere, interview and all. For a new
machine, or to change an answer you gave. Routine updates are
'$PROGRAM update', which asks nothing.
@@ -106,6 +112,8 @@ ${BOLD}Examples:${RESET}
$PROGRAM edit
$PROGRAM doctor --summary
$PROGRAM test dock
$PROGRAM test --safe
$PROGRAM contracts config/dot/quickshell/services/Displays.qml
$PROGRAM upgrade
$PROGRAM apps
$PROGRAM app
@@ -340,6 +348,32 @@ cmd_doctor() {
exec "$doctor" "$@"
}
# ----------------------------------------------------------------------------
# The desktop-hijacking ledger
# ----------------------------------------------------------------------------
#
# tests/desktop-hijacking lists, one repo-relative path per line with a '#'
# comment saying what it does to the live session, the contracts that drive the
# real shell, compositor or machine rather than a harness. Read by `test --safe`
# to decide what to skip, and by `contracts` to mark each hit.
#
# Prints the paths, comments and blank lines stripped. A missing ledger prints
# nothing: no ledger means nothing is known to hijack, which is the honest
# reading of an absent file and keeps `--safe` from failing on a fresh checkout.
DESKTOP_HIJACKING_LEDGER="tests/desktop-hijacking"
hijacking_entries() {
local ledger="$PANAMA_DIR/$DESKTOP_HIJACKING_LEDGER" line
[[ -r "$ledger" ]] || return 0
while IFS= read -r line || [[ -n "$line" ]]; do
line="${line%%#*}"
line="${line#"${line%%[![:space:]]*}"}"
line="${line%"${line##*[![:space:]]}"}"
[[ -n "$line" ]] && printf '%s\n' "$line"
done < "$ledger"
return 0
}
# ----------------------------------------------------------------------------
# Command: test
# ----------------------------------------------------------------------------
@@ -351,9 +385,34 @@ cmd_doctor() {
# Each runs in its own process and a failure does not stop the rest, because the
# useful output is the whole list of what is broken rather than the first thing
# that broke. The exit code is what a caller can act on.
#
# --safe exists because a fair number of these contracts ARE the desktop: they
# open overlays, restart the shell, move your windows. Running the suite while
# sitting in front of the machine used to mean losing the session for a few
# minutes, so the honest options were "run everything" or "run nothing". --safe
# is the third: skip exactly what tests/desktop-hijacking names, and say how
# many were skipped, so the gap is stated rather than implied.
cmd_test() {
local pattern="${1:-}"
local pattern="" safe=0 arg
# Position-independent, because 'panama test --safe dock' and
# 'panama test dock --safe' are the same intent and nobody should have to
# remember which one this accepts.
for arg in "$@"; do
case "$arg" in
--safe) safe=1 ;;
*) pattern="$arg" ;;
esac
done
local -a suite=()
local -A hijacking=()
local skipped=0 entry rel
if (( safe )); then
while IFS= read -r entry; do
hijacking["$entry"]=1
done < <(hijacking_entries)
fi
# Executables, plus the Python suites. Those are unittest files rather than
# executables, and collecting only what has the executable bit would skip them
@@ -361,11 +420,25 @@ cmd_test() {
# A runner with a blind spot is worse than no runner, because it reports PASS.
while IFS= read -r path; do
[[ -x "$path" || "$path" == *_test.py ]] || continue
[[ -z "$pattern" || "$path" == *"$pattern"* ]] && suite+=("$path")
[[ -z "$pattern" || "$path" == *"$pattern"* ]] || continue
rel="tests/${path#"$PANAMA_DIR"/tests/}"
if (( safe )) && [[ -n "${hijacking[$rel]:-}" ]]; then
(( ++skipped ))
continue
fi
suite+=("$path")
done < <(find "$PANAMA_DIR/tests" -type f -not -path '*/fixtures/*' -not -path '*__pycache__*' | sort)
if (( ${#suite[@]} == 0 )); then
err "No contracts match '${pattern}'"
# "Nothing matched" and "everything that matched was skipped" are different
# answers, and reporting the first for the second is how --safe would come
# to look like a broken pattern.
if (( skipped > 0 )); then
err "Every contract matching '${pattern}' is desktop-hijacking; --safe skipped all ${skipped}."
printf ' What they do to the session: %s/%s\n' "$PANAMA_DIR" "$DESKTOP_HIJACKING_LEDGER" >&2
else
err "No contracts match '${pattern}'"
fi
exit 1
fi
@@ -391,14 +464,111 @@ cmd_test() {
header "Result"
if (( ${#failed[@]} == 0 )); then
ok "${#suite[@]} contract(s) passed"
if (( safe )); then
printf 'Skipped %d desktop-hijacking contract(s) (%s).\n' "$skipped" "$DESKTOP_HIJACKING_LEDGER"
fi
return 0
fi
err "${#failed[@]} of ${#suite[@]} failed:"
printf ' %s\n' "${failed[@]}" >&2
warn "Run one on its own to see why: ${BOLD}${PANAMA_DIR}/tests/<name>${RESET}"
if (( safe )); then
printf 'Skipped %d desktop-hijacking contract(s) (%s).\n' "$skipped" "$DESKTOP_HIJACKING_LEDGER"
fi
return 1
}
# ----------------------------------------------------------------------------
# Command: contracts
# ----------------------------------------------------------------------------
#
# "I changed this file -- what should I run?" There are 177 contracts and no
# index, so the honest answers were "all of them" (minutes, and half of them
# take the desktop away) or "the ones whose name sounds related" (which is how
# a covering contract gets skipped).
#
# This is a grep, and says so. A contract that names the file, or a
# parent-trimmed suffix of it, or just its basename, is a contract worth
# running; one that reaches the file through a harness or a generated artifact
# is not found, which is why the empty answer says "coverage may be indirect"
# rather than "nothing covers this". Naming a file the suite does not mention is
# a real answer -- exit 1 so a script can tell the difference -- but it is a
# statement about this search, not about the file.
#
# Each hit is marked from tests/desktop-hijacking, so the output also answers
# "and can I run them right now".
cmd_contracts() {
local target="${1:-}"
if [[ -z "$target" ]]; then
err "Which file? Usage: ${BOLD}$PROGRAM contracts <file>${RESET}"
exit 1
fi
# Absolute, relative to where you are standing, or repo-relative -- all three
# are how somebody refers to a file in this tree, and readlink resolves the
# symlinked dotfile in ~/.config back into the checkout it points at.
local absolute=""
if [[ -e "$target" ]]; then
absolute="$(readlink -f "$target")"
elif [[ -e "$PANAMA_DIR/$target" ]]; then
absolute="$(readlink -f "$PANAMA_DIR/$target")"
else
err "No such file: '$target'"
printf 'Give a path, absolute or relative to here or to %s.\n' "$PANAMA_DIR" >&2
exit 1
fi
local path
case "$absolute" in
"$PANAMA_DIR"/*) path="${absolute#"$PANAMA_DIR"/}" ;;
*)
err "'$target' is outside the Panama repo (${PANAMA_DIR})."
exit 1
;;
esac
# The repo-relative path, then each parent trimmed off in turn, ending at the
# basename. Contracts refer to their subject every one of these ways: by the
# full path from the repo root, by the path from the shell directory, and by
# name alone.
local -a patterns=()
local suffix="$path"
while :; do
patterns+=(-e "$suffix")
[[ "$suffix" == */* ]] || break
suffix="${suffix#*/}"
done
local -A hijacking=()
local entry
while IFS= read -r entry; do
hijacking["$entry"]=1
done < <(hijacking_entries)
# The same collection `test` runs, so anything named here is something the
# runner would actually execute.
local -a hits=()
local candidate rel
while IFS= read -r candidate; do
[[ -x "$candidate" || "$candidate" == *_test.py ]] || continue
grep -qF "${patterns[@]}" "$candidate" 2>/dev/null || continue
hits+=("tests/${candidate#"$PANAMA_DIR"/tests/}")
done < <(find "$PANAMA_DIR/tests" -type f -not -path '*/fixtures/*' -not -path '*__pycache__*' | sort)
if (( ${#hits[@]} == 0 )); then
printf 'No contract mentions %s — coverage may be indirect (a harness or a generated artifact); nothing verified.\n' "$path" >&2
exit 1
fi
for rel in "${hits[@]}"; do
if [[ -n "${hijacking[$rel]:-}" ]]; then
printf '%s [desktop]\n' "$rel"
else
printf '%s [safe]\n' "$rel"
fi
done
}
# ----------------------------------------------------------------------------
# Command: upgrade
# ----------------------------------------------------------------------------
@@ -636,6 +806,7 @@ main() {
edit) shift; cmd_edit "$@" ;;
doctor) shift; cmd_doctor "$@" ;;
test) shift; cmd_test "$@" ;;
contracts) shift; cmd_contracts "$@" ;;
upgrade) shift; cmd_upgrade "$@" ;;
migrate) shift; cmd_migrate "$@" ;;
app) shift; cmd_app "$@" ;;