inference: frank-large returns to halogen, frank-small takes the 3090
Dankclaw's endpoints are re-split. frank-large is the halogen-flash-server quadlet again -- the 2026-09-13 unit file was never touched by the two-day ik_llama.cpp interlude, so the runtime was still in the repo and its image is still in local storage -- retuned to the shape asked for: HALOGEN_CTX 200192 with a 400,384-position pool and two slots, exactly two 200k conversations. frank-small is new: mainline llama.cpp on the RTX 3090 serving ISTA-DASLab/Qwen3.8-27B-GSQ-RCO-GGUF at IQ3_S, using the -mtp build (it carries blk.64.nextn.*, which is what lets --spec-type draft-mtp run on the main model's own weights instead of a second 12 GiB copy) plus the BF16 vision projector, as one 131,072-token slot with f16 KV on port 7771. The host is shared now, and that is what the halogen retune pays for: HALOGEN_MAX_TOK 24576 (arena 20.6 -> 16.4 GiB, ~4-5% prefill) and the vision tower dropped (1.97 GiB) hand ~6 GiB back to the host, and the reserve rises to 20 to keep the fit check honest. Vision moved wholesale to frank-small. Retired to scripts/.AGENTTRASH/: the ik trio (env, service, serve script), the Qwen-Sharp template only that runtime read, and four benchmark harnesses bound to retired runtimes. Because retiring a file makes any test that greps it pass by absence, the seams assert the archive exists AND the live path does not.
This commit is contained in:
@@ -18,7 +18,7 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
|
||||
@test "deployment planner maps large-model changes to the large model only" {
|
||||
run python3 "$PLANNER" --target dankclaw --paths \
|
||||
scripts/frank-large.env scripts/frank-large.service scripts/serve-frank-large.sh
|
||||
dankclaw/frank-large/quadlet/frank-large.container
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-large" ]
|
||||
}
|
||||
@@ -28,14 +28,18 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
! grep -q 'frank_npu\|frank-npu' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@test "chat-template changes plan frank-large: the ik runtime reads the tracked template" {
|
||||
# ik_llama.cpp (2026-09-15 cutover) serves the Qwen-Sharp template from
|
||||
# the tracked scripts/chat-template.jinja again. The vllm-radiance
|
||||
# runtime on Dankserver ships its own qwen-fixed-v22.3.jinja out of the
|
||||
# pinned clone, so a template edit deploys nothing there.
|
||||
@test "the retired ik chat template plans nothing, and its archive is still here" {
|
||||
# scripts/chat-template.jinja existed only for the ik_llama.cpp runtime
|
||||
# (retired 2026-09-16 in favour of halogen-flash-server again). The
|
||||
# llama.cpp frank-small runtime serves the template the GGUF itself
|
||||
# carries, which is the one with reasoning_effort, preserve_thinking and
|
||||
# the tool-call grammar. Editing the archive must deploy nothing -- and the
|
||||
# archive must still be present, so this cannot pass by the file having
|
||||
# vanished.
|
||||
[ -f "$REPO_ROOT/scripts/.AGENTTRASH/chat-template.jinja.ik-llama-qwen-sharp" ]
|
||||
run python3 "$PLANNER" --target dankclaw --paths scripts/chat-template.jinja
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-large" ]
|
||||
[ -z "$output" ]
|
||||
|
||||
run python3 "$PLANNER" --target dankserver --paths scripts/chat-template.jinja
|
||||
[ "$status" -eq 0 ]
|
||||
@@ -51,9 +55,19 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
[ "$output" = "frank-medium" ]
|
||||
}
|
||||
|
||||
@test "the retired small endpoint is absent from the deployment inventory" {
|
||||
! grep -q '"frank-small"' "$PLANNER"
|
||||
! grep -qE 'frank-small\) deploy|dankserver:frank-small' "$REMOTE_DEPLOY" "$REPO_ROOT/scripts/deploy.sh"
|
||||
@test "the small endpoint is Dankclaw's again, and Dankserver's copy stays retired" {
|
||||
run python3 "$PLANNER" --target dankclaw --paths \
|
||||
scripts/frank-small.env scripts/frank-small.service scripts/serve-frank-small.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-small" ]
|
||||
|
||||
# frank-small runs on Dankclaw on the RTX 3090; the Dankserver endpoint of
|
||||
# that name was retired with the FreeToken runtime on 2026-09-15 and must
|
||||
# not come back through a planner mapping.
|
||||
run python3 "$PLANNER" --target dankserver --paths \
|
||||
scripts/frank-small.env scripts/frank-small.service scripts/serve-frank-small.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[ -z "$output" ]
|
||||
}
|
||||
|
||||
@test "documentation-only changes plan no runtime deployment" {
|
||||
|
||||
+79
-61
@@ -1,86 +1,104 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: the frank-large ik_llama.cpp root unit on dankclaw.
|
||||
# ik_llama.cpp replaced the halogen rootless Quadlet on 2026-09-15. This seam
|
||||
# pins the deployment-policy properties that no reviewer can see by reading
|
||||
# the flags alone: a root unit whose files all live in this repo, the hybrid
|
||||
# placement contract (experts + PLE mmap'd on the CPU path — NEVER the
|
||||
# CUDA_Host pinned buffer), no pinned CUDA host memory, the single client
|
||||
# port every consumer already targets, the fleet alias, greedy-by-default
|
||||
# sampling, vision via the mtmd mmproj, and a deploy handler that retires
|
||||
# the halogen quadlet without deleting it.
|
||||
# Seam: the frank-large halogen-flash-server quadlet on dankclaw.
|
||||
# halogen-flash-server replaced ik_llama.cpp again on 2026-09-16, so this
|
||||
# service is once more a rootless Quadlet container on the gfx1151 iGPU. This
|
||||
# seam pins what a flag list cannot show: the boot-persistent podman posture
|
||||
# (both device nodes, memlock, the create-time image contract), the
|
||||
# matched ctx/pool/slots set that IS the two-conversation promise, the
|
||||
# co-tenancy budget the arena and reserve are chosen for, the image handoff to
|
||||
# frank-small, and a deploy handler that retires the previous ROOT unit without
|
||||
# deleting it.
|
||||
|
||||
load helpers
|
||||
|
||||
UNIT="$REPO_ROOT/scripts/frank-large.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-large.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-large.env"
|
||||
QUADLET="$REPO_ROOT/dankclaw/frank-large/quadlet/frank-large.container"
|
||||
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
|
||||
@test "frank-large unit, serve script and env exist in scripts/" {
|
||||
[ -f "$UNIT" ]
|
||||
[ -f "$SERVE" ]
|
||||
[ -f "$ENV_FILE" ]
|
||||
@test "the frank-large quadlet exists where the deployer installs it from" {
|
||||
[ -f "$QUADLET" ]
|
||||
}
|
||||
|
||||
@test "frank-large unit is boot-persistent, self-healing and unprivileged" {
|
||||
grep -q '^WantedBy=multi-user.target$' "$UNIT"
|
||||
grep -q '^Restart=on-failure$' "$UNIT"
|
||||
grep -q '^RestartSec=' "$UNIT"
|
||||
grep -q '^User=dank$' "$UNIT"
|
||||
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
||||
@test "frank-large is boot-persistent, self-healing and container-shaped" {
|
||||
grep -q '^WantedBy=default.target$' "$QUADLET"
|
||||
grep -q '^Restart=on-failure$' "$QUADLET"
|
||||
grep -q '^RestartSec=' "$QUADLET"
|
||||
grep -q '^Pull=never$' "$QUADLET"
|
||||
# The localhost/-aliased tag is what create-time resolution needs on this
|
||||
# host; the deployer pulls the ghcr.io ref and re-tags it.
|
||||
grep -q '^Image=localhost/peonist-ai/halogen-flash-server:' "$QUADLET"
|
||||
}
|
||||
|
||||
@test "frank-large unit points at the repo serve script and env" {
|
||||
grep -q 'ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-large.sh$' "$UNIT"
|
||||
grep -q 'FRANK_LARGE_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-large.env' "$UNIT"
|
||||
@test "frank-large has the gfx1151 devices and the image's documented posture" {
|
||||
grep -q '^AddDevice=/dev/kfd$' "$QUADLET"
|
||||
grep -q '^AddDevice=/dev/dri$' "$QUADLET"
|
||||
grep -q '^PodmanArgs=--ipc=host --security-opt seccomp=unconfined$' "$QUADLET"
|
||||
grep -q '^Ulimit=memlock=-1:-1$' "$QUADLET"
|
||||
# The weights mount must stay read-write: the first start downloads into it.
|
||||
grep -q '^Volume=/home/dank/models/halogen:/models$' "$QUADLET"
|
||||
}
|
||||
|
||||
@test "frank-large places experts and PLE on the mmap'd CPU path, never the pinned buffer" {
|
||||
# --cpu-moe routes CPU-overridden weights through the CUDA_Host PINNED
|
||||
# buffer (108.12 GiB measured on 2026-09-15; it evicted every co-tenant
|
||||
# into swap and starved sshd into unreachability). The -ot ...=CPU plain
|
||||
# CPU backend buffer is the mmap-backed path.
|
||||
grep -q -- '-ot "exps=CPU" -ot "per_layer_token_embd=CPU"' "$SERVE"
|
||||
grep -q '^GGML_CUDA_NO_PINNED_WEIGHTS=1$' "$ENV_FILE"
|
||||
# The serve script refuses to run without the no-pinned policy.
|
||||
grep -q 'GGML_CUDA_NO_PINNED_WEIGHTS=1 is mandatory on this host' "$SERVE"
|
||||
@test "frank-large keeps the fleet alias and publishes only the API port" {
|
||||
grep -q '^Environment=HALOGEN_MODEL_ID=frank-large$' "$QUADLET"
|
||||
grep -q '^PublishPort=7770:8731$' "$QUADLET"
|
||||
# The engine's own listener stays inside the container: it is unauthenticated.
|
||||
! grep -q 'PublishPort=.*8730' "$QUADLET"
|
||||
}
|
||||
|
||||
@test "frank-large serves the ik runtime from the unified-memory hybrid layout" {
|
||||
grep -q 'ik_llama.cpp/build/bin/llama-server' "$ENV_FILE"
|
||||
grep -q 'mradermacher-Qwen3.8-Flash-Next-Uncensored-i1-Q4_K_M' "$ENV_FILE"
|
||||
grep -q -- '--gpu-layers "$NGL"' "$SERVE"
|
||||
grep -q -- '--flash-attn "$FLASH_ATTN"' "$SERVE"
|
||||
@test "the KV pool is exactly two conversations of the per-request ceiling" {
|
||||
local ctx pool slots
|
||||
ctx="$(sed -nE 's/^Environment=HALOGEN_CTX=([0-9]+)$/\1/p' "$QUADLET")"
|
||||
pool="$(sed -nE 's/^Environment=HALOGEN_KV_POOL_POSITIONS=([0-9]+)$/\1/p' "$QUADLET")"
|
||||
slots="$(sed -nE 's/^Environment=HALOGEN_KV_SLOTS=([0-9]+)$/\1/p' "$QUADLET")"
|
||||
[ -n "$ctx" ] && [ -n "$pool" ] && [ -n "$slots" ]
|
||||
# The deployed promise is two resident conversations: the pool is twice the
|
||||
# ceiling, one slot per conversation. Slots still oversubscribe the pool for
|
||||
# any real request, because admission reserves prompt + max_tokens.
|
||||
[ "$pool" -eq $((ctx * 2)) ]
|
||||
[ "$slots" -eq 2 ]
|
||||
}
|
||||
|
||||
@test "frank-large keeps the fleet identity and the client port" {
|
||||
grep -q '^LISTEN_PORT=7770$' "$ENV_FILE"
|
||||
grep -q '^ALIAS=frank-large$' "$ENV_FILE"
|
||||
grep -q -- '--port "$LISTEN_PORT"' "$SERVE"
|
||||
grep -q -- '--host "$BIND_ADDR"' "$SERVE"
|
||||
@test "the prefill arena stays inside the range the vendor tested" {
|
||||
local max_tok reserve
|
||||
max_tok="$(sed -nE 's/^Environment=HALOGEN_MAX_TOK=([0-9]+)$/\1/p' "$QUADLET")"
|
||||
reserve="$(sed -nE 's/^Environment=HALOGEN_HOST_RESERVE_GIB=([0-9]+)$/\1/p' "$QUADLET")"
|
||||
[ -n "$max_tok" ] && [ -n "$reserve" ]
|
||||
# 32768 is the vendor default; 65536 cannot boot on this host because the
|
||||
# arena alone outgrows the device budget. The arena is a per-call prefill
|
||||
# chunk, so a smaller value costs prefill speed, not context.
|
||||
[ "$max_tok" -le 32768 ]
|
||||
[ "$max_tok" -ge 16384 ]
|
||||
[ "$reserve" -ge 15 ]
|
||||
}
|
||||
|
||||
@test "frank-large decodes greedy by default (halogen client contract)" {
|
||||
grep -q '^TEMPERATURE=0.0$' "$ENV_FILE"
|
||||
grep -q -- '--temp "$TEMPERATURE"' "$SERVE"
|
||||
@test "frank-large loads no vision tower: the fleet's image path is frank-small" {
|
||||
! grep -q 'HALOGEN_VISION_TOWER' "$QUADLET"
|
||||
grep -q -- '--mmproj' "$REPO_ROOT/scripts/serve-frank-small.sh"
|
||||
}
|
||||
|
||||
@test "frank-large keeps image input via the mtmd mmproj" {
|
||||
grep -q '^MMPROJ_PATH=.*mmproj-f16.gguf$' "$ENV_FILE"
|
||||
grep -q -- '--mmproj "$MMPROJ_PATH"' "$SERVE"
|
||||
}
|
||||
|
||||
@test "the deploy handler retires the halogen quadlet without deleting it" {
|
||||
grep -q 'retire_quadlet_llm_large' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl --user stop frank-large.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'frank-large.container' "$REMOTE_DEPLOY"
|
||||
@test "the deploy handler retires the previous ROOT unit without deleting it" {
|
||||
grep -q 'retire_root_llm_large' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl stop frank-large.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl disable frank-large.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'HOME/.AGENTTRASH' "$REMOTE_DEPLOY"
|
||||
! grep -qE '(^|[^[:alnum:]_])rm (-[a-zA-Z]+ )?.*frank-large' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@test "the deploy handler installs the root unit and refuses a missing checkpoint" {
|
||||
grep -q 'relink_unit frank-large' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-large.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'checkpoint absent' "$REMOTE_DEPLOY"
|
||||
! grep -q 'install_quadlet frank-large' "$REMOTE_DEPLOY"
|
||||
@test "the deploy handler installs the quadlet and gates the first start on weights" {
|
||||
grep -q 'install_quadlet frank-large dankclaw/frank-large/quadlet frank-large' "$REMOTE_DEPLOY"
|
||||
grep -q 'wait_for_llm_large_ready' "$REMOTE_DEPLOY"
|
||||
grep -q 'qwen38-flash-next-w4b.hgn' "$REMOTE_DEPLOY"
|
||||
grep -q '127.0.0.1:7770/health' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@test "the ik_llama.cpp runtime that held this service is archived, not live" {
|
||||
# Its files must not sit in scripts/ where a stale root unit could still be
|
||||
# pointed at them, and must not be gone either: .AGENTTRASH is the rollback.
|
||||
local retired
|
||||
for retired in frank-large.env.ik-llama.cpp frank-large.service.ik-llama.cpp \
|
||||
serve-frank-large.sh.ik-llama.cpp; do
|
||||
[ -f "$REPO_ROOT/scripts/.AGENTTRASH/$retired" ]
|
||||
done
|
||||
[ ! -e "$REPO_ROOT/scripts/frank-large.env" ]
|
||||
[ ! -e "$REPO_ROOT/scripts/frank-large.service" ]
|
||||
[ ! -e "$REPO_ROOT/scripts/serve-frank-large.sh" ]
|
||||
}
|
||||
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: the frank-small mainline-llama.cpp root unit on dankclaw.
|
||||
# frank-small is the RTX 3090 endpoint created on 2026-09-16, when frank-large
|
||||
# went back to the halogen engine on the iGPU. This seam pins what the flags
|
||||
# alone do not say: boot persistence for a NATIVE runtime (no generated quadlet
|
||||
# is involved), the repo-relative paths the unit executes, the separate client
|
||||
# port, the MTP contract (the head lives in the weights file, and no second copy
|
||||
# of the model is loaded for it), the vision handoff from frank-large, and the
|
||||
# KV budget that has to fit a 24 GiB card beside 12 GiB of weights.
|
||||
|
||||
load helpers
|
||||
|
||||
UNIT="$REPO_ROOT/scripts/frank-small.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-small.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-small.env"
|
||||
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
QUADLET_LARGE="$REPO_ROOT/dankclaw/frank-large/quadlet/frank-large.container"
|
||||
|
||||
@test "frank-small unit, serve script and env exist in scripts/" {
|
||||
[ -f "$UNIT" ]
|
||||
[ -f "$SERVE" ]
|
||||
[ -f "$ENV_FILE" ]
|
||||
}
|
||||
|
||||
@test "frank-small is boot-persistent, self-healing and unprivileged" {
|
||||
grep -q '^WantedBy=multi-user.target$' "$UNIT"
|
||||
grep -q '^Restart=on-failure$' "$UNIT"
|
||||
grep -q '^RestartSec=' "$UNIT"
|
||||
grep -q '^User=dank$' "$UNIT"
|
||||
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-small runs the repo's own serve script with the repo's env" {
|
||||
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-small.sh$' "$UNIT"
|
||||
grep -q 'FRANK_SMALL_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-small.env' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-small offloads every layer to the 3090 with flash attention" {
|
||||
grep -q 'llama.cpp-mainline/build-cuda/bin/llama-server' "$ENV_FILE"
|
||||
grep -q '^NGL=999$' "$ENV_FILE"
|
||||
grep -q -- '--gpu-layers "$NGL"' "$SERVE"
|
||||
grep -q '^FLASH_ATTN=on$' "$ENV_FILE"
|
||||
grep -q -- '--flash-attn "$FLASH_ATTN"' "$SERVE"
|
||||
# Prometheus scrapes this endpoint; without --metrics there is no /metrics.
|
||||
grep -q -- '--metrics' "$SERVE"
|
||||
}
|
||||
|
||||
@test "frank-small's MTP head comes from the weights file, not a second copy" {
|
||||
grep -q '^SPEC_TYPE=draft-mtp$' "$ENV_FILE"
|
||||
grep -q -- '--spec-type "$SPEC_TYPE"' "$SERVE"
|
||||
# The -mtp build is the one carrying blk.64.nextn.*; the plain IQ3_S has no
|
||||
# MTP tensors at all, so MTP is a property of the file, not of the flags.
|
||||
grep -q '^MODEL_FILE=.*-mtp\.gguf$' "$ENV_FILE"
|
||||
# A separate draft model would load a second 12 GiB copy of a 12 GiB model.
|
||||
! grep -q -- '--model-draft' "$SERVE"
|
||||
}
|
||||
|
||||
@test "frank-small carries the fleet's image path, and only it" {
|
||||
grep -q '^MMPROJ_PATH=.*mmproj-Qwen3\.8-27B-BF16\.gguf$' "$ENV_FILE"
|
||||
grep -q -- '--mmproj "$MMPROJ_PATH"' "$SERVE"
|
||||
! grep -q 'HALOGEN_VISION_TOWER' "$QUADLET_LARGE"
|
||||
}
|
||||
|
||||
@test "frank-small's KV fits the card beside the weights it loads" {
|
||||
local ctx parallel parallel_slots cache_k cache_v
|
||||
ctx="$(sed -nE 's/^CTX_SIZE=([0-9]+)$/\1/p' "$ENV_FILE")"
|
||||
parallel="$(sed -nE 's/^PARALLEL=([0-9]+)$/\1/p' "$ENV_FILE")"
|
||||
cache_k="$(sed -nE 's/^CACHE_TYPE_K=(.+)$/\1/p' "$ENV_FILE")"
|
||||
cache_v="$(sed -nE 's/^CACHE_TYPE_V=(.+)$/\1/p' "$ENV_FILE")"
|
||||
[ -n "$ctx" ] && [ -n "$parallel" ] && [ -n "$cache_k" ] && [ -n "$cache_v" ]
|
||||
[ "$parallel" -ge 1 ]
|
||||
# qwen35 spends KV on its 16 full-attention layers only: 2 (K,V) x 4 heads x
|
||||
# 256 dim x 2 B = 64 KiB per token at f16. 11.29 GiB of weights + 0.87 of
|
||||
# mmproj + ~2 GiB of context/compute/MTP leave under 10 GiB of the card's
|
||||
# 24 GiB for KV, and --parallel divides --ctx-size between the slots.
|
||||
[ $((ctx * 64)) -le $((10 * 1024 * 1024)) ]
|
||||
# f16 is the deployed type on purpose: a quantized KV needs the
|
||||
# GGML_CUDA_FA_ALL_QUANTS build option, without which prefill on CUDA
|
||||
# collapses about 12x (see the CUDA lesson in AGENTS.md).
|
||||
[ "$cache_k" = "f16" ] && [ "$cache_v" = "f16" ]
|
||||
}
|
||||
|
||||
@test "frank-small runs on its own port beside frank-large's" {
|
||||
grep -q '^LISTEN_PORT=7771$' "$ENV_FILE"
|
||||
grep -q '^ALIAS=frank-small$' "$ENV_FILE"
|
||||
grep -q -- '--port "$LISTEN_PORT"' "$SERVE"
|
||||
grep -q -- '--host "$BIND_ADDR"' "$SERVE"
|
||||
# The two endpoints cannot share a port, and only the halogen unit publishes
|
||||
# 7770.
|
||||
grep -q '^PublishPort=7770:8731$' "$QUADLET_LARGE"
|
||||
! grep -q 'PublishPort=.*7771' "$QUADLET_LARGE"
|
||||
}
|
||||
|
||||
@test "the deploy handler installs the root unit and refuses a missing model" {
|
||||
grep -q 'deploy_llm_small' "$REMOTE_DEPLOY"
|
||||
grep -q 'relink_unit frank-small' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-small.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl restart frank-small.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'Qwen3.8-27B-GSQ-RCO-IQ3_S-mtp' "$REMOTE_DEPLOY"
|
||||
grep -q 'refusing to start a unit that cannot load' "$REMOTE_DEPLOY"
|
||||
grep -q '127.0.0.1:7771/health' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@test "frank-small's serve script refuses to start on a half-finished download" {
|
||||
grep -q 'frank-small: missing' "$SERVE"
|
||||
}
|
||||
Reference in New Issue
Block a user