qwen38-lab

A 27B reasoning model with an agentic harness on a single consumer GPU under WSL2, kept alive unattended by a watchdog/supervisor layer, with a CPU docker fleet for memory and support services. Every number below is measured on this box (2026-08-15 … 17), not quoted from a spec sheet.

110.5 t/sgreedy, Q5 @32k, MTP depth 5
~50 t/sreal agentic use, temp 1.0
1546 t/sprefill (pp512)
22.5 GBof 24 GB VRAM, all on-GPU
~15 scold model load (DirectIO)

1The system on one screen

qwen38-lab a governed 27B reasoning model on one consumer GPU — self-healing, measured, reproducible 110.5 t/s greedy · Q5 @32k · MTP d5 ~50 t/s real agentic use, temp 1.0 1546 t/s prefill (pp512) 22.5 / 24 GB VRAM — everything on-GPU ~15 s cold load (DirectIO) HARDWARE AMD Ryzen 9 7950X3D · 32 GB DDR5 · NVIDIA RTX 4090 24 GB Windows 11 · WSL2 Ubuntu (24 GB cap, autoMemoryReclaim=gradual) · GPU via WDDM paravirt MODEL Qwen3.8-27B — hybrid attention (KV ≈ 64 KiB/token) + MTP head for self-speculation UD-Q5_K_XL 20.2 GB · 32k ctx · q8_0 KV cache · llama.cpp built native (CUDA sm_89) HARNESS governed thinking — cut only on proven repetition · breadth-first multi-pass tracker tools: python · files · bash · git · headless browser · security_scan in a kali sandbox SELF-HEALING preflight gate ≥ 1.2 GB free · 1 Hz watchdog, SIGKILL on wedge · paused-with-reason auto-restart the moment VRAM frees — the turn resumes, completed work intact DOCKER STACK CPU-only fleet: qdrant · embed / rerank / chat (0.6-1.7B) · recall-MCP memory · doc pipeline the 4090 stays exclusive to the 27B — support models never touch it measured on this box, 2026-08 — not spec-sheet numbers wbd-rd.nl/p/art_2b14ad509472
The one-image version — the whole lab on a single card.
qwen38-lab — the moving parts and how they talk inference memory & support self-healing the risk WINDOWS 11 · WDDM PARAVIRTUALIZATION Desktop apps browser/WebGL tabs, wallpaper, overlays — they share the same 24 GB card RTX 4090 · 24 GB VRAM 27B weights + KV + draft ≈ 21-22.5 GB desktop share (healthy ≈ 1.3 GB) free < 1.5 GB = the wedge zone seen twice on 17-08: GPU 100% “busy” at 85 W, decode frozen, no error — a stuck kernel in the paravirt layer. The fix lives one band lower ↓ WSL2 · UBUNTU CLI harness — cli/qwen.py governed thinking repetition detector · ceiling → harvest multi-pass tracker breadth-first · done_means · slice budget tools python · files · bash · git · browser · security memory & ledgers run-scoped recall · deterministic task_recall llama-server — native, owns the GPU Qwen3.8-27B UD-Q5_K_XL · 32k ctx · q8 KV MTP self-speculation depth 5 · port 8080 110 t/s greedy · ~50 t/s agentic self-healing ops — qwen38.sh preflight gate ≥ 1.2 GB free · supervisor restart health-sampler 1 Hz · wedge watchdog run/launcher.status — says WHY when paused recall-mcp :8187 the CLI’s memory endpoint qdrant :6333 vector store embed :8181 Qwen3-Emb-0.6B rerank :8182 reranker-0.6B chat :8188 Qwen3-1.7B util docparse · ingest · retrieve · grep document pipeline · :8183-8186 agent :8189 agent endpoint shared volumes /models (ggufs) · ~/recall/corpus qwen-kali isolated recon container for security_scan — allowlisted, refuses private ranges unless authorized=true chat · SSE weights+KV VRAM creep → WDDM starts paging → wedge risk gate-restart · poll /slots · SIGKILL on wedge why paused nvidia-smi power = the tell remember / recall · ledger reads security_scan → isolated kali DOCKER · CPU ONLY — THE GPU STAYS EXCLUSIVE TO THE 27B wbd-rd.nl/p/art_2b14ad509472
Blue: the inference path (CLI ↔ native llama-server ↔ GPU). Green: memory & support (recall fleet on CPU, kali sandbox). Amber: the self-healing loop (gate, watchdog, status file). Red: the one thing that actually breaks it — desktop VRAM creep.
1 · WEDGE GPU 100% “busy” at 85 W, decode frozen, no error 2 · WATCHDOG signature match for 120 s → SIGKILL, logged 3 · PAUSED status file names the blocker — nothing hangs 4 · YOU close the VRAM hog (or it frees itself) 5 · RESTART gate passes → reload ~15 s, automatic 6 · RESUME the turn continues — completed work intact
The self-healing loop, validated live twice on 17-08 — a wedged GPU run recovers with zero manual intervention beyond freeing the memory it names.

source: tools/qwen38.sh · tools/health-sampler.sh · cli/client.py · ~/recall/docker-compose.yml — every element in the diagram exists in the repo

2Hardware & host

3Model & serving

source: tools/qwen38.sh · README.md measurement tables · results/RESULTS.txt (repo: git.wbd-rd.nl/r.de.ren/qwen_lab)

4The ops layer — what keeps it alive unattended

1qwen38.sh supervisor→ 2preflight.sh gate→ 3llama-server+ 4health-sampler watchdog

Gate before start

preflight.sh refuses to launch without ≥ 1.2 GB VRAM headroom and ≥ 4 GB free Windows RAM — the two preconditions of every observed wedge and bugcheck.

Watchdog during

1 Hz fsync'd health CSV (post-crash forensics), plus a wedge detector on the one signature nothing healthy shares: slot processing + frozen progress + GPU power < 150 W for 120 s → log + SIGKILL. SIGTERM provably cannot reach a wedged server.

Pre-warning

One log line when free VRAM drops under 1.5 GB: both observed wedges struck at ~23.2 GB total while the healthy state sits at ~22.7 GB.

Paused, not dead

A preflight refusal becomes a PAUSED state that names the blocker in run/launcher.status ("1832 MiB VRAM held on the desktop — close what holds it") and retries every 30 s. The server starts by itself the moment headroom returns; an unexpected server death restarts through the same gate.

Client survives too

A 120 s stream-stall trip and mid-stream connection loss raise a recoverable error: completed rounds are kept, only the half-finished exchange is dropped, and the turn resumes when the server is usable again.

/health lies

A wedged server still answers /health ok — its HTTP thread is fine, only CUDA is stuck. The usable-check therefore reads /slots: a stuck is_processing slot is the tell.

Net effect, validated live twice on 17-08: wedge → kill within 2 minutes → explained pause → automatic restart when memory frees → the turn resumes. Zero manual recovery.

source: tools/qwen38.sh · tools/preflight.sh · tools/health-sampler.sh · cli/client.py (StreamStalled, server_usable) · cli/qwen.py (_heal, _wait_until_usable)

5The CLI — governed thinking + a multi-pass tracker

source: cli/qwen.py · cli/client.py · cli/tracker.py · cli/tools.py · docs/align/2026-08-16-qwen-cot-stack.md

6Failure modes worth knowing (all observed, none theoretical)

The GPU-PV wedge

Decode freezes mid-stream; GPU "utilization" pegs 100% while power collapses to ~85 W — a stuck kernel spinning, not work. No guest-visible error. Trigger both times: desktop apps grew their VRAM share mid-run until WDDM started paging.

The silent spill

Past the VRAM line, WDDM pages GPU memory to host RAM with no error — throughput quietly drops 3×. Windows-side mitigation: NVIDIA Control Panel → CUDA → Prefer No Sysmem Fallback turns the spill into a clean OOM.

Host bugcheck 0x1E

In winhvr.sys — the WSL2 hypervisor runtime, not the NVIDIA driver (confirmed from the minidump) — while the box was in the spilled state. Same layer as the wedges.

The end-game ceiling spiral

Near a full context window the thinking ceiling shrinks every round while harvests feed thinking back in; the turn dies with work done but unbooked. The crash-resume flow (fresh window + tracker re-injection) recovers it; a structural fix is parked in the harness plan.

Rule of thumb On a 24 GB card under WSL2, treat free VRAM < 1.5 GB as the danger zone. The desktop shares the card; a browser tab with WebGL is enough to cross the line mid-run.

source: docs/CRASH-2026-08-16.md · logs/stall.log · logs/health.csv (the wedge signature is in the samples)

7The docker stack — CPU fleet, GPU stays exclusive

The 27B runs native (llama.cpp build, not docker) and owns the GPU. Everything supporting runs in docker on CPU; the compose has CUDA variants of the model services, but the CPU profile is the one in use — deliberately, so the 4090 stays free.

serviceportwhat
qdrant v1.13.46333vector store behind the memory
recall-embed (llama.cpp server)8181Qwen3-Embedding-0.6B Q8
recall-rerank (llama.cpp server)8182Qwen3-reranker-0.6B Q8
recall-chat (llama.cpp server)8188Qwen3-1.7B Q4 — utility model
recall-docparse / ingest / retrieve / grep8183-8186document pipeline
recall-mcp8187the MCP bridge the CLI's memory tools talk to
recall-agent8189agent endpoint
qwen-kali—isolated recon container for security_scan (3.2 GB image)

source: ~/recall/docker-compose.yml · qwen38-lab/docker/kali/

8Daily use