# nh3-svos -> SVOS v0.0.17 (15c2d04): kernel 0.0.17 (U17 seat activity: [[seats.runtimes]] prompt/working/window, the # row's `activity`, seat/activity_changed) and UI 0.0.21 (the working flow; the voice client admits 0.1..120 s and speaks # long text in pieces). Prime 2235 2026-10-18 via svos-dev (thread 01M595YP8R62Y665C38MHPH6YX): "deploy v0.0.17 now". # PRE-REQ: nh3-svos-15c2d04-v0.0.17-stage.yaml. No schema change (14). An old kernel refuses the new runtime keys, so the # edit lands inside the stopped window: stop; backup; switch; edit (verbatim from docs/operations/u13-edit-payload.md # @15c2d04) + check-config (restore + b51aa5e on refusal); start; front door; then voice.toml utterance_seconds 30 -> 60 # (UI 0.0.21 is live by then) and the voice app starts last. nh3-dev's terminal 0.0.6 is a separate playbook (one card). steps: - name: Pre-reqs present (release staged, edit script staged, no runtime keys yet) sudo: true shell: test -f /opt/svos/releases/15c2d04/kernel-env/bin/svos-kernel && test -f /tmp/svos-stage-15c2d04/u17-runtimes-edit.py && ! grep -qE '^(prompt|working|window) *=' /var/lib/svos/config/instance.toml && readlink /opt/svos/current changed_when: "false" - name: Stop the local apps then the kernel sudo: true shell: systemctl stop svos-voice svos-judge svos-knowledge svos-interface svos-kernel; systemctl is-active svos-kernel svos-interface svos-knowledge svos-judge svos-voice | tr '\n' ' '; echo - name: Offline backup to /var/lib/svos/backup/pre-15c2d04 sudo: true shell: | set -e d=/var/lib/svos/backup/pre-15c2d04 runuser -u svc-svos -- install -d -m 0700 $d runuser -u svc-svos -- python3 -c " import sqlite3 s = sqlite3.connect('/var/lib/svos/state/svos.db'); t = sqlite3.connect('$d/svos.db'); s.backup(t); t.close(); s.close() c = sqlite3.connect('file:$d/svos.db?mode=ro', uri=True); print('integrity', c.execute('pragma integrity_check').fetchone()[0], 'user_version', c.execute('pragma user_version').fetchone()[0])" runuser -u svc-svos -- cp -p /var/lib/svos/config/instance.toml /var/lib/svos/config/instance.toml.pre-15c2d04 runuser -u svc-svos -- cp -p /var/lib/svos/config/apps/voice.toml /var/lib/svos/config/apps/voice.toml.pre-15c2d04 - name: Switch current to 15c2d04 sudo: true shell: ln -sfn /opt/svos/releases/15c2d04 /opt/svos/current.new && chgrp -h svc-svos /opt/svos/current.new && mv -T /opt/svos/current.new /opt/svos/current && readlink /opt/svos/current - name: Config - the six runtimes' prompt/working/window (verbatim); the new kernel must accept it (else restore + b51aa5e) sudo: true shell: | runuser -u svc-svos -- python3 - < /tmp/svos-stage-15c2d04/u17-runtimes-edit.py || exit 1 # stdin: svc-svos cannot read infra-ops's 0700 stage dir if runuser -u svc-svos -- /opt/svos/releases/15c2d04/kernel-env/bin/svos-kernel check-config --data-root /var/lib/svos; then exit 0; fi runuser -u svc-svos -- cp -p /var/lib/svos/config/instance.toml.pre-15c2d04 /var/lib/svos/config/instance.toml ln -sfn /opt/svos/releases/b51aa5e /opt/svos/current.new && chgrp -h svc-svos /opt/svos/current.new && mv -T /opt/svos/current.new /opt/svos/current systemctl start svos-kernel.service svos-interface svos-knowledge svos-judge svos-voice; echo "RESTORED config + b51aa5e"; exit 1 - name: Start the kernel then interface, knowledge, judge sudo: true shell: | t0=$(date +%s.%N); systemctl start svos-kernel.service; rc=$?; t1=$(date +%s.%N) echo "kernel start rc=$rc after $(python3 -c "print(round($t1-$t0,2))") s" systemctl start svos-interface svos-knowledge svos-judge sleep 8; curl -s http://127.0.0.1:8400/health; echo - name: Front door inventory (UI 0.0.21 live; b51aa5e becomes previous) sudo: true shell: /usr/local/sbin/svos-front-inventory 2>&1 | grep -E 'GENERATED|updated|root \*|path /assets' | head -4 - name: voice.toml utterance_seconds 30 -> 60 (the 0.0.21 client admits 0.1..120), then start the voice app sudo: true shell: | set -e runuser -u svc-svos -- python3 - <<'PY' import os p = "/var/lib/svos/config/apps/voice.toml"; s = open(p, encoding="utf-8").read() old = [l for l in s.split("\n") if l.startswith("utterance_seconds = 30 ")] assert len(old) == 1, old new = "utterance_seconds = 60 # 2026-10-18 v0.0.17: UI 0.0.21's voice client admits 0.1..120 s (U12 v1.4); 6 MiB output holds 65 s at 48 kHz" s = s.replace(old[0], new) t = p + ".tmp"; fd = os.open(t, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: f.write(s) os.replace(t, p); print("edited") PY grep -n '^utterance_seconds' /var/lib/svos/config/apps/voice.toml systemctl start svos-voice; sleep 5; systemctl is-active svos-voice journalctl -u svos-voice --since "-30s" --no-pager -o cat | grep -iE "error|refus|invalid|limit" | tail -4 | cut -c1-200 || true verify: - name: Health ok, nothing down shell: h=$(curl -s http://127.0.0.1:8400/health); echo "$h"; echo "$h" | grep -q '"status":"ok"' && echo "$h" | grep -q '"down":0' changed_when: "false" - name: Every app and the kernel run from 15c2d04 sudo: true shell: | for u in svos-kernel svos-interface svos-knowledge svos-judge svos-voice; do pid=$(systemctl show $u -p MainPID --value); printf '%s pid %s %s\n' $u $pid "$(grep -oE '/opt/svos/releases/[0-9a-f]+' /proc/$pid/maps | sort -u | tr '\n' ' ')"; done for u in svos-kernel svos-interface svos-knowledge svos-judge svos-voice; do pid=$(systemctl show $u -p MainPID --value); grep -q /opt/svos/releases/15c2d04 /proc/$pid/maps || { echo "$u NOT on 15c2d04"; exit 1; }; done changed_when: "false" - name: Front door inventory current sudo: true shell: /usr/local/sbin/svos-front-inventory --check changed_when: "false"