llm: retire the trio service names — fleet services renamed to frank-archon/frank-dragoon/frank-zealot
The 2026-10-09 wire aliases become the service names everywhere: systemd units, serve scripts, env files and FRANK_* variables, deploy-plan/deploy-remote service keys, container names, Prometheus job names + alert rules, Grafana dashboard queries, bats seams, runbook filenames, homepage/AGENTS lore, and historical prose. Rollback tags renamed in lockstep. Residue in the tree: zero. Retired frank-medium/small/npu names are history and stay. Known casualty: scripts/patches/*.patch context lines were rewritten; those retired-era vLLM-fork patches no longer apply byte-exact.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: autoresearch measure client behavior.
|
||||
#
|
||||
# The measure client is the whole yardstick of the frank-primary speed
|
||||
# The measure client is the whole yardstick of the frank-archon speed
|
||||
# session, so its METRIC arithmetic gets a behavior test: against a
|
||||
# deterministic mock endpoint that emits a KNOWN number of completion
|
||||
# tokens at a KNOWN per-token delay, the reported decode rate must land
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
load helpers
|
||||
|
||||
MEASURE="$REPO_ROOT/scripts/autoresearch/frank-primary-measure.py"
|
||||
MEASURE="$REPO_ROOT/scripts/autoresearch/frank-archon-measure.py"
|
||||
MOCK="$BATS_TEST_TMPDIR/mock.py"
|
||||
PORT=""
|
||||
MOCK_PID=""
|
||||
|
||||
@@ -21,16 +21,16 @@ load helpers
|
||||
[[ "$output" != *"tests/homepage_pages.bats"* ]]
|
||||
}
|
||||
|
||||
@test "changed-test wrapper maps the frank-primary trio to its focused tests" {
|
||||
@test "changed-test wrapper maps the frank-archon trio to its focused tests" {
|
||||
# The root-unit shape since the 2026-09-26 swap: the trio lives in
|
||||
# scripts/ and must select the unit seam before the generic
|
||||
# scripts/*.service fallbacks can swallow it.
|
||||
run bash "$REPO_ROOT/scripts/test-changed.sh" --list --paths \
|
||||
scripts/frank-primary.env \
|
||||
scripts/frank-primary.service \
|
||||
scripts/serve-frank-primary.sh
|
||||
scripts/frank-archon.env \
|
||||
scripts/frank-archon.service \
|
||||
scripts/serve-frank-archon.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"tests/frank_primary_unit.bats"* ]]
|
||||
[[ "$output" == *"tests/frank_archon_unit.bats"* ]]
|
||||
[[ "$output" == *"tests/llm_units.bats"* ]]
|
||||
[[ "$output" == *"tests/deployment_scoping.bats"* ]]
|
||||
[[ "$output" != *"tests/homepage_pages.bats"* ]]
|
||||
@@ -42,8 +42,8 @@ load helpers
|
||||
run bash "$REPO_ROOT/scripts/test-changed.sh" --list --paths \
|
||||
dankserver/.AGENTTRASH/20260926-frank-medium-radiance/frank-medium.container \
|
||||
scripts/.AGENTTRASH/20260920-llama-layersplit/serve-frank-medium.sh.llamacpp-layersplit \
|
||||
dankserver/.AGENTTRASH/20260926-llamacpp-cutover/frank-primary.container
|
||||
dankserver/.AGENTTRASH/20260926-llamacpp-cutover/frank-archon.container
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *"tests/frank_medium_unit.bats"* ]]
|
||||
[[ "$output" != *"tests/frank_primary_unit.bats"* ]]
|
||||
[[ "$output" != *"tests/frank_archon_unit.bats"* ]]
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ load helpers
|
||||
}
|
||||
|
||||
@test "remote runner has a handler per inference service" {
|
||||
grep -q 'deploy_llm_large' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_llm_primary' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_llm_secondary' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_llm_dragoon' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_llm_archon' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_llm_zealot' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
}
|
||||
|
||||
@test "inference restarts are absent from the top-level dispatcher" {
|
||||
! grep -qE 'systemctl .*restart (frank-medium|frank-large|frank-npu)' "$REPO_ROOT/scripts/deploy.sh"
|
||||
! grep -qE 'systemctl .*restart (frank-medium|frank-dragoon|frank-npu)' "$REPO_ROOT/scripts/deploy.sh"
|
||||
}
|
||||
|
||||
@test "remote runner health-checks an inference endpoint" {
|
||||
|
||||
@@ -18,9 +18,9 @@ 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-dragoon.env
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-large" ]
|
||||
[ "$output" = "frank-dragoon" ]
|
||||
}
|
||||
|
||||
@test "the retired NPU endpoint is absent from the deployment inventory" {
|
||||
@@ -31,7 +31,7 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
@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-secondary runtime serves the template the GGUF itself
|
||||
# llama.cpp frank-zealot 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
|
||||
@@ -63,36 +63,36 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
[ -z "$output" ]
|
||||
}
|
||||
|
||||
@test "deployment planner maps the frank-primary trio to frank-primary only" {
|
||||
@test "deployment planner maps the frank-archon trio to frank-archon only" {
|
||||
# The root-unit shape since the 2026-09-26 swap: unit, env and serve
|
||||
# script live in scripts/ and select exactly frank-primary. The
|
||||
# script live in scripts/ and select exactly frank-archon. The
|
||||
# download script fetches host-side state and must select nothing, and
|
||||
# the lucebox quadlet-era tree in dated trash plans nothing either.
|
||||
run python3 "$PLANNER" --target dankserver --paths \
|
||||
scripts/frank-primary.env \
|
||||
scripts/frank-primary.service \
|
||||
scripts/serve-frank-primary.sh
|
||||
scripts/frank-archon.env \
|
||||
scripts/frank-archon.service \
|
||||
scripts/serve-frank-archon.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-primary" ]
|
||||
[ "$output" = "frank-archon" ]
|
||||
|
||||
run python3 "$PLANNER" --target dankserver --paths \
|
||||
scripts/download-frank-primary.sh \
|
||||
dankserver/.AGENTTRASH/20260926-llamacpp-cutover/frank-primary.container
|
||||
scripts/download-frank-archon.sh \
|
||||
dankserver/.AGENTTRASH/20260926-llamacpp-cutover/frank-archon.container
|
||||
[ "$status" -eq 0 ]
|
||||
[ -z "$output" ]
|
||||
}
|
||||
|
||||
@test "the small endpoint is Dankclaw's again, and Dankserver's copy stays retired" {
|
||||
run python3 "$PLANNER" --target dankclaw --paths \
|
||||
scripts/frank-secondary.env scripts/frank-secondary.service scripts/serve-frank-secondary.sh
|
||||
scripts/frank-zealot.env scripts/frank-zealot.service scripts/serve-frank-zealot.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "frank-secondary" ]
|
||||
[ "$output" = "frank-zealot" ]
|
||||
|
||||
# frank-secondary runs on Dankclaw on the RTX 3090; the Dankserver endpoint of
|
||||
# frank-zealot 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-secondary.env scripts/frank-secondary.service scripts/serve-frank-secondary.sh
|
||||
scripts/frank-zealot.env scripts/frank-zealot.service scripts/serve-frank-zealot.sh
|
||||
[ "$status" -eq 0 ]
|
||||
[ -z "$output" ]
|
||||
}
|
||||
@@ -205,8 +205,8 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
@test "remote deployer routes inference restarts through selected handlers" {
|
||||
# The runner may restart inference only from the service-dispatch path. It
|
||||
# must not contain a host-wide restart loop.
|
||||
grep -q 'deploy_llm_large' "$REMOTE_DEPLOY"
|
||||
grep -q 'deploy_llm_primary' "$REMOTE_DEPLOY"
|
||||
grep -q 'deploy_llm_dragoon' "$REMOTE_DEPLOY"
|
||||
grep -q 'deploy_llm_archon' "$REMOTE_DEPLOY"
|
||||
grep -q 'deploy_service' "$REMOTE_DEPLOY"
|
||||
! grep -qE 'for .*frank-(small|large|npu)-?' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: frank-primary — the Dankserver LLM endpoint on :7770.
|
||||
# Seam: frank-archon — the Dankserver LLM endpoint on :7770.
|
||||
#
|
||||
# This file asserts the RADIANCE shape (StillDeadcode engine, digest-pinned
|
||||
# stilldeadcode/radiance image, BOTH R9700s TP=2 on the wht6 wire, the
|
||||
# OFFICIAL Qwen/Qwen3.8-Flash-Next-FP8 at native block-FP8 precision in a
|
||||
# rad-convert container). It replaces the FreeToken seam of 2026-10-05
|
||||
# (git tag frank-primary-freetoken-pr587-20261005) and pins what flags
|
||||
# (git tag frank-archon-freetoken-pr587-20261005) and pins what flags
|
||||
# alone do not say: the served window clears the harness worst case, the
|
||||
# pinned-host ledger has a ttm pages cap floor and the serve script
|
||||
# ENFORCES it, the served window is what models.yml must quote, the host-
|
||||
@@ -20,16 +20,16 @@
|
||||
|
||||
load helpers
|
||||
|
||||
UNIT="$REPO_ROOT/scripts/frank-primary.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-primary.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-primary.env"
|
||||
UNIT="$REPO_ROOT/scripts/frank-archon.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-archon.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-archon.env"
|
||||
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
DOWNLOAD="$REPO_ROOT/scripts/download-frank-primary-swift15.sh"
|
||||
DOWNLOAD="$REPO_ROOT/scripts/download-frank-archon-swift15.sh"
|
||||
BUILD="$REPO_ROOT/scripts/convert-swift15-w4dn8.sh"
|
||||
HFGET="$REPO_ROOT/scripts/hfget.sh"
|
||||
TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
|
||||
@test "frank-primary unit, serve script, env, fetch and build scripts and template exist" {
|
||||
@test "frank-archon unit, serve script, env, fetch and build scripts and template exist" {
|
||||
[ -f "$UNIT" ]
|
||||
[ -x "$SERVE" ]
|
||||
[ -f "$ENV_FILE" ]
|
||||
@@ -40,11 +40,11 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# The FreeToken-era Dockerfile is retired with the runtime it built:
|
||||
# the radiance image is the publisher's, pulled and digest-pinned, not
|
||||
# built on the host.
|
||||
[ ! -f "$REPO_ROOT/scripts/docker/frank-primary-freetoken.Dockerfile" ]
|
||||
[ ! -f "$REPO_ROOT/scripts/docker/frank-archon-freetoken.Dockerfile" ]
|
||||
}
|
||||
|
||||
@test "frank-primary unit is boot-persistent, self-healing and unprivileged" {
|
||||
# Root unit parity with frank-large/frank-secondary: enable is the [Install]
|
||||
@test "frank-archon unit is boot-persistent, self-healing and unprivileged" {
|
||||
# Root unit parity with frank-dragoon/frank-zealot: enable is the [Install]
|
||||
# section, the restart policy survives a crash, and the pinned host RAM
|
||||
# (expert pools + PLE table + prefix host tier, ~132 GiB) needs an
|
||||
# unbounded memlock (a root unit grants it via PID1; the dank session's
|
||||
@@ -70,9 +70,9 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
||||
}
|
||||
|
||||
@test "frank-primary runs the repo's own serve script with the repo's env" {
|
||||
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-primary.sh$' "$UNIT"
|
||||
grep -q 'FRANK_PRIMARY_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-primary.env' "$UNIT"
|
||||
@test "frank-archon runs the repo's own serve script with the repo's env" {
|
||||
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-archon.sh$' "$UNIT"
|
||||
grep -q 'FRANK_ARCHON_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-archon.env' "$UNIT"
|
||||
}
|
||||
|
||||
@test "the unit stops the container child explicitly — container identity is the unit name" {
|
||||
@@ -81,9 +81,9 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# outlives the unit and holds the GPU. The container name IS the
|
||||
# service name across runtimes (Frank's 2026-10-05 call).
|
||||
grep -q '^ExecStop=/usr/bin/podman stop' "$UNIT"
|
||||
grep -q 'podman stop -t 120 frank-primary$' "$UNIT"
|
||||
grep -q '^FRANK_PRIMARY_CONTAINER=frank-primary$' "$ENV_FILE"
|
||||
grep -q 'frank-primary-qwen' "$ENV_FILE"
|
||||
grep -q 'podman stop -t 120 frank-archon$' "$UNIT"
|
||||
grep -q '^FRANK_ARCHON_CONTAINER=frank-archon$' "$ENV_FILE"
|
||||
grep -q 'frank-archon-qwen' "$ENV_FILE"
|
||||
}
|
||||
|
||||
@test "the serve shape is direct podman run, not a launcher or a predecessor runtime" {
|
||||
@@ -106,7 +106,7 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
@test "the image is the publisher's, digest-pinned by manifest" {
|
||||
# stilldeadcode/radiance@sha256:<64 hex> — a name@digest ref exists in
|
||||
# storage only if THAT manifest was pulled. The tag form would float.
|
||||
grep -qE '^FRANK_PRIMARY_IMAGE=stilldeadcode/radiance@sha256:[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_ARCHON_IMAGE=stilldeadcode/radiance@sha256:[0-9a-f]{64}$' "$ENV_FILE"
|
||||
}
|
||||
|
||||
@test "the radiance engine shape is in the env file" {
|
||||
@@ -115,65 +115,65 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# prompt can legally reach that height — 140,492 + 36,864 = 177,356 at
|
||||
# the FreeToken-era window was the record; the same relation must hold
|
||||
# here (140,000 + 36,864 = 176,864 <= 200,000).
|
||||
grep -q '^FRANK_PRIMARY_MAX_MODEL_LEN=200000$' "$ENV_FILE"
|
||||
ml=$(awk -F= '/^FRANK_PRIMARY_MAX_MODEL_LEN=/{print $2}' "$ENV_FILE")
|
||||
grep -q '^FRANK_ARCHON_MAX_MODEL_LEN=200000$' "$ENV_FILE"
|
||||
ml=$(awk -F= '/^FRANK_ARCHON_MAX_MODEL_LEN=/{print $2}' "$ENV_FILE")
|
||||
[ "$ml" -ge 177356 ]
|
||||
# Decode-sweep shape (2026-10-06): 3 slots, spec depth 2 — the measured
|
||||
# optimum (33.06 t/s). The fused TP all-reduce is declared over
|
||||
# seqs x (1 + spec) rows = 9.
|
||||
grep -q '^FRANK_PRIMARY_MAX_SEQS=3$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_TP=2$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_TP_WIRE=wht6$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_SPEC_TOKENS=2$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_MAX_SEQS=3$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_TP=2$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_TP_WIRE=wht6$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_SPEC_TOKENS=2$' "$ENV_FILE"
|
||||
# Native-precision economics: the expert pool is per rank (56.4 GiB
|
||||
# slice per rank at TP2), the PLE ngram table is pinned in host RAM per
|
||||
# Frank's law, KV is fp8, the ratio is the publisher's production
|
||||
# value.
|
||||
grep -q '^FRANK_PRIMARY_PLACEMENT=expert_tiered$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_HOST_POOL_MIB=40960$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_VRAM_WEIGHTS_MIB=[1-9]' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_VRAM_KV_MIB=[1-9]' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_KV_DTYPE=fp8$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_NGRAM_PLACEMENT=ram$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_PLACEMENT=expert_tiered$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_HOST_POOL_MIB=40960$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_VRAM_WEIGHTS_MIB=[1-9]' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_VRAM_KV_MIB=[1-9]' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_KV_DTYPE=fp8$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_NGRAM_PLACEMENT=ram$' "$ENV_FILE"
|
||||
# Prefix cache tiers (publisher pattern; disk tier sized for 2 slots).
|
||||
grep -q '^FRANK_PRIMARY_PREFIX_HOST_MIB=4096$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_PREFIX_DISK_MIB=65536$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_PREFIX_HOST_MIB=4096$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_PREFIX_DISK_MIB=65536$' "$ENV_FILE"
|
||||
# The pinned ledger (2 x pool + 47.7 GiB PLE + prefix host) must be
|
||||
# under the ttm pages cap, and the env states the floor the serve
|
||||
# script enforces (>= 140,000 MiB — the current cap ~123 GiB fails it,
|
||||
# which is the point).
|
||||
grep -q '^FRANK_PRIMARY_TTM_MIN_MIB=' "$ENV_FILE"
|
||||
ttmm=$(awk -F= '/^FRANK_PRIMARY_TTM_MIN_MIB=/{print $2}' "$ENV_FILE")
|
||||
pool=$(awk -F= '/^FRANK_PRIMARY_HOST_POOL_MIB=/{print $2}' "$ENV_FILE")
|
||||
ph=$(awk -F= '/^FRANK_PRIMARY_PREFIX_HOST_MIB=/{print $2}' "$ENV_FILE")
|
||||
grep -q '^FRANK_ARCHON_TTM_MIN_MIB=' "$ENV_FILE"
|
||||
ttmm=$(awk -F= '/^FRANK_ARCHON_TTM_MIN_MIB=/{print $2}' "$ENV_FILE")
|
||||
pool=$(awk -F= '/^FRANK_ARCHON_HOST_POOL_MIB=/{print $2}' "$ENV_FILE")
|
||||
ph=$(awk -F= '/^FRANK_ARCHON_PREFIX_HOST_MIB=/{print $2}' "$ENV_FILE")
|
||||
# 2 pools + PLE 47.7 GiB (48,824 MiB) + prefix host, rounded up.
|
||||
ledger=$(( 2 * pool + 48824 + ph + 2048 ))
|
||||
[ "$ttmm" -ge "$ledger" ]
|
||||
# The .rad size floor is positive (a truncated convert must fail fast).
|
||||
grep -q '^FRANK_PRIMARY_RAD_MIN_MIB=' "$ENV_FILE"
|
||||
[ "$(awk -F= '/^FRANK_PRIMARY_RAD_MIN_MIB=/{print $2}' "$ENV_FILE")" -gt 0 ]
|
||||
grep -q '^FRANK_ARCHON_RAD_MIN_MIB=' "$ENV_FILE"
|
||||
[ "$(awk -F= '/^FRANK_ARCHON_RAD_MIN_MIB=/{print $2}' "$ENV_FILE")" -gt 0 ]
|
||||
}
|
||||
|
||||
@test "the serve script wires the engine flags from the env" {
|
||||
grep -q -- '--model "/models/$FRANK_PRIMARY_MODEL_FILE"' "$SERVE"
|
||||
grep -q -- '--served-model-name "$FRANK_PRIMARY_SERVED_NAME"' "$SERVE"
|
||||
grep -q -- '--host :: --port "$FRANK_PRIMARY_PORT"' "$SERVE"
|
||||
grep -q -- '--model "/models/$FRANK_ARCHON_MODEL_FILE"' "$SERVE"
|
||||
grep -q -- '--served-model-name "$FRANK_ARCHON_SERVED_NAME"' "$SERVE"
|
||||
grep -q -- '--host :: --port "$FRANK_ARCHON_PORT"' "$SERVE"
|
||||
grep -q -- '--override-chat-template /templates/template.jinja' "$SERVE"
|
||||
grep -q -- '--tp "$FRANK_PRIMARY_TP" --tp-wire "$FRANK_PRIMARY_TP_WIRE"' "$SERVE"
|
||||
grep -q -- '--max-num-seqs "$FRANK_PRIMARY_MAX_SEQS"' "$SERVE"
|
||||
grep -q -- '--max-model-len "$FRANK_PRIMARY_MAX_MODEL_LEN"' "$SERVE"
|
||||
grep -q -- '--placement "$FRANK_PRIMARY_PLACEMENT"' "$SERVE"
|
||||
grep -q -- '--host-pool-mib "$FRANK_PRIMARY_HOST_POOL_MIB"' "$SERVE"
|
||||
grep -q -- '--vram-weights-mib "$FRANK_PRIMARY_VRAM_WEIGHTS_MIB"' "$SERVE"
|
||||
grep -q -- '--vram-kv-mib "$FRANK_PRIMARY_VRAM_KV_MIB"' "$SERVE"
|
||||
grep -q -- '--kv-cache-dtype "$FRANK_PRIMARY_KV_DTYPE"' "$SERVE"
|
||||
grep -q -- '--prefix-cache-host-mib "$FRANK_PRIMARY_PREFIX_HOST_MIB"' "$SERVE"
|
||||
grep -q -- '--prefix-cache-disk-mib "$FRANK_PRIMARY_PREFIX_DISK_MIB"' "$SERVE"
|
||||
grep -q -- '--ngram-placement "$FRANK_PRIMARY_NGRAM_PLACEMENT"' "$SERVE"
|
||||
grep -q -- '--num-speculative-tokens "$FRANK_PRIMARY_SPEC_TOKENS"' "$SERVE"
|
||||
grep -q -- '--tp "$FRANK_ARCHON_TP" --tp-wire "$FRANK_ARCHON_TP_WIRE"' "$SERVE"
|
||||
grep -q -- '--max-num-seqs "$FRANK_ARCHON_MAX_SEQS"' "$SERVE"
|
||||
grep -q -- '--max-model-len "$FRANK_ARCHON_MAX_MODEL_LEN"' "$SERVE"
|
||||
grep -q -- '--placement "$FRANK_ARCHON_PLACEMENT"' "$SERVE"
|
||||
grep -q -- '--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB"' "$SERVE"
|
||||
grep -q -- '--vram-weights-mib "$FRANK_ARCHON_VRAM_WEIGHTS_MIB"' "$SERVE"
|
||||
grep -q -- '--vram-kv-mib "$FRANK_ARCHON_VRAM_KV_MIB"' "$SERVE"
|
||||
grep -q -- '--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE"' "$SERVE"
|
||||
grep -q -- '--prefix-cache-host-mib "$FRANK_ARCHON_PREFIX_HOST_MIB"' "$SERVE"
|
||||
grep -q -- '--prefix-cache-disk-mib "$FRANK_ARCHON_PREFIX_DISK_MIB"' "$SERVE"
|
||||
grep -q -- '--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT"' "$SERVE"
|
||||
grep -q -- '--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS"' "$SERVE"
|
||||
# The boot-ladder escape hatch is opt-in: unset renders NO extra argv.
|
||||
grep -q -- '${FRANK_PRIMARY_EXTRA_ARGS:+$FRANK_PRIMARY_EXTRA_ARGS}' "$SERVE"
|
||||
! grep -q '^FRANK_PRIMARY_EXTRA_ARGS=.' "$ENV_FILE"
|
||||
grep -q -- '${FRANK_ARCHON_EXTRA_ARGS:+$FRANK_ARCHON_EXTRA_ARGS}' "$SERVE"
|
||||
! grep -q '^FRANK_ARCHON_EXTRA_ARGS=.' "$ENV_FILE"
|
||||
}
|
||||
|
||||
@test "the container contract is the publisher's (host network, io_uring, pin, cards)" {
|
||||
@@ -185,16 +185,16 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
grep -q -- '--network host' "$SERVE"
|
||||
! grep -q -- '--publish' "$SERVE"
|
||||
! grep -q -- '-p 7770' "$SERVE"
|
||||
grep -q '^FRANK_PRIMARY_PORT=7770$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_SERVED_NAME=frank-archon$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_PORT=7770$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_SERVED_NAME=frank-archon$' "$ENV_FILE"
|
||||
grep -q -- '--init' "$SERVE"
|
||||
grep -q -- '--security-opt seccomp=unconfined' "$SERVE"
|
||||
grep -q -- '--ulimit memlock=-1' "$SERVE"
|
||||
grep -q -- '--device /dev/kfd' "$SERVE"
|
||||
grep -q -- '--device /dev/dri' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_PRIMARY_MODEL_DIR":/models:ro' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_PRIMARY_STATE_DIR":/data' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_PRIMARY_TEMPLATE":/templates/template.jinja:ro' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_ARCHON_MODEL_DIR":/models:ro' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_ARCHON_STATE_DIR":/data' "$SERVE"
|
||||
grep -q -- '-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro' "$SERVE"
|
||||
}
|
||||
|
||||
@test "parsers are AUTO — the engine infers them natively, the harness maps the field" {
|
||||
@@ -206,8 +206,8 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
! grep -q -- '--reasoning-parser' "$SERVE"
|
||||
! grep -q -- '--tool-call-parser' "$SERVE"
|
||||
! grep -q -- '--enable-auto-tool-choice' "$SERVE"
|
||||
! grep -q 'FRANK_PRIMARY_REASONING_PARSER' "$ENV_FILE"
|
||||
! grep -q 'FRANK_PRIMARY_TOOL_PARSER' "$ENV_FILE"
|
||||
! grep -q 'FRANK_ARCHON_REASONING_PARSER' "$ENV_FILE"
|
||||
! grep -q 'FRANK_ARCHON_TOOL_PARSER' "$ENV_FILE"
|
||||
}
|
||||
|
||||
@test "the serve script gates the image, the .rad payload, the template and the GPU nodes" {
|
||||
@@ -215,12 +215,12 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# .rad file and its size floor — a truncated convert would otherwise be
|
||||
# a guaranteed long-timeout boot instead of a fast failure. The ttm
|
||||
# preflight refuses to start under a pages cap below the pinned ledger.
|
||||
grep -q 'FRANK_PRIMARY_IMAGE' "$SERVE"
|
||||
grep -q 'FRANK_ARCHON_IMAGE' "$SERVE"
|
||||
grep -q 'podman image exists' "$SERVE"
|
||||
grep -q 'FRANK_PRIMARY_MODEL_FILE' "$SERVE"
|
||||
grep -q 'FRANK_PRIMARY_RAD_MIN_MIB' "$SERVE"
|
||||
grep -q 'FRANK_PRIMARY_TEMPLATE' "$SERVE"
|
||||
grep -q 'FRANK_PRIMARY_TTM_MIN_MIB' "$SERVE"
|
||||
grep -q 'FRANK_ARCHON_MODEL_FILE' "$SERVE"
|
||||
grep -q 'FRANK_ARCHON_RAD_MIN_MIB' "$SERVE"
|
||||
grep -q 'FRANK_ARCHON_TEMPLATE' "$SERVE"
|
||||
grep -q 'FRANK_ARCHON_TTM_MIN_MIB' "$SERVE"
|
||||
grep -q 'pages_limit' "$SERVE"
|
||||
grep -q 'pages_max' "$SERVE"
|
||||
grep -q '/dev/kfd' "$SERVE"
|
||||
@@ -231,20 +231,20 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# A crashed unit can leave the container name registered forever after;
|
||||
# the legacy identities hold the same GPUs and die here too. Then block
|
||||
# on the container so a crash is a nonzero ExecStart.
|
||||
grep -q 'FRANK_PRIMARY_LEGACY_CONTAINERS' "$ENV_FILE"
|
||||
grep -q 'frank-primary-qwen' "$ENV_FILE"
|
||||
grep -q 'frank-primary-r9v' "$ENV_FILE"
|
||||
grep -q 'FRANK_ARCHON_LEGACY_CONTAINERS' "$ENV_FILE"
|
||||
grep -q 'frank-archon-qwen' "$ENV_FILE"
|
||||
grep -q 'frank-archon-r9v' "$ENV_FILE"
|
||||
grep -q 'qwen-fp8' "$ENV_FILE"
|
||||
grep -q 'exec podman wait "$FRANK_PRIMARY_CONTAINER"' "$SERVE"
|
||||
grep -q 'exec podman wait "$FRANK_ARCHON_CONTAINER"' "$SERVE"
|
||||
}
|
||||
|
||||
@test "the model id matches the payload's build and fetch scripts" {
|
||||
# The payload dir/file are the convert script's output layout; the fetch
|
||||
# script must name the repo the convert stages from. (FP8-native era,
|
||||
# the rollback payload, keeps its own trio: build-frank-primary-rad.sh +
|
||||
# download-frank-primary.sh.)
|
||||
grep -q '^FRANK_PRIMARY_MODEL_DIR=/home/dank/models/rad$' "$ENV_FILE"
|
||||
grep -q '^FRANK_PRIMARY_MODEL_FILE=qwen4exp-swift15-w4dn8-i8-hc8m.rad$' "$ENV_FILE"
|
||||
# the rollback payload, keeps its own trio: build-frank-archon-rad.sh +
|
||||
# download-frank-archon.sh.)
|
||||
grep -q '^FRANK_ARCHON_MODEL_DIR=/home/dank/models/rad$' "$ENV_FILE"
|
||||
grep -q '^FRANK_ARCHON_MODEL_FILE=qwen4exp-swift15-w4dn8-i8-hc8m.rad$' "$ENV_FILE"
|
||||
grep -q 'qwen4exp-swift15-w4dn8-i8-hc8m.rad' "$BUILD"
|
||||
grep -q 'ukisai/Swift1.5-Qwen3.8-Flash-Next' "$DOWNLOAD"
|
||||
grep -q 'hfget.sh' "$DOWNLOAD"
|
||||
@@ -255,7 +255,7 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
@test "no bare HIP-reserved env var is defined" {
|
||||
# HIP reads bare TEMP for its JIT cache path (2026-08-13: TEMP=1.0
|
||||
# segfaulted every load), and HOST/GPU_MAX_HEAP_SIZE are the same
|
||||
# class. Every key here is FRANK_PRIMARY_-prefixed.
|
||||
# class. Every key here is FRANK_ARCHON_-prefixed.
|
||||
! grep -qE '^(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$ENV_FILE"
|
||||
! grep -qE '^(export )?(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$SERVE"
|
||||
}
|
||||
@@ -265,18 +265,18 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# storage or the .rad is missing/too small — then clears stale
|
||||
# containers (including the legacy identities), waits out the port,
|
||||
# relinks/enables/restarts the root unit and health-gates it.
|
||||
grep -q 'LLM_PRIMARY_CONTAINER=frank-primary$' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_PRIMARY_IMAGE' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_ARCHON_CONTAINER=frank-archon$' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_ARCHON_IMAGE' "$REMOTE_DEPLOY"
|
||||
grep -q 'podman image exists' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_PRIMARY_MODEL_FILE' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_PRIMARY_RAD_MIN_MIB' "$REMOTE_DEPLOY"
|
||||
grep -q 'frank-primary-qwen' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_ARCHON_MODEL_FILE' "$REMOTE_DEPLOY"
|
||||
grep -q 'FRANK_ARCHON_RAD_MIN_MIB' "$REMOTE_DEPLOY"
|
||||
grep -q 'frank-archon-qwen' "$REMOTE_DEPLOY"
|
||||
grep -q 'qwen-fp8' "$REMOTE_DEPLOY"
|
||||
grep -q 'glm-probe' "$REMOTE_DEPLOY"
|
||||
grep -q 'wait_port_free 7770' "$REMOTE_DEPLOY"
|
||||
grep -q 'relink_unit frank-primary' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-primary.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl restart frank-primary.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'relink_unit frank-archon' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-archon.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl restart frank-archon.service' "$REMOTE_DEPLOY"
|
||||
# The health gate is a bare curl: the HTTP listener binds AFTER the
|
||||
# full load (main.cpp — engine.start() then engine.serve()), so during
|
||||
# load the port refuses connections and a bare curl is honest. The
|
||||
@@ -289,6 +289,6 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja"
|
||||
# The 2026-09-26 false green: a leftover probe held :7770 and satisfied
|
||||
# the health curl while the real unit was stopped. The deploy is only
|
||||
# green when the unit's own MainPID is live behind the health answer.
|
||||
grep -q 'systemctl show -p MainPID --value frank-primary.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl show -p MainPID --value frank-archon.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'stray process holds the port' "$REMOTE_DEPLOY"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: frank-large serves the Quat3rnion ABLITERATED Swift1.5 finetune of
|
||||
# Seam: frank-dragoon serves the Quat3rnion ABLITERATED Swift1.5 finetune of
|
||||
# peonist's Qwen3.8-Flash-Next v2 checkpoint (a .hgn flash-server payload)
|
||||
# on the Strix Halo iGPU through the halogen-flash-server CONTAINER (0.16.2,
|
||||
# digest-pinned), driven by the root unit's serve script — two 262,144-token
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
setup() {
|
||||
ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
||||
SERVE="$ROOT/scripts/serve-frank-large.sh"
|
||||
ENV_FILE="$ROOT/scripts/frank-large.env"
|
||||
UNIT="$ROOT/scripts/frank-large.service"
|
||||
SERVE="$ROOT/scripts/serve-frank-dragoon.sh"
|
||||
ENV_FILE="$ROOT/scripts/frank-dragoon.env"
|
||||
UNIT="$ROOT/scripts/frank-dragoon.service"
|
||||
DEPLOYER="$ROOT/scripts/deploy-remote.sh"
|
||||
BUILD="$ROOT/scripts/build-rocmfpx.sh"
|
||||
TEST_TMP="$(mktemp -d)"
|
||||
@@ -63,47 +63,47 @@ good_env() {
|
||||
# the artifact gates below are the thing under test.
|
||||
printf 'MemTotal: 127108112 kB\nMemAvailable: 100000000 kB\n' > "$TEST_TMP/meminfo"
|
||||
GOOD_ENV=(
|
||||
"FRANK_LARGE_ENV_FILE=$TEST_TMP/empty.env"
|
||||
"FRANK_LARGE_IMAGE=ghcr.io/peonist-ai/halogen-flash-server@sha256:cafe"
|
||||
"FRANK_LARGE_CONTAINER=frank-large-halogen"
|
||||
"FRANK_LARGE_LEGACY_CONTAINERS=frank-large"
|
||||
"FRANK_LARGE_DEV_KFD=$TEST_TMP/qwen.hgn"
|
||||
"FRANK_LARGE_DEV_DRI=$TEST_TMP"
|
||||
"FRANK_LARGE_LOG=$TEST_TMP/serve.log"
|
||||
"FRANK_LARGE_PUBLISH=7770:8731"
|
||||
"FRANK_LARGE_MODEL_DIR=$TEST_TMP"
|
||||
"FRANK_LARGE_CHECKPOINT=qwen.hgn"
|
||||
"FRANK_LARGE_CHECKPOINT_BYTES=0"
|
||||
"FRANK_LARGE_NGRAM_TABLE=ngram.hgn"
|
||||
"FRANK_LARGE_NGRAM_BYTES=0"
|
||||
"FRANK_LARGE_VISION_TOWER=vision.hgn"
|
||||
"FRANK_LARGE_VISION_BYTES=0"
|
||||
"FRANK_LARGE_TOKENIZER_FILES=tok.json"
|
||||
"FRANK_DRAGOON_ENV_FILE=$TEST_TMP/empty.env"
|
||||
"FRANK_DRAGOON_IMAGE=ghcr.io/peonist-ai/halogen-flash-server@sha256:cafe"
|
||||
"FRANK_DRAGOON_CONTAINER=frank-dragoon-halogen"
|
||||
"FRANK_DRAGOON_LEGACY_CONTAINERS=frank-dragoon"
|
||||
"FRANK_DRAGOON_DEV_KFD=$TEST_TMP/qwen.hgn"
|
||||
"FRANK_DRAGOON_DEV_DRI=$TEST_TMP"
|
||||
"FRANK_DRAGOON_LOG=$TEST_TMP/serve.log"
|
||||
"FRANK_DRAGOON_PUBLISH=7770:8731"
|
||||
"FRANK_DRAGOON_MODEL_DIR=$TEST_TMP"
|
||||
"FRANK_DRAGOON_CHECKPOINT=qwen.hgn"
|
||||
"FRANK_DRAGOON_CHECKPOINT_BYTES=0"
|
||||
"FRANK_DRAGOON_NGRAM_TABLE=ngram.hgn"
|
||||
"FRANK_DRAGOON_NGRAM_BYTES=0"
|
||||
"FRANK_DRAGOON_VISION_TOWER=vision.hgn"
|
||||
"FRANK_DRAGOON_VISION_BYTES=0"
|
||||
"FRANK_DRAGOON_TOKENIZER_FILES=tok.json"
|
||||
"HALOGEN_MODEL_ID=frank-dragoon"
|
||||
"HALOGEN_CTX=262144"
|
||||
"HALOGEN_KV_POOL_POSITIONS=524288"
|
||||
"HALOGEN_KV_SLOTS=2"
|
||||
"HALOGEN_SPEC_ADAPT=0"
|
||||
"HALOGEN_MAX_TOK=8192"
|
||||
"FRANK_LARGE_MEMINFO=$TEST_TMP/meminfo"
|
||||
"FRANK_DRAGOON_MEMINFO=$TEST_TMP/meminfo"
|
||||
"STUB_DIGESTS=localhost/x ghcr.io/peonist-ai/halogen-flash-server@sha256:cafe"
|
||||
)
|
||||
}
|
||||
|
||||
@test "the env file defines the flash-server deployment values" {
|
||||
grep -qE '^FRANK_LARGE_IMAGE=ghcr\.io/peonist-ai/halogen-flash-server@sha256:[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_CONTAINER=frank-large-halogen$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_PUBLISH=7770:8731$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_CHECKPOINT=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_CHECKPOINT_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_CHECKPOINT_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_NGRAM_TABLE=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_NGRAM_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_NGRAM_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_VISION_TOWER=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_VISION_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_VISION_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_LARGE_TOKENIZER_FILES="tokenizer\.json( [a-z_.]+)+"$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_IMAGE=ghcr\.io/peonist-ai/halogen-flash-server@sha256:[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_CONTAINER=frank-dragoon-halogen$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_PUBLISH=7770:8731$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_CHECKPOINT=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_CHECKPOINT_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_CHECKPOINT_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_NGRAM_TABLE=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_NGRAM_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_NGRAM_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_VISION_TOWER=.*\.hgn$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_VISION_BYTES=[0-9]+$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_VISION_SHA256=[0-9a-f]{64}$' "$ENV_FILE"
|
||||
grep -qE '^FRANK_DRAGOON_TOKENIZER_FILES="tokenizer\.json( [a-z_.]+)+"$' "$ENV_FILE"
|
||||
grep -qE '^HALOGEN_MODEL_ID=frank-dragoon$' "$ENV_FILE"
|
||||
grep -qE '^HALOGEN_CTX=[0-9]+$' "$ENV_FILE"
|
||||
}
|
||||
@@ -131,7 +131,7 @@ good_env() {
|
||||
podman_stub
|
||||
good_env
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_DEV_KFD="$TEST_TMP/absent-node" "$SERVE"
|
||||
FRANK_DRAGOON_DEV_KFD="$TEST_TMP/absent-node" "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"no gfx1151 to serve on"* ]]
|
||||
}
|
||||
@@ -142,7 +142,7 @@ good_env() {
|
||||
# ~28 KiB/position (FLAGS.md). Against it: ~62 GiB resident weights,
|
||||
# the arena scratch 3.8 + 8.4*(MAX_TOK/16384) GiB, the vision tower
|
||||
# ~2 GiB pool charge, the 20 GiB host reserve and the host baseline
|
||||
# + co-tenancy (frank-secondary, ComfyUI, Caddy/observability) ~15. The
|
||||
# + co-tenancy (frank-zealot, ComfyUI, Caddy/observability) ~15. The
|
||||
# box has 121 GiB unified. The n-gram table rides as mmap'd page
|
||||
# cache beside the checkpoint and is not a pinned charge (the card's
|
||||
# own quickstart arithmetic does not bill it).
|
||||
@@ -171,10 +171,10 @@ good_env() {
|
||||
podman_stub
|
||||
good_env
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_CHECKPOINT=absent.hgn "$SERVE"
|
||||
FRANK_DRAGOON_CHECKPOINT=absent.hgn "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"checkpoint"*"missing"* ]]
|
||||
[[ "$output" == *"download-frank-large-flashnext.sh"* ]]
|
||||
[[ "$output" == *"download-frank-dragoon-flashnext.sh"* ]]
|
||||
}
|
||||
|
||||
@test "the serve script refuses a checkpoint of the wrong byte count" {
|
||||
@@ -183,7 +183,7 @@ good_env() {
|
||||
podman_stub
|
||||
good_env
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_CHECKPOINT_BYTES=42 "$SERVE"
|
||||
FRANK_DRAGOON_CHECKPOINT_BYTES=42 "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"expected 42"* ]]
|
||||
}
|
||||
@@ -195,11 +195,11 @@ good_env() {
|
||||
podman_stub
|
||||
good_env
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_NGRAM_TABLE=absent.hgn "$SERVE"
|
||||
FRANK_DRAGOON_NGRAM_TABLE=absent.hgn "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"n-gram-table"*"missing"* ]]
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_NGRAM_BYTES=42 "$SERVE"
|
||||
FRANK_DRAGOON_NGRAM_BYTES=42 "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"expected 42"* ]]
|
||||
}
|
||||
@@ -211,11 +211,11 @@ good_env() {
|
||||
podman_stub
|
||||
good_env
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_VISION_TOWER=absent.hgn "$SERVE"
|
||||
FRANK_DRAGOON_VISION_TOWER=absent.hgn "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"vision-tower"*"missing"* ]]
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_VISION_BYTES=42 "$SERVE"
|
||||
FRANK_DRAGOON_VISION_BYTES=42 "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"expected 42"* ]]
|
||||
}
|
||||
@@ -244,7 +244,7 @@ good_env() {
|
||||
good_env
|
||||
printf 'MemTotal: 127108112 kB\nMemAvailable: 10000000 kB\n' > "$TEST_TMP/meminfo-short"
|
||||
run env PATH="$TEST_TMP/bin:$PATH" "${GOOD_ENV[@]}" \
|
||||
FRANK_LARGE_MEMINFO="$TEST_TMP/meminfo-short" FRANK_LARGE_RAM_WAIT=0 "$SERVE"
|
||||
FRANK_DRAGOON_MEMINFO="$TEST_TMP/meminfo-short" FRANK_DRAGOON_RAM_WAIT=0 "$SERVE"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"pin gate"* ]]
|
||||
[[ "$output" == *"refusing to start"* ]]
|
||||
@@ -260,7 +260,7 @@ good_env() {
|
||||
# lands there, so the render assertions read the same log.
|
||||
output="$output
|
||||
$(cat "$TEST_TMP/serve.log")"
|
||||
[[ "$output" == *"--name frank-large-halogen"* ]]
|
||||
[[ "$output" == *"--name frank-dragoon-halogen"* ]]
|
||||
[[ "$output" == *"--publish 7770:8731"* ]]
|
||||
[[ "$output" == *"-e HALOGEN_MODEL_ID=frank-dragoon"* ]]
|
||||
[[ "$output" == *"-e HALOGEN_CTX=262144"* ]]
|
||||
@@ -293,7 +293,7 @@ $(cat "$TEST_TMP/serve.log")"
|
||||
# both monotone maxima of est + budget (est ≤ 217088 − 4096):
|
||||
# full budget at the compaction threshold: 1.03*184524 + 45056
|
||||
# clamped budget at the clamp's zero point: 1.03*212992 + 0
|
||||
# and the compaction request that rides on frank-secondary (its
|
||||
# and the compaction request that rides on frank-zealot (its
|
||||
# 200,704-token slot) must fit: input ≈ threshold − keepRecent(20k).
|
||||
grep -qE '^HALOGEN_CTX=262144$' "$ENV_FILE"
|
||||
ctx=262144
|
||||
@@ -317,41 +317,41 @@ $(cat "$TEST_TMP/serve.log")"
|
||||
# Serve and deploy must name the SAME image digest, checkpoint and
|
||||
# tokenizer: the 2026-10-01 crash-loop was exactly these twins
|
||||
# disagreeing mid-cutover.
|
||||
img="$(sed -nE 's/^FRANK_LARGE_IMAGE=(.*)$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_LARGE_IMAGE=\"\${LLM_LARGE_IMAGE:-$img}\"" "$DEPLOYER"
|
||||
dir="$(sed -nE 's/^FRANK_LARGE_MODEL_DIR=(.*)$/\1/p' "$ENV_FILE")"
|
||||
ckpt="$(sed -nE 's/^FRANK_LARGE_CHECKPOINT=(.*)$/\1/p' "$ENV_FILE")"
|
||||
tokf="$(sed -nE 's/^FRANK_LARGE_TOKENIZER_FILES=\"(.*)\"$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_LARGE_TOK_DIR=\"\${LLM_LARGE_TOK_DIR:-$dir/tokenizer}\"" "$DEPLOYER"
|
||||
grep -qF "LLM_LARGE_TOK_FILES=\"\${LLM_LARGE_TOK_FILES:-$tokf}\"" "$DEPLOYER"
|
||||
bytes="$(sed -nE 's/^FRANK_LARGE_CHECKPOINT_BYTES=([0-9]+)$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_LARGE_CKPT_BYTES=\"\${LLM_LARGE_CKPT_BYTES:-$bytes}\"" "$DEPLOYER"
|
||||
img="$(sed -nE 's/^FRANK_DRAGOON_IMAGE=(.*)$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_DRAGOON_IMAGE=\"\${LLM_DRAGOON_IMAGE:-$img}\"" "$DEPLOYER"
|
||||
dir="$(sed -nE 's/^FRANK_DRAGOON_MODEL_DIR=(.*)$/\1/p' "$ENV_FILE")"
|
||||
ckpt="$(sed -nE 's/^FRANK_DRAGOON_CHECKPOINT=(.*)$/\1/p' "$ENV_FILE")"
|
||||
tokf="$(sed -nE 's/^FRANK_DRAGOON_TOKENIZER_FILES=\"(.*)\"$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_DRAGOON_TOK_DIR=\"\${LLM_DRAGOON_TOK_DIR:-$dir/tokenizer}\"" "$DEPLOYER"
|
||||
grep -qF "LLM_DRAGOON_TOK_FILES=\"\${LLM_DRAGOON_TOK_FILES:-$tokf}\"" "$DEPLOYER"
|
||||
bytes="$(sed -nE 's/^FRANK_DRAGOON_CHECKPOINT_BYTES=([0-9]+)$/\1/p' "$ENV_FILE")"
|
||||
grep -qF "LLM_DRAGOON_CKPT_BYTES=\"\${LLM_DRAGOON_CKPT_BYTES:-$bytes}\"" "$DEPLOYER"
|
||||
}
|
||||
|
||||
@test "the deployer points a missing artifact at the flashnext fetch script" {
|
||||
grep -qE 'download-frank-large-flashnext\.sh' "$DEPLOYER"
|
||||
grep -qE 'download-frank-dragoon-flashnext\.sh' "$DEPLOYER"
|
||||
grep -qE 'podman pull' "$DEPLOYER"
|
||||
}
|
||||
|
||||
@test "the stray sweep cannot take frank-secondary or the deployer down" {
|
||||
# frank-secondary also listens on this host (7771, llama-server) and the
|
||||
# deployer's own command line contains "frank-large"; only the FULL
|
||||
@test "the stray sweep cannot take frank-zealot or the deployer down" {
|
||||
# frank-zealot also listens on this host (7771, llama-server) and the
|
||||
# deployer's own command line contains "frank-dragoon"; only the FULL
|
||||
# container name matches a stray manual flash-server run and nothing
|
||||
# else.
|
||||
grep -q "pkill -f 'frank-large-halogen'" "$DEPLOYER"
|
||||
grep -q "pkill -f 'frank-dragoon-halogen'" "$DEPLOYER"
|
||||
! grep -qE "pkill -f 'llama-server'" "$DEPLOYER"
|
||||
! grep -qE "pkill -f 'frank-large'" "$DEPLOYER"
|
||||
! grep -qE "pkill -f 'frank-dragoon'" "$DEPLOYER"
|
||||
}
|
||||
|
||||
@test "the deployed unit keeps the fleet's restart and boot-persistence shape" {
|
||||
grep -qE '^Restart=(always|on-failure)$' "$UNIT"
|
||||
grep -qE '^WantedBy=' "$UNIT"
|
||||
grep -qE '^ExecStart=.*/serve-frank-large\.sh$' "$UNIT"
|
||||
grep -qE '^ExecStart=.*/serve-frank-dragoon\.sh$' "$UNIT"
|
||||
grep -qE '^User=dank$' "$UNIT"
|
||||
grep -qE '^LimitMEMLOCK=infinity$' "$UNIT"
|
||||
# The service's lifetime is the container's; stopping the service
|
||||
# must stop the container by its real name.
|
||||
grep -qE '^ExecStop=.*podman stop .* frank-large-halogen$' "$UNIT"
|
||||
grep -qE '^ExecStop=.*podman stop .* frank-dragoon-halogen$' "$UNIT"
|
||||
}
|
||||
|
||||
@test "the unit runs the flash-server runtime and no retired path" {
|
||||
@@ -1,5 +1,5 @@
|
||||
# Seam: the frank-secondary llama.cpp root unit on dankclaw.
|
||||
# frank-secondary is the RTX 3090 endpoint; since 2026-10-07 it serves
|
||||
# Seam: the frank-zealot llama.cpp root unit on dankclaw.
|
||||
# frank-zealot is the RTX 3090 endpoint; since 2026-10-07 it serves
|
||||
# HauhauCS's Qwen3.5-9B-Uncensored-HauhauCS-Aggressive (Q6_K, qwen35 hybrid:
|
||||
# 32 layers, 8 full-attention + 24 Gated DeltaNet, no MTP tensors in the file)
|
||||
# via the CUDA (sm_86) build of llama.cpp master: TWO 200,704-token
|
||||
@@ -13,11 +13,11 @@
|
||||
|
||||
load helpers
|
||||
|
||||
UNIT="$REPO_ROOT/scripts/frank-secondary.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-secondary.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-secondary.env"
|
||||
UNIT="$REPO_ROOT/scripts/frank-zealot.service"
|
||||
SERVE="$REPO_ROOT/scripts/serve-frank-zealot.sh"
|
||||
ENV_FILE="$REPO_ROOT/scripts/frank-zealot.env"
|
||||
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
ENV_LARGE="$REPO_ROOT/scripts/frank-large.env"
|
||||
ENV_LARGE="$REPO_ROOT/scripts/frank-dragoon.env"
|
||||
|
||||
setup() {
|
||||
STAGE="$(mktemp -d)"
|
||||
@@ -64,7 +64,7 @@ SPEC_DRAFT_N_MAX=$(sed -nE 's/^SPEC_DRAFT_N_MAX=([0-9]+)$/\1/p' "$ENV_FILE")
|
||||
VERBOSITY=$(sed -nE 's/^VERBOSITY=([0-9]+)$/\1/p' "$ENV_FILE")
|
||||
NGL=$(sed -nE 's/^NGL=([0-9]+)$/\1/p' "$ENV_FILE")
|
||||
EOF
|
||||
run env FRANK_SECONDARY_ENV_FILE="$envf" nvidia-modprobe=true bash "$SERVE"
|
||||
run env FRANK_ZEALOT_ENV_FILE="$envf" nvidia-modprobe=true bash "$SERVE"
|
||||
}
|
||||
|
||||
argv_value() {
|
||||
@@ -76,23 +76,23 @@ argv_value() {
|
||||
# append a drafter) must exec through this, not serve_argv — which silently
|
||||
# undoes the mutation and makes the assertion a tautology.
|
||||
run_stage() {
|
||||
run env FRANK_SECONDARY_ENV_FILE="$STAGE/test.env" nvidia-modprobe=true bash "$SERVE"
|
||||
run env FRANK_ZEALOT_ENV_FILE="$STAGE/test.env" nvidia-modprobe=true bash "$SERVE"
|
||||
}
|
||||
|
||||
@test "frank-secondary unit, serve script and env exist in scripts/" {
|
||||
@test "frank-zealot unit, serve script and env exist in scripts/" {
|
||||
[ -f "$UNIT" ]
|
||||
[ -f "$SERVE" ]
|
||||
[ -f "$ENV_FILE" ]
|
||||
}
|
||||
|
||||
@test "frank-secondary is boot-persistent, self-healing and unprivileged" {
|
||||
@test "frank-zealot is boot-persistent, self-healing and unprivileged" {
|
||||
grep -q '^WantedBy=multi-user.target$' "$UNIT"
|
||||
grep -q '^Restart=' "$UNIT"
|
||||
grep -q '^RestartSec=' "$UNIT"
|
||||
grep -q '^User=dank$' "$UNIT"
|
||||
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
||||
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-secondary.sh$' "$UNIT"
|
||||
grep -q 'FRANK_SECONDARY_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-secondary.env' "$UNIT"
|
||||
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-zealot.sh$' "$UNIT"
|
||||
grep -q 'FRANK_ZEALOT_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-zealot.env' "$UNIT"
|
||||
}
|
||||
|
||||
@test "the shipped env points at the llama.cpp runtime and the Qwen3.5-9B Q6_K GGUF" {
|
||||
@@ -107,7 +107,7 @@ run_stage() {
|
||||
# would be gating on a file nobody reads — and a missing projector would
|
||||
# ship a blind endpoint.
|
||||
local env_v dep_v path pair
|
||||
for pair in "MODEL_FILE LLM_SECONDARY_MODEL_FILE" "MMPROJ_FILE LLM_SECONDARY_MMPROJ"; do
|
||||
for pair in "MODEL_FILE LLM_ZEALOT_MODEL_FILE" "MMPROJ_FILE LLM_ZEALOT_MMPROJ"; do
|
||||
env_v="${pair%% *}"
|
||||
dep_v="${pair##* }"
|
||||
path="$(sed -nE "s/^${env_v}=(.+)$/\1/p" "$ENV_FILE")"
|
||||
@@ -236,7 +236,7 @@ run_stage() {
|
||||
# The documented opt-out must reach the engine as ABSENCE of the flag,
|
||||
# not as an argument pointing at an empty string.
|
||||
sed -i 's|^MMPROJ_FILE=.*|MMPROJ_FILE=|' "$STAGE/test.env"
|
||||
run env FRANK_SECONDARY_ENV_FILE="$STAGE/test.env" nvidia-modprobe=true bash "$SERVE"
|
||||
run env FRANK_ZEALOT_ENV_FILE="$STAGE/test.env" nvidia-modprobe=true bash "$SERVE"
|
||||
[ "$status" -eq 0 ]
|
||||
! grep -qxF -- '--mmproj' <<<"$output"
|
||||
}
|
||||
@@ -256,30 +256,30 @@ run_stage() {
|
||||
rm -f "$MODEL_DIR/$MM_STUB"
|
||||
serve_argv
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"frank-secondary: missing"* ]]
|
||||
[[ "$output" == *"frank-zealot: missing"* ]]
|
||||
|
||||
rm -f "$RUNTIME_DIR/bin/llama-server"
|
||||
serve_argv
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"frank-secondary: missing"* ]]
|
||||
[[ "$output" == *"frank-zealot: missing"* ]]
|
||||
}
|
||||
|
||||
@test "the deploy handler gates on binary, GGUF and projector, then MainPID-hardens health" {
|
||||
grep -q 'deploy_llm_secondary' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_SECONDARY_RUNTIME' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_SECONDARY_MODEL_FILE' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_SECONDARY_MMPROJ' "$REMOTE_DEPLOY"
|
||||
grep -q 'relink_unit frank-secondary' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-secondary.service' "$REMOTE_DEPLOY"
|
||||
grep -q 'deploy_llm_zealot' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_ZEALOT_RUNTIME' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_ZEALOT_MODEL_FILE' "$REMOTE_DEPLOY"
|
||||
grep -q 'LLM_ZEALOT_MMPROJ' "$REMOTE_DEPLOY"
|
||||
grep -q 'relink_unit frank-zealot' "$REMOTE_DEPLOY"
|
||||
grep -q 'systemctl enable frank-zealot.service' "$REMOTE_DEPLOY"
|
||||
grep -q '127.0.0.1:7771/health' "$REMOTE_DEPLOY"
|
||||
grep -q 'frank-secondary.service has no MainPID' "$REMOTE_DEPLOY"
|
||||
grep -q 'frank-zealot.service has no MainPID' "$REMOTE_DEPLOY"
|
||||
}
|
||||
|
||||
@test "the two endpoints keep separate ports and the large handler never pkills llama-server" {
|
||||
# frank-large's sweeps must not take down frank-secondary, whose
|
||||
# frank-dragoon's sweeps must not take down frank-zealot, whose
|
||||
# process is llama-server on the SAME host.
|
||||
grep -q '^LISTEN_PORT=7771$' "$ENV_FILE"
|
||||
local large
|
||||
large="$(sed -n '/^deploy_llm_large() {/,/^}/p' "$REMOTE_DEPLOY")"
|
||||
large="$(sed -n '/^deploy_llm_dragoon() {/,/^}/p' "$REMOTE_DEPLOY")"
|
||||
! grep -q 'pkill -x llama-server' <<<"$large"
|
||||
}
|
||||
@@ -97,7 +97,7 @@ webui_service_yaml() {
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "hermes" ]
|
||||
# And an unrelated service must not be dragged in.
|
||||
! grep -qE 'caddy|prometheus|frank-large' <<< "$output"
|
||||
! grep -qE 'caddy|prometheus|frank-dragoon' <<< "$output"
|
||||
}
|
||||
|
||||
@test "remote deployer accepts and dispatches hermes-webui" {
|
||||
|
||||
@@ -316,7 +316,7 @@ PAIRS
|
||||
@test "prometheus scrapes every LLM endpoint that exports metrics" {
|
||||
# The LLM endpoints are the services whose behaviour this fleet argues about
|
||||
# most (KV pressure, prefix-cache reuse, queue depth). Both Dankclaw
|
||||
# endpoints export the llamacpp:* family. frank-primary LEFT the set
|
||||
# endpoints export the llamacpp:* family. frank-archon LEFT the set
|
||||
# 2026-10-05: the FreeToken PR587 ROCm engine has NO /metrics endpoint —
|
||||
# scraping it was a structural never-green (404), so the job was deleted
|
||||
# rather than left vacuous (the Lucebox DS4.1 precedent, 2026-09-26).
|
||||
@@ -325,18 +325,18 @@ PAIRS
|
||||
# container, and on this netavark host a container can only reach the
|
||||
# host's LAN IP at a PUBLISHED port — a host-process bind like
|
||||
# llama-server's 0.0.0.0:7770 is refused at 192.168.0.143:7770 while it
|
||||
# answers at 169.254.1.2:7770 (why frank-secondary stayed red by construction
|
||||
# answers at 169.254.1.2:7770 (why frank-zealot stayed red by construction
|
||||
# for days until the 2026-09-20 /targets audit).
|
||||
local cfg="$REPO_ROOT/shared/prometheus/prometheus.yml"
|
||||
grep -q '"host.containers.internal:7771"' "$cfg" || { echo "frank-secondary not scraped"; return 1; }
|
||||
grep -q '"host.containers.internal:7770"' "$cfg" || { echo "frank-large not scraped"; return 1; }
|
||||
grep -q '"host.containers.internal:7771"' "$cfg" || { echo "frank-zealot not scraped"; return 1; }
|
||||
grep -q '"host.containers.internal:7770"' "$cfg" || { echo "frank-dragoon not scraped"; return 1; }
|
||||
! grep -q '"192.168.0.235:7770"' "$cfg"
|
||||
grep -q '"host.containers.internal:7770,192.168.0.235:7770"' "$cfg" \
|
||||
&& { echo "frank-primary folded into a Dankclaw gateway target"; return 1; }
|
||||
for job in frank-secondary frank-large; do
|
||||
&& { echo "frank-archon folded into a Dankclaw gateway target"; return 1; }
|
||||
for job in frank-zealot frank-dragoon; do
|
||||
grep -q "job_name: \"$job\"" "$cfg" || { echo "no scrape job for $job"; return 1; }
|
||||
done
|
||||
! grep -q 'job_name: "frank-primary"' "$cfg"
|
||||
! grep -q 'job_name: "frank-archon"' "$cfg"
|
||||
# None of them is reached through a guarded vhost: Prometheus cannot solve
|
||||
# an Anubis challenge, so a franksdank.cloud target is red by construction.
|
||||
! grep -qE '^\s*-\s*"?https?://[^"]*franksdank' "$cfg"
|
||||
@@ -383,11 +383,11 @@ for want in ('job:llm_prefix_cache_reuse:rate5m',
|
||||
# Every rule must be keyed to a series that actually exists. A rule naming a
|
||||
# series nobody exports evaluates nothing forever and errors never — the
|
||||
# failure this seam exists for. Since the 2026-09-26 cutover the only scraped
|
||||
# LLM runtime is llama.cpp (frank-secondary, frank-large); the vllm: family left
|
||||
# LLM runtime is llama.cpp (frank-zealot, frank-dragoon); the vllm: family left
|
||||
# with frank-medium's radiance runtime and must not survive in any expr.
|
||||
exprs = [r.get('expr', '') for g in d['groups'] for r in g['rules']]
|
||||
# llama.cpp families measured from /metrics on 2026-09-16 and 2026-09-20
|
||||
# (frank-secondary, frank-large). Anything else is a guess.
|
||||
# (frank-zealot, frank-dragoon). Anything else is a guess.
|
||||
live = {'llamacpp:prompt_tokens_total', 'llamacpp:prompt_tokens_cached_total',
|
||||
'llamacpp:requests_deferred', 'llamacpp:requests_processing',
|
||||
'llamacpp:spec_decode_num_drafts_total',
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# The old open-webui was a bare container on dankserver (port 3000) pointing at a
|
||||
# dead LLM backend (:9090). This unit stands one up on dankclaw on a free port
|
||||
# (3005), on the CPU image (dankclaw is CPU-only), wired to the live
|
||||
# llama.cpp backend (192.168.0.143:7770, model frank-large).
|
||||
# llama.cpp backend (192.168.0.143:7770, model frank-dragoon).
|
||||
|
||||
load helpers
|
||||
|
||||
@@ -63,7 +63,7 @@ QDIR="$REPO_ROOT/dankclaw/open-webui/quadlet"
|
||||
# gateway (10.89.3.1) lives in the rootless netns, NOT the host netns
|
||||
# where llama-server runs -- it refuses. The host's LAN IP reaches it
|
||||
# through the rootless NAT (verified from the container, 2026-08-22).
|
||||
# 2026-08-22: frank-large moved from :52625 to :7770.
|
||||
# 2026-08-22: frank-dragoon moved from :52625 to :7770.
|
||||
grep -qE '^Environment=OPENAI_API_BASE_URL=http://192\.168\.0\.143:7770' \
|
||||
"$QDIR/open-webui.container" \
|
||||
|| { echo "open-webui.container must set OPENAI_API_BASE_URL to the LLM at 192.168.0.143:7770"; return 1; }
|
||||
|
||||
Reference in New Issue
Block a user