From c179389731663d60b5d06aaaeb323dbf1454b3a5 Mon Sep 17 00:00:00 2001 From: Keysat Date: Mon, 15 Jun 2026 23:18:28 -0500 Subject: [PATCH] docs: trim Current state post-matrix-bridge ship; add bot-tile ops note to runbook --- AGENTS.md | 6 +++--- runbook.md | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3e7d461..e515a74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,11 +56,11 @@ Subsystem guidance lives in `docs/guides/` and loads when matching files are tou ## Current state - **Working (v0.21.0:1, installed and serving):** swap dashboard; chat / transcribe / diarize(+chunk) / TTS proxies; embeddings + rerank + hybrid search (Qdrant); `/scrub` + `/rehydrate`; label-merge incl. dual-channel; per-Spark SSH-key copy + WireGuard `VPN ` hardware-card badge. Spark 2 audio stack healthy. Security hardening (v0.19.0:0 — shellsafe SSH-injection guard, Qdrant path-injection, same-origin CSRF guard) shipped and stable; evidence in `EVALUATION.md`. -- **matrix-bridge tile (v0.21.0:1 — installed & verified 2026-06-16):** "matrix-bridge" service tile (kind `bot`) on the Always-on services panel. Status badge (docker-state only — no HTTP health port), Restart/Stop/Start (generic `/api/services` path), **Update** (streamed `git fetch && git reset --hard origin/ && docker compose up -d --build` via `app/matrix_bridge.py`, 25-min cap, fail-loud), **View logs** (`docker logs --tail 100`). Driven as a dedicated SSH user **directly** (no `sudo -iu` — spark2 has no passwordless sudo). The user is a **blank-default "Configure Sparks" field** (`matrix_bridge_user`, set to `modelo`); blank → service unconfigured → tile hidden (portable, no hardcoded username). Host reuses `spark2_host` (= `192.168.1.87` = the bot's box `spark-32d0`); container/dir/branch env-overridable defaults. Verified live: badge Healthy, Update (rebuild+recreate), Restart, View logs all work. Note: a fast `docker restart` won't visibly flip the badge (status re-checked only after the command returns, by which point it's back up — matches the sub-5s-poll-miss limit). **Ops dependency:** the Update button runs `git fetch` as `modelo` on the Spark, which relies on `modelo`'s `~/.ssh/config` pinning the Gitea deploy key (`Host immense-voyage.local … IdentityFile ~/.ssh/id_ed25519` + `IdentitiesOnly yes`) — without it another key is offered first and Gitea denies (publickey). Don't remove that block. New endpoints: `POST /api/matrix-bridge/update` (+`/{id}`, `/{id}/stream`), `GET /api/matrix-bridge/logs`. **Owner prereq before Update works:** convert `~/matrix-bridge` to a Gitea clone, and authorize the package key for `modelo` unless `spark2_user == modelo`. Then bump-build-install (`cd package && make x86 && make install` — restarts live service, get go/no-go). +- **matrix-bridge bot tile (done, v0.21.0:1, verified live):** `bot`-kind service tile — status badge from docker-state only (no HTTP port), plus **Update** / Restart / Stop/Start / **View logs**. Code: `app/matrix_bridge.py` + `/api/matrix-bridge/{update,logs}` (update streams; 25-min cap; fail-loud). Driven directly as `modelo` on Spark 2 (**no `sudo -iu`** — spark2 has no passwordless sudo). User is a blank-default Configure-Sparks field (`matrix_bridge_user`); blank → tile hidden (portable). Host reuses `spark2_host` (`192.168.1.87` = the bot's box `spark-32d0`); container/dir/branch are env-overridable defaults. **Load-bearing ops dep:** Update's `git fetch` runs as `modelo`, which needs `modelo`'s `~/.ssh/config` pinning the Gitea deploy key with `IdentitiesOnly yes` — else the wrong key is offered and Gitea denies (publickey). Optional next, only if the bot dev asks: Docker `HEALTHCHECK` for running-but-disconnected detection (spec §Note). - **Tests:** offline pytest harness in `image/tests/` — `cd image && .venv/bin/python -m pytest` (70 passing). Covers `build_launch_command` (incl. the shell-injection round-trip), the transcript↔diarizer label-merge, the `shellsafe` validators, and `matrix_bridge.build_update_command` (+ phase detection). Mock-heavy swap/proxy tests deliberately skipped (low ROI). Redaction + live-audio suites remain standalone scripts. - **Signal Engine "flakiness":** diagnosed as *not* a server bug — transient 1–4s unresponsiveness while the single GPU is busy. Client-side remedy (in-flight cap 2 / ceiling 3 / retry-on-timeout+503) drafted and **forwarded to that dev (owner confirmed 2026-06-15)**. Awaiting whether they want the measured concurrency knee. - **Stance (decided, not built):** no public interface / no API-token auth — LAN + WireGuard/Tailscale split-tunnel only; the CSRF guard covers the browser-driven vector. -- **Known limits:** `/health` blips while the GPU is busy (mitigated client-side); dual-channel can miss a quiet local word under loud remote bleed; connectivity log misses sub-5s outages between 5s polls; diarizer caps at 4 speakers. +- **Known limits:** `/health` blips while the GPU is busy (mitigated client-side); dual-channel can miss a quiet local word under loud remote bleed; connectivity log misses sub-5s outages between 5s polls; diarizer caps at 4 speakers; matrix-bridge badge won't visibly flip on a fast `docker restart` (status re-checked only after the command returns). - **Infra gotcha (safety):** passwordless sudo is NOT configured on spark2 — design unprivileged probes for any Spark feature (the badge uses `ip`, not `sudo wg show`). spark2 sits on the `starttunnel` WireGuard subnet (`10.59.211.6/24`, survives reboot). Owner declined SSH-key rotation after the 2026-06-12 history scrub (only the key *name* leaked) — don't re-flag. - **Hosting:** self-hosted Gitea — remote `gitea`, branch `master`, over SSH; push after committing. (Wart: commit `8d839e3` is mislabeled `v0.13.0:4` but contains through v0.18.0:0.) -- **Next:** (1) matrix-bridge Phase 3 — **done & shipped (v0.21.0:1, pushed)**; nothing outstanding unless the dev wants the optional Docker `HEALTHCHECK` follow-up (running-but-disconnected detection, spec §Note). (2) audio concurrency sweep — only if the Signal Engine dev wants the measured knee; needs owner OK in a quiet window. (3) Otherwise pull from `ROADMAP.md`: local-path/fine-tuned model support (new) or P2 tech-debt. Parakeet long-audio guard is deferred (rationale in ROADMAP). +- **Next:** (1) audio concurrency sweep — only if the Signal Engine dev wants the measured knee; needs owner OK in a quiet window. (2) Otherwise pull from `ROADMAP.md`: local-path/fine-tuned model support (new) or P2 tech-debt. (matrix-bridge Phase 3 shipped v0.21.0:1; only open item is the optional Docker `HEALTHCHECK` if the bot dev asks. Parakeet long-audio guard deferred — rationale in ROADMAP.) diff --git a/runbook.md b/runbook.md index 0df49a4..bf9636b 100644 --- a/runbook.md +++ b/runbook.md @@ -34,6 +34,24 @@ These take effect on the **next swap to that model**. If a swap fails after this - Status auto-refreshes every 5 s. - A swap takes 3–6 minutes depending on the model. Don't close the tab — but if you do, the swap continues; reopen and you'll re-attach to the log stream. +## matrix-bridge bot tile (optional) + +If you run the matrix-bridge bot container on a Spark, set its SSH user in **Configure Sparks** (e.g. the user that owns `~/matrix-bridge`) and a tile appears under "Always-on services" with status, Update, Restart, Stop/Start, and View logs. Status is docker-state only (no HTTP health), so a `running` badge means the container is up, not necessarily that the bot is connected. + +The **Update** button runs `git fetch && git reset --hard origin/ && docker compose up -d --build` as that SSH user. For it to reach your git remote: + +1. `~/matrix-bridge` must be a clone of the repo (not loose files). Gitignored secrets (`.env`, etc.) survive a `git reset --hard`. +2. If that user has more than one SSH key, pin the remote's key so git doesn't offer the wrong one first (a common `Permission denied (publickey)` cause). In the user's `~/.ssh/config`: + + ``` + Host + Port + IdentityFile ~/.ssh/id_ed25519 + IdentitiesOnly yes + ``` + +3. Spark Control's own package key must be authorized for that SSH user (Show Public Key → add to their `authorized_keys`) unless it's the same user Spark Control already uses for that Spark. + ## Adding a new model 1. Add an entry to `image/models.yaml`. Required fields: `display_name`, `repo`, `size_gb`, `mode` (`solo` or `cluster`), `vllm_args`. Optional but recommended: `description` (one paragraph — what the model is, what it's good for, how it differs from others; renders below the meta tags in each card), `capabilities` (tags like `[vision, reasoning, tools]`), `expected_ready_seconds`.