Skip to content

Pre-release bug-hunt fixes, llama.cpp b11815, the SYCL installers and a README audit - #554

Merged
bernardladenthin merged 589 commits into
mainfrom
ccr-90fc5f6a-vs4s0f
Oct 22, 2026
Merged

bernardladenthin merged 589 commits into
mainfrom
ccr-90fc5f6a-vs4s0f

Conversation

@bernardladenthin

@bernardladenthin bernardladenthin commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Bug-hunt and pre-release fixes (every finding has its id, reproduction and red/green test in BUGHUNT-FOUND.md, the user-visible ones are listed in CHANGELOG.md): values that were ignored or misread are refused when set (TrainingParameters bounds, setPredict below -1, adapter paths with a colon, empty JSON fragments, NaN biases); the repeatable adapter options add up instead of replacing; one request is one prompt and one completion on every native path (LlamaModel, the C API, llama-ffm, every OpenAiCompatServer route); slot files are names inside --slot-save-path as llama.cpp's slot route resolves them; LlamaLoader.initialize() is idempotent; a malformed stream envelope is an error, not the end of the stream (the translation lives in StreamEnvelope so its test runs without the natives, F263); infill fields and messages on the raw completion paths take effect (template stops, reasoning budget, preserved tokens, upstream's multimodal prompt object) or are refused; both servers default to llama.cpp's port 9931; chatBatch / completeBatch leave the common ForkJoinPool; ServerMetrics.getCumulativeUsage() counts cached prompt tokens; a LoRA change no longer answers from the old slot cache (new patches/0021); a vocab-only model refuses server operations instead of crashing; the classes jar carries Main-Class: ServerLauncher again (lost with the fat-jar assembly, so every documented jbang --deps <natives jar> net.ladenthin:llama:<v> line had no entry point; smoke-natives-jars.sh reads it back from the built jar, F269); jllama_rpc_server_stop() is for the serve calls in progress when it is made (every serve call has an id, the stop waits for the serves up to its target and issues ggml's stop under the registration mutex, so a serve started while the stop still waits is not ended too; C API and llama-ffm only, the Java RpcServer was not affected; red/green over a new stop seam, F271); eleven tests compared two greedy generations across a prompt-cache hit (the second request re-evaluates one token over the cached prefix, upstream [TAG_PROMPT_LOGITS], whose logits are not bit-identical to the batched prompt evaluation; measured on the random test model over 4000 prompts: the first token's logprob differs in 3999 first-vs-second pairs and the text in 4, while the second and the third cached request agree in all 4000; the three that the MSVC job's failure named and eight more found by a sweep of every test tree now compare the second with the third cached request and assert the reuse through the timings, or run both requests without the cache and prove that through the timings; CLAUDE.md records the rule and names the helpers, F272).
  • CI: the Windows sign job runs on every run instead of being skipped (ported as a fresh change from the unmerged branch claude/jolly-brahmagupta-0ydzby, d10f211). A skipped job skips every job behind it in the dependency chain past any if: in between: since the job existed (2026-10-15) every run without the sign_windows switch ended "success" with package green and the smoke sets, the report and both publish jobs skipped (run 38870889665 attempt 2 on main, and every run since) -- no smoke set and no publish job has run since. Now the job always runs, its steps are gated on the switch, the environment is maven-central only when signing and the unprotected unsigned otherwise, package is back on the default condition, and check-natives.py refuses a job-level if: on the sign job (unit test, proven red with the old condition put back).
  • OpenAiCompatServer parity with upstream and the protocols: the token-count routes (/v1/messages/count_tokens, /v1/responses/input_tokens, /v1/chat/completions/input_tokens), logit_bias / n_probs / response_fields forwarded, Ollama /api/generate with Ollama's template semantics, format and images, Anthropic's named tool_choice forced and id_slot / extra_params passed through, TEI-style rerank requests, a failure after a stream started reported as the route's error event, wrong-typed number fields and unknown input items answered 400 instead of silently replaced. New builder methods: withLogitBiasJson, withResponseFields, the reasoning-budget tags, enableContextShift, RouterModel.getAliases() / Status.INCOMPLETE, OpenAiServerConfig.totalSlots.
  • llama.cpp b11639 → b11815 in eight reviewable steps (b11760, b11761, b11799, b11800, b11803, b11809, b11814, b11815; docs/history/llama-cpp-breaking-changes.md has a row per step): patch 0016 (Kolibri-1) dropped for upstream's own implementation (#30673, community GGUFs need reconversion, documented in the README), patch 0019 dropped (this project's ggml-cpu : select the NEON fp32->fp16 conversion ggml-org/llama.cpp#30505 merged at b11761), patch 0007 refreshed for POST /tts and the /v1/realtime WebSocket, server-connect.cpp compiled in, tts_engine.cpp moved to the gen_audio init/valid API, test_kolibri1.cpp rewritten against upstream's converter format; the b11803 step brings Flint, SenseNova U1 (with its vision projector) and a jinja namespace fix; the last three steps (2026-10-22) bring LoRA on prism.hadamard folded weights, an OpenCL ARGMAX kernel the three OpenCL module jars embed, the tokenizer.ggml.clean_spaces GGUF key with changed detokenizer defaults for ten pre-tokenizers, the Pixtral pre-tokenizer moved to Tekken, KleidiAI v1.32.0 (not built here) and a SYCL CONV_2D layout fix -- no source change here in any of them, and all 12 patches apply as they are (no patch-target file changed in b11803..b11815, the drop-checks re-read at b11815).
  • README audited against the code (one reader per section, every finding adversarially verified, 63 confirmed and applied; the CHANGELOG "Changed" entry lists them): no 32-bit Windows natives, the snapshot channel is a manual Publish run, OpenVINO opt-in wherever the additive rule is described, the static library jars, the release assets, the overridden build options, GPU backends as module builds (-DLLAMA_CURL is gone), the loader's search order and the four Windows extras, handleTokenize / handleDetokenize arguments, streaming /v1/completions, OpenAiServerConfig.builder() and x-api-key, the router statuses, RPC in the library jars, the LangChain4j adapter's mapped features, the agent's prompt and status line, chatWithTools' round cap, the infill prompt position, video input shapes, the reactive cancellation semantics, the Kotlin wrappers, the Akka snippet, the logging verbosity split, the Android ABIs, emulator coverage and from-source recipe, the Windows import table, the PIT scope, and three test properties added to the reference table.
  • CI: both SYCL natives jobs install upstream's toolchain (Intel Deep Learning Essentials 2026.1.4 + oneDNN 2026.0.2 offline installers + Level Zero, pinned by URL as llama.cpp's ubuntu-24-sycl / windows-sycl jobs do) instead of the unpinned apt repository and the 2025.3 bundle; the shipped SYCL modules now import ze_loader and the Windows one needs the oneAPI 2026 runtime, both named in the README's classifier table. The OpenSSL half of upstream's move does not apply: the SYCL jars are module-only builds with no cpp-httplib.

Test plan

  • Affected unit / integration tests pass locally: the C++ suite built from a fresh tree and run at every bump step (b11799, b11800, b11803, b11809, b11814, b11815: 686/686 at the last three, the rewritten cache-path tests included), the Java pin smoke (NativeLibraryLoadSmokeTest, 7/7 against the b11815 library), the Java classes touched by each change (AnthropicApiSupportTest, RouterModelTest, OpenAiCompatServerHttpTest, StreamEnvelopeTest, the mapper and translator tests, the loader tests, the ten rewritten cache-path Java tests against the random tiny model, ...), the buildcheck unit tests (145), spotbugs:check, spotless:check, check-patches.py, check-natives.py (red with the sign job's old if: put back, green without), check-shared-files.py, check-release-gate.py, check-run-scripts.py and the PyYAML parse of the workflows; the classes jar's manifest read back after mvn package; the full model-backed suites and the native matrix are left to CI on purpose.
  • CI is green on this branch -- the run on d10f211 is the first since 2026-10-16 in which the smoke sets, the report and the publish-job gates can run at all (the skipped sign job had silently skipped everything behind package), so it is also the first exercise of the Main-Class smoke (F269), the natives-jar smokes and the RPC smoke on the published jars at b11815. Run 39702748614 (head 272c8fc) was green in 69 of 72 jobs: the two verify-signing-key jobs are red by design on a branch, and the MSVC Windows Java job failed in ChatScenarioTest#testChatCompleteTextMatchesChatCompleteContent (F272, fixed in 85ebbfd and f64a42e). The run on the b11815 head is also the proof for the natives builds at b11815, for the SYCL installer URLs (unreachable from the sandbox, mirrored verbatim from upstream's release.yml), for the new manifest check in the package job and for the model-backed forms of the rewritten tests; the two grammar tests of LlamaModelTest (F270) were green in 39702748614.
  • Docs / CHANGELOG updated: CHANGELOG.md, README.md, CLAUDE.md, TODO.md, docs/patches.md (rendered), docs/history/llama-cpp-breaking-changes.md, docs/history/dropped-llama-patches.md, docs/upgrade/llama-cpp-version-bump.md, BUGHUNT-FOUND.md / BUGHUNT-CHECKED.md.

Related issues / PRs

Checklist

  • I have read CONTRIBUTING.md and CODE_OF_CONDUCT.md
  • My commits follow Conventional Commits -- they are imperative one-line subjects in the repository's existing style (Refuse ... (F266), Upgrade llama.cpp from b11814 to b11815), not type(scope): prefixed.
  • No security-sensitive changes beyond the hardening described above (slot names with a directory part or .. are refused, F251), which needs no private disclosure.

Generated by Claude Code

claude added 30 commits October 20, 2026 23:42
Upstream's schema reads "n" as n_cmpl, limited to the slot count, and the
server answers the extra completions in child tasks. The engine posts one
task and creates none, so "n": 2 came back as one choice without a word on
every native path: C API, FFM, LlamaModel.handle*, the blocking
/v1/completions that forwards its body, and since F186 the streamed one --
F186 moved that route onto the native OAI path and with it dropped the Java
refusal F180 had added. Found by the branch review.

populate_completion_task refuses n_cmpl > 1 after the schema, as F184
refuses several prompts, which covers the blocking, streamed and chat paths
in one place.

Tests: a C API case on a two-slot model (four paths refused, n:1 answers
one choice; red before, green after), and the HTTP and model-level Java
assertions back for both /v1/completions routes (the test model now has two
slots, so "n": 2 passes the schema and reaches the engine's refusal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
F16 fixed the use-after-free between close() and synthesize() for the JNI
TextToSpeech and named FfmTextToSpeech as affected too, but the FFM class
stayed as it was: synthesize() checked a flag and called into the engine
without a lock, and close() freed the engine (and the mutex a synthesis
holds) underneath it. Found by the branch review.

A ReentrantReadWriteLock as in the JNI class: syntheses share the read lock
(the engine serializes them itself), close takes the write lock and waits.
The two native calls move behind a Backend seam, as in FfmNativeServer, so
the locking is tested without the library.

FfmTextToSpeechTest (5): close waits for a synthesis inside the native call
(red with the seam but without the lock, green with it), synthesize after
close is refused without touching the handle, close twice frees once, and
the plain contract. llama-ffm verify 35/35. F16's ledger status now says the
FFM half came with this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
…ream (F199)

streamAnthropic and streamResponses scheduled the heartbeat before setting the
opening event (message_start / response.created). A heartbeat that fired first
started the stream with an empty prelude, and startWith only set the field the
stream writes when it starts: the opening event was lost. startWith now writes
the text at once on a started stream, and both routes set the opening before
scheduling the heartbeat. ResponseStreamTest pins it over a fake HttpExchange.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
…(F200)

runEachOnItsOwnThread made its pool as large as the batch, so ten thousand
requests were ten thousand threads, although the native scheduler only runs
as many as it has slots. It now takes a bound (chatBatch passes 64) and the
rest start as threads free up. An Error from a request was rethrown at the
first future holding it, returning while the others still ran; every failure
now propagates after all requests finished. BatchDispatchTest pins both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The CLI passes the advertised id on as --alias, which llama.cpp splits at
commas and strips into a set, naming the first entry in every answer:
--model-id my,model advertised "my,model" and answered as "model". The flag
now refuses a comma, an empty value and surrounding whitespace, and an id
derived from a file name replaces commas with '_' and is trimmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The Anthropic translation set "verbose" to read __verbose.stopping_word, and
upstream's debug object is the whole native result: the rendered prompt, the
tokens and the generation settings, carried through JNI with every answer and
dropped. Upstream's response_fields projects exactly that object. It is now a
RequestField (SCHEMA, checked by test_wire_contracts) with
InferenceParameters.withResponseFields, the mapper forwards it (a non-string
array is a 400), and the Anthropic route asks for ["stopping_word"].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
buildRawValueObject read each value with a plain readTree, which parses the
first JSON value and drops the rest: "true false" reached the template as
true. It now reads with FAIL_ON_TRAILING_TOKENS, so such a value falls back to
a string literal as documented, the same rule JsonParameters and ChatRequest
already apply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
throw_utf8_impl replaced a pending exception with ThrowNew on its ASCII path
and called FindClass/GetMethodID/NewObject over it on the other, which the
JNI spec forbids and Android's CheckJNI aborts on. Both helpers now check
ExceptionCheck first, as jni_guard_impl does: the pending exception is the
more precise error. Pinned by JniUtf8.APendingExceptionIsLeftInPlaceOnBothPaths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Ollama clients preload a model by sending /api/generate without a prompt, and
Ollama answers at once with done and done_reason "load". Ours sent an empty
user turn through the chat template and generated an answer. The route now
answers such a request (no prompt, no suffix) with Ollama's load answer
without calling the backend; an empty prompt with a suffix stays FIM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The overview stopped at F158 and showed F158 as behaviour still open; it is
now generated from the entries (121, every one with its anchor). F16, F59,
F95, F158 and F180 note what later fixes closed (F198, F180, F186, F197);
BUGHUNT-CHECKED records F168 for JllamaNative and adds BatchDispatch (F200).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
jllama_api.h and docs/c-api.md: a completion request takes one prompt and one
choice (F180/F197), the answer is one object. CLAUDE.md, the OpenAiCompatServer
and server package Javadoc, and applyLlamaCppSampling: a streamed
/v1/completions is forwarded verbatim (F186). README: the embedding example
sets the alias the answers report (F189), /api/generate without a prompt
(F205). TODO.md: F112 count_tokens and model unloading recorded as limits, the
retired (n) numbering explained, the dangling TODO (n) comments point at
their finding ids. C++ test table: 645 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
107 fixes had no line; they are grouped under Fixed by surface (server,
Ollama, Anthropic, Responses, rerank, Java API, loader, FFM, langchain4j),
the behaviour changes a caller must react to under Changed and Upgrading
from 5.1 (items 8 to 13), and the new API under Added. The one internal
finding id in the text is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
handleOllamaChat translated the request before the try that maps a
rejection to 400 and a failure to 500. The translator copies every
messages element with a cast to ObjectNode, so a string, null or array
element threw ClassCastException out of the handler; no headers had
been sent, and the JDK server closed the connection without a status
line, streamed or not. A messages value that was no array was silently
read as no messages.

The translator now refuses both with upstream's wording plus the index
(common/chat.cpp: "Expected 'message' to be an object"), and the
handler answers that IllegalArgumentException with 400 and Ollama's
error body, as handleResponses does since F89. Any other runtime
failure stays a logged server error.

Red before the fix: the HTTP test failed with "SocketException:
Unexpected end of file from server" and the translator test with "was:
<java.lang.ClassCastException>"; green after it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
OpenAiBackend allows stream/streamCompletions to throw IOException when
generation fails, and the blocking routes answer it with 500. The five
streaming routes took any IOException for a client that had gone away:
they logged it at DEBUG and wrote nothing. Since F182 the response
starts with its first write, so such a failure ended the exchange with
no headers and the JDK server dropped the connection without a status
line.

The IOException arms now answer 500 with the route's error body while
the stream has not started, and keep the DEBUG line otherwise.
ResponseStream records the start before it writes the headers, so a
client that is noticed gone at the header write counts as started: the
request is not answered a second time and a later write fails instead
of sending the headers again.

Red before the fix: the HTTP test over every streaming route failed
with "SocketException: Unexpected end of file from server" and the
ResponseStream test with "Expected: is <false> but: was <true>"; green
after it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The raw branch of /api/generate sent only the prompt and the sampling
options to the completion endpoint; a system, template or context next
to "raw": true was dropped without a word, and the CHANGELOG, the F179
ledger entry and a test described that as Ollama's behaviour. Ollama's
GenerateHandler refuses exactly that combination first, before its load
answer and before the suffix path, with 400 "raw mode does not support
template, system, or context".

hasRawConflict checks Ollama's condition (non-empty system or template,
non-empty context; empty values are no conflict), and the handler
answers it right after reading the body with that 400 and without
calling the backend, streamed or not. The test that pinned the silent
drop is replaced by one expecting the refusal, next to a raw request
without a conflict; the CHANGELOG line and the F179 fix line are
corrected.

Red before the fix: "Expected: is <400> but: was <200>" for a raw
request with a system prompt; green after it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Ollama answers /api/chat without messages (absent, null or empty) by
loading the model: one object with an empty assistant message, done
and done_reason "load", whatever "stream" says. Clients preload a model
that way through the chat route. Here the request was translated to an
empty conversation, which the chat mapper refused with 400.

handleOllamaChat now answers such a request before the translation and
without calling the backend, as handleOllamaGenerate does since F205;
keep_alive 0 gets the load answer too, since this server's model stays
loaded. A messages value of the wrong type is still refused by the
translation. The test backend records stream calls as well, so the
test can show that nothing was generated on the streaming path.

Red before the fix: "Expected: is <true> but: was <false>" for done on
a body without messages; green after it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The Ollama translation turned "think": false into reasoning_effort
"none" and a level string into reasoning_effort, but dropped "think":
true. Upstream starts from the server's default (--reasoning off turns
thinking off) and lets a request's chat_template_kwargs.enable_thinking
true override it, so an OpenAI client can switch thinking on while an
Ollama client asking for it was silently ignored by such a server.

"think": true now becomes chat_template_kwargs {"enable_thinking":
true}, a JSON boolean as upstream requires; /api/generate gets it
through the same translation. The F78 ledger line that said true keeps
the template's default is corrected.

Red before the fix: "Expected: is <true> but: was <false>" for
enable_thinking after the chat mapper; green after it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
…sts (F272)

ChatScenarioTest#testChatCompleteTextMatchesChatCompleteContent,
ChatAdvancedTest#testCachePromptConsistentOutput and
MemoryManagementTest#testPromptCacheStableAcrossMultipleCalls set the
texts of two identical greedy requests equal, with a prompt-cache hit
between them: the second request takes every prompt token but the last
from the slot and re-evaluates that one token in a batch of its own
(upstream [TAG_PROMPT_LOGITS]), whose logits are not bit-identical to
the batched prompt evaluation of the first request. On a near tie the
greedy argmax flips, which the MSVC Windows job of run 39702748614 saw:
"2 plus 2 is 4.<|im" against "4.<|im_end|>".

Measured on the random test model over 4000 prompts: the first token's
logprob differs between the first and the second request in 3999 pairs
and the text in 4; the second and the third request, both over the
cached prefix, agree in all 4000; two requests with cache_prompt=false
are bit-identical (150 of 150).

ChatScenarioTest sets cache_prompt=false on both requests and proves it
through the second response's timings (cache_n 0, prompt_n equal to the
prompt tokens). The other two tests make three requests, assert that
the second and the third reuse the cache (cache_n == prompt_tokens - 1,
prompt_n == 1) and compare those two with each other; the first is only
checked for output. CLAUDE.md records the rule, the ledger carries F272.
Test and documentation change only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Six upstream commits, the first runbook chunk on the way to b11815: LoRA
adapters on prism.hadamard folded matmul weights (#30910, the delta reads
the primal input; only a latent lookup table is still refused), dflash's
optional fc.input_scale (#30945), an OpenCL F32-to-I32 ARGMAX kernel
(#30897, embedded by the two OpenCL module builds), WebGPU Q2_0 (#30914)
and two WebUI commits. Nothing in common/, include/, tools/server/,
tools/mtmd/, the root CMakeLists.txt or upstream's .github/, so no source
change here, the server contract and the toolchain pins are unchanged,
and all 12 patches apply as they are (fresh configure at 0b1281aee,
check-patches.py 12/88/0). Built from the pin in a fresh tree, ctest
686/686. CHANGELOG, TODO.md and the history rows updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
Five upstream commits, the second runbook chunk on the way to b11815:
tokenizer.ggml.clean_spaces as a GGUF key (#30940, with the pre-tokenizer
defaults turning the space clean-up off for lfm2, glm4/glm5, dbrx,
exaone4, mellum2, minicpm5, gemma-4 and chatglm-bpe), the Pixtral
pre-tokenizer moved to Tekken (#30960), the granite graphs recording their
layer inputs (#30957), KleidiAI v1.32.0 with SVE Q8_0 kernels (#30808, not
built here) and the SYCL dequant switches merged (#30740). Nothing in
common/, include/, tools/server/, tools/mtmd/, the root CMakeLists.txt or
upstream's .github/, so no source change here, the server contract and
the toolchain pins are unchanged, and all 12 patches apply as they are
(fresh configure at d88040c70, check-patches.py 12/88/0). Built from the
pin in a fresh tree, ctest 686/686. CHANGELOG, TODO.md and the history
rows updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
…tests (F272)

A sweep of every test tree for the comparison 85ebbfd removed from three
tests found eight more: two generations set equal with a prompt-cache hit
between them, where the second re-evaluates one token over the cached
prefix (upstream [TAG_PROMPT_LOGITS]) and does not reproduce the batched
logits bit for bit. MemoryManagementTest (the deterministic-output test,
the stable-across-calls test through a shared helper, and the
complete-miss test, whose fresh model now gets the same warm-up),
LlamaModelTest#testCompleteAsync and ChatScenarioTest's stop-string test
(cache_prompt=false on both requests, proven through the timings; the
stopped content is a prefix of the unconstrained one now), and in the C++
suite the two LoRA cache tests (a third cached request, and the restored
slot against the saved one) and the two reasoning-budget tests (both
requests without the cache, proven through the timings). Test and
documentation change only; the ledger carries the Nachtrag and CLAUDE.md
names the helpers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
One upstream commit, the last runbook chunk: the SYCL CONV_2D kernel
supports the channel-fastest CWHN layout instead of asserting on it
(#30363), which reaches the two SYCL module jars; the regenerated
docs/ops/SYCL.csv is what put this single commit over the 100 KiB
threshold. Nothing in common/, include/, src/, tools/server/, tools/mtmd/,
the root CMakeLists.txt or upstream's .github/, so no source change here,
the server contract and the toolchain pins are unchanged, and all 12
patches apply as they are (fresh configure at 7170cad4d, git apply in
order on a pristine worktree, check-patches.py 12/88/0; no patch-target
file changed anywhere in b11803..b11815, the drop-checks re-read at
b11815 give the b11803 answers). Built from the pin in a fresh tree,
ctest 686/686, NativeLibraryLoadSmokeTest 7/7 against the b11815 library.
CHANGELOG, TODO.md and the history rows updated, with one correction to
the b11809 rows: three OpenCL module jars embed the new ARGMAX kernel,
not two.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
@bernardladenthin bernardladenthin changed the title Pre-release bug-hunt fixes, llama.cpp b11803, the SYCL installers and a README audit Pre-release bug-hunt fixes, llama.cpp b11815, the SYCL installers and a README audit Oct 22, 2026
…use a job-level if on it

A skipped job skips everything behind it in the dependency chain, past
any `if:` of the jobs in between (GitHub's documented rule). Measured in
run 38870889665 attempt 2, a dispatch on main and the first run to reach
package after the sign job existed: sign-windows-natives was skipped (no
sign_windows switch), package tolerated the skip with !cancelled() and
ran green, and the smoke sets, the report and both publish jobs behind
package were skipped all the same, with the run concluding "success".
Every run since did the same, so no smoke set and no publish job has run
since 2026-10-16.

The job now runs on every run and is never skipped: without the switch
every step but the first is gated off, and the environment is an
expression -- maven-central only when signing, otherwise the unprotected
`unsigned`, which holds no secrets -- so the protected environment's
rules still never apply to a pull request. package goes back to the
default condition: a sign job that ran and failed still skips it.
natives.check_signing refuses a job-level `if:` on the sign job (unit
test for both forms; proven red with the old condition put back). The
workflow header comment, CLAUDE.md, TODO.md item 11 and the CHANGELOG
describe the always-running job.

Ported as a fresh change from the unmerged branch
claude/jolly-brahmagupta-0ydzby (commits 251bcab and 2ac4ea8 of
2026-10-16), which is left to be deleted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
The package job's "Load the natives jars together" step died on its first
run since the sign-job fix (run 39763815465): smoke-natives-jars.sh line 84,
`path: unbound variable`. Commit 68ab75d (F269) replaced the line that
assembles the consumer's classpath -- the classes jar, every natives jar and
the runtime dependencies -- with the Main-Class check and dropped it; bash -n
cannot see an unbound variable, so no check caught it.

Proven with a stub java on PATH that records its arguments: the committed
script fails with the same message before any java call, the restored one
runs both the classpath and the module-path round and hands java the
classes jar, all natives jars and the dependencies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBFFnrhtvXiUeyxjmUc4R2
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@bernardladenthin
bernardladenthin merged commit b2dec05 into main Oct 22, 2026
11 of 33 checks passed
@bernardladenthin
bernardladenthin deleted the ccr-90fc5f6a-vs4s0f branch October 22, 2026 14:31

This branch was successfully deployed

1 inactive (outdated) deployment
startgate — 7de7a846 Deployed Oct 22, 2026 by bernardladenthin via Start gate (abort window) #1313
maven-central — 7de7a846 Deployed Oct 22, 2026 by bernardladenthin via Verify GPG signing key (no secrets printed) #1313
unsigned — d10f211a Deployed Oct 22, 2026 by bernardladenthin via Sign the Windows DLLs (SSL.com eSigner) #1312
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants