Files
esh-pfi-infrastructure/persistent-memory.md
T

465 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Persistent memory — eshpfi-management
_Last updated: 2026-06-20_
## Repo purpose
Reference workspace for PFI infrastructure: server inventory, canonical
Docker Compose stacks, ops playbooks, and conventions. Authoritative
copies of compose files live on the servers under
`/opt/docker/compose/<stack>/`; this repo mirrors them for version
control, editing, planning, and CI-driven deploys. **It was originally
spun up to handle the fleet backups** — keep that lens when triaging
backup/storage issues.
## Tools and conventions
Sister repos (separate gitea repos, deployed by playbooks here):
| Repo | Role | CI status |
|---|---|---|
| `vh/task-board` | MCP + web dashboard for assistant task state (port 7878) | push-to-main → CI deploys (2026-04-29) |
| `vh/vor` | Inquisitor UI sidecar (port 7879) | push-to-main → CI deploys (2026-04-29) |
| `vh/nevermore` | Twice-daily LLM-curated briefing (port 8181, replaces news-digest) | push-to-main → CI deploys (2026-04-30) |
| `vh/asset-engine` | Internal control plane over inference services (port 8200, LAN-direct) | push-to-main → CI deploys (2026-05-12) |
| `vh/althing` | Inter-agent message bus (chamber UI port 7881, forseti + agent-runner daemons, valkey IPC) | push-to-main → CI deploys (2026-05-14) |
| `vh/mead-hall` | Bifrost tool-provider sidecar (port 5173 on dev VM 10.100.10.50) | push-to-main → CI deploys (2026-05-16) |
| `vh/skaldsong` | Wizard + reader surface (port 8300, ana-docker, registry-pull pattern) | push-to-main → CI deploys (2026-05-19) |
| `vh/Worldtree` | Conversation API (corviduo-dev demo :8080 / personal :8081 / pinned :8082) — Heimdall auth, Bifrost integration. **gitea-runner builds on ana-docker** (the image-bloat source); claude-bot now ADMIN collaborator (2026-06-20) | push-to-main → CI build-and-deploy (runner on ana-docker) |
| `vh/yt-voice-clipper` | YouTube → diarized voice-clip dataset builder + audition console (irv-ml1 :8000) | push-to-main → **gitea-webhook auto-deploy** to irv-ml1 (2026-06-03) — see `docs/runbooks/ytvc-autodeploy.md` |
| `vh/arbo` | Catalog-driven ComfyUI engine (irv-ml1 :8201, comfy-dev owns engine/catalog/image) | push-to-main → gitea Actions CI (deploy-engine.sh, build-local, health-gated) now LIVE; catalog via :9009 webhook |
(`vh/volva` + Heid were re-architected from systemd daemons to Claude Code
session orchestrators 2026-06-08; their nh3-dev `.service` units were removed —
no longer deployed sidecars here. See Recent decisions.)
- **Two-layer backups** — Backrest orchestrates restic for file+DB (5
fleet repos, daily 01:00 PDT); PBS-ANA primary + PBS-NH3 DR mirror for
VM images. ana-nas is the SPOF for postgres + PBS-ANA datastore +
cross-site restic targets — see `docs/runbooks/disaster-recovery.md`
for the blast-radius matrix. **⚠️ The restic file+DB layer routes
through TWO rest-servers** (`rest-server-ana` @ ana-docker:8000 →
ana-docker/ana-ml2/esh-docker-vm/vm-esh-nas; `rest-server-nh3` @
nh3-nas:8000 → irv-ml1/nh3-docker). Both depend on their NAS's NFS
export of `/mnt/backup`. **As of 2026-06-20 `rest-server-ana` is DOWN
on a failed ana-nas NFS mount — see Current state.**
- **`pull-hf-repo.yaml`** is the canonical "get a HuggingFace
model/dataset onto ana-ml2's shared cache at
`/tank/aimodels/huggingface/`" playbook. Supports `--var repo_type=model|dataset|space`. Replaces ad-hoc `huggingface_hub.snapshot_download` patterns.
- **Worldtree admin auth — per-instance.** Each Worldtree deployment
(demo :8080, personal :8081, pinned :8082) has its own Heimdall
registry and its own bootstrap admin key. Infra-ops's stored
long-lived admin key (`key_id 61419c92`) at
`ana-docker:/opt/docker/conf/.secrets/worldtree-infra-ops-admin`
auths against **demo only**. Personal-instance admin (the
`~/.config/worldtree/personal-admin-token`, mode 600) POSTs
`/admin/keys` (mints per-project keys; takes `user_id`+`label`, **no
scope param** — scopes are tier-derived, so admin-tier scopes like
`admin.events.read` must be granted WT-side by worldtree-dev).
- **Per-project user keys against personal Worldtree** (issued
2026-05-19): `skaldsong:79744637` (nh3-dev iteration),
`skaldsong:7c1dbbbe` (ana-docker prod), `althing:50d85460`,
`mead-hall:a360822d`. Same `user_id=skaldsong` across both
skaldsong keys → shared Heimdall agent slot; different `key_id`
→ independently rotatable. Pattern: mint via `/admin/keys`, drop
value to `/tmp/wt-personal-<name>.key` mode 600, dev collects +
shreds (DO NOT cat to chat transcript).
- **Skaldsong CD pattern (registry-pull).** Differs from althing /
asset-engine which build-on-host. vh/skaldsong's CI builds and
pushes `gitea.phasefinal.com/vh/skaldsong:<sha>` + `:latest`;
`playbooks/deploy-skaldsong.yaml` on ana-docker pulls + recreates.
SHA-pin only (no `:latest` health-gated advance yet). Prereq: host
needs `docker login gitea.phasefinal.com` once (read:package PAT) —
not currently in the workflow.
- **gitea internal route for fleet hosts.** gitea is a container on
**ana-docker** — git-SSH `10.250.50.70:222`, HTTP `:3000`. Fleet/colo
hosts must use this internal route, NOT public `gitea.phasefinal.com`
(`38.120.12.44`, ana-srv1) — the public path fail2bans the host egress
IP and wedges webhook deploys. `:22` on `10.250.50.70` is ana-docker's
HOST sshd, not gitea. Full gotcha in `docs/orientation.md` → Git/gitea.
- **docker-as-root pattern** (for ops with no admin API, or to edit
deploy-owned/root-owned files without sudo): `docker run --rm -v
<target-dir>:/wt [-v /var/run/docker.sock:/var/run/docker.sock]
docker:cli sh -c "..."` (or `alpine` for plain file ops). docker-group
membership is effectively root via bind-mount; treat as sudo-equivalent.
**Foot-gun: relative paths in compose.yaml resolve against the sandbox
CWD but the Docker daemon interprets them against the HOST fs — always
pass `-e VAR=/abs/path` for any relative-default config dir.**
- **`scripts/elway` sudo handling** — elway prompts for the sudo password
ONCE via `getpass` before the first `sudo: true` step → can't run
unattended from a non-TTY tool if any step needs sudo. Sudo-free
playbooks run fully non-interactive over key SSH.
- **Per-host SSH identity matters for sudo.** infra-ops has NOPASSWD sudo
on most PFI Linux boxes (corviduo-dev included since 2026-06-15). On
ana-docker there are TWO identities: the **default `ssh ana-docker` =
`lkraven`** (docker-group, NO passwordless sudo — docker works, root-file
edits don't); **but `ssh infra-ops@ana-docker` HAS NOPASSWD root** (verified
2026-06-20). **→ For any sudo op on ana-docker (mount, root-owned files,
service control), use `ssh infra-ops@ana-docker`, NOT the default session.**
lkraven-owned files (litellm config, most stack compose/conf) still take
plain `cp`/edit under either identity.
## Current state / in-flight
_As of 2026-06-20:_
- **Worldtree capability-gateway migration — LANDED + DEPLOY TRIGGERED.**
The role→capability indirection (worldtree-dev's #257/ADR-0012 direction;
operator: NO `wt-` prefix, reuse the existing capability-alias convention)
is live on the LiteLLM gateway: `gen`/`gen-reasoning` (→qwen3.5-122-a10b),
`classifier`/`summarizer` (→granite), `chat-judge` (→selene-1-mini-8b),
`reranker` (→qwen3-reranker), `scalar-judge` (passthrough → Skywork-Reward-V2
@ ana-ml2:8003 — LiteLLM has no reward MODE), `gen-frontier`/`-reasoning`
(→GLM 5.2, PAID). **`qwen3-embedding` kept model-named ON PURPOSE** — the
swap-transparency rule: embedding vectors aren't swap-transparent, so a
generic `embedding` alias is a footgun. The `*` wildcard → dead llama-swap
was REMOVED (unknown models now 404 cleanly). WT's full re-point (granite
SPLIT into granite-classifier/granite-summarizer + role rebind + edges→gen +
selene→chat-judge) landed as worldtree-dev's commit **3fbf338 / v0.37.5**;
I staged its `providers.yaml`+`model_roles.yaml` byte-identical into
demo+personal bind-mounts and triggered build-and-deploy via claude-bot.
Pinned rides CI. (d372103, d0eb09c, 7819f96)
- **Worldtree demo → v0.37.7 GREEN (2026-06-20) — two-half fix.** worldtree-dev's
v0.37.5 config (3fbf338) carried a dangling `granite-4.1-8b` catalog ref →
demo crash-blocked at startup validation. Fix needed BOTH halves: (a) gitea
was silently not creating Actions runs so no deploy could fire (the earlier
disk-full wedged its notifier — `docker restart gitea` cleared it; see
Tried-and-abandoned); (b) the v0.37.7 IMAGE alone wouldn't fix demo because
demo+personal read BIND-MOUNTED config — I re-staged `config/providers.yaml`
+ `config/model_roles.yaml` from gitea at **439bebf** byte-identical into BOTH
`/opt/worldtree{,-personal}/config` (sha256-verified across source + both
instances; `granite-4.1-8b``summarizer`, `granite-classifier/summarizer`
`classifier/summarizer`; old configs saved `.bak-pre-439bebf`; NO container
recreate — avoided the stale-`:latest` footgun). worldtree-dev self-served the
CI re-run via the claude-bot Actions token → **run 1290 GREEN, demo on
v0.37.7**, capability routing live. claude-bot token migration DONE for
worldtree-dev (off vh's personal PAT). **RATATOSKR → READONLY (2026-06-20, final):**
operator first said admin (worldtree-dev minted interim `ratatoskr-admin` 90db1fbd),
then flipped to least-privilege → that key REVOKED (DELETE 200). I re-staged 439bebf's
`config/policies.yaml` to `/opt/worldtree-personal/config` (byte-identical, sha256
f3ca3e6…, `.bak-pre-439bebf`) and reloaded Heimdall via `docker restart
worldtree-personal-worldtree-api-1` (same d2e9f05 SHA — the SAFE reload, no recreate/
no `:latest` flip); personal came back healthy + the `readonly-admin` tier (7 read
scopes incl. admin.events.read) is now in the loaded policy. **FOLLOW-UP cb2a79a
(v0.37.9):** the 439bebf tier-only stage was NOT sufficient — WT's PDP is RULE-based,
so a tier with scopes but NO allow RULES is default-denied; cb2a79a adds the 4
readonly-admin allow rules. Re-staged cb2a79a `config/policies.yaml` to BOTH demo +
personal (sha256 d853e51…, `.bak-pre-cb2a79a`) + restarted BOTH API containers
(`worldtree-worldtree-api-1` + `…-personal-…`); both healthy + serving. (Still on
d2e9f05 image — CI cb2a79a deploy pending, but the bind-mount policy is the
load-bearing fix.) worldtree-dev mints the ratatoskr readonly key via their admin key.
**Lessons: (1) reload bind-mounted WT config via `docker restart <container>`, NEVER
`compose up` (the `:latest` footgun); (2) a WT tier needs allow RULES, not just
scopes — the PDP is rule-based, scopes alone default-deny.**
- **🟠 BACKUP DIAGNOSIS (2026-06-20, full probe) — REVISED from "all ana
backups down": PBS + nh3-restic are HEALTHY & CURRENT; only the ANA-side
restic file+DB layer is dead, and the one host with NO other cover is
ana-ml2.** Three layers:
-**PBS-ANA (VM images)** — healthy, snapshots TODAY. All PFI guests
backed up under PBS namespaces `ana-pve` / `esh-pve` / `nh3-pve` (+ tenant
`sfsrv-pve`); PBS-ANA's own NFS datastore mounts ana-nas fine (1.2T/20T).
Gaps to note: `ana-pve/vm/100` has no snapshots; **there is NO `esh-pve-nas`
PBS namespace** → vm-esh-nas + esh-vm-db may be PBS-UNCOVERED (VERIFY).
-**restic file+DB nh3-side** (`rest-server-nh3` @ nh3-nas:8000, UP→401) —
irv-ml1 + nh3-docker, last snapshot TODAY 01:00. Repos at
`nh3-nas:/volume1/Backup/restic/{irv-ml1,nh3-docker}`.
- 🔴 **restic file+DB ANA-side** (`rest-server-ana` @ ana-docker:8000) — DOWN,
crash-looping. Last successful snapshot **2026-05-06 (~6.5 weeks)** across
ALL 5 clients (ana-docker, ana-ml2, esh-docker-vm, esh-vm-db, vm-esh-nas).
- **Scheduler:** NOT Backrest (it has **0 plans** — it's just a repo viewer).
Backups run via **`resticprofile` systemd timers** (`resticprofile-backup@
profile-default.timer`, daily 01:00; `…-check@…` Sun 05:00). The ana timer
fires daily and **FAILS SILENTLY** (no alerting → why the gap went unnoticed
6.5 wks).
**Root cause:** ana-nas NFS fstab bare-`defaults` (no `_netdev`/retry) →
`mnt-backup.mount` stuck `failed` → rest-server-ana's bind source
`/mnt/backup/restic/repo/ana` resolves to an empty LOCAL ghost dir (no
`.htpasswd`) → crash-loop (`cannot load /data/.htpasswd: permission denied`).
The REAL repos + `.htpasswd` are intact on ana-nas at
`/mnt/backup/restic/repo/ana/{<client>/,.htpasswd}`. ana-nas itself is FINE.
**Real exposure, ranked:** (1) 🔴 **ana-ml2** — BARE METAL, no PBS coverage;
ana-side restic is its ONLY layer → ~6.5 wks fully unprotected (bespoke
at-risk: in-house NVFP4 quants / configs / scripts; bulk `/tank` models are
re-downloadable). (2) 🟠 **esh-vm-db** (a DB VM: postgres+mongo) + vm-esh-nas
IF PBS-uncovered (verify the esh-pve-nas gap). (3) 🟡 **ana-docker /
esh-docker-vm** — VMs, PBS image-CURRENT today, only the granular restic
layer is stale (full-VM restore available; no recent file/DB-granular point).
**RECOVERY (needs root on ana-docker; the session there = `lkraven`, NO
NOPASSWD sudo → operator `!`-sudo or bootstrap infra-ops there):** `sudo
mount -a``sudo docker restart rest-server` (recreate if the bind doesn't
re-resolve onto the NFS; if the ghost persists: stop container → umount → rm
the ghost `repo/ana` → remount → start) → verify → next 01:00 succeeds.
**PREVENTION (the systemic fixes):** fstab `_netdev`+retry so it self-heals
on reboot; a **backup-freshness alert** (the real miss — 6.5 wks unnoticed).
Recovery steps mirror `docs/runbooks/disaster-recovery.md` Tier-0.
**⚠️ Disclosed creds:** diagnosing dumped the Backrest config, exposing the 5
per-repo rest-server basic-auth passwords into the session transcript →
rotate after recovery (add to the disclosed-keys rotation queue).
**✅ RECOVERED (2026-06-20):** via `ssh infra-ops@ana-docker` (NOT the default
lkraven session) — `sudo mount -a` + `reset-failed mnt-backup.mount` re-attached
the NFS, then `docker compose up -d --force-recreate` rebound rest-server onto
the real `/data` (now `Loaded htpasswd file`, 401, healthy). Verified end-to-end:
triggered backups on the two no-PBS hosts' priority — **ana-ml2 snapshot landed
22:53Z** (total 19→20); ana-docker's larger catch-up was still running at hand-off
(will land). esh-docker-vm/esh-vm-db/vm-esh-nas auto-catch-up at their next 01:00
timers (or trigger manually). **Full topology + 2-min freshness-check now documented
in `docs/runbooks/backups.md`.** **PREVENTION DONE (2026-06-20):** (1) freshness
alert — `scripts/check-backup-freshness.sh` + daily systemd user timer on nh3-dev
(08:00) → althing alert to infra-ops on any stale/down layer (proven end-to-end);
(2) fstab hardened — ana-docker `/mnt/backup``noauto,x-systemd.automount,…`
(autofs self-heals, active next boot; `.bak-pre-harden` saved); (3) esh-pve-nas
VERIFIED **not** PBS-covered → esh-vm-db (a DB!) + vm-esh-nas are restic-only.
`/mnt/compose` ALSO hardened + automount activated live (2026-06-20, binds no
container — proved the autofs pattern works on ana-docker). STILL OPEN: rotate the
5 rest-server creds (operator, offline); the 3 esh + ana-docker restic clients
clear at tonight's 01:00.
- **ana-docker disk incident RESOLVED — root cause was a 94 GB unrotated
`langfuse-clickhouse` log, NOT (just) image bloat.** ClickHouse logs
verbosely to stdout + there was NO log rotation anywhere (no per-stack
`logging:`, no daemon default) → its json.log hit ~94 GB and filled `/`
(100%, 28/48 containers unhealthy on `runc /tmp ENOSPC`). Fixed: truncated
the log, pruned ~101 GB of images (the gitea-runner accumulated 18
worldtree build versions), retired Langfuse. Disk → ~51%. Installed a
daily image+buildx prune cron (`lkraven` crontab on ana-docker). **DEFERRED
to clean context:** a **docker-daemon default log cap** (`daemon.json`
log-opts + docker restart, needs root → infra-ops) — the real systemic fix
so no container can ever spew unbounded again. (Note: named buildx-builder
state volumes aren't cleared by `docker image/builder prune` — orphaned
ones need `docker volume rm`.)
- **Langfuse RETIRED (2026-06-20, operator).** Redundant with LiteLLM's
native logging (`store_prompts_in_spend_logs: true` → full prompts/
responses/tokens/cost at `:4000/ui`); nothing used its trace-grouping/eval
features; and it's a 6-container crash-prone surface (the 94 GB spew).
Dropped the `success_callback`/`failure_callback: [langfuse]` from the
litellm config (gateway observability stays native) and `compose down -v`
the stack. (f8eda1c)
- **OmniVoice gained a streaming `/tts` + language-safe sanitizer** (irv-ml1
:8199, `stacks/omnivoice/`), driven by a VENDORED copy of chatterbox-fast's
buffer-ratchet scheduler. KEY FINDING: OmniVoice is DIFFUSION → a ~fixed
per-call overhead sets a TTFA FLOOR (~0.7 s @16 steps), and measured RTF is
~2.8×/5.6× on the 3090 (NOT the upstream-claimed 40×). Tuned: streaming
num_step=16/batch 32, rtf_prior=20. **chatterbox-fast (autoregressive,
~0.5 s TTFA) stays the lower-latency front-end** — OmniVoice is the
multilingual/voice-design complement, NOT a replacement. (288d085, cd92b85;
auto-memory `reference_omnivoice_streaming_tts`)
- **arbo v0.14.9 deployed** (muse prompt-enhance → `summarizer-large`, was
granite which mode-collapsed at temp 1.0) via the canonical health-gated
`scripts/deploy-engine.sh` on irv-ml1. arbo's gitea Actions CI is now LIVE
(runner-label mismatch fixed by comfy-dev) → future src pushes auto-deploy;
manual deploy only when CI is down. (auto-memory `reference_arbo_engine_deploy`)
- **ratatoskr `:8392` (composite Bifrost provider) added** to the personal
WT `BIFROST_CLIENT_ALLOWED_HOSTS` (footgun-safe recreate: inline sha pin +
`--pull never`, the `.env` still pins stale `:latest`). And ratatoskr's
**admin.events.read key (ratatoskr#11) BROKERED** with worldtree-dev — the
scope is tier-derived (not mint-settable), so worldtree-dev defines the
isolated admin-tier user/scope, then I mint + secure-deliver. NON-URGENT.
- **claude-bot granted ADMIN on vh/Worldtree** (2026-06-20, via operator
vh-admin → migration-enabler) so I can self-serve WT deploy re-runs +
provision worldtree-dev's own Actions token (pending their gitea username).
- **arbo + brokkr litellm keys = `all-proxy-models`** (verified — full gateway
access incl. paid GLM, no key change needed). `all-agents-local` shared key
stays fenced to free local models only. claude-bot Gitea service account is
the credential-migration foundation (admin on vh/arbo + now vh/Worldtree).
- **Worldtree config-propagation:** demo+personal bind-mount their
`model_roles.yaml`/`providers.yaml` (`/opt/worldtree{,-personal}/config`,
infra-ops-deployable); **pinned is IN-IMAGE** (worldtree-dev CI bakes it).
worldtree-dev authors the canonical config; infra-ops deploys to the
bind-mounted instances byte-identical.
- **Still open from prior:** Mac Pro migration (`migration-plan.md`,
workstation-only, hardware-gated); R17 v2 corpus push HELD (local-only
soundgasm-derived, distribution barred); disclosed-keys hygiene rotation
queue; clean legacy `news-digest` on ana-docker.
## Recent decisions
- `[2026-06-20]` **claude-bot issue-scope token minted for worldtree-dev self-serve**
(closes their last `tea`-as-vh fallback — issues; they already self-serve Actions +
deploys). Gitea PAT scopes are IMMUTABLE → minted a NEW claude-bot PAT
`worldtree-dev-actions-issues-20260621` (id 16) with `write:repository`+`write:issue`
via basic-auth (`claude-bot:gitea-password`, POST `/users/claude-bot/tokens`); dropped
mode-600 `~/.claude-bot-token-issues` → worldtree-dev swaps. **Gitea COLLAPSES
`read:issue` into `write:issue`** (write implies read) so the granted set shows
write-only but read IS satisfied (GET issues → 200). Old token (id 15,
worldtree-dev-actions-20260620) REVOKED (DELETE 204) after worldtree-dev verified
read+write end-to-end via `core.issues` (show/list/comment on #311) → claude-bot now
carries ONE consolidated worldtree-dev token (id 16) + arbo-ci (id 14), no stale dups.
Advances the credential-migration directive (worldtree-dev fully self-serve: Actions +
deploys + issues on one token). ALSO this session: re-staged cb2a79a `policies.yaml` (readonly-admin allow
rules) to demo+personal (see Current-state ratatoskr entry).
- `[2026-06-20]` **rest-server-ana recovered + backup prevention shipped + worldtree-dev
admin keys provisioned** (operator-directed). rest-server-ana fixed (mount-a +
force-recreate via `infra-ops@ana-docker`); freshness alert + fstab hardening landed
(see Current-state BACKUP entry + `docs/runbooks/backups.md`). Minted worldtree-dev
**admin-tier Heimdall keys** on demo (key_id d113207c) + personal (f4f75adb) via
`POST /admin/keys {tier:admin}` + `POST /admin/users/worldtree-dev/tier`, verified
read+write, dropped mode-600 to `~/.wt-admin-{demo,personal}` on nh3-dev → worldtree-dev
now self-serves key minting (cuts infra-ops out of the per-key loop, like the
claude-bot gitea token). Cred rotation (5 rest-server pw) BELAYED per operator.
- `[2026-06-20]` **Worldtree capability-gateway aliases stood up; NO `wt-`
prefix (operator) — reuse the existing capability convention.** gen/
gen-reasoning/classifier/summarizer/chat-judge/reranker/scalar-judge
(passthrough)/gen-frontier/-reasoning. The **swap-transparency rule**:
embedding stays model-named (`qwen3-embedding`) because vectors aren't
swap-transparent; everything else can swap behind a stable alias. (d372103,
7819f96)
- `[2026-06-20]` **Removed the litellm `*` wildcard → llama-swap** (operator;
llama-swap decommissioned, :9292 confirmed down). Unknown/typo'd models now
404 cleanly instead of a misleading "Connection error" — closes the
long-standing footgun. (d0eb09c)
- `[2026-06-20]` **Langfuse retired** (operator) — redundant with LiteLLM
native spend_logs + a 6-container crash-prone surface (the 94 GB clickhouse
spew). Callbacks dropped, stack torn down. (f8eda1c)
- `[2026-06-20]` **OmniVoice streaming `/tts` — vendor chatterbox-fast's
scheduler, not its whole package** (operator-approved vendor-copy). Diffusion
TTFA floor finding → tuned 16-step streaming + aggressive packing; chatterbox-
fast remains the lowest-latency front-end. (288d085, cd92b85)
- `[2026-06-20]` **claude-bot → ADMIN on vh/Worldtree** (operator-authorized;
one-time use of operator vh-admin to enable the migration) — claude-bot
self-serves WT deploys/tokens henceforth, reducing personal-cred fallbacks.
- `[2026-06-20]` **Daily image+buildx prune cron on ana-docker** (the missing
automation behind the recurring image bloat) — `lkraven` crontab, prune
unused images >48 h + per-builder buildx cache. The real systemic fix
(daemon log cap) is deferred to clean context.
- `[2026-06-19]` **litellm task-aliases: `classifier`→granite-4.1-8b, `summarizer-large`→gen/qwopus** (`summarizer`→granite already existed). Also added then REMOVED `gen-nt`/`gen-reasoning-nt` (redundant with the global `strip_empty_tools` hook). (ef45f6d, 2e5ab72, 75bd4c3)
- `[2026-06-19]` **gateway-chat: model-smoking web chat → PERSISTENT container.** `/v1/models` auto-discovery + image-upload; `stacks/gateway-chat/` (nginx:alpine, ana-docker:8091, homepage tile). (4c40b9f, 740bcae)
- `[2026-06-19]` **pi on nh3-dev wired to `gen`**`~/.pi/agent/models.json` + a `gen` launcher mirroring `glm`. Local box config, not a repo artifact. (untracked by operator choice)
- `[2026-06-19]` **`gen` model → Qwopus3.5-122B-A10B (vision-intact NVFP4), full 256K @ fp8.** ana-ml2 GPU 0, served-name `qwen3.5-122-a10b`. STABLE vLLM + fp8 KV reaches 262144 — nightly+turboquant-4bit-KV was UNNECESSARY. 92.7 tok/s warm. (20e796c, 5b06514)
- `[2026-06-19]` **TP=2 across the two ana-ml2 Blackwells REJECTED**`PIX` (PCIe, NO NVLink) → all-reduce-bound → SLOWER. One-model-per-card is optimal; PP=2 only if a >96 GB model is ever wanted. (untracked by operator choice)
- `[2026-06-19]` **qwen-image-bench (T2I judge, NVFP4) replaced qwen3.6-35b-a3b on GPU 1**, aliased `image-judge`. (bfae924, 5dfce04)
- `[2026-06-18]` **heretic abliterated Mistral Small 4 NVFP4 built + LIVE as `mistral-small-4`** (in-house NVFP4, drop-in stack, A/B'd vs official, "heretic stays"). DISPLACED from GPU 0 on 2026-06-19 for the gen/Qwopus swap. (dd3a5c9, f566f61, `tools/mistral-small4-nvfp4/`)
- `[2026-06-18]` **irv-ml1 VRAM consolidation + comfy-dev torch-pin** — ComfyUI pinned to the A6000 (48 GB), audio zoo → 3090; `DISABLE_UPGRADES=true` @ torch 2.12.1. (a8550ad)
- `[2026-06-18]` **ComfyUI acceleration set (9 nodes) installed for comfy-dev** on irv-ml1.
- `[2026-06-17]` **ana-ml2 `vm.overcommit_memory=1` made durable** (sysctl drop-in) — overcommit=0 + zero swap caps CommitLimit; large model-file mmap ENOMEM'd despite ~393 GB free. (fc88eff)
- `[2026-06-17]` **GLM 5.2 wired into litellm** (`glm-5.2` + `-reasoning`, z.ai passthrough, `extra_body.thinking.type` toggle). (fe77a35)
- `[2026-06-17]` **nh3-extdev stood up as a sudo-LESS infra-ops manager box** (successor to nh3-ansible); hosts `/opt/externs` pi-on-GLM-5.2 client workspaces. (a841eab)
- `[2026-06-14]` **STANDING DIRECTIVE: migrate ALL infra access to Claude-specific credentials.** Stand up service accounts (claude-bot Gitea user + scoped tokens, distinct litellm admin key); re-mint consumer creds under them; flag personal-cred fallbacks until done. (auto-memory `project_migrate_infra_access_to_claude_credentials`)
_101 older entries archived to archival-memory.md._
## Tried and abandoned
- `[2026-06-20]` **A full disk wedges gitea's Actions notifier SILENTLY — and it
STAYS wedged after disk recovers; only a `docker restart gitea` clears it.** After
the 94 GB clickhouse disk-full event, gitea stopped CREATING workflow runs on push
(push succeeds, ref lands, but NO run spawns — newest run stale, queue empty), while
the act_runner stayed registered. NOT run-pickup, NOT disk-now (52% free), NO gitea
errors/panics — a silent notifier stall. Hit BOTH vh/arbo (comfy-dev) and vh/Worldtree
(worldtree-dev's deploys) → it's global, not repo-specific. Fix: `docker restart gitea`
on ana-docker (it had been up 2 weeks, never bounced). A restart does NOT retroactively
fire pushes made during the outage — re-push/re-trigger after. Reinforces the deferred
docker-daemon-default log-cap fix (the disk-full that started it can't be allowed to recur).
- `[2026-06-20]` **Mistral-Medium-3.5-128B NVFP4 (RecViking) on ana-ml2 GPU 0 —
ABANDONED, too slow (operator confirmed).** Stood up as a temporary speed-check
displacing mistral-small-4; measured base **~19.2 tok/s** decode on one Blackwell
(vs `gen`/Qwopus3.5-122B ~92.7 tok/s warm) → confirmed the operator's "too slow"
suspicion. KEEP these serving findings: (1) vLLM **nightly** loads the HF-format
NVFP4 weights DIRECTLY — no Mistral native-convert (unlike Small 4, same `mistral3`
arch) — via the FlashInfer Cutlass NVFP4 kernel + `turboquant_4bit_nc` KV; TP=1
fits the ~70 GB NVFP4 on one 96 GB Blackwell. (2) **EAGLE was a dead end**: the
official native FP8 head (`mistralai/Mistral-Medium-3.5-128B-EAGLE`) crashes in
CUDA-graph replay with graphs on, and nets NO speedup with `--enforce-eager`
(~18.5 vs ~19.2 base) — likely low draft acceptance against the NVFP4
(non-official-FP8) base. Untracked workspace files (`stacks/mistral-medium-3.5/` +
`playbooks/serve-mistral-medium-3.5.yaml`) removed. ⚠️ Weights still staged on
ana-ml2 `/tank/aimodels/mistral-medium-3.5-{nvfp4,eagle}` (~70 GB+) — pending
operator OK to free.
- `[2026-06-20]` **A 94 GB unrotated `langfuse-clickhouse` json.log was the
REAL disk-filler (not image bloat) — there was NO log rotation anywhere.**
No per-stack `logging:` limit and no docker-daemon default → ClickHouse's
verbose stdout grew unbounded to ~94 GB and filled ana-docker's `/`
(healthchecks then failed fleet-wide on `runc /tmp: no space left`). Lesson:
on a full disk, the symptom (all-unhealthy) is the FORK-can't-write
healthcheck, not the containers; find the runaway via per-container-dir `du`,
not `docker system df`. The systemic fix is a daemon-default `log-opts`
(`max-size`/`max-file`) — NOT just per-service patching.
- `[2026-06-20]` **OmniVoice's upstream "RTF 0.025 / 40×" does NOT hold —
diffusion has a ~fixed per-call overhead → TTFA floor + multi-chunk
streaming is a net loss.** Measured ~2.8× (32-step) / 5.6× (16-step) on the
3090; every chunk costs ~the same regardless of length, so naive
per-sentence streaming triples total gen time + starves. Use few/aggressive
chunks; chatterbox-fast (autoregressive) stays the low-TTFA front-end.
- `[2026-06-20]` **rest-server `.htpasswd: permission denied` = the ana-nas
NFS mount FAILED (ghost file on the local mount point), NOT a decommission.**
`mnt-backup.mount` stuck `failed` (fstab bare `defaults`, no retry) → the
rest-server serves an empty local dir with a root:root 0-byte `.htpasswd`.
Documented recovery in disaster-recovery.md. Don't tear down what looks like
a crash-looping legacy container until you've checked fstab + the docs — it
was the live ana-side restic target.
- `[2026-06-20]` **Named buildx builders accumulate cache the standard prunes
MISS.** `docker image prune -a` + `docker builder prune` don't touch
`buildx_buildkit_<name>-builder0_state` volumes (per-builder buildkit
state). Prune them with `docker buildx prune --builder <name> -af`, or
`docker volume rm` orphaned ones (builder already removed).
- `[2026-06-20]` **The DEFAULT `ssh ana-docker` is `lkraven` (no NOPASSWD) —
but `ssh infra-ops@ana-docker` HAS NOPASSWD root** (corrected later same day).
Early on a `sudo cp` as lkraven silently failed (password prompt) → one
wasted gateway bounce; I then wrongly concluded "no sudo on ana-docker" and
nearly punted the rest-server-ana recovery to the operator. The real rule:
reach for `infra-ops@ana-docker` for sudo ops; lkraven-owned files (litellm
config, most stack compose/conf) take plain `cp` under either identity.
- `[2026-06-19]` **litellm CONFIG-loaded models can't be hot-removed — `/model/delete` is DB-only.** Only a process restart drops a config model. The INVERSE works: `/model/new` live-ADDS (no bounce) but dups with config on restart. Clean no-bounce-add: live-add via API, delete the DB copy before the eventual bounce.
- `[2026-06-19]` **the litellm `*` wildcard routed to DECOMMISSIONED llama-swap → a stale/typo'd model name returned a misleading `Connection error`, not `model not found`.** Bit a brokkr call to the renamed `qwen-image-judge`. **→ RESOLVED 2026-06-20: wildcard removed (d0eb09c) — unknown models now 404 cleanly.**
- `[2026-06-19]` **A MoE card can't be filled to 0 bytes free — the FusedMoE transient workspace (~3.09 GB) is the floor**, allocated OUTSIDE `gpu-memory-utilization`. FIX: `PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True` + leave ~3.2 GB free (util ≤ ~0.95 on a tight MoE).
- `[2026-06-19]` **vLLM decode tok/s: ALWAYS discard the first generation (cold warmup).** Cold ≈ 24.8 tok/s vs warm 92.7 — a cold read undersells decode ~34×. Measure run 2+ over a ≥256-token output.
- `[2026-06-19]` **For full native 256K on one 96 GB card, nightly+turboquant-4bit-KV was unnecessary for the Qwopus MoE.** Stable fp8 KV already fits 262144 (hybrid SSM+attn caches KV only on attn layers → small pool). Reach for fp8 first.
- `[2026-06-18]` **mmartial `comfyui-nvidia-docker`: root pip installs CRASH-LOOP the container.** `docker exec -u 0 pip install` leaves root-owned files in the uid-1000 venv → the boot script (uid 1000) fails its torch step → crash loop. FIX: `chown -R 1000:1000 /comfy/mnt/venv`; pin with `DISABLE_UPGRADES=true`. (auto-memory `reference_irv_ml1_comfyui_mmartial`)
- `[2026-06-18]` **ComfyUI custom nodes break on version-assumption drift** — box runs 0.24.1; TeaCache imports `precompute_freqs_cis` at MODULE level (guard the LTX-only import). `pip install tensorrt` defaults to cu13 → use `tensorrt-cu12`.
- `[2026-06-17]` **Mistral HF→NVFP4 quant: the placement knob is the whole game.** `device_map="cpu"` (CPU-resident, sequential onload) works; `"auto"` OOMs, `max_memory` offloads to meta. Read shards with plain `read()` + `safetensors.torch.load(bytes)`, NOT `safe_open` (mmaps the 50 GB shard → ENOMEM on `/tank` ZFS).
- `[2026-06-17]` **HF-format Mistral Small 4 is UNSERVEABLE on vLLM** — no HF `Mistral4` backbone; serves ONLY via the native loader. A HF-format quant MUST be converted to native first.
_84 older entries archived to archival-memory.md._