gglib_core/request_pipeline/explain.rs
1//! Resolving a model's *stored* sampling configuration, with provenance.
2//!
3//! The live pipeline answers "what did this request end up sampling with?".
4//! This answers the question the explain surfaces ask instead — "what would
5//! this model sample with, and which rung supplied each value?" — with no
6//! request in hand, so the top rung is empty by construction.
7//!
8//! # Why it is shared rather than written twice
9//!
10//! `gglib model explain` and the GUI's sampling panel had a copy each, and
11//! they had to agree: the same ladder, followed by the same stage-5b effort
12//! gate applied to the resolution rather than to a request. Two copies of a
13//! rule can only ever drift into two accounts of one resolution, and the whole
14//! value of an explain surface is that it describes the resolution that
15//! actually runs. So the rule lives here once, and the callers keep only what
16//! genuinely differs between them — one prints, the other builds a DTO.
17//!
18//! It sits beside [`effort_gate`](super::effort_gate) because
19//! [`suppress_stored_effort`] does, and applying that gate offline is half of
20//! what this function is.
21
22use crate::domain::{
23 FieldSources, InferenceConfig, InferenceProfile, ModelSamplingContext, TemplateCaps,
24};
25
26use super::effort_gate::{SuppressedEffort, suppress_stored_effort};
27
28/// Resolve stored sampling for one model, and report where each value came
29/// from and whether the template gate silently dropped an effort level.
30///
31/// The request rung is deliberately empty: this explains configuration, not a
32/// call, so there are no per-request parameters to occupy the top of the
33/// ladder.
34#[must_use]
35pub fn explain_stored(
36 profile: Option<&InferenceProfile>,
37 model_defaults: Option<&InferenceConfig>,
38 global_defaults: Option<&InferenceConfig>,
39 model_ctx: ModelSamplingContext,
40 caps: &Option<TemplateCaps>,
41) -> (InferenceConfig, FieldSources, Option<SuppressedEffort>) {
42 let (mut resolved, mut sources) = InferenceConfig::default().resolve_with_profile_explained(
43 profile.map(|selected| &selected.config),
44 model_defaults,
45 global_defaults,
46 model_ctx,
47 );
48 let suppressed = suppress_stored_effort(&mut resolved, &mut sources, caps);
49 (resolved, sources, suppressed)
50}