retire frank-medium: tests, planning and observability ground on frank-primary
The frank-medium retirement tail the 2026-09-26 lucebox cutover left uncommitted: the radiance quadlet tree, its swap/fetch tooling and its seam test are deleted (archive copies live in dankserver/.AGENTTRASH/ 20260926-frank-medium-radiance/ and scripts/.AGENTTRASH/20260926- frank-medium-radiance/), the planner/allowlist/test-changed mappings drop the service, and frank-large's chat template moves to scripts/ (its old home was the retired frank-medium dir). Finished here: - tests/frank_primary_unit.bats: the lucebox quadlet seam (boot persistence, host-network bind, HIP_VISIBLE_DEVICES=0,1, HIP-reserved env-name guard, checkout-mounted entrypoint/healthcheck, first-start patience, deployer payload/port gates). - test-changed.sh: explicit .AGENTTRASH/ case — retirement commits move files to trash, and the wrapper refused those additions with "no focused-test mapping". - observability: the vllm: namespace left with the radiance runtime. Rules keep only llamacpp:* series (prefix-cache reuse, spec-decode, queueing, endpoint-down); the dashboard drops the vLLM KV/latency panels; prometheus.yml documents that frank-primary (lucebox) has no /metrics and therefore no scrape job. llm-fleet.json was left corrupted mid-edit (missing opening brace) and is rewritten from HEAD. Suite: 339 green (was 7 red).
This commit is contained in:
1 parent
32d264ccda
commit
d7bf9f119a
22 files changed
+243
-2001
No files matched your search
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: frank-primary — the Dankserver LLM endpoint on :7770.
|
||||
#
|
||||
# This file asserts the LUCEBOX shape (the 2026-09-26 cutover that replaced
|
||||
# frank-medium): a rootless Quadlet running the lucebox DS4.1 engine on the
|
||||
# two R9700s, with the model mmapped out of /home/dank/models and the
|
||||
# entrypoint/healthcheck mounted straight out of this checkout.
|
||||
|
||||
load helpers
|
||||
|
||||
UNIT="$REPO_ROOT/dankserver/frank-primary/quadlet/frank-primary.container"
|
||||
EP="$REPO_ROOT/dankserver/frank-primary/frank-primary-entrypoint.sh"
|
||||
HC="$REPO_ROOT/dankserver/frank-primary/frank-primary-healthcheck.py"
|
||||
|
||||
@test "the frank-primary quadlet file and its mounted scripts exist" {
|
||||
[ -f "$UNIT" ]
|
||||
[ -x "$EP" ]
|
||||
[ -f "$HC" ]
|
||||
# The healthcheck is python; a syntax error would leave the container
|
||||
# permanently unhealthy with the failure hidden inside HealthCmd.
|
||||
python3 -m py_compile "$HC"
|
||||
}
|
||||
|
||||
@test "frank-primary is boot-persistent and self-healing" {
|
||||
# Rootless Podman does not auto-start bare containers and restart:
|
||||
# unless-stopped does not survive shutdown's explicit stop. The unit must
|
||||
# carry both the boot symlink and a restart policy (2026-08-26 incident:
|
||||
# a compose-only Caddy never came back after a reboot).
|
||||
grep -q '^WantedBy=default.target' "$UNIT"
|
||||
grep -qE '^Restart=(always|on-failure)' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-primary binds the host network and needs no published port" {
|
||||
# luce_server binds 0.0.0.0:7770 directly, so the container takes the
|
||||
# host netns. A PublishPort would be dead config.
|
||||
grep -q -- '--network=host' "$UNIT"
|
||||
! grep -q '^PublishPort=' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-primary reaches both R9700s and hides the Raphael iGPU" {
|
||||
# /dev/kfd + /dev/dri via AddDevice; HIP_VISIBLE_DEVICES=0,1 keeps the
|
||||
# host's Raphael iGPU (index 2) out of the enumeration so the engine's
|
||||
# device picks cannot land on it.
|
||||
grep -q '^AddDevice=/dev/kfd' "$UNIT"
|
||||
grep -q '^AddDevice=/dev/dri' "$UNIT"
|
||||
grep -q '^Environment=HIP_VISIBLE_DEVICES=0,1$' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-primary never names a bare HIP-reserved env var" {
|
||||
# The HIP runtime reads bare TEMP for its JIT cache path (the 2026-08-13
|
||||
# incident: TEMP=1.0 sent the JIT cache to path "1.0" and segfaulted every
|
||||
# load). HOST and GPU_MAX_HEAP_SIZE are the same class. The unit's
|
||||
# Environment= lines must not define them; the entrypoint exports
|
||||
# GPU_MAX_HW_QUEUES (explicitly not GPU_MAX_HEAP_SIZE).
|
||||
! grep -qE '^Environment=(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$UNIT"
|
||||
! grep -qE '^(export )?(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$EP"
|
||||
}
|
||||
|
||||
@test "the unit mounts the entrypoint and healthcheck from the checkout" {
|
||||
# deploy.sh git-pulls this checkout before dispatching, so a Volume
|
||||
# reference is how an edit here reaches the container without an image
|
||||
# rebuild. Absolute host paths, read-only.
|
||||
grep -q 'Volume=/home/dank/serverAppConfigs/dankserver/frank-primary/frank-primary-entrypoint.sh:/usr/local/bin/frank-primary-entrypoint.sh:ro' "$UNIT"
|
||||
grep -q 'Volume=/home/dank/serverAppConfigs/dankserver/frank-primary/frank-primary-healthcheck.py:/usr/local/bin/frank-primary-healthcheck.py:ro' "$UNIT"
|
||||
}
|
||||
|
||||
@test "first-start patience is configured on both sides of the health check" {
|
||||
# Cold start page-ins the dense weights and builds the graphs; the
|
||||
# container must not be killed as unhealthy while that happens, and the
|
||||
# deployer must wait the same order of magnitude.
|
||||
grep -q '^HealthStartPeriod=1800s' "$UNIT"
|
||||
grep -q '^TimeoutStartSec=1800$' "$UNIT"
|
||||
grep -q 'wait_container_healthy frank-primary 1800' \
|
||||
"$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
}
|
||||
|
||||
@test "the deployer refuses to start without image and complete payload" {
|
||||
# A 377 GiB partial download must never be served: the handler gates on
|
||||
# the image being present and the model file existing at its exact
|
||||
# declared byte count (stat -c %s, never wc -c — wc read the whole stream
|
||||
# for minutes on 2026-09-26).
|
||||
grep -q 'deploy_llm_primary() {' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'podman image exists localhost/lucebox-rocm:gfx1201' \
|
||||
"$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'want_size=405349859328' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'stat -c %s' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
}
|
||||
|
||||
@test "the deployer gates on the port actually being free" {
|
||||
# 7770 is a host-network bind: the previous holder must release it before
|
||||
# the new container can be created, or pasta's bind fails at create time
|
||||
# and the failure hides behind Restart=.
|
||||
grep -q 'wait_port_free 7770' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
}
|
||||
Reference in new issue
Block a user