Repository navigation
SuperSLM 1.15.0
Released 2026-10-23.
SuperSLM 1.15.0 makes schema-bound decode faster on the CPU. A schema-bound decode is a generation that must match
a bound schema, for example a JSON order such as potion_shop_order. It ships three things:
- The masked finish. It is always on, and the tokens are unchanged. When a schema is bound, the last step of each
token scores only the tokens the schema allows at that point, not the whole vocabulary. - Jump-forward. It is opt-in, and its canonical mode changes the tokens. Where the schema leaves only one possible
text (a key name, a quote, a brace), the engine writes that text in one batched pass, not one token at a time. - Exact jump-forward. It is opt-in, and the tokens are unchanged. The host offers a guess at the next tokens. The
engine checks each guessed token with the model's own decode rule and keeps only the ones the model would have
written itself.
No existing declaration, struct layout, status ordinal or save format changes, and no model artifact needs
reconversion. The GPU backend is unchanged, and so is decode without a bound schema.
What it buys, measured
All rows were measured on an AMD Ryzen 9 3950X with an MSVC Release build and Qwen2.5-0.5B-Instruct (the Unreal
example's model). The prompt is the example's potion-shop order: 41 prompt tokens, and 28 generated tokens to the
schema's end. The times are generation only, not prefill. Each time is the median of 15 runs, one process per run,
and each ratio is the median of the per-round ratios. The first two rows are from 2026-10-20. The jump-forward rows
are from 2026-10-21, against "off": 1.15.0 with jump-forward off (the masked finish), timed in the same session.
| Configuration | Tokens written | One thread | 4 tasks (parallel-for hook) |
|---|---|---|---|
| 1.13.1 / 1.14.0 | 28 | 1,257 ms | 711 ms |
| Masked finish (1.15.0, always on) | 28, same tokens | 921 ms (1.37x) | 560 ms (1.27x) |
| Exact jump-forward, draft learned from earlier orders | 28, same tokens | 604 ms against 897 ms off (1.48x) | 557 ms against 549 ms off (0.996x) |
| Exact jump-forward, the engine's own draft (NULL) | 28, same tokens | 1,112 ms against 897 ms off (0.81x, slower) | 572 ms against 549 ms off (0.96x) |
| Canonical jump-forward | 21, different tokens | 471 ms (1.96x against the masked finish) | 456 ms (1.21x against the masked finish) |
The 1.48x row comes from one prompt. Over 20 other orders, exact mode with the learned draft took 12,878 ms against
16,676 ms off, which is 1.295x in total. The median per order was 1.42x. One order was slower (0.82x), and two broke
even. These figures are for a 0.5B model on one CPU. In a game, the plan estimates (not measured end to end) that exact
mode saves about 0.2 to 0.3 s per extraction at one thread, and about nothing under threaded decode.
What this means for a host:
- Do nothing and get the masked finish. Schema-bound generation is about 1.3x faster, and every token, save blob
and anti-LM state is byte-identical to 1.14.0. This holds for any model with a hidden size of at most 131,071.
Every certified model is within that bound. - Exact mode pays only with a good draft, and only at one thread. The model must accept about 60% or more of the
drafted tokens before exact mode gains anything. A wrong guess costs about 0.6 of a token pass. The engine's own
draft is the schema's canonical spelling. This model rarely writes that spelling, so with that draft exact mode is
slower than not using it. A draft learned from the model's own earlier outputs is what gave 1.3x to 1.5x. Under a
threaded decode (a parallel-for hook with 2 or more tasks), exact mode is about even with off. - Canonical mode is the fastest, and it changes what the model writes. It writes the schema's own spelling of the
forced text, so the model then reads text it would not have written. On 40 test orders, 32 came out different from
off, and the quality verdict was inconclusive. Use it only if you have checked the outputs for your schema. Its
output is also not the GPU's.
What changed
- Masked finish. Under a bound schema, when the model's hidden size is at most 131,071 (computed once at
sslm_model_map), the token finish computes only the head rows of the tokens the schema allows. At that size no
row's dot product can leave int32. So tokens, the damped-greedy anti-LM state and save blobs equal the full
finish's, greedy and damped greedy alike. A model above the bound keeps the full finish. - The parallel-for hook under a bound schema splits the list of allowed rows, not the vocabulary.
runis called
if and only ifmax_tasks >= 2and the state allows at least one token (parallel_for.h). The documented
partition changes, and so does the task count a host's hook sees, for bound decode only. sslm_seq_forced_tokens(model, seq, ids, cap, &count, &accepting), new and read-only. It returns the forced
chain at the sequence's walk state: the tokens that spell the one text the schema allows before its next choice.
It also reports whether the state is accepting.sslm_model_mapbuilds the table it reads, at 8 bytes per schema
state. An allocation failure there fails the map withSSLM_ALLOCATION_FAILED.sslm_seq_jump_forward(model, seq, chunk_budget, params, opts, ws, out, cap, &count), new. It admits the
pending token and up tochunk_budgettokens in one batched pass through the prefill path. WithoptsNULL or
modeSSLM_JUMP_CANONICAL, it admits the forced chain. With modeSSLM_JUMP_EXACT, it admits the draft in
sslm_jump_options(or the forced chain when the draft is NULL), checks each drafted token with the decode step's
own finish, and keeps the confirmed ones. Exact mode returnsSSLM_OKfor any draft. Rejected rows' pages go back
to the sequence's reserve.- Both verbs return
SSLM_ARTIFACT_REJECTEDon an artifact without a schema section and a tokenizer. - Damped-greedy parameters feed the admitted tokens to the anti-LM history, so pass the same
paramsto the verb
and tosslm_decode_step_v2. docs/api.md(Jump-forward) gives the host loop, the refusals, the limits and the threading cost. In
canonical mode, the host loop is what keeps the output independent ofchunk_budget. In exact mode, no host
loop is needed.
- Both verbs return
- New types:
sslm_jump_mode(SSLM_JUMP_CANONICAL= 0,SSLM_JUMP_EXACT= 1) andsslm_jump_options
(struct_size,mode,draft,draft_count). - Fixes in the decode step. They apply with or without jump-forward:
- Damped greedy, a failed re-key. When a call named a new anti-LM order and the new state's allocation failed,
the old state had already been freed but was still referenced. The next save then read freed memory, and the
next re-key or release freed it twice. Now the replacement is created first, and a failure returns
SSLM_ALLOCATION_FAILEDwith the old state intact. - Damped greedy, a failed history update. An allocation failure inside the anti-LM history update could leave
a context entry with no observations. The next damped finish then divided by zero (SIGFPE). 1.14.0 and earlier
have this latent crash. The update is now all-or-nothing. - A failed finish. If the token finish failed after the layers had run (a numeric rejection, a damped-greedy
refusal or an allocation failure), the sequence was left half-moved. Later decode steps were refused, the retry
re-embedded the last token, or the retry emitted a different token. A failed finish now leaves the sequence
where the finish began, and a retry equals a run that never failed. Success paths, tokens and save blobs are
unchanged.
- Damped greedy, a failed re-key. When a call named a new anti-LM order and the new state's allocation failed,
Compatibility and required action
- The ABI change is additive: two C verbs (55 in all), one enum and one struct. No existing declaration, struct
layout, status ordinal or save format changes. - Tokens are unchanged unless you opt in to canonical jump-forward. The masked finish and exact mode both give
1.14.0's tokens, digests and save blobs. - A parallel-for hook sees a different partition under a bound schema. It sees the allowed rows, and a smaller
task count. A hook that only runs the tasks it is handed needs no change. - Saves are unchanged.
SSB5,SSB6,SPX1and the GPU's saves written by 1.14.0 restore on 1.15.0. AnSPX1
prefix blob, though, records its producer. A blob written by 1.14.0 is refused by 1.15.0 with
SSLM_RESTORE_PRODUCER_MISMATCH, as 1.14.0 documents. A host that caches prefix blobs rebuilds them by prefill
after the upgrade. - No model artifact needs reconversion, and the shaders are unchanged.
- The GPU prefix twins stay unreleased until 1.16.0. These are
sslm_gpu_prefix_saveand
sslm_gpu_prefix_restore; they are exported, and nothing about them changes in this release.
Verification
- Exactness on the box (B7b). The 40 population prompts and the timing prompt were run with off and three exact
arms: the learned draft, the NULL draft, and a draft that is always wrong. Each exact arm's token stream and text
were compared with off's, byte for byte. 0 of 123 arms differed at one thread, and 0 of 123 at 4 tasks. - Timing. The timings above come from two sets of box runs. The off, masked-finish and canonical rows
(1,257 and 921 ms, 711 and 560 ms, 471 and 456 ms) are from steps B2 and B3 (2026-10-20), at build79e5b923, an earlier
build of this line. The exact jump-forward rows are from steps B7c to B7e (2026-10-21), at buildf03a5358, with the
bench's draft sources. B7's off arm atf03a5358(897 ms at one thread, 549 ms at 4 tasks) runs the released
masked finish and is no slower than B2 and B3's figures. The raw box records stay on the release branch
(claude/sfd-1p15, undertools/schema_fast_decode_box/results/), not onmain. - The released engine source. The CPU engine source in this release equals B7's measured build,
f03a5358. The
only differences are the version header, a comment insrc/matmul.cpp, the option labels in the headers' comments,
and 1.14.0's GPU prefix fixes. It does not equal B2 and B3's build,79e5b923. - On the release tree, on the box (2026-10-23), exact mode was byte-identical to off on all 123 arms at one
thread and at 4 tasks, the MSVC GEMM placement check passed, and the 7-token prefill took 148.2 ms against the
measured build's 148.3 ms. These records are on the release branch too (docs/release/1p15-box/). - On Linux with GCC, the full CPU suite, the schema fast-decode cells and the release-tree checks ran on this
tree.
Files changed
include/superslm/sslm_abi.h,include/superslm/sslm_abi_functions.inc: the two verbs,sslm_jump_modeand
sslm_jump_options.include/superslm/parallel_for.h: the partition under a bound schema.include/superslm/forward_sites.h: the
batched pass's per-row saturation counts.src/sslm_abi.cpp,src/forward/,src/detail/,src/kv_pages.*,src/tokenizer.cpp,
src/tokenizer_tables.h,src/damped_greedy_antilm.cpp,src/bad_alloc_wrap.h: the masked finish, the
forced-next table, the verbs, exact mode and the fixes.src/matmul.cpp: a comment (the GEMM placement pin is 1.14.0's, unchanged).docs/api.md,CHANGELOG.md, this note.tests/test_schema_fast_decode.cpp,tests/schema_fast_decode/: the cells.tools/schema_fast_decode_bench.cpp,tools/schema_fast_decode_box/: the box bench, its driver and the results.
CI note: a test-only fix landed on main after the tag (aa27623). It adds a missing include that the macOS test build needs and shortens the branch-coverage job. The engine code is unchanged.