Repository navigation
Releases: crit-labs/crit
Release list
crit 0.5.0
Overview
crit 0.5.0 judges quality on what an engine serves. Eval protocol crit-eval-v6 scores fixed
text once per model on the reference and stores it; each engine scores the same ids through
crit serve's new chat-score-v1 (its prefill and its decode forced to the text), is judged on
the positions it serves, and must score its own served replies alike (honesty). No reference
runs per candidate, and the reference itself streams layers ahead, gathers rows in parallel
reads and runs long prompts layer-major. Eval also runs in one attempt with no fixed time cap,
measures follow-up turns and prompt caches, and repeats a speed case only when its runs
disagree. Core adds batched paged serving, hybrid and sliding-window prefix reuse and faster
constraints; Inference gains paged attention, a batched reference engine, GGUF projections and
dense-layer offload. Breaking: v6 quality results do not compare with v5 (prepare data again;
crit eval status refuses other majors); the native engine ABI is 2, so engines built on
crit/native_engine.h must be rebuilt; crit run eval needs packages declaring
chat-score-v1, whose score_tokens takes prompt_rows. The Python distribution and the Core
SDK share version 0.5.0.
Changed
-
Eval protocol
crit-eval-v6measures quality on fixed text through the engine's serving paths
instead of scoring every candidate's replies on the reference. Each quality text is a
conversation's generation prompt followed by its written answer (restored in
suite/quality.json, cut to 256 tokens);crit eval reference --model --datascores every
position once per model, suite and reference version and stores each position's log-probability
and top 16 under the data (about 16 MB). The engine scores the same ids through crit serve's
chat-score-v1, prompt positions from its prefill and answer tokens from its decode forced to the
answer, and each set is judged on the positions it serves (SET/served: the answer's first token
from the prefill's last position, the rest from decode); prompt positions, whose prefill logits no
request returns, are reported inquality.promptand not judged. Both come with figures by
position bucket so thresholds show as steps. An honesty check
scores the engine's served greedy replies through the same call; they must agree within 1e-3
nats.crit run ... evalscores the data's texts before serving the first candidate and needs
chat-score-v1; no reference runs per candidate. v5 results do not compare with v6, and a
baseline compares only within its prepared data, suite and major version. Prepare data again
for v6. -
crit eval statusjudges results of the current protocol major only and refuses others (their
status is stored in them), instead of rendering pre-v4 results without the request-history and
retrieval gates, results without an exactness mode asrequired, and v5 quality as unmeasured. -
v5's per-reply quality scoring is gone:
StreamingReference.score(each sequence run whole) and
metrics.reply_quality. The reference scores throughscore_textsonly. -
Eval measures follow-up turns (protocol
followup, suitefollowup.json): a conversation's
turns, each resending the history, may be served from a prompt cache; each reports time to
first token, its cached prompt tokens and the prefill rate of the rest (followupKPIs), and
the turns run again after every other part must answer as they did first (prompt_cache
gate). An engine without a cache reports its fresh prefill and passes.crit servereports
the prompt tokens an engine did not compute asusage.prompt_tokens_details.cached_tokens. -
At the required context, the long-context curve's prompt holds the retrieval facts, and the
retrieval request right after that point shares its prompt up to the end of the document,
then asks the retrieval question (suitelong.jsonretrieval.question), so an engine with a
prompt cache prefills that text once. Retrieval requests may be served from a prompt cache
(they are judged on their text; their cached tokens are recorded); every timed request still
prefills. Prepare data again. -
Eval measures each speed case twice after its warmup and a third time only when the two
disagree: decode speed or time to first token spread by more than 5%, or the outputs differ
(protocolspeed.extra_repetition); before, every case ran three times. -
Eval's quality phase records where its time goes (
quality.timing: per score request, honesty
reply and rescore, the request's seconds, the engine's own prefill and decode time, the rest,
response bytes and parse time), and the honesty rescore asks the score call for the reply's
rows alone:chat-score-v1takes"prompt_rows": false, andscore_tokenstakes
prompt_rows, so the engine prefills the prompt as for a reply instead of scoring every
position the fixed texts already scored. Results are unchanged. -
crit run evalruns every part in oneevalattempt on one loaded engine instead of within the
1800 s benchmark cap, which a long required context outgrew and made Eval run in parts, each
loading the engine again. The attempt runs to the segment's deadline; each request to the
engine may take the protocol's floor plus a slack times what the engine's earlier requests in
the same Eval say it should (requests.timeout), so a hung engine ends the attempt
(eval_failed). crit serve's own bound on each request is then the attempt's deadline. -
Native engine ABI 2 (
crit/native_engine.h):crit_engine_scoretakestop_kand returns the
engine's own ranked alternatives with the target scores, query rows and argmax. Every export is
required:crit_core.nativeno longer probes for the request and log-probability exports and
refuses ABI-1 libraries; rebuild native engines against this crit's headers.
NativeEngine.score(ids, first_target, path, queries, top_k)returns
Scores(target, query, argmax, top). -
crit eval referencedrives the text model's own transformers forward instead of rebuilding
its embedding, masks, positions and final norm: decoder layers still stream onto the GPU one at
a time, but what the forward hands each layer is recorded first and its own tail runs on the
last layer's output. Models that do more around their layers (repeated residual streams,
multi-axis rotary positions, per-layer inputs, a final mixer, a sparse-attention indexer that
needs a mask) score as transformers scores them. Experts run transformers' eager per-expert loop
rather than its grouped GEMM. Scores of models the reference already read are unchanged (the
existing reference and format tests pass with exact equality). -
The reference reads safetensors tensors through a mapping of the file made per read, so the
pages it reads stay in the page cache rather than in its own resident memory, and no open
mapping holds the files. -
crit eval referencescores long texts in chunks of 8,192 tokens that resume the cache the
model's own forward builds (transformers' Cache: keys and values, sliding windows,
linear-attention and Mamba states), kept per decoder layer in FP32 scratch files while the text
is scored, so no mask of a whole long prompt is built. A model whose cache cannot be resumed is
scored by whole passes. -
crit run ... evalstops the reference at the reservation's deadline, checked between its
layers and sequences, and settles the attempt as timed out instead of scoring past it. -
The reference gathers embedding rows (such as a hashed n-gram table far larger than memory) by
parallel reads of exactly their bytes, every part of a split table in one batch, instead of
faulting pages in through a mapping one at a time: a Flash-Next pass gathers its 25,791 rows in
seconds rather than minutes. The rows are byte-identical. -
The reference reads each decoder layer's stored tensors ahead, while the previous layer runs: in
large reads in file order into one page-locked host buffer (at most one layer, up to 8 GiB),
copied to the GPU in one transfer and dequantized there as before, instead of mapping, copying
and transferring thousands of tensors one by one (a Flash-Next layer holds 6,166). Loaded layers
are bit-identical. -
The reference runs the texts' chunks layer-major: each decoder layer, once loaded, runs every
chunk it can, rather than every layer being loaded again for each round of 8,192-token chunks.
Only the layers up to those whose cache state the forward reads between chunks (the first layer
of each kind) run chunk by chunk: Flash-Next's 32K-token texts load 64 layers instead of 240.
Reads of another layer's cache state, or of the cache's own attributes, that would differ from
the chunk-major order make the texts run chunk-major; either order gives the same scores. -
The schema/regex compiler is
crit-language-compiler-2: it builds unbounded repetition left
recursive, which an Earley recognizer extends in constant work per item, so compiled artifacts
change while the languages they accept do not; cached artifacts compile again under the new
version. Eval compiles no constraints, so its results are unaffected. -
Host ISA detection (cpuid, xgetbv) lives in host-expert-arithmetic's
host_isa.h, shared by
every host path with AVX2/AVX-512 files, andcrit_inference_isa_sourcesbuilds those files
under one x86-64 condition.
Added
crit servescores fixed text through an engine's serving paths:POST /v1/crit/scorewith
prompt and continuation ids returns every prompt position's log-probability and top
alternatives from the engine's prefill and every continuation token's from its decode,
forced to the continuation (packages declaringchat-score-v1;ResidentChat.score_tokens).
crit_core.native.ResidentEngineimplements it for engines with query scoring, replay and
token log-probabilities, throughcrit_engine_scorewith `top...
crit 0.4.0
Overview
crit 0.4.0 reads models in the formats they are published in. Eval, crit run recon, crit serve
and calibration open a Hugging Face folder or a single weight file through one model source:
safetensors, GGUF (a lone .gguf included, with its config and tokenizer derived from its own
metadata), PyTorch state dicts and ONNX graphs. The reference and the decode ceiling read the
common quantization schemes as stored (compressed-tensors, FP8 blocks, AWQ, GPTQ, MLX, bitsandbytes
and ONNX MatMulNBits), each decoded to exactly the FP32 weights its own library gives. EXL2 and
EXL3 are refused by name. crit ships no GGUF runtime; gguf-py is needed only to score a GGUF with
crit eval reference. Eval data prepared with 0.3.0 for a safetensors model stays valid. The
Python distribution and the Core SDK share version 0.4.0.
Added
- GGUF models, pointed at as they come: a lone
.gguf, the first part of agguf-splitset, or a
folder holding one.crit_core.modelgets a strict, standard-library GGUF reader (inspect_gguf,
inspect_gguf_model) and derives the description files from the GGUF's own metadata
(crit_core.model.gguf_files):config.jsonfor thellama,qwen2,qwen3,qwen3moe,
qwen35andqwen35moearchitectures,tokenizer.jsonfor byte-level BPE vocabularies with
theqwen2,qwen35,llama-bpeandgpt-2pre-tokenizers,tokenizer_config.json, the
chat templates andgeneration_config.json. The base model's files beside the GGUF are used
instead where present, andcheck_gguf_folderrefuses them when their shapes, norm epsilon,
RoPE base, tokens or merges disagree with the GGUF. The context, ceiling and model identity count
the GGUF's stored bytes per block type. The reference decodes blocks with gguf-py and undoes
the reference converter's layout for the same six architectures (crit_eval.gguf_layout); a lone
GGUF from that converter gives back every tensor, the original config.json and
tokenizer, and the same reference scores. The derived tokenizers match Hugging Face's on
the reference converter's vocabulary test sets. crit runs no GGUF runtime. - Model sources.
crit_core.model.open_model(path)reads any model folder or weight file as one
ModelSource(weight headers, weight files, description files real or derived), and Eval,
crit run recon,crit serveand calibration read models only through it. A weight format is
oneModelFormat(safetensors, GGUF, PyTorch and ONNX today). - PyTorch state dicts:
pytorch_model.bin(sharded with its index too),.ptand.pth.
crit_core.model.inspect_torchreads torch.save's zip format with an unpickler that resolves
only what a state dict uses and refuses any other global, so the pickle never runs; tied
weights, float8 and storage offsets are kept, transposed views and the pre-1.6 format refused.
A safetensors checkpoint beside it wins, as in transformers. - ONNX graphs exported from a Hugging Face checkpoint (Optimum, torch.onnx), with external data.
crit_core.model.inspect_onnxwalks the protobuf with the standard library and names every
weight as the checkpoint it came from, through the consuming node's module scope (a linear
layer's transposed MatMul operand becomes<module>.weight); MatMulNBits weights keep their
node's attributes. onnxruntime-genai builder graphs and other quantized ops are refused. - Quantization schemes, decided in one place for the ceiling and the reference
(crit_eval.schemes): compressed-tensors int (pack-quantized W4A16/W8A16 with or without zero
points, int-quantized W8A8), FP8 per block (compressed-tensors andweight_scale_inv), AWQ GEMM,
GPTQ (2/3/4/8 bits,gptqandgptq_v2), MLX (affine, mixed, mxfp4, nvfp4, mxfp8),
bitsandbytes NF4/FP4/LLM.int8 and ONNX MatMulNBits, beside the FP8 and NVFP4 already read. The
reference decodes each to exactly the FP32 weights the format's own library gives (tested against
GPTQModel, AutoAWQ, mlx, bitsandbytes, compressed-tensors and onnxruntime on models those tools
wrote), and the ceiling counts each scheme's matrices at its GEMM rate. - EXL2 and EXL3 checkpoints are refused by name, by their config or their tensors, rather than
counted and read without their matrices: exllama decodes them only in CUDA kernels, so there is
no CPU dequantization to check a reference decoder against.
crit 0.3.0
Overview
crit 0.3.0 measures engines the way a chat client uses them. Eval protocol crit-eval-v5 sends
every prompt as chat messages to an OpenAI-compatible /chat/completions, so crit eval run --url
measures any served engine, built with crit or not, and crit eval reference scores quality on the
engine's own greedy replies against the checkpoint the data was prepared from. crit run measure
and crit run eval measure a packaged candidate through crit serve. crit serve talks to its
resident host over one loopback connection instead of polled files, streams tool calls as they are
written, returns token log-probabilities and reports tokens per round. Core serves concurrent native
engines, preempts and restores requests under memory pressure and schedules dependent request
steps. Nothing measured before carries over: prepare Eval data again for v5, capture run cases kept
as token ids again as chat messages, and expect no quality figures from an Eval adapter. The Python
distribution and the Core SDK share version 0.3.0.
Added
-
crit eval run --urlmeasures any engine behind an OpenAI-compatible chat API, no adapter
needed: the speed cases, held-out prompts, request history, long-context curve and retrieval
go to/chat/completionsas the chat messagespreparefreezes next to their token ids, with
lengths from the usage counts the server must stream, and quality from the engine's own replies.
It takes no engine lock, so it measures an enginecrit serveis serving. -
crit servereturns token log-probabilities (logprobs,top_logprobsup to 20) for packages
declaringchat-logprobs-v1: every generated token with its bytes and ranked alternatives, in
the finish chunk when streaming. ResidentChat adapters setlogprobs = Trueand receive
logprobs=n; native libraries rebuilt against thiscrit/native_engine.hexport
crit_engine_request_wait_outputand pass"logprobs": nthrough to Core, so
crit_core.native.ResidentEngineserves them when the model declares 20 alternatives. -
crit servereportstokens_per_round(output tokens per target pass) incrit_telemetry, and
a stream's usage chunk now carriescrit_telemetrytoo, when the engine reports its decode
rounds: response telemetry takes an optionaldecode_rounds, ResidentChat passes
generate_tokens' timingrounds, and Core engine libraries report theirs as Eval counts them. -
crit run ... eval --candidate ID --data DIRmeasures a packaged candidate the way a chat client
gets it: under one benchmark reservation it serves the candidate throughcrit servebefore
sealing, runs Eval over the chat API with the run's quality terms and context, stops the server,
scores the quality replies on the run's model and retains the result as
candidates/ID/eval/ATTEMPT.json. Every engine Eval opens is the candidate served at the context
it asks for, so the lower-context gate is measured too. Packages needchat-stream-v1and
chat-logprobs-v1from their first Eval. -
Core accepts an optional prefill work quantum for engines that pad prompt
computation. Mixed scheduling reserves those padded columns without consuming
nonexistent input, exceeding the batch budget or rounding decode grants up.
This closes a concrete integration gap exposed by a retained engine's kernels. -
Native HTTP integration fixtures exercise concurrent streaming and buffered clients,
both supplied recovery adapters, and client cancellation during prefill. An optional
CUDA recurrence example verifies device-carried dependent steps while predecessor
readback is blocked, with ordered publication and cancellation cleanup. -
Core can schedule bounded dependent steps for one request before host publication,
using engine-owned continuations and per-request eligibility. It reserves unresolved
output grants, publishes in order, and settles discarded descendants before retirement.
A portable asynchronous recurrent reference covers real dependent computation, seeded
sampling, stops, failure ownership and full-state recovery under memory pressure. -
Core's optional memory preemption path accepts typed pre-submission pressure,
suspends reclaimable settled requests, and restores their original streams and
identities after other resident work finishes. Recovery has separate telemetry,
cancellation and failure ownership. A paged-attention reference reuses physical
pages and replays accepted history without resampling or duplicate output. -
Native serving supports explicitly concurrent engine libraries through private resident
request wrappers and the configured Core admission capacity. Additive ABI request handles
allow cancellation during prefill, before any output; request-owned result facts avoid
shared mutable statistics. Older libraries retain serial serving. -
Core's reasoning and tool parsers accept tokenizer-bound delimiters and retain token identity
through incremental decoding and reasoning-to-tool routing. Single special-token boundaries
distinguish control ids from ordinary tokens with the same spelling; multi-token text
delimiters and explicitdelimiters="text"formats retain text matching.
Changed
crit run measure --candidate ID [--seconds N]measures the run's cases throughcrit serve, as a
chat client gets them, instead of through the package's Eval adapter in a child process. Each case
keeps its chat request as a captured{"messages": [...]}JSON file, andcrit serve's usage must
count the workload's prompt tokens for it. Every candidate decodes its own greedy reply, so no text
is pinned any more, and a reply that ends early is measured on the tokens it has. Memory is sampled
on the resident host process, which now names itself tocrit serve, and tokens per round comes
fromcrit serve's telemetry.--adapter,--modeland--configare gone; capture cases kept
as{"ids": [...]}again as messages. The resident host, like the worker before it, writes no
core file the size of the model when it crashes.- ResidentChat streams a tool call as the model writes it instead of as one delta
when its block closes: the call's id and name as soon as the name is written, then its arguments
as they become certain, for both registered call syntaxes and for a packageToolFormatthat
gives the newstreamfunction. Eval overcrit servetherefore times a reply that ends in a
call by when its tokens were written. A block that has begun streaming is that call: one that
closes without parsing, or that the model ends its reply inside, fails the reply instead of
staying content, and onemax_tokenscuts comes back with the arguments written so far and
finish_reason: "length", as OpenAI's API returns it. A Hermes-style JSON call that repeats a
key stays content. crit servetalks to its resident host over one loopback connection the host opens with the
runtime's ownership token, instead of command, result and stream-snapshot files polled every
20 ms. A streamed reply's first token arrives about 30 ms sooner, and each delta the engine
emits reaches the client as its own chunk instead of one coalesced update per 50 ms; the HTTP
server sends chunks without Nagle's delay. Only failed requests leave records in the runtime
directory, andServedEngine.generate'son_textreceives each piece instead of the
cumulative text.- Eval protocol
crit-eval-v5: the long-context curve's prompts are the longest speed case
with its document followed by suite filler text, cut to fit, instead of copies of its whole
prompt, so every prompt Eval sends is chat messages and served engines run the curve and
retrieval too. Curve scores move: prepare data again for v5. - Eval protocol
crit-eval-v5measures quality on the engine's own replies, as a chat API user
gets them. Each quality prompt goes as chat messages withlogprobsand 16top_logprobs;
crit eval reference --model --data --resultthen scores the greedy reply teacher-forced on the
checkpoint the data was prepared from: KL over both top-16 lists plus the rest, the perplexity
ratio and top-1 agreement over every reply token. The conversations and the replies after 1K-,
4K- and 32K-token prompts are each a set judged by the drift budget. The server must render each
prompt to the token count the model's chat template does and name reply tokens by their bytes.
Adapter scoring (score(),score_paths,prefill_decode, and the stock
crit_core.native.EvalEngine's) andreference.jsonare gone, so an adapter's engine gets no
quality figures; Core's scoring andcrit_engine_scorestay for engines. crit models eval --record --data --result --evaluationbinds acrit eval run --urlresult of
the engine serving a transform's output to its record and scores its quality replies on the
source checkpoint, instead of running an adapter;models_evaluationrecords the server's URL
and model name in place of the adapter and its configuration.- Eval protocol ids have a major and an optional minor version:
crit-eval-v4is 4.0 and
crit-eval-v4.1is 4.1. A change that can move a score takes the next major version,
any other the next minor; scores compare within a major version andcomparewarns across
majors. Prepared data runs under every minor version of its major when it froze the current
suite, and a test pins each version to its protocol and suite, so an edit to either needs a
new version.
Fixed
- A resident host run in-process no longer writes a
__pycache__into the sealed package it loads,
which failed the package's verification on the next request; the test suite run without-Bhit it. - Core fails an individually blocked request when all resident requests hold
nonreclaimable memory and no work ...
crit 0.2.3
Overview
crit 0.2.3 makes crit serve hold up under real clients: a closed connection, a stalled reader, a
failing consumer or Ctrl+C now cancels the turn and settles the engine instead of leaving it running
or wedged. One server can serve a named catalog of models from several runs, admit bounded concurrent
requests for adapters that declare a capacity, and take image input for vision packages. crit run
publishes candidates, seals and packages atomically and recovers cleanly after a crash, crit run measure retires its whole worker tree on every exit, and Core keeps native resources owned until the
work borrowing them has settled. Serving clients must keep their connection open until the reply
completes, since closing or half-closing it now cancels the request. The Python distribution and the
Core SDK share version 0.2.3.
Added
crit serve --models catalog.jsonserves named sealed candidates from several runs, each with its
own capabilities and context limits (Serving). Switching models releases the old
weights before the new ones load, so one server fits a one-model memory budget; an unknown model
name returns 404.- Concurrent serving: an adapter that declares
chat-concurrent-v1and a request capacity gets that
many requests at once, each with its own stream, cancellation and cleanup. A model switch queues
fairly behind active work, and an unrecoverable failure retires the shared host before the next
request is admitted. Other adapters stay serial. - Image input:
crit servepasses ordered image and text parts tochat-images-v1packages through
the chat template, tool history included.ResidentChatgives engines request-scoped prepared
prompts for their vision inputs; text-only adapters are unchanged.
Changed
crit servecancels a turn when its client goes away: a closed or reset connection, also during
non-streaming replies and quiet stretches of a stream. A client that half-closes its sending side
while waiting cancels too. Cancelled requests leave the wait for the engine at once without
touching the active turn.- Final replies, stream snapshots and tool deltas go through one content check. Streams still accept
whitespace and incomplete tool arguments as prefixes; the completed reply meets the same rules as a
JSON reply. - Core validates model progress the same way on serial and batched execution, and run records share
reservation and attempt-result validation between publication and recovery. Malformed retained
records are now rejected before anything is published; valid records are read as before.
Fixed
crit serveaccepts a reply that is only reasoning, including one cut off while reasoning, instead
of rejecting it and retiring the resident host. Empty replies, malformed text, tool-policy
violations and exceeded budgets still fail.- A stalled streaming client no longer holds the engine: writes observe the request's deadline,
cancellation and shutdown, the connection is dropped, and a partial frame is never followed by an
error or[DONE]. crit serveshutdown (Ctrl+C, SIGINT, SIGTERM) cancels active requests before waiting and answers
queued ones with 503. An exception escaping a streaming consumer retires the resident host before the
next request, so it gets a fresh engine. In both cases a failed cleanup stays blocked until a retry
succeeds instead of passing for a completed close.crit run measureretires its whole worker tree, pinning process and adapter helpers included, on
success, failure, timeout and interruption, and when the coordinator dies, on Linux as on Windows.
Ctrl+C on Windows takes effect promptly. Reservations count the time spent waiting for the engine
lock, so an expired attempt can neither launch nor publish a benchmark, and every setup error or
interruption records an outcome.crit runpublishes atomically: a candidate's source and identity together, a package only after its
bytes and launch recipe check out, a seal with its temporary files outside the candidate. An
interrupted create, seal or package no longer leaves a half-written directory that blocks recovery,
and a retry keeps the original outcome. Staging stays outsidework/, so the whole work directory can
be an input.- Run recovery and ordinary writers take one lock on the coordinator lease, so two writers can no
longer own the same run. Windows recovery recognizes a dead coordinator whose process handle another
process still holds. - Core keeps native resources owned until the work using them has settled: graph caches keep
unsettled executables through cleanup failures, final buffer release no longer loses an allocation's
ownership when host memory runs out, and native engine libraries keep their resource owner alive
while request handles are outstanding.
crit 0.2.2
Overview
crit 0.2.2 makes serving one shared path for every engine. crit_core.serving.ResidentChat
renders the chat template, parses tool calls in the syntax the template teaches (or one the
engine package supplies), returns reasoning apart from the reply as reasoning_content, forwards
per-request sampling and streams, so an engine supplies only its token generator and gets every
serving fix without changes. Engines whose weights live in host memory get Core's HostBlock
and a machine-wide engine lock that also covers Windows and WSL together, and Inference gains
entries for host work inside captured graphs and bit-exact NVFP4 experts on the CPU. Config
readers take their key spellings from one shared table, Eval classifies tensors in one place, and
What belongs in crit states the criteria every change must meet.
Eval data prepared for 0.2.1 stays valid; references for Mamba-2 models must be built again (they now
follow the model's own time-step limit). The Python distribution and the Core SDK share version
0.2.2.
Added
crit_core.serving.ResidentChat: the shared body of a resident chat adapter (chat template,
tools, per-request sampling, streaming, cancellation, telemetry); an engine supplies only
its token generator.crit_core.native.resident_engineis built on it.- Tool calls without model-specific code in crit: ResidentChat renders tools and tool history
with the model's chat template and parses the calls (crit_core.text.ToolCallParser) in the
syntax the template teaches when crit registers it (Qwen3-Coder<function=...>and Hermes
JSON blocks), or in the package's ownResidentChat.tool_format. It declares
chat-tools-v1and streams each call as one delta. Packages that declared the interim
chat-tool-template-v1are served aschat-tools-v1. - Core
HostBlockandHostBlockPool(crit/host_block.h) withcuda_pin_host_block: large host weight
blocks filled by the loader's threads, then pinned once and touched, and a process-wide pool that reuses a
block only for the same key, size and identity and frees a mismatched one before the next engine
allocates, so engines opened one after another never hold two copies. - A machine-wide engine lock (
crit_core.machine,CRIT_ENGINE_LOCK):crit eval run/pin/ab/kernels/reference,
crit run measureandcrit serveload one model at a time and say who holds the lock while waiting. A
lease in a location every OS instance reads (CRIT_ENGINE_LEASE) makes Windows and WSL wait for each other. - Eval records the CPU cores other processes kept busy during each speed case and names them in disturbed
andlower_contextfailures. - What belongs in crit: the criteria every change to crit must meet.
- Reasoning apart from the reply: ResidentChat splits a reasoning model's thinking in the markers its chat
template uses (crit_core.text.reasoning,<think>...</think>; a package can set its own
ResidentChat.reasoning_format), and crit serve returns it asreasoning_content, streamed before the
content. Adapters return it as the response record's optionalreasoningand stream it as
emit({"reasoning": text}). - Inference entry host-work-mailbox: host work the device posts and a
stream joins inside a captured graph (device-reset doorbells, release, terminal failure answering), with the
stream-front-end and poll-kernel waits chosen by a measured probe and an eager fallback. - Inference entry host-expert-arithmetic: NVFP4 expert rows on the
CPU in a declared operation order (element-scaled or block-dot products; scalar oracle, AVX2 and AVX-512
paths chosen at run time) that a matching CUDA function reproduces bit for bit, with a scale-decode hook for
checkpoint-specific scale encodings. - Reverse loans in expert-residency:
SettledSlots::begin_slot_loanlets an owner that lent its memory to the
expert cache (KV positions a request cannot reach, an idle prompt workspace) reclaim any set of slots with the
existing loan lifecycle (protected-reader refusal, survivor relocation, binding invalidation, empty return).
Changed
- Both config readers take the keys that spell each field from one table,
crit_core/model/config_keys.json(CMake generates the C++ arrays), which also readsllm_config
wrappers andlayers_block_type. Eval's ceiling and context limit classify tensors in one place
(crit_eval.tensors); results are unchanged on the checkpoints checked. crit run packagerefuses a resident chat package that does not accepttemperature, or
that offers no tool calls although the model's chat template teaches them.crit run measurepins cases in a separate process that exits before the measured engine loads.- Eval prepare scores the turn of a template whose generation prompt holds more than a history turn (Gemma 4's
empty thought channel) from where that turn's content begins, so a reply that starts like the prompt's extra
text keeps those characters. Prepared data is unchanged for the checkpoints checked. - Eval's reference gives Mamba-2 mixers config.json's
time_step_limitinstead of transformers'
time_step_minclamp, which broke retrieval beyond about 64K tokens and read as drift. - Inference entries: exact host/device expert splits and the worker-generation race
(heterogeneous-expert-dispatch), lent cache capacity (device-expert-cache), W4A4 prompt GEMMs from
calibrated input scales (quantized-projections), each stated as a rule to measure on the target machine.
crit 0.2.1
Overview
crit 0.2.1 makes Eval catch engines that go wrong only after a long prompt: decode after
1K to 32K prompt tokens is now scored against the reference, long-context retrieval and
repeated requests are gates, and AGENTS.md treats unexplained output differences as bugs.
Serving accepts per-request sampling and tool calls, and crit serve loads the model
right away instead of hashing the whole checkpoint first. Eval data prepared for 0.2.0
(crit-eval-v3) must be prepared again, and Eval adapters need the new prefill_decode
score path. The Python distribution and the Core SDK share version 0.2.1.
Added
- Serving passes validated per-request sampling overrides to opt-in resident adapters,
including native Core penalties and logit bias. Model cards list supported sampling
parameters and package capabilities. chat-tools-v1carries function definitions, choice policies, correlated tool-result
history and validated calls in JSON and SSE responses.chat-tools-strict-v1compiles
argument schemas with Core and verifies replies;chat-tool-stream-v1carries live,
indexed argument fragments with append-only and strict-prefix validation.
Model-specific adapters supply prompting, parsing and constrained decoding.- Eval protocol
crit-eval-v4adds three gates. The requiredprefill_decodequality
path prefills 1,024-, 4,096- and 32,768-token prompts and scores the reference
continuation through ordinary decode steps against the drift budget, per prompt length.
The retrieval gate asks for facts placed at the start, middle and end of prompts up to
the required context and checks the answers verbatim. The request-history gate requires
the same greedy tokens on a fresh engine and after every other request it served, in
every exactness mode. With--baseline, status notes a drop in plain-greedy equality. crit serve --verify-modelreads and SHA-256s every model file against the run's frozen
manifest before loading, and gives engines withoutchat-model-file-v1a private copy.
Changed
crit servechecks each model file's size against the frozen manifest and maps it in
place by default, so the engine starts loading at once instead of after a full read and
hash of the checkpoint. A checkpoint with the same sizes but other bytes is served
unnoticed unless--verify-modelis given. The default load timeout assumes 200 MB/s
(50 MB/s with--verify-model), and Windows no longer re-hashes copied model files on
every read.- AGENTS.md lays out the build loop (recon, plan, build, evaluate, revisit recon, repeat)
with its commands and stop conditions, and treats a drop in plain-greedy equality or a
difference between repeated identical requests as a bug until a root cause is shown. - README case study 02 shows the corrected Flash-Next candidate 6; candidate 5 is marked
superseded (it used prefetched experts before their scales were set). - Data prepared for
crit-eval-v3must be prepared again, with a new reference and pin:
prepared.jsonnow holds the long prompts and the token strings retrieval matches with.
An Eval adapter must declare and implement theprefill_decodescore path. - Unsupported sampling controls and unknown request parameters now return HTTP 400
instead of being ignored. Existing sealed packages continue to serve plain chat;
clients must omit unsupported overrides or use a newly built capable adapter.
Fixed
- Windows resident startup no longer treats a transient permission denial during
ownership-record replacement as owner death: the guardian uses the supervisor's
bounded retry. Changed ownership and persistent failures still stop execution.
Unexpected resident exits report their exit code and diagnostic log location.
crit 0.2.0
Overview
crit 0.2.0 adds the Models module for recorded weight transforms, a recon step that freezes
each model's sampling, chat template and stop tokens into its candidates, measured run
benchmarks, and Core engine libraries that need no adapter code. Eval checks exactness on
the loaded engine, replays pinned text at long context and stops disturbed rounds. The
Python distribution crit (now including crit_models) and the native Core SDK
(critCore) share version 0.2.0. Runs recorded with 0.1.0 still verify.
Added
- Models (guide):
crit modelsproduces transformed weights and
records how they were made. The first workflow is post-training quantization:
planresolves a recipe against checkpoint headers,ptqquantizes projections to
FP8 per-channel or NVFP4 by round-to-nearest or GPTQ (layer-streamed calibration
through the officialtransformerscode) and exports a compressed-tensors checkpoint,
evalruns the output in an engine through Eval against the source model's data and
reference, andverifyre-hashes it. Themodels_transformrecord keeps the
resolved recipe, calibration data and token-window hashes, seed, source and output
file hashes, error measures and transform cost;models_evaluationbinds an Eval
result to it. crit run --id RUN recongathers the model's sampling defaults, stop tokens, chat
templates and keyconfig.jsonfields with file hashes intowork/recon.jsonand
scaffoldswork/recon.md; later candidates freeze itsfrozenblock as
configuration.recon. A run whose model is a folder needs recon before its first
candidate; single-file models are unchanged.crit serve --load-timeout. The default bound on loading the starting candidate is now
600 s plus the model's size at 50 MB/s, instead of a fixed 600 s.- Run records explain ineligibility.
crit run benchmarkandsealwarn when a benchmark
or candidate cannot qualify, andselectnames every blocker. The reasons are derived
when asked; telemetry keeps the 0.1.0 projection, so earlier runs still verify. crit run measurebenchmarks a candidate's resident cases itself, through the package's
Eval adapter in a reserved child process. The first measurement of a case pins its greedy
text, when two runs repeat it, and every later candidate replays it, so decode speeds compare across candidates;
load time and host and device memory are sampled during the run.- Core engine libraries:
crit/native_engine.hexports a Core engine from a shared
library with a C ABI (CRIT_EXPORT_ENGINE(factory)), andcrit_core.nativeloads it
and supplies the stock eval-v1 and chat-resident-v1 adapters, so an engine needs no
adapter code of its own.ReplayContinuationcarries Eval's replay text to the session. - Eval checks exactness on the loaded engine when the adapter declares
plainand offers
generate_plain(), instead of opening a second engine withspeculativefalse. For an
engine that streams 64 GB of experts from host memory, that removes one of three loads per
round (about 3 minutes of 19).PlainDecoding("plain": truein the generate options)
carries the request to native engines, and the stock adapter offers it when the engine
declaresplain. - Eval stops a round when a speed case's decode speeds spread by more than
disturbed_spread(25%) between repetitions: the device was disturbed. The partial result is
markedaborted,runexits with code 3, and--keep-disturbedfinishes the round anyway.
A disturbed Flash-Next round previously ran its full 25 minutes, failed the lower-context gate
on noise and had to be repeated. fp8-kv-attentionaddsprefill_fp8: prompt attention with Q·Kᵀ and P·V on E4M3 tensor
cores for head dimensions 64, 128 and 256, about twiceprefill's throughput at long
contexts with E4M3 rounding of queries and probabilities. Opt-in;prefillis unchanged.
Changed
- A benchmark record that cites no checks binds the case's latest check per gate for the
same package, instead of staying exploratory. - Safetensors indexes may list shards in subfolders (
tensors/model-00001-of-00004.safetensors)
as portable relative paths, in Core's C++ and Python readers and in the import audit;
Eval's model identity counts them. - Core's static libraries build position-independent, so engines can link them into a
shared library without rebuilding Core. - Under WSL,
--write-launcherswrites aserve.cmdthat startsserve.shin the same
distribution. - A killed process tree has 60 s instead of 5 s to exit before cleanup counts as failed.
Engines that pin tens of GB of host memory take longer than 5 s. - Eval's long-context points replay the longest speed case's pinned continuation when the
data has one and the adapter replays, socontext_decodeno longer moves with each
engine's own text; it compares only between results decoded on the same text. - Eval's prefill and TTFT floors count attention at the faster of the BF16 and FP8 rates.
An engine with FP8 attention beat the BF16 floor. crit eval kernelscharges each kernel only the time after every earlier kernel ended,
so a kernel launched early under programmatic dependent launch is not charged its wait;
span_mskeeps raw durations.
Documentation
- Eval adapter: an adapter may keep host-side weights in the process across the engines one
crit eval runopens one after another; device state is built fresh for each engine. - RUN_RECORDS and AGENTS: publish a case's checks before the benchmark that cites them.
- BUILDING_ENGINES: the example request no longer overrides
settings.tomlheadroom. - CUDA backend: free memory under WDDM. device-expert-cache: measured next-layer
prefetch results. - README: case studies for the Qwen3.8-27B NVFP4 and Qwen3.8-Flash-Next FP4-Local engines
on one RTX 5090.
crit 0.1.0
Overview
First public release of crit: reusable infrastructure for building a bespoke inference
engine around a chosen model, workload and target hardware, with a common evaluation
suite and an OpenAI-compatible serving API. The Python distribution crit and the
native Core SDK (critCore) share version 0.1.0.
Added
- Core (guide): a C++20 SDK with Model, Session and Backend
interfaces for generation and query scoring, request scheduling and admission,
resource accounting, readiness, cancellation, deadlines, quarantine and safe
retirement. Mixed batching of up to 4096 request lanes with shared token-work budgets,
decode priority with prefill aging and an optional async batch pipeline. Requests
carry sampling rules (temperature, top-k, top-p, min-p, penalties, logit bias,
min_tokens), log-probabilities with top alternatives, stop strings, decoded text and
per-token output events, and report phase timing and reused prompt tokens. - Core component libraries, each optional and documented beside its sources:
text (crit/text.h: stop matching, streaming detokenization), sampling
(crit/sampling.h: Philox counter-based draws usable in device code, aSampler
with a documented rule order), state (crit/state.h: a storage-agnostic ledger of KV
pages and recurrent state slots with prefix reuse), files and checkpoints
(crit/json.h,crit/file.h,crit/sha256.h,crit/safetensors.h,
crit/model_config.h), host-memory admission (crit/host_memory.h), structured output
(crit/constraints.h: token, choice, JSON-object and byte-grammar matchers), operator
ranges (crit/trace.h, with an optional NVTX sink), and CUDA services (graph capture,
shared device allocations, category timing, spare device memory). - The
crit_corePython package: model files, strict JSON and safetensors readers,
config.jsonrules, tokenizer, Hugging Face chat templates, generation config,
streaming detokenization and the JSON schema/regex/EBNF compiler for structured output. - Inference (guide): 26 techniques with implementation code, runnable
examples, ownership contracts and adaptation guides, grouped by category: attention
(attention-state, flash-prefill-attention, fp8-kv-attention, partitioned-attention,
rotated-kv-quantization), projections (quantized-projections, rmsnorm-bf16,
stored-tile-gemm), experts (async-expert-contributions, device-expert-cache,
expert-residency, heterogeneous-expert-dispatch, ssd-expert-materialization),
speculation (device-speculative-round, draft-vocabulary-subset, mtp-decode,
recurrent-state-recovery), sampling and constraints (token-constraints,
token-sampling), execution (concurrent-request-execution, recorded-selection,
session-scheduling) and memory and loading (artifact-loading, checkpoint-storage,
host-memory-admission, model-import-audit). - Kernels (guide): checks for outside kernels (native integration,
the actual device, exactness across column counts), pinned dependency retention,
artifact verification and preservation of third-party notices, with native
integration examples. - Eval (guide): one speed, quality and exactness suite that
every engine runs the same way through a smalleval-v1Python adapter, with prompts
frozen as token ids per model and a layer-streamed FP32 reference. It reports decode,
prefill, time to first token and quality against physical limits, computes an engine's
max context from device memory, checks capacity and long-context behavior, scores
held-out prompts in eight languages plus code and SQL, and offers pinned decode text
(crit eval pin), paired A/B runs (crit eval ab), a CUPTI kernel report
(crit eval kernels) and device probes (crit eval probe). - Serving (guide):
crit serveserves a sealed candidate as an
OpenAI-compatible API with/v1/models,/v1/chat/completions(JSON or streamed,
stop strings, system messages,response_formatJSON object and JSON schema), optional
API keys and CORS, and/health;--write-launcherswritesserve.cmdandserve.sh. - Run records (guide):
crit runkeeps retained candidate
source and packages, lineage, checks, measurements, candidate budgets, quality and
exactness terms, a weights policy, process reservations with owner-aware leases,
cleanup and immutable sealed outcomes. An optional untrackedsettings.tomlholds
machine settings. - Validation and packaging: host and native fixtures, one installable
crit
distribution (crit,crit_api,crit_eval,crit_kernelsandcrit_core), an
installable C++ SDK and Windows/Linux CI workflows.
Inference examples include host proofs of concept and native sources with explicit
validation scopes. Model arithmetic, formats, tokenization and sampling choices belong
to each engine; model quality and device performance require target validation.