feat(svos): v0.0.17 live on nh3-svos and nh3-dev — kernel 0.0.17 + UI 0.0.21, the six runtimes' activity marks (gen 29bc36bf), terminal 0.0.6, voice utterance_seconds 60; activity events verified

This commit is contained in:
vh
2026-10-18 22:57:27 -07:00
parent 42c146c6e7
commit 4cc605ecbc
5 changed files with 180 additions and 4 deletions
@@ -0,0 +1,29 @@
# nh3-dev phase of the v0.0.17 rollout: app-terminal 0.0.6 (U17: the seat host classifies each live pane working/waiting
# against the kernel's per-runtime marks; activity_interval_seconds at its default 5, no terminal.toml edit). Release
# 15c2d04 is already built beside the live one in /opt/svos/releases/15c2d04 (uv pip freeze differs from 3726d73 in
# svos-terminal only). Restarts ONLY svos-terminal; postoffice, miranda and agent keep running 3726d73's identical code until
# their next restart. Terminal's manifest changes: registration raises ONE card, and the app refuses wrong-revision until
# Prime approves it (he is at the board: Prime 2235 2026-10-18 via svos-dev, thread 01M595YP8R62Y665C38MHPH6YX).
# Run as: scripts/elway infra-ops@10.100.10.50 (the apps are lkraven USER units, driven with runuser + XDG_RUNTIME_DIR).
steps:
- name: Release 15c2d04 is built and carries terminal 0.0.6
shell: test -f /opt/svos/releases/15c2d04/release.json && /opt/svos/releases/15c2d04/apps-env/bin/python -c "from importlib.metadata import version; v = version('svos-terminal'); print('terminal', v); assert v == '0.0.6'"
changed_when: "false"
- name: Switch current to 15c2d04 (as lkraven, who owns /opt/svos on nh3-dev)
sudo: true
shell: runuser -u lkraven -- sh -c 'ln -sfn /opt/svos/releases/15c2d04 /opt/svos/current.new && mv -T /opt/svos/current.new /opt/svos/current && readlink /opt/svos/current'
- name: Restart ONLY svos-terminal
sudo: true
shell: |
runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 systemctl --user restart svos-terminal
sleep 6; runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 systemctl --user is-active svos-terminal
pid=$(runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 systemctl --user show svos-terminal -p MainPID --value); grep -oE '/opt/svos/releases/[0-9a-f]+' /proc/$pid/maps | sort -u
runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 journalctl --user -u svos-terminal --since "-60s" --no-pager -o cat | grep -i -E "manifest|card|held|revision|activity|error" | tail -8 | cut -c1-200
verify:
- name: Terminal runs 15c2d04 and its seat host came up
sudo: true
shell: |
pid=$(runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 systemctl --user show svos-terminal -p MainPID --value)
grep -q /opt/svos/releases/15c2d04 /proc/$pid/maps && echo "terminal pid $pid on 15c2d04"
! runuser -u lkraven -- env XDG_RUNTIME_DIR=/run/user/1000 journalctl --user -u svos-terminal --since "-5min" --no-pager -o cat | grep -i "Seat host unavailable"
changed_when: "false"
@@ -0,0 +1,37 @@
# nh3-svos: STAGE SVOS v0.0.17 (15c2d04) beside the live release. Installs into /opt/svos/releases/15c2d04 and runs the
# new kernel's check-config against the live configuration. Does NOT switch current, stop or start anything.
# svos-dev's ask (thread 01M595YP8R62Y665C38MHPH6YX); Prime's "deploy now" 2235 2026-10-18. Kernel 0.0.17, terminal 0.0.6
# (nh3-svos keeps it installed, unused), UI 0.0.21; everything else carried from b51aa5e. The cutover is
# nh3-svos-15c2d04-v0.0.17.yaml. The runtimes edit script is staged here too and dry-run against a copy of the live file.
steps:
- name: Private staging dir
shell: install -d -m 0700 /tmp/svos-stage-15c2d04
- {name: stage release, upload: {src: /tmp/claude-1000/-home-lkraven-development-eshpfi-management/e0be18fd-0734-4786-b933-904f0a74d2a2/scratchpad/svos-15c2d04/svos-release-15c2d04.tar.gz, dest: /tmp/svos-stage-15c2d04/release.tar.gz, mode: "0644"}}
- {name: stage uv, upload: {src: /home/lkraven/bin/uv, dest: /tmp/svos-stage-15c2d04/uv, mode: "0755"}}
- {name: stage installer, upload: {src: /tmp/claude-1000/-home-lkraven-development-eshpfi-management/e0be18fd-0734-4786-b933-904f0a74d2a2/scratchpad/svos-15c2d04/install-release.py, dest: /tmp/svos-stage-15c2d04/install-release.py, mode: "0644"}}
- {name: stage runtimes edit, upload: {src: /tmp/claude-1000/-home-lkraven-development-eshpfi-management/e0be18fd-0734-4786-b933-904f0a74d2a2/scratchpad/svos-15c2d04/u17-runtimes-edit.py, dest: /tmp/svos-stage-15c2d04/u17-runtimes-edit.py, mode: "0644"}}
- name: Verify staged hashes
shell: cd /tmp/svos-stage-15c2d04 && printf '%s %s\n' f6e4ff1e49f98482afad510bb591c9ebc9087ec792677b6190c1839f2939b2b2 release.tar.gz 83aa128da93e168283ed32cf75cd819fe17b135b3fc1f7ccb3c912eec198d9fb uv 53bb68360eedbd8694ea89d9212c2eea80027655991a0bc7bf690ad76d18a217 u17-runtimes-edit.py | sha256sum -c -
changed_when: "false"
- name: Install release 15c2d04 beside the live one (current NOT switched)
sudo: true
shell: python3 /tmp/svos-stage-15c2d04/install-release.py
creates: /opt/svos/releases/15c2d04/apps-env/pyvenv.cfg
verify:
- name: New kernel 0.0.17 accepts the live configuration as it is
sudo: true
shell: runuser -u svc-svos -- /opt/svos/releases/15c2d04/kernel-env/bin/svos-kernel check-config --data-root /var/lib/svos
changed_when: "false"
- name: Dry run of the runtimes edit on a private copy (the live file is not touched); the result parses as TOML
sudo: true
shell: |
set -e
d=$(mktemp -d); cp -p /var/lib/svos/config/instance.toml $d/instance.toml
sed "s#/var/lib/svos/config/instance.toml#$d/instance.toml#" /tmp/svos-stage-15c2d04/u17-runtimes-edit.py > $d/edit.py
python3 $d/edit.py
python3 -c "import tomllib,sys; c=tomllib.load(open(sys.argv[1],'rb')); r=c['seats']['runtimes']; print([(x['name'], x.get('window'), bool(x.get('prompt')), bool(x.get('working'))) for x in r])" $d/instance.toml
diff /var/lib/svos/config/instance.toml $d/instance.toml | grep -c '^>' ; rm -rf $d
changed_when: "false"
- name: current still points at the live release
shell: readlink /opt/svos/current
changed_when: "false"
@@ -0,0 +1,80 @@
# 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"