feat(frank-tts-engine): the arm A engine as a boot-persistent quadlet unit
Repo state only: nothing deployed, no host touched, no container started. - `frank-tts-engine` on Dankclaw: `qwentts.cpp` commit 5916bf7c79dbb4e66fc059cdc507a79a23a28bb4, resident `tts-server`, 1.7 B base talker Q4_K_M + Q8_0 tokenizer, container port 8880. It is deliberately NOT a fleet endpoint — `frank-tts` on 7772 is the endpoint consumers address. - Publishes NOTHING. A host-loopback publish would have been useless to the façade (netavark DNATs published ports only, so a bridge container cannot reach a host loopback bind — the shape that 502'd hermes) and would have been the one LAN-reachable surface of an unauthenticated synthesiser. Both voice containers sit on one committed quadlet network, `frank-tts-engine.network` pinned to 10.89.5.0/24 (next free /24 after open-notebook's 10.89.4.0/24), and peers address the engine by container name. Diagnostics and the deployer's health gate run inside the netns (`podman exec`, `wait_container_healthy`). - Cold-voice law honoured in the unit: the first request for a registered voice decodes its whole reference to snapshot codec state (6.2-8.0 s, first audio byte 5 530 ms), later ones restore in 0.5 ms, and the registry is memory-only. `ExecStartPost=-/usr/bin/podman exec frank-tts-engine /app/warm-voices.sh` with `TimeoutStartSec=900`; the `-` prefix keeps a failed warm from crash-looping the endpoint under `Restart=always`. It logs cold=/warm= per voice, so the under-a-second second request is proven on every boot. - Thread law recorded: `tts-server` has no `--threads`; src/backend.h uses hardware_concurrency()/2, so a cpuset pin silently changes the thread count. - Image builds from the pinned commit with the proven line (GGML_BLAS=OFF forced by this host, every GPU backend off, -j 8, no -DGGML_NATIVE because ggml defaults to -march=native for the building host). Two stages; the runtime stage COPYs both the entrypoint and the warmer, because a container that publishes nothing is reached with `podman exec`, not a port. - `scripts/download-frank-tts-engine-qwentts.sh` fetches the two GGUFs with byte and LFS-oid checks (talker 1 219 245 248 B, tokenizer 291 150 624 B); the deployer gates on --verify-only instead of pulling 1.4 GiB mid-deploy. - Registered in SERVICE_ORDER, DANKCLAW_SERVICES, the deploy-remote.sh dispatch, its pre-deploy requirement, deploy.sh's regex, the planner's path map (the whole `dankclaw/voiceservice/` tree mapped to nothing before this), and test-changed.sh ABOVE the `dankclaw/*.container` case whose `*` crosses `/`. - New seam tests/frank_tts_engine.bats (19): the Quadlet generator's own output for network/publish/boot/warm shape, entrypoint argv driven from the tracked env file, the warmer against a stub tts-server over a real socket (registration keys, ref_text absent, late engine, hung synthesis, name refusal), the fetcher's verifier, the pinned cmake line, and both routing tables. Suite: 422 passed. - Vault: [[Frank TTS Engine]] linked from the index; log.md entry for the day.
This commit is contained in:
@@ -138,6 +138,21 @@ for path in "${CHANGED[@]}"; do
|
||||
add_test tests/docs_completeness.bats
|
||||
add_test tests/deployment_scoping.bats
|
||||
;;
|
||||
# The voice stack: the arm A engine unit, the private bridge it owns,
|
||||
# its image and its entrypoint. Like the open-notebook block above,
|
||||
# this case MUST precede the dankclaw/*.container glob — that `*`
|
||||
# crosses `/`, so without this case
|
||||
# dankclaw/voiceservice/quadlet/frank-tts-engine.container is routed to
|
||||
# the open-webui/pihole/searxng seams and its own seam never runs.
|
||||
# The façade's seam rides along: the two share a directory, a network
|
||||
# and the request path a consumer takes.
|
||||
dankclaw/voiceservice/*)
|
||||
add_test tests/frank_tts_engine.bats
|
||||
add_test tests/frank_tts_unit.bats
|
||||
add_test tests/deployment_flow.bats
|
||||
add_test tests/deployment_scoping.bats
|
||||
add_test tests/docs_completeness.bats
|
||||
;;
|
||||
dankclaw/*.container|dankclaw/*.network)
|
||||
add_test tests/open_webui_quadlet.bats
|
||||
add_test tests/pihole.bats
|
||||
@@ -197,6 +212,19 @@ for path in "${CHANGED[@]}"; do
|
||||
# as additions, with "no focused-test mapping".
|
||||
.AGENTTRASH/*|*/.AGENTTRASH/*)
|
||||
;;
|
||||
# The two voice env files both reach a container through a Quadlet unit
|
||||
# (EnvironmentFile=), so they select the voice seams plus the
|
||||
# script-syntax seam. This case has to precede the generic
|
||||
# scripts/*.service and scripts/* fallbacks below, or a change to
|
||||
# scripts/frank-tts-engine.env would run nothing but bash -n. The
|
||||
# warmer is NOT here: it ships inside the engine image and is routed
|
||||
# with the rest of dankclaw/voiceservice/* above.
|
||||
scripts/frank-tts-engine.env|scripts/frank-tts.env)
|
||||
add_test tests/frank_tts_engine.bats
|
||||
add_test tests/frank_tts_unit.bats
|
||||
add_test tests/deployment_scoping.bats
|
||||
add_test tests/scripts_syntax.bats
|
||||
;;
|
||||
# frank-archon is llama.cpp (the unsloth b11030-mix prebuilt) on the
|
||||
# two R9700s as a ROOT unit — the 2026-09-26 swap that replaced the
|
||||
# Lucebox DS4.1 quadlet on :7770. Its env, unit and serve script all
|
||||
|
||||
Reference in New Issue
Block a user