Skip to main content

Module effort_gate

Module effort_gate 

Source
Expand description

Stage 5b: suppress a resolved reasoning_effort when the model’s observed template never reads it — and say so.

ADR 0007 decision 3: the resolved reasoning_effort is suppressed when — and only when — the observed caps positively say the template does not read the variable. This module is that sentence.

§Why it must be reported rather than performed quietly

A template that does not read the variable ignores it in perfect silence: HTTP 200, prompt byte-identical, no warning, no status change (ADR 0007 finding 7c, confirmed live). Neither reasoning control is echoed anywhere — not in /slots.params, not in /props (finding 7a) — so no readback will ever notice that a level went nowhere. If gglib deletes the key without a record, the fact is unrecoverable from every surface at once.

So the suppression writes itself down twice. ParamSource::SuppressedByTemplate replaces the rung in the decision’s provenance — no surface can print reasoning_effort=profile for a value that was never sent — and SuppressedEffort carries the level and the rung that supplied it, so a surface can say which value was dropped and who asked for it.

Both records are read downstream: gglib model explain renders the provenance, and the proxy hands SuppressedEffort to its sampling audit so the dashboard can name the level and the rung.

This module’s own debug! stays, and is not redundant with the pipeline’s "sampling resolved" line. That line is rendered by sampling_log after this stage precisely so it describes what was sent — which means that on a suppression it reads reasoning_effort=None … reasoning_effort=suppressed-by-template, and the level and rung this stage threw away appear nowhere in it.

§Unknown never gates

The predicate is deliberately conservative in the same shape strip_unsupported_tools uses (tools.rs:29-40): it acts only on a catalog_resolved context, and only on a positive Support::No. A passthrough model, a model nobody has launched yet, a /props read that failed, and a caps object that did not carry the field all mean nobody knows, and all keep their effort.

The precedent is a shape, not an equivalence, and the difference is worth stating: tool stripping reads gglib’s own catalog row — a fact this system recorded about the model — while this reads llama-server’s self-report, a fact another process stated about itself. ADR 0007 names that posture (a runtime self-report used as a policy input) precisely because it is not the same thing as a stored capability, and it carries the extra rule that a report which failed to arrive must never be read as one that arrived negative.

§Scope: the top-level key, and only the effort

This gate governs the top-level reasoning_effort key alone. A client’s chat_template_kwargs remains a verbatim passthrough — gglib neither reads nor edits it, and a caller who puts an effort level in there is addressing the template directly, over gglib’s head, which is a different (and unmodelled) act from setting the field the ladder resolves.

reasoning_budget_tokens is never suppressed here. It is not a template variable at all: it is enforced by llama.cpp’s own sampler-side budget (common/reasoning-budget.{h,cpp}) and range-validated upstream, so a template that ignores reasoning_effort still honours the budget. Gating it on a caps bit that describes a template would be a category error, and the_budget_survives_a_model_that_cannot_honour_effort pins it.

Structs§

SuppressedEffort
A resolved effort level this stage threw away, and where it came from.

Functions§

describe_rung 🔒
Name the rung a suppressed level came from, for the debug line.
suppress_stored_effort
Stage 5b’s rule, applied to a resolution with no request in hand.
suppress_unsupported_effort
Remove a resolved reasoning_effort the observed template cannot read, and return what was removed.