Docs / Reference / Decision log

Reference

Decision log

Every non-obvious choice made while building this stack, with the reason and the measurement behind it.

Updated Aug 9, 2026

Recorded so that a future change is an informed reversal rather than an accident.

Native virtual environment, not a container

Plain ComfyUI with SDXL-class models compiles nothing, so a container buys isolation at the cost of debuggability. Containers stay the escape hatch for custom nodes that need nvcc.

Python 3.12, not the system 3.14 and not 3.13

The system interpreter is ahead of PyTorch’s published wheels. 3.12 over 3.13 because custom ComfyUI nodes are the least-maintained part of the ecosystem and lag the newest interpreter.

torch 2.11.0, not the newest 2.13.0

torchaudio — which ComfyUI requires — stops at 2.11.0 on every CUDA index. 2.11.0 is the newest fully-matched torch/torchvision/torchaudio trio. Taking the newest torch would have made ComfyUI’s own dependency list unsatisfiable.

cu130, not cu128

The driver exposes CUDA 13.3. Matching the wheel to the driver generation rather than to habit. Verified sm_120 is in the compiled architecture list, not merely that CUDA reported available.

Weights outside the ComfyUI checkout

extra_model_paths.yaml points at a sibling directory. Reinstalling ComfyUI then costs a clone rather than re-downloading tens of gigabytes.

klein-4B as primary, not SDXL

Reversal of the original plan, made after re-checking the landscape rather than trusting a stale mental model. A 4B Apache-2.0 model that generates and edits in ~5 GB beats SDXL on memory, licence clarity, and multi-reference consistency. SDXL stays installed for its LoRA back catalogue and for ControlNet-Union ProMax.

Three base models, not one

Because the winner differs by axis: klein for style and identity, Z-Image for ControlNet conditioning (klein has none), SDXL for the long tail of community LoRAs.

Apache-2.0 models preferred throughout

Several strong models — FLUX.2-dev, Ideogram 4.0, two of the three best pixel upscalers — are non-commercial. Anything that might end up in a shipped game was chosen for a permissive licence even where a non-commercial option scored higher.

Both fp8 and NVFP4 builds of klein

Blackwell executes 4-bit natively, so NVFP4 is a genuine hardware advantage on this specific card rather than a quality compromise. fp8 is the safer default; both are on disk so the comparison can be made rather than argued.

Evict on demand rather than relocating the residents

The alternative was moving the RAG replica and the pinned language model to another machine so this box is dedicated. Eviction was chosen because generation is bursty: claim the card, generate, release it. The scripts make it a single command in each direction.

The replication containers are never stopped

They hold no VRAM, and the primary’s replication push talks to them and the filesystem rather than to the query API. Stopping them would break replication for zero gain. Verified live: a scheduled push fired 25 seconds after an eviction, with ComfyUI holding the GPU, and completed cleanly.

Restore is verified, not assumed

comfy-down polls the health endpoint and exits non-zero if the service never answers. A restore that silently failed would leave the corpus unqueryable with nothing to indicate it.

Exactly one custom node pack

Custom nodes run arbitrary code inside ComfyUI, so each one is a supply-chain decision rather than a convenience. ComfyUI-PixelArt-Detector was installed (well-starred, actively maintained) because it covers grid detection, palette quantisation, dithering and indexed-PNG export by itself. Three alternatives that do the same job were skipped as small, low-traffic repositories adding no capability. Its requirements.txt lists a bare torch, so its dependencies were installed explicitly and the CUDA build re-verified afterwards.

The site shipped noindex, then went live the same day

A new public site stays out of search engines until someone has actually read it. It shipped with three independent controls (meta tag, X-Robots-Tag header, robots.txt) and went live on 2026-08-09 once reviewed. All three had to be removed together — leaving any one in place keeps the site unindexed while looking published, which is a confusing failure to debug later.

Measurements taken along the way

WhatValue
fp16 matmul, cold14.1 TFLOPS
fp16 matmul, warmed36.6 TFLOPS
Power draw under load91 W
SM clock under load1290 MHz
VRAM before eviction7359 MiB
VRAM after eviction2 MiB
Free VRAM seen by ComfyUI15.3 GiB
RAG API, just started~1.3 GB
RAG API, after first query~3.0 GB
SDXL + pixel LoRA, 1024², 20 steps8 s, peak 7.3 GB
klein-4B fp8, 1024², 20 steps16 s, peak 8.6 GB
Pixel pipeline output341×341, 20 colours (from 58,325)

The cold-versus-warm figure is the one to remember: a 2.5× difference that comes entirely from whether you warmed up before timing.

Source: content/reference/decisions.md · maintained in the nuilab-aigaming repository.