0.0.0-alpha.12
Pre-release
Pre-release
- Mixture-of-Experts support shipped end-to-end:
Qwen3MoeForCausalLMandOlmoeForCausalLMare routed through a newMoeFeedForwardmodule with top-k router, hybrid sparse/naive dispatch chosen per call fromn_tokensvstop_k, and runtime-verified output coherence onallenai/OLMoE-1B-7B-0924-Instruct. - AWQ checkpoints now stay packed in memory on Metal: a fused W4A16 GEMV kernel (
PackedQuantLinear) cuts resident weight memory ~3× (Qwen3-4B-AWQ: 7.5 → 2.5 GB) while keeping decode throughput on par with the previous fp16 dequant-at-load path. - W8A16 GEMV + dequant wrappers built off the same bit-parametric AWQ template;
hf_parsernow accepts AWQ withbits ∈ {4, 8}and dispatches the right kernel at runtime. - GPTQ checkpoints (4-bit and 8-bit,
desc_act=false) load and run end-to-end with a dedicated Metal resident kernel family (gptq{4,8}_gemv_*+dequantize_gptq{4,8}_*);Qwen/Qwen3-{0.6B,1.7B}-GPTQ-Int8reach 85+ tok/s decode on Apple Silicon. - Bf16-aware GGUF Metal fast path now covers ten quant types —
Q4_0,Q4_1,Q5_0,Q5_1,Q8_0,Q2_K,Q3_K,Q4_K,Q5_K,Q6_K— with a fusedmul_mmfor prefill that dequantizes inline and removes the previous 2× residency cost on the M=1 fast path. - GGUF loader rewritten on top of
memmap2:Qwen3-4B-Q4_K_Mcold load drops from 9.4 s to 2.7 s (3.47×) with bit-identical outputs on the verified checkpoint set. - FP8 dequant on Metal is now numerically correct on block-wise-scaled checkpoints (
Qwen3-4B-Instruct-2507-FP8): the weight × scale_inv multiply is promoted to F32 to avoid the BF16 mantissa loss that produced coherent-but-wrong outputs through 36 layers of rescaling. - HTTP API hardened with optional Bearer authentication, per-request wall-clock timeout, sampling parameter range validation, and queue-full backpressure.
- Batched scheduler now derives
max_num_seqsautomatically from the available KV cache and exposes a bounded request queue via--max-queued-requests. - Prometheus metrics endpoint (
/metrics) exposes TTFT, decode throughput, queue depth, prefix-cache hit ratio, model weight memory, and KV cache allocation. - New CLI commands:
oxydllm update [--pre|--nightly]for self-update via GitHub releases andoxydllm uninstall [--purge]for clean removal of binary + OS service. CUDA_COMPUTE_CAPis validated at compile time against a curated list of supported architectures; the loader also warns when the binary's compiled cap is below the hardware cap.- GPU is now required by default; pass
--allow-cpu(orOXYDLLM_ALLOW_CPU=1) to opt into the CPU fallback path. - New Metal fused kernels (
GatedGeLU-Tanh,GeLU-Tanh-Mul) for Gemma-family activations, plus a NaN-propagation fix in SDPA full mode for sequences past 16 tokens. - Per-layer KV contig buffer pool (
ContigBufferPool) recycles tensors across sequences, removing the per-fresh-prefill zero-fill allocation. - A focused code review pass identified 34 findings and closed 31 of them across server, performance, robustness, model loading, and engine.
New Features
- Mixture-of-Experts (MoE) (
src/common/moe.rs):MoeFeedForward { router, experts, top_k, activation, norm_topk }with top-k softmax routing (arg_sort_last_dim+gather+scatter_add). The transformer block dispatches to a denseFeedForwardorMoeFeedForwardbased onBlockConfig.moe. Two equivalent forward paths are picked per call:- Naive (
n_tokens ≤ top_k): dense gate viascatter_add, run each non-empty expert on the fullx_flat. Decode-friendly (no per-expertindex_select/index_addoverhead). - Sparse (
n_tokens > top_k): group token indices per expert on the CPU (small:n_tokens × top_kints), thenindex_select+ FFN +index_addper non-empty expert. Per-expert compute drops fromn_tokensto~n_tokens × top_k / num_experts— up to ~8× on OLMoE-1B-7B for long prefill.
- Naive (
- OLMoE / Qwen3-MoE support (
src/models/arch_defaults.rs,src/models/parsers/hf_parser.rs):OlmoeForCausalLMandQwen3MoeForCausalLMare now inarch_defaults.hf_parserreadsnum_experts/num_local_experts,num_experts_per_tok, andnorm_topk_probfromconfig.json. Mixtral / DeepSeek-V2/V3 remain unsupported (different tensor naming or MLA attention). QkNormLayoutauto-detection (src/common/attention.rs):q_norm/k_normweight shape is inspected at load;[head_dim]selects per-head normalisation (Qwen3, Gemma3),[n_heads × head_dim]selects flat normalisation applied to[B, T, q_dim]before reshape (OLMoE). Forward branches on the detected layout; no config flag added because the two cases are mutually exclusive at the shape level.- AWQ W4A16 resident path on Metal (
src/common/quant_kernels.metal,src/common/metal_ops.rs,src/common/linear.rs): packed 4-bit weights stay resident; decode runs a fused split-K GEMV kernel (w4a16_gemv_*), prefill/M>1 uses an inlinedequantize_w4_*plus matmul. Qwen3-4B-AWQ resident weight memory drops from ~7.5 GB (fp16 dequant-at-load) to ~2.5 GB. - W8A16 (8-bit AWQ) kernel wrappers:
w8a16_gemv_{f16,bf16}anddequantize_w8_{f16,bf16}are bit-parametric instantiations of the same template as the 4-bit path.PackedQuantLinearcarries abitsfield and dispatches to the right kernel;validate_quantization_configacceptsawqwithbits ∈ {4, 8}. - GPTQ end-to-end support:
validate_quantization_confignow acceptsgptqwithbits ∈ {4, 8}anddesc_act=false;weights.rs::try_get_gptqloadsqweight(packed alongin_features),qzeros,scales, and optionalg_idx;dequantize_gptqimplements the PlusOne zero-point convention. AQuantWeightstruct unifies AWQ and GPTQ behind a singleAnyLinear::from_quantfactory with apack_dimfield that disambiguates the layouts. - GPTQ resident Metal kernel (
src/common/quant_kernels.metal): a dedicatedgptq_gemv_impl<T, BITS>template handles the GPTQ[in/pack_factor, out]layout (1 thread per output column instead of AWQ's 1 thread perpack_factorcolumns) plusgptq_dequantize_impl<T, BITS>. Wrappersgptq{4,8}_gemv_{f16,bf16}+dequantize_gptq{4,8}_{f16,bf16}are dispatched byPackedQuantLinearbased onpack_dim. Decode onQwen3-0.6B-GPTQ-Int8improves from ~50 tok/s (dequant-at-load) to ~89 tok/s with the resident path. - GGUF kernel suite bf16-aware (
src/common/quant_kernels.metal): ten quant types —Q4_0,Q4_1,Q5_0,Q5_1,Q8_0,Q2_K,Q3_K,Q4_K,Q5_K,Q6_K— each with agguf_*_gemv_bf16(M=1 decode) and a fusedgguf_*_mul_mm_bf16(M>1 prefill, dequant inline).GgufFastPathinlinear.rs::QLinearactivates the fast path on Metal + BF16;QMatMulfallback is dropped when active so weights are not held twice (no 2× memory cost). Coverage spans ~98% of the GGUF mainstream parc. - GGUF mmap loader (
src/common/gguf_weights.rs):GgufWeights::loadandload_shardsopen the file withmemmap2::Mmap, parse the header from aCursor, and buildQTensorfrom slices of the mmap (zero copy in user space; one memcpy intoMTLBuffer).parallelise_tensor_loadmaterialises tensors in parallel viarayon::par_iter. End-to-end load + first inference on Qwen3-4B-Q4_K_M drops from 9.4 s to 2.7 s (3.47×). - Stress baseline script (
scripts/stress_baseline.py): per-model cold/warm load time, TTFT, median decode TPS, RSS, and deterministic coherence check ("Tokyo is the capital of"→ must contain"japan"). Writes CSV + JSON per run undertest-results/stress-baseline/for regression tracking. - HTTP API authentication (
src/server/routes/mod.rs): optionalOXYDLLM_API_KEY/--api-keyenables a Bearer-token middleware on/v1/*and/metrics;X-API-Keyis accepted as an alternative header;/healthstays unauthenticated for liveness probes; mismatches return401 invalid_api_keyvia a constant-time comparison. - Per-request wall-clock timeout (
--request-timeout/OXYDLLM_REQUEST_TIMEOUT, default 300 s,0disables): non-streaming responses return408 Request Timeout; streaming responses emit a finalrequest_timeouterror chunk followed by[DONE]via a watchdog that races the SSE task. Dropping the inner future closes the engine channel so the underlying sequence is aborted at the next step boundary. - Sampling parameter range validation (
validate_sampling_paramsinchat.rs): out-of-range values fortemperature,top_p,min_p,frequency_penalty,presence_penalty,top_logprobs,repetition_penalty,n,max_tokens, andmax_completion_tokensreturn400 invalid_request_errorinstead of silently degrading the sampler. Also closes the user-triggerable NaN-logits path throughrepetition_penalty: 0. - Batched scheduler with dynamic concurrency: at model load,
max_num_seqsis computed astotal_kv_blocks / ceil(max_context_len / block_size), capped at 256, and logged. Overridable via--max-num-seqs/OXYDLLM_MAX_NUM_SEQS. Requests are held in a boundedtokio::sync::mpscchannel of capacity--max-queued-requests(default 200); once full, new arrivals receive HTTP 429 immediately. - Prometheus metrics endpoint (
/metrics,src/server/routes/metrics.rs):oxydllm_ttft_milliseconds(histogram),oxydllm_tokens_per_second(histogram),oxydllm_requests_total(counter by status),oxydllm_queue_depth(gauge),oxydllm_prefix_cache_requests_total(counter byhit/miss),oxydllm_model_weights_bytes(gauge),oxydllm_kv_cache_allocated_bytes(gauge),oxydllm_vram_used_bytes(gauge). Every request is also assigned a UUID-v4request_idthat propagates through structured logs; settingLOG_FORMAT=jsonswitches the logger to JSON-per-line for Loki / Datadog /jq. oxydllm update [--pre|--nightly]: queries the GitHub releases API for the latest stable / pre-release / nightly build, compares against the version compiled into the binary (orOXYDLLM_BUILD_TSfor nightly), and re-runsinstall.shwith the appropriate channel set. Source builds print an error and exit cleanly.oxydllm uninstall [--purge]: stops and removes the OS service (launchd on macOS, systemd on Linux), then self-removes the binary.--purgealso removes~/.oxydllm/, including all downloaded models and configuration data. Always shows a confirmation prompt before mutating anything.- CUDA compute capability validation (
build.rs):CUDA_COMPUTE_CAPis matched against a curatedSUPPORTED_COMPUTE_CAPSlist (Ada Lovelace 8.9, Hopper 9.0, Blackwell 10.0/10.3, Jetson GB 11.0, Blackwell Desktop 12.0, Blackwell Edge 12.1). Out-of-list or below-minimum values fail the build with an actionable message. At runtime,loader::select_device_atwarns when the binary's compiled cap is below the actual GPU's hardware cap. - GPU required by default:
select_device_atreturns an error if no GPU device is available unless--allow-cpuis passed (orOXYDLLM_ALLOW_CPU=1is set). Avoids silently serving requests at CPU-speed throughput. ContigBufferPool(src/common/paged.rs): eachBlockAllocatorowns a small pool of retired KV contig buffers (default 4 per layer).PagedKvCache::clearretires the buffer instead of dropping it, andPagedKvCache::appendtakes the smallest-fit buffer from the pool on grow or fresh-start. The "stale" tail of a reused buffer is never observed: all reads narrow tocontig_len.- Metal
GatedGeLU-TanhandGeLU-Tanh-Mulkernels (src/common/metal_ops.rs): single-dispatch fused activations for Gemma-family models (GeLU tanh-approximation with multiplicative gate). Mirror the existinggated_silu/silu_mulshapes for Llama / Qwen. - FP8 quantization in validation logic:
validate_quantization_configacceptsfloat8_e4m3fnand routes the load through the FP8 path established in alpha.11. - Discovery cache with atomic snapshot:
ModelManager::discovered_with_registry()returns(Vec<DiscoveredModel>, BTreeMap)from a single mutex acquisition with a 5 s TTL on the filesystem scan. Removes both the TOCTOU between manager-lock release anddiscover_models, and the per-request disk scan onGET /v1/models{,/:id}. - GGUF CPU expansion factor:
manager.rsreads GGUF metadata viaestimate::gguf_cpu_expansionto compute the dequantized memory footprint (Q4_K_M~7×,Q8_0~4×, etc.) instead of using a flat 2× for all formats. Eliminates first-load CPU OOM on very quantized GGUF models. - Discovered models metadata:
DiscoveredModelcarriescreated_atandowned_by(HF namespace) fields exposed by/v1/modelsand/v1/models/{id}. - Tools-streaming
[DONE]sentinel: the tools n ≥ 1 streaming branch now emits[DONE]after error /JoinErrorevents, matching the non-tools paths. - Strict-mode JSON schema catches non-parseable JSON: a
response_format: json_schemarequest withstrict: truewhose model output is not parseable JSON now ends withfinish_reason: "content_filter"andcontent: nullinstead of slipping through asstop.
Performance and Efficiency
- AWQ W4A16 fused matmul on Metal: Qwen3-4B-AWQ resident weight memory drops from ~7.5 GB to ~2.5 GB; QKV and gate+up are fused at load (matmul count per layer = 2, same as fp16); single-shot decode throughput catches up to Ollama's Q4_K_M reference within noise.
- GPTQ Metal resident path: Qwen3-0.6B-GPTQ-Int8 decode improves from ~50 tok/s (dequant-at-load) to ~89 tok/s; Qwen3-1.7B-GPTQ-Int8 reaches ~42 tok/s.
- GGUF Metal fast path: bf16-aware GEMV port of llama.cpp / candle templates removes the bf16↔f32 host-side casts. Measured deltas (steady-state, M=1 decode):
- Qwen2.5-1.5B-Q4_K_M: 81.5 → 92.5 tok/s (+13.5%)
- Qwen2.5-1.5B-Q3_K_M: ~89 tok/s (≈8% faster than Q4_K_M same model)
- Qwen3-4B-Q4_K_M: 28.8 → 31.5 tok/s (+9.4%)
- Qwen3-4B-Q5_0: 25.6 → 27.5 tok/s (+7.4%)
- Qwen3-1.7B-Q8_0: ~43 tok/s
All quant types converge at ~50% memory-bandwidth utilisation, on par with the host-side cast cost they eliminated.
- GGUF mmap loader: Qwen3-4B-Q4_K_M cold load 9.4 s → 2.7 s (3.47×); steady-state warm load matches mmap-only baselines. Zero copy in user space, one memcpy into
MTLBuffer. - GGUF fused
mul_mm(M>1 prefill): dequantizes inline in the matmul kernel; previously the prefill path materialised a transient bf16 weight matrix per call (up to ~192 MB forgate_up_projon Qwen3-4B). The previous M=1-only fast path doubled resident memory; the fused kernel removes that — Qwen3-4B-Q4_K_M RSS measured at 2.48 GB (was ~4.6 GB). - MoE hybrid dispatch: on OLMoE-1B-7B-0924-Instruct the hybrid is ~25% faster on TTFT (256-word prompt: 9.8 s → 7.3 s) and ~60% faster on decode (6.5 → 10.6 tok/s) compared to the naive ALL-experts variant.
- AWQ load-time parallelism: safetensors materialisation runs through
rayon::par_iter, paired with a dtype short-circuit when the target matches the on-disk type. gemma-4 (2011 tensors): cold load 14 s → 9.2 s; Qwen3-0.6B: 1.5 s → 0.26 s. - In-place sampling filters:
apply_min_p/apply_top_k/apply_top_pmutate&mut [f32]instead of returning a freshVec<f32>per token. Auxiliary buffers forselect_nth_unstableand the indices sort are thread-local and amortize to zero allocation after the first sample — saves roughly 1.8 MB of allocation/free traffic per decoded token on Qwen-3's 152 K vocab. ContigBufferPoolreuse: sequences on the same allocator skip theTensor::zerosfor the contig KV buffer after the first one. On Apple Silicon with 32 layers × 4-buffer pool, this avoids hundreds of MB of zero-fill at the start of each fresh prefill under steady-state churn.apply_top_ksingle-pass filtering: the old three-pass (filter, count, renormalize) is now one in-place pass that trackssuminline.- KV-quant dtype reorder:
to_device(Cpu)is applied beforeto_dtype(F32)when reading quantized K/V back to host, so the dtype cast runs on CPU and is skipped entirely when the tensor is already F32. discover_modelscache: the per-request filesystem scan is replaced by a 5 s TTL cache shared between/v1/modelsand/v1/models/{id}.
Reliability and Correctness
- FP8 dequant precision fix (
src/common/weights.rs::apply_weight_scale_inv): on Metal, FP8 weights are dequanted at load (F8E4M3 → F32 → BF16) because Metal has no FP8 compute. The previous code did theweight × scale_invmultiply in BF16, which compounded mantissa rounding error across 36 layers of block-wise rescaling onQwen3-4B-Instruct-2507-FP8, producing coherent-but-wrong outputs ("Tokyo is not the capital of Japan") or, at lowmax_tokens, token degeneracy. The multiply is now done in F32 with a single cast back to the target dtype. - MoE qk_norm layout auto-detection: OLMoE applies
q_norm/k_normto the flat[B, T, hidden]tensor before reshape into heads (weight shape[hidden]), whereas Qwen3 / Gemma3 apply per-head on[B, H, T, head_dim](weight shape[head_dim]). The variance differs, so the layouts are not interchangeable.Attention::loadnow inspects the loaded weight'selem_countand branches at forward time; no config flag because the two shapes are disjoint. - MoE routing correctness: top-k routing uses
arg_sort_last_dim(false)+narrow+gatherto extract the top-k probabilities, optionally renormalises (controlled bynorm_topk_probfromconfig.json), and dispatches via a hybrid sparse/naive path. Three unit tests cover the degenerate case (num_experts=1, top_k=1 must equal a single dense FFN), the routing-mass shape, and the top_k > num_experts rejection at load. - Greedy NaN guard: the greedy fast-path in
sample()now sums logits and bails on NaN beforeargmax. Closes the "silent BOS storm" failure mode where NaN logits madeargmaxdeterministically return token 0. - Sampler-side NaN guard on the non-greedy path: scans
logits_vecfor NaN after dtype conversion and bails before any filter touches the tensor. Combined with the greedy guard, eliminates the NaN → sampler → serde-panic chain that could abort a streaming connection mid-response. - Template-render failure surfaces: a failed
apply_chat_templateno longer falls back to a plain-text render with a 200 OK; the error now propagates as a structured500so thinking-model requests can't be silently downgraded to non-thinking. - Metal SDPA NaN propagation in full mode (
src/common/metal_ops.rs): the full path (sequences > 16 tokens) had a mask-handling path that let NaN values leak into the attention output. The fix masks before softmax in a way that keeps the output NaN-free even when the input mask is-inf. - Model warmup hardening: the per-model warmup step runs through more code paths to prevent first-request NaN logits on Metal, with JIT-compilation optimizations.
- Tied-embeddings load-time check:
load_standard_safetensorswarns whentie_word_embeddings = trueis selected but the safetensors file also contains an explicitlm_head.weight— the file'slm_headwould otherwise be silently ignored, producing wrong logits. The default for Gemma family staystruebecause the official Gemma checkpoints omit the field. - Randomized top-k tie-break: when multiple tokens tie at the top-k threshold, the kept set is now picked uniformly at random via
splitmix64priorities (seedable for reproducibility) instead of iterating in ascending token-ID order. Removes a small but real sampling bias toward low-ID tokens during ties. - Atomic registry write:
save_registrywrites to.oxydllm_registry.json.tmpand renames atomically. Multi-process scenarios (e.g. the server plus an interactiveoxydllm runsharing--models-dir) can no longer produce a torn or empty registry. - Malformed-JSON recovery in
load_registry: a corrupt registry now emitstracing::warn!(with path and parse error) before falling back to an empty map, instead of silently dropping the file. Linear::newreturnsResult: a malformed checkpoint with a non-2D weight tensor in aLinearlayer now produces an anyhow error at load instead of a runtime panic.parse_compute_caprejects two-digit minor versions: themajor*10+minorflat encoding becomes ambiguous past.9, so values like"12.10"now fail explicitly instead of silently collapsing to130.u32::try_fromon slot indices: replaces silentas u32narrowing onblock_id * block_sizeinPagedKvCachewith explicit overflow checking.- AWQ
pack_factorhelper: the hard-coded8for 4-bit packing inweights.rsruntime-size accounting is now apack_factor(bits)helper that future bit-widths (AWQ-3 / AWQ-8) can extend without silently mis-reporting memory. - Metal
sdpa()device check at call site:metal_ops::sdpa()rejects non-Metal inputs at the entry point with an actionable error instead of letting candle dispatch fall through tocpu_fwd's opaque "Metal-only" bail. - Route parameter syntax fix: the
/v1/models/{*model_id}capture now correctly handlesuser/modelids with embedded slashes. - Assorted sampling / KV cache / loader hardening: defensive cleanups across the inference path, including explicit error propagation from
AnyLinear::from_weight_with_scale_invcallers inload_standard_safetensors.
Refactors and Maintainability
QuantWeightgeneralisation (src/common/awq.rs): the originalAwqRawTensorsstruct grew into a unifiedQuantWeight { bits, group_size, pack_dim, pack_order, zero_point, qweight, qzeros: Option, scales, g_idx: Option }that carries enough metadata to disambiguate AWQ and GPTQ at runtime.AwqRawTensorsstays as a type alias so existing call sites keep working; the new constructors areQuantWeight::new_awq(bits, …)andQuantWeight::new_gptq(bits, sym, …).AnyLinear::from_quantdispatches based on the metadata.QuantSchemeplumbed model-wide:ModelWeightscarriesOption<QuantScheme>(set by the loader fromhf_parser);try_get_quant(prefix)returns the rightQuantWeightshape without each caller needing to know the format.concat_awq_along_outchecksbitsconsistency across fused parts.FeedForwardLayerenum inblock.rsselects between denseFeedForwardandMoeFeedForwardpolymorphically; the transformer block does not branch outside this enum'sforward().GgufFastQuantenum inmetal_ops.rscarries each supported quant type's block size, GEMV kernel name, fusedmul_mmkernel name, op-name, and dispatch geometry. Adding a new quant type is now a single match arm per method plus the Metal kernels.engine::step()decomposition: the ~280-line monolithic function is now a ~95-line orchestrator. Five private helpers own the phases (plan_prefill_inputs,build_batch_input,run_forward_pass,sample_prefill_outputs,sample_decode_outputs).StopRulesandPrefixRegistrybundles drop the per-function argument count enough to remove every#[allow(clippy::too_many_arguments)]from the codebase.- Debug-only device asserts at hot-path entries:
block::run_transformer_layers_batchcross-checkstoken_ids↔position_ids;attention::forward_batch_optional_ropecross-checksx↔position_ids↔mask. Pre-empts the cross-device misroute that will become possible once tensor-parallel inference lands; no release-build cost. - Build script comment for
OXYDLLM_COMPILED_CAP: documents why the value is emitted ascargo:rustc-envrather thancargo:rustc-cfg, and what to add if per-arch CUDA kernels are ever introduced. - Simplified model directory resolution: legacy fallback branches in
resolve_model_pathremoved; discovery logic consolidated. - Outdated review documents removed: the old
CODE_REVIEW/snapshot was misleading after the alpha.12 fixes landed; replaced by a single livingCODE_REVIEW_2026-05-15.mdat the repo root.
Tests
- MoE unit tests (
src/common/moe::tests):moe_single_expert_topk1_matches_single_ffn(degeneracy check),moe_topk_routing_uses_only_topk_experts(output finiteness + convex-combination scale), andmoe_rejects_invalid_topk(load-time guard). - GPTQ parity tests (
src/common/awq::tests+src/common/metal_ops::fused_kernel_parity_tests):dequantize_gptq_int4_matches_referenceanddequantize_gptq_int8_matches_reference(CPU path against a hand-built reference),gptq{4,8}_gemv_{bf16,f16}_matches_referenceandgptq8_dequantize_bf16_matches_reference(Metal kernels against the CPU reference). - W8A16 parity tests:
w8a16_gemv_{bf16,f16}_g{64,128}_matches_referenceanddequantize_w8_bf16_matches_referenceexercise the bit-parametric template instantiated withBITS=8against synthetic data (no real AWQ-8bit checkpoint locally). - GGUF Q3_K coverage: Q3_K kernel + dispatch added with the same naive-tiled
mul_mmpattern as Q4_K / Q5_K, plus a Qwen2.5-1.5B-Q3_K_M smoke run. scripts/stress_baseline.pybaseline run committed: 18 local models pass the deterministic coherence prompt, including the FP8 fix and OLMoE-1B-7B.- 26 new
http_compat_testsfor the auth / timeout / validation / schema work: scripted-engine fixture covering auth on/off (Bearer +X-API-Key),/healthexemption,/metrics+/v1/modelsgating, every sampling field at its range edge accepted plus every OOB value rejected, stuck-engine408, streaming error +[DONE], fast-engine not falsely timed out, and strict / non-strict schema paths under both parseable-but-invalid and non-JSON output. - Three coverage gaps from the May review's §E: streaming error mid-stream emits the error chunk +
[DONE];n > 1non-streaming returns exactly N choices with distinct indices;stream_options.include_usage: trueemits a trailing usage chunk with emptychoicesbefore[DONE]. ContigBufferPoolunit tests: recycle across sequences, evict smallest on overflow, smallest-fit selection, growth retires old buffer.- Engine cache & prefix-cache tests:
KvFakeModeltest fixture plus a unit test asserting prefix cache hits on a repeated prompt. - Sampling tie-break tests: unbiased over many seeds (within ±15 % over 4 000 trials with all-equal probs) and reproducibility —
apply_top_kwith the same seed/step yields the same kept set. hf_parsertie_word_embeddingstests: Gemma config without the field defaults totrue; non-Gemma defaults tofalse; explicit value is respected on both.- Discovery cache tests: repeated reads within TTL don't rescan; explicit invalidation forces refresh; snapshot stays consistent with the registry across mutations.
Documentation
- README — Security section: documents
OXYDLLM_API_KEYsetup, the Bearer /X-API-Keyflow, the/healthexemption, and reverse-proxy recommendations. - README — CUDA Status: added a
[!IMPORTANT]callout above the Docker tag table to make the "no tag is validated on physical NVIDIA hardware" disclaimer impossible to miss. - README — Compute capability table: updated to match
build.rs::SUPPORTED_COMPUTE_CAPSand to document the compile-time validation. - Public documentation site (
docs.html): added a Security section mirroring the README; added a cache-TTL note underGET /v1/models; addedOXYDLLM_ALLOW_CPUto the environment-variables table; fixed two anchor labels pointing at the "Advanced Topics → KV cache quantization" section. - Code review:
CODE_REVIEW_2026-05-15.mdis a single living document tracking the 34 findings from the May 15 review pass; 31 are closed with commit hashes, the remaining four are allINFO/LOW.
CI / Infra
oxydllm update/oxydllm uninstallinheritinstall.sh's service-management story end to end: theupdatecommand re-runsinstall.shfor the appropriate channel (stable / pre / nightly); theuninstallcommand stops the launchd agent or systemd unit before removing the binary.
Dependencies
memmap2 = "0.9.10"added for the GGUF zero-copy loader.
Full Changelog: 0.0.0-alpha.11...0.0.0-alpha.12