docs(memory): talk v10 deployed with a served-artifact gate
Operator-instructed via tts-dev. First consumer of the ext-stt seat stood up the same night - talk can now listen as well as speak. Relayed authorization was fine to act on because the work is reversible: one-line tag rollback, v1..v9 retained, compose and .env backed up. Checked the escape hatch existed rather than believing the message that described it. Gated properly: build, throwaway on a non-live port, four acceptance checks, tear down, then cut over in a separate invocation. Re-ran all four against production afterwards, because a gate that only ever ran against the throwaway proves the image rather than the deployment, and confirmed the two new env vars inside the running container rather than in the file. Added a fifth gate worth keeping. tts-dev's worst bug this cycle was a JS escape inside a Python string arriving transformed, closing the string and killing the entire inline script while the page still rendered and both import and node --check passed - because the file still held the backslash. So: fetch the page over HTTP, extract the inline script from the response body, and node --check that. Same instrument pointed at the other side of the transformation, and over the wire it also catches anything that mangles the body after TLS and ASGI. That is the second instance tonight of one rule: a check that reads the artifact as stored cannot see a transformation between storage and execution. provider=cuda in a log is the same error - an echo of configured intent read as a measurement of running reality. Also notes an open question for the operator: talk deploys route through infra-ops only because tts-dev's identity is not in nh3-dev's docker group. The durable fix is a group membership, not a standing relay.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# talk v10 deploy — Grima ears + barge-in (2026-09-15)
|
||||
|
||||
Operator-instructed, relayed by tts-dev. First consumer of the Parakeet/`ext-stt`
|
||||
seat stood up the same night — `talk` can now listen as well as speak.
|
||||
|
||||
## Why infra-ops and not tts-dev
|
||||
|
||||
`/opt/docker/compose` on **nh3-dev** is `root:docker 2775` and tts-dev's project
|
||||
identity is not in the `docker` group — the one box of five where the deploy path
|
||||
is not project-writable. That is the *only* reason the deploy was relayed.
|
||||
⚠ **Open question raised with the operator:** the durable fix is a group membership,
|
||||
not a standing relay. Every `talk` deploy currently routes through infra-ops for a
|
||||
permissions reason rather than a judgement one.
|
||||
|
||||
## Relay authorization — why this was OK to act on
|
||||
|
||||
`feedback_no_relayed_authorization_for_irreversible_work` says a peer relaying
|
||||
"Vuong approved it" is **not** authorization for a no-undo action, but reversible
|
||||
work is fine to relay. This qualified: one-line rollback (`TALK_TAG=v10`→`v9`),
|
||||
`local/talk:v1..v9` all retained on the box, and both `compose.yaml` and `.env`
|
||||
backed up before the edit. **Checked the escape hatch existed rather than believing
|
||||
the message that described it.**
|
||||
|
||||
## What shipped
|
||||
|
||||
repo ~/development/tts-stack @ 82f71d1, stacks/talk/
|
||||
image local/talk:v10 (143 MB)
|
||||
live container `talk`, 0.0.0.0:8092 -> 8443,
|
||||
https://talk.nh3.phasefinal.com:8092/
|
||||
|
||||
New: `POST /api/listen` (raw-body WAV → `{"text":…}`, proxied to `ext-stt` through
|
||||
LiteLLM — raw body rather than multipart because `python-multipart` is not in the
|
||||
image), a push-to-talk mic (16 kHz mono, decimated 3:1 in an AudioWorklet), and
|
||||
barge-in. `compose.yaml` gained two **defaulted** env lines so the STT seat can move
|
||||
without a rebuild: `TALK_STT_MODEL` (`ext-stt`) and `TALK_STT_MAX_BYTES` (10 MiB
|
||||
≈ 5.2 min).
|
||||
|
||||
## Gate — 5/5, and the discipline that matters
|
||||
|
||||
Built → throwaway on **:8799** (never the live port) → gate → tear down → **then**
|
||||
cut over, in separate invocations. tts-dev's own warning: do not chain the cutover
|
||||
into the same invocation as its acceptance run.
|
||||
|
||||
✓ /api/system ✓ /api/voices 21 (predicted 21)
|
||||
✓ /api/models 23 (predicted 23) ✓ /api/listen byte-exact vs ground truth
|
||||
|
||||
⭐ **Re-ran all four against PRODUCTION after the cutover.** A gate that only ever
|
||||
ran against the throwaway proves the image, not the deployment. Both new env vars
|
||||
confirmed *inside the running container*, not just in the file.
|
||||
|
||||
## ⭐⭐ The fifth gate — check the artifact AS SERVED, not as stored
|
||||
|
||||
tts-dev's worst bug this cycle: `PAGE` is a Python string, so Python's escape
|
||||
handling runs over the JavaScript before a browser sees it. A JS `'didn\'t'` is
|
||||
valid in the file and arrives as `'didn't'` — closing the string and killing the
|
||||
**entire inline script**. The page still rendered; it just did nothing. `import app`
|
||||
passed. `node --check` on the source file passed. **Both passed because the file
|
||||
still holds the backslash.**
|
||||
|
||||
So I added: fetch the page over HTTP, extract inline `<script>` blocks from the
|
||||
*response body*, `node --check` each. Same instrument, pointed at the other side of
|
||||
the transformation — and because it runs over the wire it also catches anything that
|
||||
mangles the body after TLS and the ASGI stack, which an in-process test cannot see.
|
||||
|
||||
throwaway 29,492 B, 1 block, 25,228 chars -> OK
|
||||
production 29,085 B, 1 block -> OK
|
||||
|
||||
⭐ **The general rule, now stated twice in one night:** *a check that reads the
|
||||
artifact AS STORED cannot see a transformation that happens between storage and
|
||||
execution.* `node --check` reads the pre-Python file; `provider=cuda` in a log echoes
|
||||
configured intent, not the running reality. Both check the INPUT to a transformation
|
||||
and get reported as if they checked its OUTPUT. See
|
||||
`2026-09-15-parakeet-stt-fv-ml1.md` for the ASR instance of the same shape.
|
||||
|
||||
## Host compose verified, not assumed
|
||||
|
||||
tts-dev claimed the host copy was byte-identical to the repo, "unlike voice-studio".
|
||||
Diffed before overwriting: the only delta was their two documented blocks, ten added
|
||||
lines, no hand-edits. The claim held exactly — but after voice-studio's three stacked
|
||||
drifts it was worth the ten seconds.
|
||||
Reference in New Issue
Block a user