Dark-Scarlett v1.0 refuses too much on the char-rp-reasoning seat. Root
cause is visible on its card: ReadyArt/Dark-Scarlett-v1.0-27B is a plain
finetune of stock Qwen/Qwen3.6-27B, tagged unaligned/nsfw/erp but carrying
no abliteration -- the base model's refusal machinery is intact, so
off-distribution prompts revert to safety-tuned Qwen3.6 behaviour.
Candidate kkuspa/Qwen3.6-27B-Fable-Fusion-711-...-NVFP4A16 is refusal-ablated
(Heretic), a structural edit rather than a behavioural preference. Verified
before pulling: Qwen3_5ForConditionalGeneration wrapper class, 15 mtp.*
tensors in a separate bf16 shard AND individually enumerated in
quantization_config.ignore, NVFP4A16 with null input_activations, FP8 KV
scales shipped, 262K context, Apache-2.0. Staged byte-verified at
/tank/aimodels/fable-fusion-711-nvfp4a16 (28.55 GB).
services/refusal-probe: deterministic marker-based classifier (LLM judge
only breaks AMBIGUOUS ties, never overrides), intensity-graded battery so
the report renders a refusal curve rather than an average, benign controls
that gate run validity, and explicit handling of the thinking-budget trap
-- empty content with finish_reason=length is reasoning exhausting the
budget, not a refusal, and is excluded from the denominator.
stacks/fablefusion-charrp-probe: throwaway :8019 seat serving as
char-rp-probe, never aliased to char-rp-reasoning. MTP depth 3 rather than
the card's 5 -- its 1.56x was measured greedy, and acceptance degrades at
the temp 1.0 this seat is probed at. GPU1 is zero-sum at 94.9/97.9 GB, so
this seat takes Dark-Scarlett's vacated slot; the A/B is sequential.
Quants are hard-fought and we keep re-paying for the same lessons. A survey
found quant knowledge scattered across 18 files in four trees, with three
documents having independently discovered and recorded overlapping
"landmines" sections — and one of them now actively misleading.
Adds docs/pfi/model-quantization-playbook.md as the single home for the
TRANSFERABLE lessons, with per-model artifacts demoted to worked examples
that link up to it. Contents:
- scheme decision table, incl. that a literal "W4A8" NVFP4 checkpoint is
unservable on vLLM (two legal activation settings, FP8 is not one)
- the reference mixed-precision recipe and the three parts of it that are
load-bearing and easy to drop
- the recurring landmines, ordered by cost: the loader-class trap
(rediscovered THREE times), the three separate ways to lose the MTP head,
toolchain deadlocks, vision configs, memory/device placement
- pipeline shape: prove targets before spending GPU time; mandatory
post-steps that verify rather than assume
- the acceptance gate, and the three ways measurement has lied to us —
prefix caching faking both speed metrics, prompt_logprobs going uniform
under speculative decoding, and a 0600 .env making compose silently no-op
- hardware/co-residency, including that a SMALLER model can starve its
neighbour because gpu-memory-utilization is a fraction of the whole card
- a superseded-claims table, and measured negatives not to re-chase
The superseded table earns its place immediately: the heretic2 runbook tells
readers to use modelopt because "compressed-tensors can't load the BF16 MTP
head, 0% acceptance". That symptom was real but the cause was not the format
-- it was the missing re:^mtp.* ignore entry. compressed-tensors gives
47.7-83.2% acceptance in production. A fresh session following that doc would
be sent down the modelopt path that current memory calls dependency hell, so
the runbook now carries a stale-warning header pointing here.
Wires discovery: an orientation.md "Where to look for what" row, pointers
from the gen-seat / heretic2 / mistral artifacts, and a CLAUDE.md maintenance
rule so the playbook gets fed instead of going stale -- model-agnostic
lessons land in the playbook, model-specific ones stay put, and a wrong
claim earns a dated superseded row rather than a silent edit.
Motivated by Qwen3.8 having just released: the next model swap will need a
requant, and this is what that session should read first.
Closes the one axis of the original premise left unverified. Measured
cold (cache-busted) on both builds under matching serve configs:
~6.7k-token prompt 3,206 -> 6,334 tok/s prefill (+98%)
~27k-token prompt 2,862 -> 5,085 tok/s prefill (+78%)
TTFT on a ~27k doc 9.43 -> 5.31 s (-44%)
Prefill gains far exceed the +18% decode gain, and that ordering is the
expected one: decode at bs=1 is memory-bandwidth-bound and the weights
are 4-bit under either scheme, so little changes; prefill is
compute-bound, which is where native Blackwell FP4 tensor cores replace
the Marlin dequant-to-BF16 path. The summarizer aliases are the
consumers that feel this.
Adds bench/prefill_bench.py plus the raw JSON. The harness deliberately
uses SystemRandom: a seeded nonce regenerates the previous run's prompts
verbatim, prefix caching then serves them, and the first attempt read
~41k tok/s of cache-hit rather than ~5k of actual prefill.
Re-quantizes the fleet `gen` seat from weight-only NVFP4A16 to a
mixed-precision build: NVFP4 W4A4 for layers 0-55 MLPs, FP8 W8A8 for the
attention projections / linear_attn / lm_head / layers 56-63 MLPs, FP8 KV
cache. Replicates the scheme of unsloth/Qwen3.8-27B-NVFP4 on the
abliterated weights.
The queued task named this "W4A8" (NVFP4 weights + FP8 activations). That
checkpoint cannot be served: vLLM 0.24's compressed-tensors dispatcher
(compressed_tensors.py:704-713) accepts NVFP4 weights with either no input
quantization (W4A16, which forces the Marlin kernel) or NVFP4 input
quantization (W4A4) -- anything else, FP8 included, raises ValueError at
load. CompressedTensorsW4A8Fp8 is INT4 weights gated on an exact-sm90
check, so it is closed on Blackwell twice over. The ~20% intuition was
correct; the scheme name was not. Getting FP8 into the mix has to be done
per-layer-group.
Established the gain before spending GPU time: unsloth's build was already
on-box, so serving it as a probe measured +19.1% over our seat at identical
MTP acceptance -- a kernel-level result, no requant needed to learn it.
Measured, cache-busted, bs=1:
decode 80.12 -> 94.53 tok/s (+18.0%)
MTP acceptance 47.8% -> 47.7% (unchanged)
perplexity (n=6) 6.941 -> 7.059 (+1.7%)
abliteration 4/4 -> 4/4 (preserved)
weights on disk 27.7 -> 22.5 GB (-19%)
Surface test green on the live seat: plain chat, vision, tool calling,
thinking split, 36K-token needle retrieval, streaming. All 7 LiteLLM
aliases verified routing.
GEN_GPU_MEM_UTIL 0.45 -> 0.43: the new weights are 5.2 GB smaller, and at
0.45 the seat absorbed that slack as KV, leaving meromero-charrp 0.18 GiB
short of its budget on the shared GPU0 -- it crash-looped. Handing the
space back leaves gen 422K tokens of KV (1.6x its 262K context) and both
seats co-resident at 89.8/97.9 GB.
Also records two measured negatives so they are not re-chased:
GEN_SPEC_TOKENS is already optimal at 3 (swept 2/3/4/5 -> 77.1/80.1/78.7/
75.9 tok/s), and vLLM's prompt_logprobs are ~uniform while speculative
decoding is on, so perplexity must be measured with spec off.
Pipeline, acceptance harness and raw measurements land in
services/gen-seat-mixed-quant/. Rollback is one .env line; the previous
build is untouched at /tank/aimodels/qwen38-27b-uncensored-nvfp4.
The char-rp seat shipped with no tool-call parser at all, so every
tools-bearing request was rejected outright:
400 "auto" tool choice requires --enable-auto-tool-choice and
--tool-call-parser to be set
MeroMero-v2 is Gemma-4, which emits its own native
`<|tool_call>call:name{...}<tool_call|>` syntax rather than the
qwen3_coder XML the Qwen-family seats use. vLLM 0.24 ships a matching
`gemma4` parser whose TOOL_CALL_START/END, CHANNEL_START/END and escape
token constants line up with this tokenizer's etc/eoc/escape tokens
exactly.
Three flags, and they are a set:
- --tool-call-parser gemma4 + --enable-auto-tool-choice: the fix proper.
- --reasoning-parser gemma4: without it the post-tool-response turn
leaks a literal `<|channel>thought\n<channel|>` prefix into content
(upstream vllm #45834 — the chat template leaves the prompt inside an
open channel block).
- --default-chat-template-kwargs '{"enable_thinking": false}': MANDATORY
companion to the reasoning parser. The parser reads enable_thinking
from chat_template_kwargs and defaults it to True
(vllm/parser/gemma4.py:439); True makes is_reasoning_end() return
False at a new turn, pre-initialising the engine to REASONING, which
routes ALL plain RP prose into reasoning_content and returns a null
content — breaking every char-rp consumer. This template already
defaults enable_thinking to false (chat_template.jinja:350), so
passing it explicitly renders a byte-identical prompt (verified across
plain / tools / post-tool-response / system-prompt shapes). It changes
generation not at all; it only corrects the parser state machine.
Verified green on the live seat after deploy: tool call streaming and
non-streaming, tool-result round-trip (leak gone), plain prose in
content with reasoning null, vision unchanged.
A booth of a dozen webms fetched them all at page load
(preload=metadata still pulls real byte ranges per file); nothing
loads now until the viewer hits play.
Operator-directed (Vuong 2026-08-13): migrated stonehenge-park off the nh3-docker
beta deployment to a permanent fixture on ana-docker (10.250.50.70) before the
v1.0.0 final cut. SQLite (park-data) migrated consistently (stop -> tar-copy ->
start; byte-identical). restic auto-covered by ana-docker's /var/lib/docker/volumes
source. Stable name park.phasefinal.com -> 10.250.50.70 (Cloudflare DNS-only) so
clients decouple from the host IP. Homepage tile 'The Henge' added. nh3-docker stack
left stopped as rollback pending park-dev cutover verification.
Operator-facing voice mint/audition/keeper-mark front-end (tts-dev), sited next
to The Booth in Apps — LAN/WG-internal, no auth. siteMonitor on /health verified
reachable from the homepage host (esh-docker-vm). Deployed via rsync.
New self-contained stack (FastAPI + SQLite + in-process scheduler) from
vh/stonehenge-park tag v1.0.0-beta.1, deployed to nh3-docker per park-dev's
operator-approved request. Port 8420, LAN/WG-internal; park-data volume (SQLite
sole source of truth) covered by the host's /var/lib/docker/volumes restic source.
Image built locally (no registry yet); .env carries PARK_API_KEY from the vault.
althing push to henge-crow deferred (PARK_ALTHING_CHANNEL empty) until althing-cli
is wired into the container.
The TTS path was hardwired to the parked zonos-gateway: it force-reverted the
endpoint field back to zonos :8890 on load, hardcoded model=ext-tts, and decoded
the response as Zonos-specific raw float32 PCM @ 44.1kHz. Result: quoted-text TTS
was dead once zonos was parked, and pointing the field elsewhere silently failed.
- Honor the interface: set endpoint/model/voice defaults only when a field is
empty; never rewrite a user-typed value (removed the zonos auto-revert regex).
- Add a TTS model field (ttsModel); send the UI's model instead of hardcoding.
- Playback: request standard OpenAI /v1/audio/speech mp3 and decode via
audioCtx.decodeAudioData (handles wav/mp3/ogg/flac from any endpoint).
- Defaults: endpoint = LiteLLM ext-tts alias (fleet TTS gateway), voice = nova.
wgtunnel deployed + accepted end-to-end (tunnel-dev): erebe/wstunnel v10.6.2 behind
traefik on ana-docker, Host boring.phasefinal.com (Mode A anaprod cert), --restrict-to
ana-wg:31337 (not an open relay). Mirror per fleet convention; full project in vh/wgtunnel.
56KB deep-research report on thinking-capable eRP finetunes 15-30B, weighted for
spatial/state coherence, targeting RTX PRO 6000 Blackwell (sm_120) NVFP4. Preserved
from an ephemeral Booth (gecko-65) into durable reference for the quant decision.
boring.phasefinal.com CNAME -> ana-srv1 (DNS-only) published + verified; unblocks
the wstunnel ACME cert. Operator handed over an all-zones Zone:DNS:Edit token, now
vaulted at nh3-dev/.config/cloudflare/infra-ops-dns-token — fleet DNS is self-serve.
Flip the queued-project pointer: wgtunnel is now a standalone repo, pre-seeded
after a live verification pass (ana-wg UDP/31337 endpoint, traefik TLS edge on
ana-docker, direct-A public edge). Ground truth captured in the new repo;
/vor-plan is the next step. Do wgtunnel work in ~/development/wgtunnel, not here.
Current state rewritten to session-end: secrets-broker LIVE (secret CLI + 25-item
backfill + rm/warn), stonehenge-park /park service repo stood up (vor-plan+vor-ui),
dots-tts extracted to tts-stack; NEXT PROJECT = wgtunnel (WireGuard over a plane's
wifi). Two detail files added; 2 oldest T&A entries archived. Handoff written to
/tmp/infra-ops-handoff.md for the post-clear pickup.
jackdaw-dev observation (2026-08-12): the new-namespace warning is non-blocking +
stderr, so a scripted put suppressing stderr can still mis-namespace silently.
Deliberately not blocking (domain-scoped names would misfire on auto-prefix);
revisit with an opt-in --strict flag only if scripted callers appear.
Both from jackdaw-dev feedback after a mis-namespaced item (missing host prefix)
hid under a prefix nobody searches:
- 'secret rm <name>' — delete an item by exact name (bw soft-delete to trash,
recoverable); closes the 'no delete path, append-only in practice' gap.
- 'secret put' now warns (stderr, non-blocking) when a name opens a brand-new
top-level namespace, listing existing ones + suggesting the host prefix —
catches a typo'd/missing prefix at store time.
Installed copy at ~/.local/bin/secret synced.
Scope corrected to per-dev-box (CC sessions on this box), not a fleet service; each
box duplicates the stack and backs up its own local secrets, hostname-namespaced.
CLI:
- backfill is local-only (scan this box's ~/development/*/{env.sh,.env} + ~/.config
credentials; exclude bootstrap.env/examples/AIPA-Data archives).
- large files (>6000 B) route to a bw ATTACHMENT instead of the note field
(Vaultwarden caps notes at ~10000 encrypted chars); get/verify read it back.
- backfill catches per-item failures and continues (bw errors raise BwError,
main converts to a clean exit); idempotent upsert makes re-runs safe.
Backfilled all 25 nh3-dev secret files into the infra-ops org's Default collection
(folder = hostname), every one round-trip verified (2 large via attachment, 23 via
note). README added for duplicating the stack to new dev boxes. Contract scope +
data-model sections updated (bw, org/collection, per-box).
secret put/get/list/backfill over Vaultwarden via the bw CLI. Items land in the
infra-ops org's Default collection (visible to the operator's primary account via
org share), organised by folder + <host>/<stack>/<file> naming; text in the note,
binary base64'd into a hidden field; sha256 + source metadata fields; idempotent
upsert keyed by name. Auth bootstraps from ~/.config/secrets-broker/bootstrap.env
(0600, apikey login + master-password unlock, per-invocation session).
Verified live end-to-end (create/upsert/get-note/get-field/list). Contract updated:
bw replaces rbw (rbw register 400'd undebuggably despite valid creds).
Known limitation: bw-subprocess-per-op is ~3s/call → ~15-25s/command; too slow for
a fleet-scale backfill. Next: a bw serve broker (fast + central-cred fleet model).
TTS development moves to a dedicated repo (~/development/tts-stack) so a separate
agent can own tuning/dev. Mirrors the chatterbox-fast extraction:
- stacks/dots-tts/ reduced to a pointer README (code/Dockerfile/compose/tests/env
now canonical in tts-stack).
- voices/ canonical corpus moved out to tts-stack/voices/. Blast-radius checked:
no eshpfi playbook/script reads the corpus (other voices/ refs are unrelated
host paths under /worktank/...).
- persistent-memory updated: TTS dev extracted + stood down; reverses the earlier
"corpus home = eshpfi voices/" call.
The ~15 experimental TTS compose wrappers stay here as reference (catalogued in
tts-stack/KNOWLEDGE.md). Live service on irv-ml1:8198 is unaffected (runs from a
copy on the host).
dots' prosody honors a pause only for ellipsis (~+0.43s) and period (~+0.3s);
comma/semicolon/colon/dash all run flat (~+0.03s vs no-punct), measured via a
duration-over-N-runs pause probe against the live service. Two sub-causes for
the flat clause reads: em-dashes regressed in v2 (the —→- fold made them read
as word-joiners), and semicolons were never honored by dots at all.
Operator ruled ellipsis "too much" → map semicolon, clause colon, and em-dash
to a period in _sanitize (believable ~0.3s clause pause). Guards, pinned by
tests: digit-guarded colon so times (3:45) and ratios (2:1) keep their colon;
en-dash kept folding to hyphen so numeric ranges (10–20) don't become "10.20";
a genuine ellipsis retains its strong pause.
Deployed to irv-ml1:8198 as local/dots-tts:v3 via the redeploy2 build →
:8199-test → pause-gate → cutover pattern (gate measured +0.427s, live healthy).
Curly apostrophes (ratatoskr's LLM emits typographic punctuation) made dots
mispronounce contractions ("Donut's"->"donut ess"); fold curly->ASCII before
synth, keep normalize_text on. Add server-side sentence-chunking so long turns
stop truncating at dots' ~40s single-generate cap (verified full 160s Zev).
Dockerfile: pin dots.tts==0.2.1 + torch/torchaudio==2.8.0 (upstream constraints
now pin a phantom gradio==6.17.0; float torchaudio->2.11.0 crashes the load).
LFM2.5 is </think>-delimited (opening tag in prompt); deepseek_r1 splits
reasoning into reasoning_content so content is the clean post-</think>
answer. Re-smoke: content valid JSON + reasoning_content populated. License
production-cleared (operator <$10M ruling), still out of routing per the
measurement gate.
vllm-lfm25 on ana-ml2 GPU1 :8021 (LiquidAI/LFM2.5-2.6B, util 0.09 into
unreserved slack, max-len 16384, no reasoning-parser so content is non-empty).
LiteLLM alias lfm2.5-2.6b with vendor sampling baked as default (temp 0.1;
top_k 50 + repetition_penalty 1.1 via extra_body). Eval-only, not in any
routing chain, pending operator ruling on LFM Open License production use.
Long operator-driven diagnosis: the 'broken/German/dead-air' was the Turbo T3
model over-running its generation tail (garble in final ~2-3s, worse with
length + tight sampling), NOT a language leak or OOM. Fix = server-side
max_chunk_chars=250 cap (:v2), keeping 3-4 sentence clean chunks with smooth
joins. Method (amplitude-gated voiced-ZCR), foot-guns (tail-trim unreliable,
build-context/image drift), and the flat-vs-repo divergence recorded.
Freed ~17.4GB (3090 728MiB->18.2GB free) for co-resident chatterbox-fast
(was OOMing). Detached native process; GPU mem held by multiprocessing-fork
children that orphan to init - kill children explicitly. Restore cmd +
affected consumers (asset-engine, gateway-chat) recorded.
Comment-only bump built from clean git archive of Worldtree origin/main
(578f8fc, on the b182 line). Index + clean-venv install + metadata==0.1.6
verified; muninn-dev + worldtree-dev pinged. Cleared from carried-pending.
Operator-authorized (via worldtree-dev thread 01KZE6TGRHAW) cleanup of the WT
#394 contamination: b182 deployed onto personal, all 3 preconditions verified,
reconcile --repair swept the 5,354 orphan index rows. Fresh reconcile confirms
orphan=0/missing=0/stale=0. Evidence-hold index-row half lifted+done; on-disk
generation-dir file-retention hold still stands. reconcile --repair exited rc=1
on a non-blocking worldtree-side git-staging bug (index.add on a deleted
uncommitted path) — flagged to worldtree-dev, not fixed here.
Brokkr independent verify clean (maxdiff 0.000000, no split). R42 v13
acceptance gate PASSES first time in its history: main+kb 56/90->90/90,
evictions 33->0. A2 control torn down. A3 throughput characterized at
~34 req/s (graceful queueing), with A4/util-bump/replica as levers.
A3 now backs the prod reranker alias but was launched --restart no;
docker update to unless-stopped so an ana-ml2 reboot can't silently
break the alias. Full compose-service promotion tracked as a follow-up
in the selection ledger.
The incumbent Qwen3-Reranker-0.6B was measured actively harming 80/90
fleet queries on main+knowledge_base (and inverting the bare-name region
behind Worldtree #389) — no-reranker beat it 89/90 vs 56/90. Brokkr's R43
bake-off selected BAAI/bge-reranker-v2-m3 (A3): 90/90 top-10, mean rank
0.19, multilingual (XLM-R), ~1.2 GB lighter than the incumbent.
Control arm (A2 = same Qwen weights, seq-cls head) scored identical to the
incumbent, proving the fault is a training prior, not the serving head —
which cancelled the expensive Qwen3-4B arm before it cost a GPU seat.
Cutover boundary 2026-08-06T17:37:48Z. The qwen3-reranker alias and the
:8002 backend are retained for one-edit rollback. Adds the process audit
trail at docs/pfi/reranker-selection-ledger.md.
Session (2026-08-05): 3 Booth features live+tagged (verbatim-wrap chip, .md/.txt
doc-viewer, image prev/next arrows); worldtree herald re-nudge bug -> forseti
althing-core v2.1.2; fleet-CI-resilience flip attempted end-to-end and PARKED on
an act_runner->gitea action-fetch auth blocker (infra-ops to research, deferred).
Archived the 2026-07-15/16 recent-decisions batch (8 entries) to keep the index
under the soft cap.
Zooming an image now shows ‹ / › arrows at the left/right edges that step
to the previous/next image in the booth (gallery sorted-rel order), wrapping
around, plus keyboard ←/→. Arrows are hidden when a booth has a single image.
booth_view_file computes neighbors via a new booth_image_names() helper and
passes prev_url/next_url to view.html. 3 new tests, suite 47 passing;
deployed + verified live on nh3-dev :8090.
Loose .md/.txt/.log files rendered as forced-download links in the gallery
and downloaded (or showed raw) when opened. Now they open in a readable
in-booth page via the existing /b/<name>/view route:
- .md -> rendered HTML (Python-Markdown: fenced code, tables, sane lists),
styled in an Australis .markdown-body with the viewer chrome;
- .txt/.log -> preformatted <pre> text view.
The gallery links docs to the viewer (📄) instead of a download; the view
page keeps a ⬇ (?dl=1) for saving. Files over 2 MB hand back raw. New
markdown dep (optional-import: degrades .md to text view if absent).
booth_image_view -> booth_view_file (now handles image + doc + raw-fallback).
9 new tests, suite 44 passing; deployed + verified live on nh3-dev :8090.
Recorded under Tried-and-abandoned: --enable-triton-backend on irv-ml1's
A6000 crashes every render (triton's fp8 dequant needs fp8e4nv/e4m3, which
sm_86 lacks; the global --fp8_e4m3fn-text-enc dequant dies at CLIPTextEncode,
taking fp8 and int8 alike). Reverted cleanly; cu130 rebuild won't fix a
hardware format limit; revisit at the Ada refresh. Also captures the
compose-env-needs-recreate-not-restart mechanics lesson.
Verbatim-index.html booths were served raw (FileResponse) with no base
template, so they had no favicon and no way back to the booth index — the
gap the app-rendered gallery/zoom pages already covered via base.html.
booth_view now reads a small verbatim index.html and, via a pure
wrap_verbatim_html(), injects:
- a fixed-position 'all booths' chip (scoped class, max z-index, hidden
in print), pinned top-right (empty on left-aligned report layouts; a
top-left chip clips the page title) and appended at the END of the
document so it never reorders the page;
- the Booth favicon at the first head-ish seam, only if the page declares
no icon of its own.
Injection is doctype/charset-safe for the compact HTML real booths use
(<!doctype html><meta charset><title><style>…content, no explicit head/
body): nothing is ever placed ahead of a leading <!doctype> (which would
force quirks mode), and the ~250B favicon link keeps the charset <meta>
inside the first-1024-byte detection window. The raw file route
(/b/<name>/index.html) stays byte-for-byte, so assets and ?dl=1 downloads
are unchanged; files over 8 MB serve raw, unwrapped.
Verified live on nh3-dev :8090 across the real booth shapes (compact-HTML
crow-*/jackdaw-*/mimir-favicon, well-formed dcc-summarizer-ab, own-icon
edict-favicon). 10 new tests; suite 38 passing.
The [2026-07-25] nh3-extdev herald-install entry claimed infra-ops was
sudo-less on extdev, explaining the use of the lkraven@ NOPASSWD path.
That parenthetical was wrong: infra-ops has had full NOPASSWD sudo on
extdev since 2026-06-25. Kept the historical action (lkraven@ was used)
and appended a dated correction so a future session self-serves as
infra-ops instead of taking the lkraven@ hop unnecessarily. Surfaced
during the 2026-08-03 herald.py:363 re-nudge-bug arc.
Collapsed the completed-arc bloat out of Current state / in-flight (line 125:
6487->1073 chars; runbooks moved to persistent-memory.d/2026-08-03-worldtree-b168-384-385-arc.md).
Added the 2026-08-03 arc Recent-decisions entry. Auto-archived 20 oldest
Recent-decisions entries (2026-07-08..07-14) to archival-memory.md (index 345->308
lines). Refreshed the b169-deploy watch, unpushed-count, and handoff.
corviduo-dev demo+personal+pinned share one containerd; concurrent pull of b169's
torch layer failed personal mid-race while demo completed. Image 6e34a87 fully
valid (demo running it healthy). Fix = re-run. NEAR-MISS: prune/rmi 6e34a87 would
have downed demo. Lesson: docker ps running images before any prune cleanup.
worldtree-dev closed the watch with git evidence: both round-2 wing commits
landed clean under exec -u 1000; loose-object chown enabled it. Self-healed as
predicted; last thread of the reindex-as-root fallout closed.
os.access(ingestion_root, W_OK) tests only the root dir, so a root-owned job
subdir passes requeue guards + /health both while being unclaimable by uid 1000.
muninn-dev added an ownership column to the post-move check.
muninn-dev tested on coreutils 9.1: mv src failed/ with failed/ missing STILL
silently renames (rc=0) — trailing slash buys nothing. mv -t <dir> <src> refuses
a missing target loudly (rc=1). Adopted as house convention. Also: DCC+P&P rest
in failed/ with manifest=complete until round-2 (requeue keys on dir placement) —
deliberate, don't tidy.
A misplaced ingestion-state move is silent (list_jobs OK, files inert; sole
symptom = job absent from board, job_row->None/404). Verify job is on the board
+ job.dispatch.json survived after any move; don't trust mv exit codes.
worldtree-dev round-2 unblock: mv job complete/->failed/ assumed failed/
existed; it didn't on personal, so mv renamed job1 to 'failed' + nested job2.
Caught + reconstructed via complete/ scratch, no data loss. Lesson: verify dir
exists with [ -d ] before mv-into (empty ls is ambiguous); guard peer fs cmds
with mkdir -p.
worldtree-dev accepted #384 recovery. Wing-git BrokenPipeError ruled a
watch-item (self-heals on DCC round-2 re-run; escalate only if 2-in-a-row).
Recorded a heads-up for a future production delete-by-job_id of 785 April-era
DCC orphans (job_id=b59c147c5ce0, 'main' collection) — to be handled supervised
(backup + scope-confirm + operator-in-loop) after ratatoskr's verify.
worldtree-dev pushed the train (main + tags v1.0.0b168/staging) and verified my
pre-sync matches the commit byte-for-byte. Recorded the next pending op: after
b168 CI-lands on personal, run --reindex of job mimir-6351554e8e8f + #381 restart
on their exact commands.
Synced the boot-gating summarization block + deep-reasoning desc to demo +
personal via deploy-wt-config (health-gated); replied GO. Recorded gotchas:
unpushed-commit fetch falls back to default branch (verify SHA exists), and
paste-sourced YAML needs indent/validate (8-space desc was invalid).
worldtree-dev advance notice: #384/#385 train adds a boot-blocking
'summarization' capability block (vastblueai-gateway/gen) that in-image
muninn/config.yaml references. Must pre-sync into providers.yaml on demo
+ personal via deploy-wt-config BEFORE the image deploy, from the exact
commit. ACKed; recorded as an open watch.
worldtree-dev gave advance notice: standing #381 restart of
worldtree-personal-worldtree-api-1 will be requested when DCC re-ingest
job mimir-6351554e8e8f (fiction wing) goes terminal in a few hours.
ACKed no scheduling constraints; recorded as an open watch so a fresh
session catches the request.
A/B (5 pinned-seed neutral pairs) showed original single-clip seg000
(16.3s) beats the 52s 4-take concat on timbre fidelity — reverted live +
build-source to seg000-alone. Recorded two craft lessons: more reference
audio is not automatically better when takes vary; emotion steering pulls
output away from a cloned voice fast (keep clones emotion-neutral).
Folded the onyx-58 Booth bundle (seg101/seg110/seg148, all Princess Donut
per operator-confirmed misdiarization of seg148) into the Zonos gateway
donut voice reference alongside the original 65-frost seg000. New ref =
52.0s @ 44.1kHz mono s16, deployed to irv-ml1 live bind-mount +
build-source tree; old ref backed up. A/B audition in booth donut-onyx58.
Gate rebuilt off vh/muninn-gate main (bc04c4c) for the muninn-dispatch
0.1.4->0.1.5 bump (concept_schema/concept_schema_source row fields). Gate
version unchanged at 0.0.14; note to also tag the image with the source SHA
for traceability, and that the pin is authoritative in pyproject.
The mimir-inbox deploy changed two things the committed example documents:
the mimir-inbox key gained the control scope (2026-08-01, for cancel/retry),
and the staging root is no longer a placeholder — it's the real shared dir on
corviduo-dev, path-agreement probe PASS (muninn-dev). Bind was already correct
at :8090 (the stale :8080 was only in the gate repo's own example).
WG-internal FastAPI+HTMX front end for large-document ingestion into the
Muninn KB, over the muninn-gate API (browser -> mimir-inbox -> staging ->
path-addressed POST /jobs). Co-located on corviduo-dev with the gate (:8090)
and the worldtree-personal muninn watcher per the operator's 2026-08-01
co-location ruling (reversing the earlier off-box/NFS plan; worldtree-dev
approved the box placement).
- Dockerfile: python:3.11-slim + uv sync --no-dev --frozen (--no-dev is
load-bearing; the dev group's muninn-dispatch path source is absent in-image
and INV-MI-7 forbids importing it). Single-stage by design — src/ stays in
the final image (uv installs the project editable-linked to src/).
- compose.yaml: uid 1000, host-net bind 10.250.50.152:8091, staging :rw,
TCP-liveness healthcheck (deliberately not coupled to gate reachability).
- Built from vh/mimir-inbox HEAD c8ab38f; deployed + healthy.
Records the open-in-place claim semantics (worldtree-dev, runner.py:362-367)
and the INV-MI-19 retention rule (staged files persist until job terminal;
gate retry returns a false-200 on a swept source) in persistent memory.
Deployed on corviduo-dev, co-located with the worldtree-personal muninn
watcher. ingestion_root=/data/state/ingestion (shared state volume, byte-
identical to the watcher); runs as uid 1000 to write the queue; staging
bound :ro at the ratified /mnt/muninn-staging/mimir-inbox (local placeholder
until the shared mount + mimir-inbox writer land). Boot verified: /ping
{"service":"ok"}, /health watcher.running=true (byte-identity proven).
Image built out-of-band with the Gitea read token as a BuildKit secret.
Real config (bearer keys) lives on-server at /opt/docker/conf 0600.
A verbatim index.html booth (e.g. edict-design-brief: a rendered brief + its
.md) had no download affordance — the page is served raw with no gallery/per-file
chrome. Adds:
- GET /b/<name>/?download=1 -> streams the whole booth as <name>.zip (attachment)
- GET /b/<name>/<file>?dl=1 -> forces Content-Disposition: attachment (html/md/
text otherwise render inline with no easy save)
- a download link on the index card (the accessible spot for verbatim booths)
and the gallery header
Tests for both; verified live against edict-design-brief on nh3-dev :8090.