feat(frank-tts): deploy wiring for the 7772 voice endpoint, and voice naming written down
Stage 2 of the voice stack. Repo state only: nothing deployed, no host touched, no container started. - `frank-tts` is now registered everywhere a dankclaw service has to be: `SERVICE_ORDER` (after `frank-tts-engine`, before the consumers), the planner's dankclaw set, `deploy-remote.sh`'s allowlist + dispatch + a `deploy_frank_tts` handler, and `deploy.sh`'s dispatch regex — plus the `build_compose_image` arm naming `dankclaw/voiceservice/Containerfile`, without which the build silently returns 0 and the unit's `Pull=never` tag never exists. - The unit joins TWO networks, in order: `dankclaw_default` first (default route, where consumers and open-notebook live), then the voice bridge. `TTS_UPSTREAM` moves from `host.containers.internal:8880` to `http://frank-tts-engine:8880` — the actual fix for a shape that could never work, since a bridge container cannot reach a host-loopback bind and the engine publishes nothing at all. - `Wants=`/`After=` on the engine, never `Requires=`: the `llama-tts-cli` rollback backend needs no upstream, so a broken engine may delay this endpoint but must not take its unit down. - The handler installs the engine's quadlet pair too, because a referenced `Network=` file the generator cannot find means no façade unit is produced at all, and `--only frank-tts` has no other way to get it. It creates `/home/dank/voices` as the deploy user (rootless podman would auto-create a missing bind source root-owned, which reads as "no voices"), and gates on podman's recorded health. - Voice naming is now written down where it can be found: a voice is a lowercase directory name matching `^[a-z0-9][a-z0-9._-]*$`, at most 64 chars. That shape is the intersection of two rules that disagree — the shim would accept mixed case, the engine lowercases names — so a mixed-case pack resolves on one side only, and the boot warmer refuses it loudly. `narrator1/2/3` are load-bearing for open-notebook. - Homepage card for the pair, `wip: down` and hidden, probing `127.0.0.1:7772`; the engine gets no card because it publishes nothing and could never be probed. - **No Prometheus job, deliberately.** No `/metrics` exists on the shim, this Prometheus 3 refuses HTML/JSON bodies (the existing `comfyui` and `services` probes are documented down for exactly that), and `LlmEndpointDown` is scoped `up{job=~"frank-.*"}` — so a `/health` job would page on Signal for a healthy endpoint. Recorded in the page instead of quietly skipped. - Vault: new [[Frank TTS]] page linked from the index; [[Frank TTS Engine]] now points at it for the pair's public signal; log entry for the day. - Seam grows to 25 tests: the generator's rendering of the pair (both attachments, first-network order, one publish, Wants-not-Requires, bounded per-unit blocks), the env file's upstream checked as a network JOIN rather than a string, planner separation and order, the handler's steps, the card's gating, routing that selects both seams for either deployable.
This commit is contained in:
@@ -66,6 +66,7 @@ SERVICE_ORDER = (
|
||||
# a dependency of the 7772 facade, so it is planned (and therefore
|
||||
# restarted) first.
|
||||
"frank-tts-engine",
|
||||
"frank-tts",
|
||||
"frank-dragoon",
|
||||
"frank-zealot",
|
||||
"frank-archon",
|
||||
@@ -102,6 +103,7 @@ DANKCLAW_SERVICES = {
|
||||
"frank-dragoon",
|
||||
"frank-zealot",
|
||||
"frank-tts-engine",
|
||||
"frank-tts",
|
||||
}
|
||||
|
||||
DANKSERVER_SERVICES = {
|
||||
@@ -342,6 +344,15 @@ def services_for_path(path: str, target: str) -> set[str]:
|
||||
"Containerfile.engine", "tts-engine-start.sh",
|
||||
"tts-engine-warm.sh"}:
|
||||
_add(services, "frank-tts-engine")
|
||||
# The 7772 façade is the other deployable in this directory. The
|
||||
# bridge file is named after the ENGINE unit (install_quadlet copies
|
||||
# `$unit.network` beside `$unit.container`), yet both units attach
|
||||
# to it, so a subnet change is a change to both. Anything else here
|
||||
# belongs to neither deployable and plans nothing.
|
||||
if parts[-1] in {"frank-tts.container", "app.py", "Containerfile"}:
|
||||
_add(services, "frank-tts")
|
||||
if parts[-1] == "frank-tts-engine.network":
|
||||
_add(services, "frank-tts")
|
||||
return services
|
||||
# frank-dragoon left the quadlet shape on 2026-09-19 (CIRU v4.4.1 host
|
||||
# build, root unit): its files live in scripts/ and map there.
|
||||
|
||||
Reference in New Issue
Block a user