Files
Your Name 0b5043a9f3
gates / consistency-and-conventions (push) Successful in 26s
fix: llama-server start breakage — version detection, flag-validation race, model dir resolution, user-bus pre-flight
User report after the llamacpp app install: 'installed llama.cpp unknown',
valid flags rejected (randomly per run), 'Model not found' for the HF
downloader's own layout, and a systemd user-bus failure over SSH. Detective
(real b10822 binary, FACT) found four independent causes:

- version: llama-server --version prints to STDERR; detect_llama_version's
  2>/dev/null swallowed it -> always 'unknown'. Now captures 2>&1 + accepts
  semver/build tokens (incl. build 1.2.3 edge)
- validation: printf|grep -q under pipefail -> SIGPIPE rc=141 race randomly
  rejected flags present in the 59 KB --help. Now pipe-less grep (no race);
  20x determinism regression test
- model resolution: resolve_model accepted files only, but the HF downloader
  creates <models>/<repo>/file.gguf dirs. Now expands a dir with exactly one
  *.gguf (never silently picks; multi-gguf lists + errs)
- port: llama.cpp default 8080 vs tool/adapter 8088; validation reliability
  means --port is now always pinned in the unit
- user bus: headless/SSH sessions lack XDG_RUNTIME_DIR -> ensure_user_bus in
  lib/common.sh pre-flights all three systemctl --user tools with remediation
  text; pos ai server --no-unit direct-run escape hatch (pidfile) for boxes
  with no bus
- find_llamacpp narrowed to llama-server/llama-server-cuda (bare 'server'
  fallback hazard); installer post-install sanity (version+help execute,
  symlink targets resolve)

Architect decisions DQ1-DQ6 recorded. Tester: 4 new regression files
(version-from-stderr, 25x flag-validation determinism, model dir expansion,
bus pre-flight + E2E) + 3 fixture updates; suite 16 files / 269 checks.

Verified: make gen idempotent; make check OK; make lint 0 FAIL, 0 WARN;
make test 269/269 (~49s); bash -n clean; git diff --check clean.
2026-09-06 09:25:52 -04:00

100 lines
4.4 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
# t-llamacpp-install.sh — F7: `apps/ai/llamacpp.sh` post-install sanity.
# After the installer drops llama-server + symlinks it into the bin dir, the
# sanity check must verify the binary actually runs (version/help readable via
# the same stdout/stderr the tool chain reads) and the symlink is not dangling.
# healthy → passes, logs "llama.cpp sanity OK"
# dangling symlink → err (rc 1, "dangling symlink")
# non-executable → err (rc 1, not on PATH)
# broken binary → err (rc 1, --version did not run → missing shared lib)
# Uses the LLAMACPP_BIN_DIR seam; calls the REAL shipped function.
#
# Note: the real installer cannot run in the sandbox (network + sudo + root
# paths), so the sanity function is extracted verbatim and exercised directly.
# extract_fn <source-file> <fnname> — print one brace-delimited function body.
extract_fn() {
local file="$1" fn="$2"
awk -v fn="$fn" '
BEGIN { found=0; depth=0 }
{
if (!found && $0 ~ ("^" fn "\\(\\)")) { found=1; depth=0 }
if (found) {
n_open = gsub(/\{/, "{")
n_close = gsub(/\}/, "}")
depth = depth + n_open - n_close
print
if (depth <= 0) exit
}
}
' "$file"
}
run_test() {
local app="$ROOT/apps/ai/llamacpp.sh"
local com="$ROOT/lib/common.sh"
# Extract the REAL llamacpp_sanity from the shipped installer.
local fn_file="$TEST_TMP/llamacpp-fns.sh"
extract_fn "$app" llamacpp_sanity > "$fn_file"
local sandbox bindir
sandbox="$(mksandbox llamacpp-install)"
bindir="$sandbox/bin"
mkdir -p "$bindir"
# 1. healthy fixture → rc 0 + "llama.cpp sanity OK"
cat > "$bindir/llama-server" <<'STUB'
#!/usr/bin/env bash
# healthy: version + help both readable; llama.cpp prints version to stderr
printf 'version: 0.4.0-dev (build 10822, commit c457e3bf7)\n' >&2
exit 0
STUB
chmod +x "$bindir/llama-server"
test_run_env LLAMACPP_BIN_DIR="$bindir" PATH="$bindir:/usr/bin:/bin" -- \
bash -c "source '$com'; source '$fn_file'; llamacpp_sanity" 2>&1
check_rc "F7 healthy fixture sanity rc 0" 0 "$TR_RC"
check_contains "F7 healthy fixture sanity OK log" "llama.cpp sanity OK" "$TR_OUT"
# 2. dangling symlink → err, rc 1, names the broken link
rm -f "$bindir/llama-server"
ln -s "$bindir/no-such-target" "$bindir/llama-server"
test_run_env LLAMACPP_BIN_DIR="$bindir" PATH="$bindir:/usr/bin:/bin" -- \
bash -c "source '$com'; source '$fn_file'; llamacpp_sanity" 2>&1
check_rc "F7 dangling symlink errs (rc 1)" 1 "$TR_RC"
check_contains "F7 dangling symlink message" "dangling symlink" "$TR_OUT"
# 3. non-executable fixture → err, rc 1 (bash `command -v` finds the file
# by PATH existence; the binary fails when actually executed, so the
# sanity errs at the --version step — the contract is a non-zero err).
rm -f "$bindir/llama-server"
printf '#!/usr/bin/env bash\nexit 0\n' > "$bindir/llama-server"
chmod 644 "$bindir/llama-server" # NOT executable
test_run_env LLAMACPP_BIN_DIR="$bindir" PATH="$bindir:/usr/bin:/bin" -- \
bash -c "source '$com'; source '$fn_file'; llamacpp_sanity" 2>&1
check_rc "F7 non-executable errs (rc 1)" 1 "$TR_RC"
check_contains "F7 non-executable message is a sanity err" "llama.cpp install sanity failed" "$TR_OUT"
# 4. broken binary (--version fails like a missing shared lib) → err, rc 1
rm -f "$bindir/llama-server"
cat > "$bindir/llama-server" <<'STUB'
#!/usr/bin/env bash
# simulates a truncated/missing-shared-lib binary: version unreadable
echo "error while loading shared libraries: libllama.so: cannot open" >&2
exit 1
STUB
chmod +x "$bindir/llama-server"
test_run_env LLAMACPP_BIN_DIR="$bindir" PATH="$bindir:/usr/bin:/bin" -- \
bash -c "source '$com'; source '$fn_file'; llamacpp_sanity" 2>&1
check_rc "F7 broken binary errs (rc 1)" 1 "$TR_RC"
check_contains "F7 broken binary message" "did not run" "$TR_OUT"
# 5. static guard: the shipped installer actually CALLS the sanity after
# the symlink loop (the wiring that makes F7 real).
if grep -q 'llamacpp_sanity' "$app"; then
printf ' PASS F7 installer wires llamacpp_sanity into install\n'
else
printf ' FAIL F7 installer does not call llamacpp_sanity\n'
fi
}