Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and `merge --ff-only` refuses while tracked paths are dirty. Discard is not available here (workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed. - `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new prose — the commit exists so the trunk merge can proceed. - `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat owns (AGENTS.md § Live-sync tiers). `ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the inert all-zero AWS example id — and they appear inside the two skill pages that teach that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal dies with this landing. No `--no-verify` was used: the gate ran and its verdict is recorded here. Refs #61
4.3 KiB
name, description
| name | description |
|---|---|
| frank-tts-voice-pack-audit | Census live frank-tts voice packs against scripts/voice-packs.env to catch name-drift (renamed/retired packs) and untracked CLI-built packs; use after any voice add/rename when reconciling the builder recipe with what is actually on disk. |
frank-tts voice-pack audit (builder ↔ live census)
Read-only census answering: does scripts/voice-packs.env still describe the packs that actually exist, and is every live pack reproducible from the repo? Run it after anyone adds or renames a voice. The runtime being healthy (all voices synthesize) does NOT mean the builder is honest — the gap is reproducibility, not serving.
Why this exists
Packs are host state under /home/dank/voices (never in git). A voice can be:
- built by the env (a
VOICE_PACK_<NAME>_*block exists), or - built by CLI override (
build-voice-pack.sh <name> <dir> --source --offset --duration --sha256with NO env block) — then its only provenance is/home/dank/voices/<name>/manifest.json, and--allsilently skips it.
Renaming a pack directory (e.g. narrator1 → wilwheaton) preserves the crop bytes and its source sha256, so the env recipe stays correct but keyed under a dead name. build-voice-pack.sh --all then rebuilds the dead names and skips the live ones.
Procedure (on Dankclaw)
- Live set + which builder made each — the manifest
kindfield tells them apart:kind: "voice-pack"→ built byscripts/build-voice-pack.sh(env or CLI override).kind: "voice-reference-pack"→ the older trialpipeline.sh.
for d in /home/dank/voices/*/; do n=$(basename "$d"); [ -f "$d/reference.wav" ] \ && printf '%-16s %8sB %s\n' "$n" "$(stat -c%s "$d/reference.wav")" "$(stat -c %y "$d/reference.wav" | cut -d. -f1)"; done - Per-voice provenance —
manifest.jsonis the sole record for CLI-built packs. Readname/voice,kind,source.path,source.sha256,crop.offset_seconds,crop.duration_seconds. Usepython3 -c 'import json,...', NOT ajq '{a,b,c}'object — the brace form gets brace-expanded by the remote zsh and errors. - Builder tracked list:
Diff the names in
grep -E '^VOICE_PACKS=|^VOICE_PACK_[A-Z0-9_]+_(SOURCE|OFFSET|DURATION|SHA256)=' /home/dank/serverAppConfigs/scripts/voice-packs.envVOICE_PACKSagainst the live dirs. Three findings to report:- env keys that have no live dir (renamed/retired),
- live dirs with no env block (CLI-built, unreproducible from repo),
- matching source sha256 between a dead env key and a live dir = that live pack is the renamed crop (safe to re-key the env, don't recompute).
- Distinguish CLI-built from uncommitted env drift — check the deployed env matches the repo:
Empty diff + a
cd /home/dank/serverAppConfigs && git diff --stat HEAD -- scripts/voice-packs.env # empty = no driftkind: "voice-pack"manifest with no env block ⇒ built via CLI overrides (correct, just untracked), NOT a rogue remote edit.
Repoint the consumers (separate concern)
If voices were renamed/retired, the runtime consumers still point at dead names — see the frank-tts-repoint-voice-consumers skill. Consumers that name a voice: scripts/frank-tts.env DEFAULT_VOICE, Open Notebook dank-duo speaker profile (voice_id, app-side REST), OpenWebUI audio.tts.voice (config DB). A voice-less request to frank-tts 400s naming DEFAULT_VOICE, so a dead default is a live break, not just cosmetic.
Gotchas
- A published port is reachable at
host.containers.internaltoo. OpenWebUI's docs say use the LAN IP because that name "doesn't resolve on the bridge" — true only for non-published ports. frank-tts 7772 IS published, sohost.containers.internal:7772answers 200 from the open-webui container. Verify before calling a URL the cause; the real break is usually the dead voice name. - Source custody is split:
audiosample*.mp3/m4blive on the workstation (/home/blank), newer sources on Dankclaw (/home/dank/voice-sources).--allis only reproducible once each env SOURCE path points at where the file actually is. - Do NOT edit
voice-packs.envto add CLI-built voices without confirming each source path + offset + sha against its manifest, then run./tests/run.sh(the pack-list invariant invoice_pack_unit.batswalksVOICE_PACKS).