Skip to main content

gam_solve/rho_optimizer/
run.rs

1use super::*;
2use gam_problem::StationarityRung;
3
4use super::asymptote_certificate::{
5    AsymptoteSample, AsymptoteSide, AsymptoteTolerances, AsymptoteVerdict, AsymptoteWindow,
6    MIN_TAIL_SAMPLES, assess_coordinate,
7};
8use super::rail_face::{
9    RailFaceLimit, RailFaceLimitOutcome, RailFaceProof, RailFaceVerdict, certify_rail_face,
10};
11
12pub(crate) const OPERATOR_TRUST_RESTART_RADIUS_FLOOR: f64 = 1.0e-6;
13
14/// Inner coefficient state bound to one exact outer seed.
15///
16/// A cached coefficient vector is only a valid initialization for the outer
17/// coordinate that produced it.  Keeping the coordinate beside the vector
18/// prevents a multi-start run from silently reusing one basin's coefficients
19/// at a different seed.
20#[derive(Clone, Debug)]
21pub(crate) struct BoundInnerSeed {
22    pub(crate) theta: Array1<f64>,
23    pub(crate) beta: Array1<f64>,
24}
25
26pub(crate) fn outer_theta_bitwise_eq(left: &Array1<f64>, right: &Array1<f64>) -> bool {
27    left.len() == right.len()
28        && left
29            .iter()
30            .zip(right.iter())
31            .all(|(left, right)| left.to_bits() == right.to_bits())
32}
33
34/// Install cached inner state only at the exact outer coordinate that owns it.
35///
36/// This function is called after a seed-attempt reset and immediately before
37/// the literal seed can be evaluated. Generated multistart candidates never
38/// inherit coefficients from another outer point.
39pub(crate) fn install_matching_initial_inner_seed(
40    obj: &mut dyn OuterObjective,
41    config: &OuterConfig,
42    seed: &Array1<f64>,
43    context: &str,
44) -> Result<(), EstimationError> {
45    let Some(bound) = config.initial_inner_seed.as_ref() else {
46        return Ok(());
47    };
48    if !outer_theta_bitwise_eq(&bound.theta, seed) {
49        return Ok(());
50    }
51    match obj.seed_inner_state(&bound.beta)? {
52        SeedOutcome::Installed => log::info!(
53            "[CACHE] beta-warm context={} theta_dim={} beta_dim={} action=installed",
54            context,
55            bound.theta.len(),
56            bound.beta.len(),
57        ),
58        SeedOutcome::NoSlot => log::warn!(
59            "[CACHE] beta-warm context={} theta_dim={} beta_dim={} action=skip \
60             reason=objective_has_no_inner_beta_slot",
61            context,
62            bound.theta.len(),
63            bound.beta.len(),
64        ),
65        SeedOutcome::Incompatible => log::info!(
66            "[CACHE] beta-warm context={} theta_dim={} beta_dim={} action=rho-only \
67             reason=seed_beta_incompatible_with_inner_state",
68            context,
69            bound.theta.len(),
70            bound.beta.len(),
71        ),
72    }
73    Ok(())
74}
75
76/// Hold terminal evidence at full inner-solve fidelity.
77///
78/// Search-time REML evaluations may deliberately cap P-IRLS.  A terminal
79/// certificate or final state installation is a different operation: it must
80/// run with the cap lifted, then restore the scheduler's value after the
81/// operation completes.  The objective reset performed by the callers clears
82/// any evaluation/P-IRLS entries created under the search state before the
83/// full-fidelity request is made.
84pub(crate) struct TerminalInnerCapGuard<'a> {
85    cap: &'a AtomicUsize,
86    previous: usize,
87}
88
89impl<'a> TerminalInnerCapGuard<'a> {
90    pub(crate) fn lift(feedback: &'a InnerProgressFeedback) -> Self {
91        let cap = feedback.cap.as_ref();
92        let previous = cap.swap(0, Ordering::Relaxed);
93        Self { cap, previous }
94    }
95}
96
97impl Drop for TerminalInnerCapGuard<'_> {
98    fn drop(&mut self) {
99        self.cap.store(self.previous, Ordering::Relaxed);
100    }
101}
102
103/// Configuration for the outer optimization runner.
104#[derive(Clone, Debug)]
105pub(crate) struct OuterConfig {
106    pub(crate) tolerance: f64,
107    /// Optional override for the *relative-cost-decrease* convergence stop,
108    /// decoupled from `tolerance`. `outer_gradient_tolerance` normally derives
109    /// BOTH the absolute projected-gradient floor
110    /// (`max(tolerance, scale·√ε_machine)`)
111    /// AND the relative-cost stop (`rel_cost = tolerance`) from the single
112    /// `tolerance`. That conflation forces a caller who needs a *tight absolute
113    /// floor* (to resolve λ to the genuine REML optimum at large `n`, where the
114    /// floor is `scale·√ε_machine`) to also accept a *tight rel-cost stop*,
115    /// which on a flat REML ridge never trips and grinds the optimizer to `max_iter` —
116    /// dozens of surplus O(D·p³) Laplace-derivative outer iterations (the #1082
117    /// multinomial smooth-by-factor wall-clock blow-up). When `Some(r)`, the
118    /// rel-cost stop uses `r` while the absolute floor keeps using `tolerance`
119    /// via `objective_scale`, so accuracy (absolute floor) and perf (loose
120    /// rel-cost) are selected independently. `None` preserves the legacy coupling
121    /// (`rel_cost = tolerance`) for every existing path byte-for-byte.
122    pub(crate) rel_cost_tolerance: Option<f64>,
123    pub(crate) max_iter: usize,
124    pub(crate) bounds: Option<(Array1<f64>, Array1<f64>)>,
125    pub(crate) seed_config: gam_problem::SeedConfig,
126    pub(crate) rho_bound: f64,
127    pub(crate) heuristic_lambdas: Option<Vec<f64>>,
128    pub(crate) initial_rho: Option<Array1<f64>>,
129    pub(crate) initial_inner_seed: Option<BoundInnerSeed>,
130    pub(crate) fallback_policy: FallbackPolicy,
131    pub(crate) screening_cap: Option<Arc<AtomicUsize>>,
132    pub(crate) screen_initial_rho: bool,
133    /// Outer-aware inner-PIRLS iteration cap (sibling of `screening_cap`).
134    /// When set, the BFGS bridge drives this atomic on every accepted
135    /// gradient eval to coarsen the inner Newton solve at early outer iters
136    /// (when ρ is far from converged) and lift it back to full as
137    /// convergence approaches. Distinct from `screening_cap` in that it
138    /// does NOT suppress cache writes / warm-start updates / KKT
139    /// enforcement; it is purely a budget. See
140    /// `RemlObjectiveState::outer_inner_cap` for dual-cap semantics.
141    pub(crate) outer_inner_cap: Option<InnerProgressFeedback>,
142    pub(crate) operator_initial_trust_radius: Option<f64>,
143    pub(crate) arc_initial_regularization: Option<f64>,
144    /// Optional scale factor for the objective's natural magnitude.
145    /// Used to widen the absolute gradient-norm floor on objectives whose
146    /// gradient lives on a non-unit scale (e.g. Gaussian-identity REML at
147    /// large `n`, whose ∂/∂logλ inherits the O(n) likelihood constant).
148    /// `None` falls back to the bare `tolerance` floor.
149    pub(crate) objective_scale: Option<f64>,
150    /// BFGS line-search infinity-norm cap applied to the leading `rho_dim`
151    /// outer parameters (log-λ axes). Documented natural step for
152    /// `log(lambda)` is ≈ 5 (`e^5 ≈ 148`-fold smoothing-parameter change
153    /// per accepted outer iter — matches typical quasi-Newton direction
154    /// magnitude on flat REML surfaces). Setting this `None` disables the
155    /// rho-axis cap entirely.
156    pub(crate) bfgs_step_cap: Option<f64>,
157    /// BFGS line-search infinity-norm cap applied to the trailing `psi_dim`
158    /// outer parameters (kappa / aniso-log-scale axes). Required because
159    /// the kernel scale axes need much tighter control (`e^1 ≈ 2.7`-fold
160    /// per iter is plenty) — using the rho-axis cap here lets the optimizer
161    /// jump kappa by orders of magnitude per step and oscillate. Setting
162    /// this `None` disables the psi-axis cap.
163    pub(crate) bfgs_step_cap_psi: Option<f64>,
164    /// Optional persistent-cache session. When `Some`, every finite objective
165    /// evaluation is written through to disk (rate-limited, atomic-rename)
166    /// and the best on-disk rho is prepended as a seed at the start of each
167    /// plan attempt. Defaulted off so test-only paths skip filesystem I/O.
168    pub(crate) cache_session: Option<Arc<CacheSession>>,
169    /// Optional mirror cache sessions. Checkpoints and successful finalize
170    /// writes are also written to each of these sessions (different keys,
171    /// shared store). Used for hierarchical broadcast: the current best ρ is
172    /// written to the exact-key (primary) AND the data-independent
173    /// seed-prefix key so the next fit with related structure can warm-start
174    /// from this one, even after an interrupted run.
175    pub(crate) cache_mirror_sessions: Vec<Arc<CacheSession>>,
176    pub(crate) rho_uncertainty_problem_size: crate::rho_uncertainty::RhoUncertaintyProblemSize,
177    /// Converged exact outer Hessian `H(θ̂)` transferred from a prior
178    /// structurally-matching fit via the persistent cache (a warm-start *hit*),
179    /// in the full θ layout. When present and SPD, the BFGS host path seeds its
180    /// iter-0 metric with `InitialMetric::DenseInverseHessian(H⁻¹)` so the first
181    /// outer step is quasi-Newton instead of unscaled steepest descent — the
182    /// dominant LOSO line-search-bracketing cost (each bracketing probe is a
183    /// full inner joint-Newton re-solve). Strictly stronger than the scalar
184    /// `1/‖g₀‖` metric: it carries the full anisotropic curvature, which across
185    /// folds (one held-out point) is nearly identical to this fold's. Never
186    /// changes the converged optimum — BFGS reaches `∇V=0` under any SPD initial
187    /// metric. `None` on every cold-start / no-cache / pre-Hessian-schema path,
188    /// which falls back to the scalar warm metric byte-for-byte.
189    pub(crate) warm_start_outer_hessian: Option<Array2<f64>>,
190    /// Per-ρ-coordinate structural keys, in the objective's NATIVE (formula)
191    /// coordinate order, used to make the outer smoothing-parameter search
192    /// invariant to the order the user wrote the smooth terms / tensor margins
193    /// (#1538/#1539).
194    ///
195    /// When `Some` and the keys induce a non-identity canonical permutation,
196    /// [`run_outer`] reorders the coordinate layout the optimizer sees into a
197    /// stable canonical order (derived purely from the keys, never from the
198    /// native position) before seeding/optimizing, and inverts the permutation
199    /// on the returned ρ / gradient / Hessian so the caller still receives the
200    /// native layout. Seeding, multistart and tie-breaking then all operate on
201    /// the identical canonical layout for every term order, so both orders
202    /// reach the same λ̂ and the same fitted surface. `None` (or an identity
203    /// permutation) leaves the legacy native-order path byte-for-byte unchanged.
204    pub(crate) rho_canonical_keys: Option<Vec<u64>>,
205}
206
207impl Default for OuterConfig {
208    fn default() -> Self {
209        Self {
210            tolerance: 1e-5,
211            rel_cost_tolerance: None,
212            max_iter: 200,
213            bounds: None,
214            seed_config: gam_problem::SeedConfig::default(),
215            rho_bound: 30.0,
216            heuristic_lambdas: None,
217            initial_rho: None,
218            initial_inner_seed: None,
219            fallback_policy: FallbackPolicy::Automatic,
220            screening_cap: None,
221            screen_initial_rho: false,
222            outer_inner_cap: None,
223            operator_initial_trust_radius: None,
224            arc_initial_regularization: None,
225            objective_scale: None,
226            bfgs_step_cap: None,
227            bfgs_step_cap_psi: None,
228            cache_session: None,
229            cache_mirror_sessions: Vec::new(),
230            rho_uncertainty_problem_size:
231                crate::rho_uncertainty::RhoUncertaintyProblemSize::default(),
232            warm_start_outer_hessian: None,
233            rho_canonical_keys: None,
234        }
235    }
236}
237
238// ─── OuterProblem builder ─────────────────────────────────────────────
239//
240// Declarative builder for outer optimization problems.  Derives
241// OuterCapability flags from high-level inputs (gradient/hessian
242// availability, psi dimension, EFS eligibility) so call sites never
243// hand-copy capability flags.
244
245/// Declarative outer-problem builder.  Produces both the
246/// [`OuterCapability`] (what the objective can provide) and the
247/// [`OuterConfig`] (how the runner should behave) from a small set
248/// of high-level declarations.
249pub struct OuterProblem {
250    n_params: usize,
251    gradient: Derivative,
252    hessian: DeclaredHessianForm,
253    prefer_gradient_only: bool,
254    disable_fixed_point: bool,
255    psi_dim: usize,
256    barrier_config: Option<BarrierConfig>,
257    tolerance: f64,
258    rel_cost_tolerance: Option<f64>,
259    max_iter: usize,
260    bounds: Option<(Array1<f64>, Array1<f64>)>,
261    rho_bound: f64,
262    seed_config: gam_problem::SeedConfig,
263    heuristic_lambdas: Option<Vec<f64>>,
264    initial_rho: Option<Array1<f64>>,
265    fallback_policy: FallbackPolicy,
266    screening_cap: Option<Arc<AtomicUsize>>,
267    screen_initial_rho: bool,
268    outer_inner_cap: Option<InnerProgressFeedback>,
269    operator_initial_trust_radius: Option<f64>,
270    arc_initial_regularization: Option<f64>,
271    objective_scale: Option<f64>,
272    bfgs_step_cap: Option<f64>,
273    bfgs_step_cap_psi: Option<f64>,
274    cache_session: Option<Arc<CacheSession>>,
275    cache_mirror_sessions: Vec<Arc<CacheSession>>,
276    rho_uncertainty_problem_size: crate::rho_uncertainty::RhoUncertaintyProblemSize,
277    rho_canonical_keys: Option<Vec<u64>>,
278}
279
280impl OuterProblem {
281    pub fn new(n_params: usize) -> Self {
282        Self {
283            n_params,
284            gradient: Derivative::Unavailable,
285            hessian: DeclaredHessianForm::Unavailable,
286            // Closed-form/test objectives preserve explicit ARC availability;
287            // production family-ladder entry points opt into #2359's
288            // optimize-3/certify-4 protocol with
289            // `with_prefer_gradient_only(true)`.
290            prefer_gradient_only: false,
291            disable_fixed_point: false,
292            psi_dim: 0,
293            barrier_config: None,
294            tolerance: 1e-5,
295            rel_cost_tolerance: None,
296            max_iter: 200,
297            bounds: None,
298            rho_bound: 30.0,
299            seed_config: gam_problem::SeedConfig::default(),
300            heuristic_lambdas: None,
301            initial_rho: None,
302            fallback_policy: FallbackPolicy::Automatic,
303            screening_cap: None,
304            screen_initial_rho: false,
305            outer_inner_cap: None,
306            operator_initial_trust_radius: None,
307            arc_initial_regularization: None,
308            objective_scale: None,
309            bfgs_step_cap: None,
310            bfgs_step_cap_psi: None,
311            cache_session: None,
312            cache_mirror_sessions: Vec::new(),
313            rho_uncertainty_problem_size:
314                crate::rho_uncertainty::RhoUncertaintyProblemSize::default(),
315            rho_canonical_keys: None,
316        }
317    }
318
319    /// Supply per-ρ-coordinate structural keys (native/formula order) so the
320    /// outer search is canonicalized to be invariant to the order the smooth
321    /// terms / tensor margins were written (#1538/#1539). See
322    /// [`OuterConfig::rho_canonical_keys`].
323    pub fn with_rho_canonical_keys(mut self, keys: Option<Vec<u64>>) -> Self {
324        self.rho_canonical_keys = keys;
325        self
326    }
327
328    pub fn with_gradient(mut self, d: Derivative) -> Self {
329        self.gradient = d;
330        self
331    }
332    pub fn with_hessian(mut self, form: DeclaredHessianForm) -> Self {
333        self.hessian = form;
334        self
335    }
336    /// Choose whether analytic Hessian work is reserved for terminal
337    /// certification (`true`, the generic derivative-ladder protocol) or may
338    /// also be consumed by the search (`false`, for closed-form objectives).
339    pub fn with_prefer_gradient_only(mut self, prefer_gradient_only: bool) -> Self {
340        self.prefer_gradient_only = prefer_gradient_only;
341        self
342    }
343    /// Forbid the planner from selecting EFS/HybridEfs, even when the
344    /// objective implements `eval_efs()` and the coordinate structure would
345    /// otherwise make pure/hybrid EFS eligible.
346    ///
347    /// Callers use this for families where the Wood-Fasiolo structural
348    /// property is known not to hold (e.g. GAMLSS/location-scale with
349    /// β-dependent joint Hessian), so EFS would stagnate and burn budget
350    /// before the automatic cascade falls back to gradient-based BFGS.
351    pub fn with_disable_fixed_point(mut self, disable: bool) -> Self {
352        self.disable_fixed_point = disable;
353        self
354    }
355    // MEASURE-JET ψ REGISTRATION: the engine below is already complete for a
356    // 3-coordinate measure-jet ψ group (s, α, ln τ) — `psi_dim` is generic,
357    // `with_bounds` carries the s ∈ (0, 2) box (the same convention matern κ
358    // uses for its log-κ window; no logistic reparameterization exists or is
359    // needed in-house), `with_bfgs_step_cap_psi` caps per-iteration ψ moves,
360    // and `DirectionalHyperParam::new_compact` (solver/reml/mod.rs) carries
361    // penalty-only first/second/cross jets with `is_penalty_like`
362    // auto-derived from the identically-zero design drift (∂X/∂ψ ≡ 0).
363    // Every remaining registration arm is formula-layer dispatch in
364    // src/terms/smooth.rs (eligibility in
365    // `spatial_term_supports_hyper_optimization`, dims in
366    // `spatial_dims_per_term`, seed/bounds/write-back on
367    // `SpatialLogKappaCoords`, the per-trial rebuild in
368    // `apply_log_kappa_to_term`, and the derivative bundle in
369    // `try_build_spatial_term_log_kappa_derivative`, which currently returns
370    // `Ok(None)` for `SmoothBasisSpec::MeasureJet`) plus the
371    // `build_measure_jet_basis_psi_derivatives` producer in
372    // src/terms/basis/measure_jet_smooth.rs; both are owned by the
373    // measure-jet terms actor. Registration stays gated on those arms — do
374    // NOT add measure-jet-specific branches to this engine.
375    pub fn with_psi_dim(mut self, dim: usize) -> Self {
376        self.psi_dim = dim;
377        self
378    }
379    pub fn with_barrier(mut self, cfg: Option<BarrierConfig>) -> Self {
380        self.barrier_config = cfg;
381        self
382    }
383    pub fn with_tolerance(mut self, tol: f64) -> Self {
384        self.tolerance = tol;
385        self
386    }
387    pub fn with_max_iter(mut self, n: usize) -> Self {
388        self.max_iter = n;
389        self
390    }
391    pub fn with_bounds(mut self, lo: Array1<f64>, hi: Array1<f64>) -> Self {
392        self.bounds = Some((lo, hi));
393        self
394    }
395    pub fn with_rho_bound(mut self, b: f64) -> Self {
396        self.rho_bound = b;
397        self
398    }
399    pub fn with_seed_config(mut self, sc: gam_problem::SeedConfig) -> Self {
400        self.seed_config = sc;
401        self
402    }
403    pub fn with_heuristic_lambdas(mut self, h: Vec<f64>) -> Self {
404        self.heuristic_lambdas = Some(h);
405        self
406    }
407    pub fn with_initial_rho(mut self, rho: Array1<f64>) -> Self {
408        self.initial_rho = Some(rho);
409        self
410    }
411    pub fn with_screening_cap(mut self, screening_cap: Arc<AtomicUsize>) -> Self {
412        self.screening_cap = Some(screening_cap);
413        self
414    }
415    /// Allow seed screening to rank the explicit initial rho against generated
416    /// candidates even when the effective seed budget is one. The default keeps
417    /// a user-provided initial point authoritative and avoids a separate
418    /// screening pass.
419    pub fn with_screen_initial_rho(mut self, screen_initial_rho: bool) -> Self {
420        self.screen_initial_rho = screen_initial_rho;
421        self
422    }
423    /// Wire the bidirectional inner-PIRLS feedback channel.
424    ///
425    /// The outer bridge writes a coarsened iteration cap into
426    /// `feedback.cap` on every accepted gradient/Hessian eval; the inner
427    /// solver writes back into `feedback.last_iters` /
428    /// `feedback.last_converged` after each non-screening solve so the
429    /// next outer iter's schedule can adapt to the inner solver's
430    /// actual convergence behavior. Typical caller passes
431    /// `InnerProgressFeedback {
432    ///     cap: Arc::clone(&reml_state.outer_inner_cap),
433    ///     last_iters: Arc::clone(&reml_state.last_inner_iters),
434    ///     last_converged: Arc::clone(&reml_state.last_inner_converged),
435    /// }` so the inner and outer observe the same atomics.
436    pub fn with_outer_inner_cap(mut self, feedback: InnerProgressFeedback) -> Self {
437        self.outer_inner_cap = Some(feedback);
438        self
439    }
440
441    /// Wire a one-shot "re-evaluate the inner solve COLD" signal that the outer
442    /// cost-stall guard raises when it grants a STUCK-stall escape (#2349).
443    ///
444    /// A profiled objective whose inner solve is warm-started along the outer
445    /// trajectory can carry value HYSTERESIS on a near-flat inner ridge — the
446    /// multinomial simplex-boundary regime where the softmax Fisher weight
447    /// `diag(p) − ppᵀ` collapses is the motivating case: two warm starts
448    /// converge to different ridge points whose Laplace `½log|H(β)|`, hence the
449    /// profiled objective, differ by more than the outer descent resolution, so
450    /// the optimizer's step-acceptance cannot separate real descent from that
451    /// hysteresis and grinds to `max_iter` at a non-stationary point. Uncapping
452    /// the inner cycle budget does not cure it (a fully converged warm solve
453    /// still lands on the warm-biased ridge point); the objective must re-solve
454    /// COLD to see a consistent surface.
455    ///
456    /// The caller shares this `Arc<AtomicBool>` with its objective closure and
457    /// consults it there, re-solving the inner problem from a canonical seed
458    /// (dropping the warm cache) whenever the flag is raised. The signal rides
459    /// the internal inner-cap feedback channel, but its `cap` slot is a private
460    /// throwaway so wiring the signal never perturbs the caller's own inner-cap
461    /// scheduling (custom families hold their real inner cap separately).
462    /// Objectives that do not warm-start, or never near-separate, simply never
463    /// observe the flag raised.
464    pub fn with_stuck_stall_cold_reeval_signal(self, signal: Arc<AtomicBool>) -> Self {
465        self.with_outer_inner_cap(InnerProgressFeedback {
466            cap: Arc::new(AtomicUsize::new(0)),
467            accepted_iter: Arc::new(AtomicUsize::new(0)),
468            // `last_iters == 0` ⇒ `snapshot()` returns `None` ⇒ no cap-schedule
469            // adaptation is derived from this dummy; `last_converged == true`
470            // matches the `None` default of `inner_solve_converged`, so
471            // terminal-fidelity gating is byte-for-byte unchanged.
472            last_iters: Arc::new(AtomicUsize::new(0)),
473            last_converged: Arc::new(AtomicBool::new(true)),
474            ift_residual: Arc::new(AtomicU64::new(f64::NAN.to_bits())),
475            accept_rho: Arc::new(AtomicU64::new(f64::NAN.to_bits())),
476            force_cold: signal,
477        })
478    }
479    pub fn with_operator_initial_trust_radius(mut self, radius: Option<f64>) -> Self {
480        self.operator_initial_trust_radius = sanitized_operator_trust_restart_radius(radius);
481        self
482    }
483
484    /// Override the ARC initial cubic-regularization parameter sigma
485    /// (default in `opt`: 1.0). Smaller sigma → less cubic penalty on the
486    /// first step → larger first move on benign objectives. The matrix-
487    /// free Newton-TR analog is `with_operator_initial_trust_radius`.
488    ///
489    /// Used by Gaussian-identity REML at large-scale n: the objective is
490    /// quadratic-like in log-λ near the optimum (sigma is the right
491    /// scale), and log-λ moves of 2–4 units in the early iters
492    /// otherwise burn 4–8 iters of trust-region expansion before the
493    /// model trusts the analytic Hessian.
494    pub fn with_arc_initial_regularization(mut self, sigma: Option<f64>) -> Self {
495        self.arc_initial_regularization = sigma.filter(|v| v.is_finite() && *v > 0.0);
496        self
497    }
498
499    /// Set the objective's natural magnitude scale, used to derive an
500    /// `n`-aware absolute gradient-norm floor. When set to `Some(s)`,
501    /// the runner uses `abs_floor = max(tol, s * √ε_machine)` for the
502    /// projected-gradient convergence check.
503    ///
504    /// Rationale: a fixed `abs = tol` (e.g. 1e-6) is appropriate when the
505    /// objective and its gradient live on a unit scale, but Gaussian-
506    /// identity REML carries an O(n) likelihood constant that flows into
507    /// ∂/∂logλ. At large-scale n the floor becomes binding even when the
508    /// relative-from-seed component (`rel_initial_grad * ‖g0‖`) declared
509    /// convergence iters earlier — chasing sub-ULP changes in log-λ at
510    /// the cost of repeated k²·n·p² analytic-Hessian assemblies.
511    pub fn with_objective_scale(mut self, scale: Option<f64>) -> Self {
512        self.objective_scale = scale.filter(|v| v.is_finite() && *v > 0.0);
513        self
514    }
515
516    /// Decouple the *relative-cost-decrease* convergence stop from the
517    /// absolute projected-gradient floor. By default both are derived from the
518    /// single `with_tolerance` value (`abs = max(tol, scale·√ε_machine)`,
519    /// `rel_cost = tol`). Supplying `Some(r)` here makes the rel-cost stop use
520    /// `r` while the absolute floor keeps using `tolerance` (so a caller can
521    /// keep a tight absolute floor for accuracy at large `n` AND a loose
522    /// rel-cost stop for perf on a flat REML ridge — see #1082). `None` keeps
523    /// the legacy coupling.
524    pub fn with_rel_cost_tolerance(mut self, rel_cost: Option<f64>) -> Self {
525        self.rel_cost_tolerance = rel_cost.filter(|v| v.is_finite() && *v > 0.0);
526        self
527    }
528
529    /// Cap the infinity-norm displacement of BFGS cost-only line-search probes
530    /// on the **rho axes** (the first `n_params - psi_dim` outer parameters,
531    /// = log-λ). Also scales the initial inverse metric so the first trial
532    /// direction respects the same local budget coordinate-wise. Documented
533    /// natural step on log-λ is ≈ 5; tighter values throttle BFGS and starve
534    /// convergence on flat REML valleys.
535    pub fn with_bfgs_step_cap(mut self, cap: Option<f64>) -> Self {
536        self.bfgs_step_cap = cap.filter(|v| v.is_finite() && *v > 0.0);
537        self
538    }
539
540    /// Cap the infinity-norm displacement of BFGS cost-only line-search probes
541    /// on the **psi axes** (the trailing `psi_dim` outer parameters, = kappa
542    /// or anisotropic log-scales). Mirrors [`Self::with_bfgs_step_cap`] but
543    /// scoped to kernel-scale parameters whose natural step is much smaller
544    /// than log-λ (≈ ln 2 per iter keeps kappa from oscillating). Without
545    /// this split, a uniform rho-scale cap lets psi explode while a uniform
546    /// psi-scale cap throttles rho — both fail the survival-marginal-slope
547    /// path at large scale, where rho needs |d|≈5 while psi wants |d|≤1.
548    pub fn with_bfgs_step_cap_psi(mut self, cap: Option<f64>) -> Self {
549        self.bfgs_step_cap_psi = cap.filter(|v| v.is_finite() && *v > 0.0);
550        self
551    }
552
553    pub fn with_cache_session(mut self, session: Arc<CacheSession>) -> Self {
554        self.cache_session = Some(session);
555        self
556    }
557
558    /// Attach mirror cache sessions that receive a broadcast copy of
559    /// the final-result finalize write. See
560    /// [`OuterConfig::cache_mirror_sessions`].
561    pub fn with_cache_mirror_sessions(mut self, sessions: Vec<Arc<CacheSession>>) -> Self {
562        self.cache_mirror_sessions = sessions;
563        self
564    }
565
566    pub fn with_problem_size(mut self, n_obs: usize, p_coefficients: usize) -> Self {
567        self.rho_uncertainty_problem_size = crate::rho_uncertainty::RhoUncertaintyProblemSize {
568            n_obs: Some(n_obs),
569            p_coefficients: Some(p_coefficients),
570        };
571        self
572    }
573
574    /// Override the fallback policy. Default is [`FallbackPolicy::Automatic`].
575    ///
576    /// Set [`FallbackPolicy::Disabled`] when the caller requires the primary
577    /// plan to stand on its own. Exact-Hessian objectives use this to ensure
578    /// failures surface on the analytic geometry instead of being reinterpreted
579    /// by a different optimizer class.
580    pub fn with_fallback_policy(mut self, policy: FallbackPolicy) -> Self {
581        self.fallback_policy = policy;
582        self
583    }
584
585    /// Derive the capability flags from the builder state.
586    /// `fixed_point_available` is set to `false` here; `build_objective`
587    /// overrides it based on whether an EFS closure is actually provided.
588    fn capability(&self) -> OuterCapability {
589        OuterCapability {
590            gradient: self.gradient,
591            hessian: self.hessian,
592            prefer_gradient_only: self.prefer_gradient_only,
593            disable_fixed_point: self.disable_fixed_point,
594            n_params: self.n_params,
595            psi_dim: self.psi_dim,
596            fixed_point_available: false,
597            barrier_config: self.barrier_config.clone(),
598        }
599    }
600
601    /// Derive the runner configuration from the builder state.
602    pub(crate) fn config(&self) -> OuterConfig {
603        OuterConfig {
604            tolerance: self.tolerance,
605            rel_cost_tolerance: self.rel_cost_tolerance,
606            max_iter: self.max_iter,
607            bounds: self.bounds.clone(),
608            seed_config: self.seed_config,
609            rho_bound: self.rho_bound,
610            heuristic_lambdas: self.heuristic_lambdas.clone(),
611            initial_rho: self.initial_rho.clone(),
612            initial_inner_seed: None,
613            fallback_policy: self.fallback_policy,
614            screening_cap: self.screening_cap.clone(),
615            screen_initial_rho: self.screen_initial_rho,
616            outer_inner_cap: self.outer_inner_cap.clone(),
617            operator_initial_trust_radius: self.operator_initial_trust_radius,
618            arc_initial_regularization: self.arc_initial_regularization,
619            objective_scale: self.objective_scale,
620            bfgs_step_cap: self.bfgs_step_cap,
621            bfgs_step_cap_psi: self.bfgs_step_cap_psi,
622            cache_session: self.cache_session.clone(),
623            cache_mirror_sessions: self.cache_mirror_sessions.clone(),
624            rho_uncertainty_problem_size: self.rho_uncertainty_problem_size,
625            // Populated only by the persistent-cache resume path in `run` after
626            // a warm-start hit decodes a converged outer Hessian.
627            warm_start_outer_hessian: None,
628            rho_canonical_keys: self.rho_canonical_keys.clone(),
629        }
630    }
631
632    /// Construct a [`ClosureObjective`] with capability flags derived from the
633    /// builder state **and** the closures actually provided.
634    ///
635    /// `fixed_point_available` is set to `true` when `efs_fn` is `Some`,
636    /// regardless of whether `.with_efs()` was called.  This is the canonical
637    /// way to create production objectives — it eliminates the drift risk of
638    /// manually entering capability flags.
639    pub fn build_objective<S, Fc, Fe, Fr, Fefs>(
640        &self,
641        state: S,
642        cost_fn: Fc,
643        eval_fn: Fe,
644        reset_fn: Option<Fr>,
645        efs_fn: Option<Fefs>,
646    ) -> ClosureObjective<S, Fc, Fe, Fr, Fefs>
647    where
648        Fc: FnMut(&mut S, &Array1<f64>) -> Result<f64, EstimationError>,
649        Fe: FnMut(&mut S, &Array1<f64>) -> Result<OuterEval, EstimationError>,
650        Fr: FnMut(&mut S),
651        Fefs: FnMut(&mut S, &Array1<f64>) -> Result<EfsEval, EstimationError>,
652    {
653        let mut cap = self.capability();
654        // Derive fixed_point_available from whether the caller actually
655        // provided an EFS hook, rather than relying on manual flags.
656        cap.fixed_point_available = efs_fn.is_some();
657        ClosureObjective {
658            state,
659            cap,
660            cost_fn,
661            eval_fn,
662            eval_order_fn: None,
663            reset_fn,
664            efs_fn,
665            fixed_point_certificate_fn: None,
666            exact_polish_fn: None,
667            rail_face_limit_fn: None,
668            screening_proxy_fn: None::<fn(&mut S, &Array1<f64>) -> Result<f64, EstimationError>>,
669            seed_fn: None::<fn(&mut S, &Array1<f64>) -> Result<SeedOutcome, EstimationError>>,
670            terminal_eval_order: None,
671        }
672    }
673
674    /// Construct a [`ClosureObjective`] with an order-aware evaluation hook.
675    ///
676    /// This lets the runner request first-order vs second-order work based on
677    /// the active outer plan while preserving the legacy eager `eval_fn`.
678    pub fn build_objective_with_eval_order<S, Fc, Fe, Feo, Fr, Fefs>(
679        &self,
680        state: S,
681        cost_fn: Fc,
682        eval_fn: Fe,
683        eval_order_fn: Feo,
684        reset_fn: Option<Fr>,
685        efs_fn: Option<Fefs>,
686    ) -> ClosureObjective<S, Fc, Fe, Fr, Fefs, Feo>
687    where
688        Fc: FnMut(&mut S, &Array1<f64>) -> Result<f64, EstimationError>,
689        Fe: FnMut(&mut S, &Array1<f64>) -> Result<OuterEval, EstimationError>,
690        Feo: FnMut(&mut S, &Array1<f64>, OuterEvalOrder) -> Result<OuterEval, EstimationError>,
691        Fr: FnMut(&mut S),
692        Fefs: FnMut(&mut S, &Array1<f64>) -> Result<EfsEval, EstimationError>,
693    {
694        let mut cap = self.capability();
695        cap.fixed_point_available = efs_fn.is_some();
696        ClosureObjective {
697            state,
698            cap,
699            cost_fn,
700            eval_fn,
701            eval_order_fn: Some(eval_order_fn),
702            reset_fn,
703            efs_fn,
704            fixed_point_certificate_fn: None,
705            exact_polish_fn: None,
706            rail_face_limit_fn: None,
707            screening_proxy_fn: None::<fn(&mut S, &Array1<f64>) -> Result<f64, EstimationError>>,
708            seed_fn: None::<fn(&mut S, &Array1<f64>) -> Result<SeedOutcome, EstimationError>>,
709            terminal_eval_order: None,
710        }
711    }
712
713    /// Construct a [`ClosureObjective`] with both an order-aware evaluation
714    /// hook and a custom seed-screening ranking proxy. The proxy fires only
715    /// when the cascade in `rank_seeds_with_screening` calls it; outside
716    /// screening the regular cost path is unaffected.
717    pub fn build_objective_with_screening_proxy<S, Fc, Fe, Feo, Fr, Fefs, Fsp>(
718        &self,
719        state: S,
720        cost_fn: Fc,
721        eval_fn: Fe,
722        eval_order_fn: Feo,
723        reset_fn: Option<Fr>,
724        efs_fn: Option<Fefs>,
725        screening_proxy_fn: Fsp,
726    ) -> ClosureObjective<S, Fc, Fe, Fr, Fefs, Feo, Fsp>
727    where
728        Fc: FnMut(&mut S, &Array1<f64>) -> Result<f64, EstimationError>,
729        Fe: FnMut(&mut S, &Array1<f64>) -> Result<OuterEval, EstimationError>,
730        Feo: FnMut(&mut S, &Array1<f64>, OuterEvalOrder) -> Result<OuterEval, EstimationError>,
731        Fr: FnMut(&mut S),
732        Fefs: FnMut(&mut S, &Array1<f64>) -> Result<EfsEval, EstimationError>,
733        Fsp: FnMut(&mut S, &Array1<f64>) -> Result<f64, EstimationError>,
734    {
735        let mut cap = self.capability();
736        cap.fixed_point_available = efs_fn.is_some();
737        ClosureObjective {
738            state,
739            cap,
740            cost_fn,
741            eval_fn,
742            eval_order_fn: Some(eval_order_fn),
743            reset_fn,
744            efs_fn,
745            fixed_point_certificate_fn: None,
746            exact_polish_fn: None,
747            rail_face_limit_fn: None,
748            screening_proxy_fn: Some(screening_proxy_fn),
749            seed_fn: None::<fn(&mut S, &Array1<f64>) -> Result<SeedOutcome, EstimationError>>,
750            terminal_eval_order: None,
751        }
752    }
753
754    /// Run the outer optimization with a given objective.
755    pub fn run(
756        &self,
757        obj: &mut dyn OuterObjective,
758        context: &str,
759    ) -> Result<OuterResult, EstimationError> {
760        let mut config = self.config();
761        let objective_lower = obj.outer_domain_lower_bound()?;
762        let objective_upper = obj.outer_domain_upper_bound()?;
763        if objective_lower.is_some() || objective_upper.is_some() {
764            install_objective_domain(&mut config, self.n_params, objective_lower, objective_upper)?;
765        }
766        let Some(session) = config.cache_session.clone() else {
767            return run_outer(obj, &config, context);
768        };
769        let key_hex = session.key().to_hex();
770        let short_key = &key_hex[..8.min(key_hex.len())];
771        let mut had_hit = false;
772        let mut cached_inner_seed: Option<BoundInnerSeed> = None;
773        if let Some(loaded) = session.try_load_with_source() {
774            match classify_cache_entry_for_outer(&loaded, self.n_params) {
775                CacheSeedDecision::ExactFinal {
776                    rho,
777                    beta,
778                    iterations,
779                    prior_obj_display,
780                } => {
781                    log::info!(
782                        "[CACHE] final-hit key={}.. context={} rho_dim={} prior_obj={:.6e} iter={} action=resume-and-recertify",
783                        short_key,
784                        context,
785                        rho.len(),
786                        prior_obj_display,
787                        iterations,
788                    );
789                    config.initial_rho = Some(rho.clone());
790                    config.screen_initial_rho = false;
791                    if !beta.is_empty() {
792                        cached_inner_seed = Some(BoundInnerSeed {
793                            theta: rho,
794                            beta: Array1::from_vec(beta),
795                        });
796                    }
797                    had_hit = true;
798                }
799                CacheSeedDecision::Seed {
800                    rho,
801                    beta,
802                    hessian,
803                    prior_obj_display,
804                    iteration,
805                } => {
806                    let beta_len = beta.len();
807                    let beta_arr = if beta.is_empty() {
808                        None
809                    } else {
810                        Some(Array1::from_vec(beta))
811                    };
812                    // Adopt the transferred converged outer Hessian only when it
813                    // matches this fit's full-θ dimension; a dimension drift
814                    // (structural change the cache key did not capture) falls
815                    // back to the scalar warm metric in run_plan.
816                    config.warm_start_outer_hessian = if self.hessian.is_analytic() {
817                        hessian.and_then(|(dim, flat)| {
818                            if dim == self.n_params && flat.len() == dim * dim {
819                                Array2::from_shape_vec((dim, dim), flat).ok()
820                            } else {
821                                None
822                            }
823                        })
824                    } else {
825                        None
826                    };
827                    if config
828                        .initial_rho
829                        .as_ref()
830                        .is_none_or(|initial| initial != rho)
831                    {
832                        log::info!(
833                            "[CACHE] hit  key={}.. context={} rho_dim={} beta_dim={} prior_obj={:.6e} iter={}",
834                            short_key,
835                            context,
836                            rho.len(),
837                            beta_len,
838                            prior_obj_display,
839                            iteration,
840                        );
841                        config.initial_rho = Some(rho.clone());
842                        config.screen_initial_rho = false;
843                        had_hit = true;
844                    } else {
845                        log::info!(
846                            "[CACHE] hit  key={}.. context={} rho_dim={} beta_dim={} already-aligned prior_obj={:.6e}",
847                            short_key,
848                            context,
849                            rho.len(),
850                            beta_len,
851                            prior_obj_display,
852                        );
853                        had_hit = true;
854                    }
855                    if let Some(beta) = beta_arr {
856                        cached_inner_seed = Some(BoundInnerSeed { theta: rho, beta });
857                    }
858                }
859                CacheSeedDecision::Discard {
860                    reason: "payload-shape-mismatch",
861                    ..
862                } => {
863                    log::info!(
864                        "[CACHE] skip key={}.. context={} reason=payload-shape-mismatch n_params={}",
865                        short_key,
866                        context,
867                        self.n_params,
868                    );
869                }
870                CacheSeedDecision::Discard {
871                    reason,
872                    prior_obj_display,
873                    all_rho_finite,
874                } => {
875                    log::info!(
876                        "[CACHE] skip key={}.. context={} reason={} prior_obj={:.6e} all_rho_finite={}",
877                        short_key,
878                        context,
879                        reason,
880                        prior_obj_display,
881                        all_rho_finite.unwrap_or(false),
882                    );
883                }
884            }
885        } else {
886            log::info!(
887                "[CACHE] miss key={}.. context={} reason=fresh-fingerprint n_params={}",
888                short_key,
889                context,
890                self.n_params,
891            );
892        }
893        // Preserve the ownership relation between a cached coefficient vector
894        // and the exact outer coordinate that produced it. The runner installs
895        // this seed only after resetting for that bitwise-matching candidate;
896        // it is never replayed at another generated seed.
897        config.initial_inner_seed = cached_inner_seed;
898        let mut checkpointing = CheckpointingObjective::new(
899            obj,
900            Arc::clone(&session),
901            config.cache_mirror_sessions.clone(),
902        );
903        let result = run_outer(&mut checkpointing, &config, context);
904        // Pull the most-recent inner β surfaced by the inner solver so the
905        // finalize write encodes the (ρ, β) pair the BFGS optimum was
906        // actually fitted at, not a ρ-only seed that resumes at cold β.
907        let final_beta = checkpointing.last_inner_beta();
908        if let Ok(result) = result.as_ref()
909            && result.final_value.is_finite()
910            && result.converged
911            && result
912                .criterion_certificate
913                .as_ref()
914                .is_some_and(OuterCriterionCertificate::certifies)
915            && let Some(bytes) = encode_iterate(
916                &result.rho,
917                final_beta.as_ref(),
918                result.final_hessian.as_ref(),
919                result.final_value,
920                result.iterations as u64,
921            )
922        {
923            let saved = session.finalize(
924                &bytes,
925                Some(result.final_value),
926                Some(result.iterations as u64),
927            );
928            if saved {
929                log::info!(
930                    "[CACHE] save key={}.. context={} final_obj={:.6e} iter={} resumed={}",
931                    short_key,
932                    context,
933                    result.final_value,
934                    result.iterations,
935                    had_hit,
936                );
937            }
938            // Broadcast finalize to mirror keys. The seed-prefix mirror
939            // exists so future fits with related-but-not-identical
940            // structure can warm-start from this run via the dispatcher's
941            // prefix lookup.
942            for mirror in &config.cache_mirror_sessions {
943                let mirror_saved = mirror.finalize(
944                    &bytes,
945                    Some(result.final_value),
946                    Some(result.iterations as u64),
947                );
948                if mirror_saved {
949                    let mirror_hex = mirror.key().to_hex();
950                    log::info!(
951                        "[CACHE] save key={}.. context={} mirror final_obj={:.6e} iter={}",
952                        &mirror_hex[..8.min(mirror_hex.len())],
953                        context,
954                        result.final_value,
955                        result.iterations,
956                    );
957                }
958            }
959        }
960        result
961    }
962
963    /// Run the outer optimization and return an unforgeable certified-result
964    /// carrier.  Callers that only need checkpoints or diagnostics should use
965    /// [`Self::run`]; fit assembly after an optimized outer coordinate must use
966    /// this boundary so a caller-constructed [`OuterResult`] cannot mint
967    /// convergence provenance.
968    pub fn run_certified(
969        &self,
970        obj: &mut dyn OuterObjective,
971        context: &str,
972    ) -> Result<CertifiedOuterResult, EstimationError> {
973        let result = self.run(obj, context)?;
974        CertifiedOuterResult::from_optimizer_result(result).map_err(|reason| {
975            EstimationError::RemlOptimizationFailed(format!(
976                "{context}: outer result failed certified-fit validation: {reason}"
977            ))
978        })
979    }
980}
981
982/// Internal outcome of one planned solver/multistart attempt.
983///
984/// Exhausted checkpoints carry resumable work only. They never pass through
985/// finalization, cache promotion, uncertainty diagnostics, or fitted-model
986/// construction.
987pub(crate) enum PlanRunOutcome {
988    Converged(OuterResult),
989    Exhausted(OuterResult),
990}
991
992/// Which certificate concluded a CONVERGED outer run (#2235/#2241).
993///
994/// `OuterResult.converged == true` bundles genuinely different endings, each
995/// with its own certificate. Distinguishing them is pure evidence for the
996/// caller's termination report — every variant is a converged fit. There is
997/// deliberately no "budget/freeze" variant: exhaustion is a typed error
998/// carrying the resume checkpoint, never a minted fit (SPEC 20; the #2235
999/// forcing-function redesign deleted the freeze lanes).
1000#[derive(Clone, Copy, Debug, PartialEq)]
1001pub enum OuterConvergedVia {
1002    /// The bound-projected analytic gradient at the returned point cleared the
1003    /// solver's absolute/score-scaled stationarity tolerance.
1004    GradientStationary,
1005    /// Criterion-flat certificate (#2241/#2253): the criterion stalled over the
1006    /// cost-stall window and the residual projected gradient sits inside the
1007    /// flat certificate band — the score-relative stationarity bound
1008    /// (`flat_valley_converged_grad_bound`), the probe-noise-floor bound
1009    /// measured from the stall window's own value scatter, and/or the
1010    /// curvature-scaled Newton-decrement bound (`newton_predicted_decrease`),
1011    /// under which a residual above the gradient-magnitude bands is still
1012    /// stationary when the second-order-predicted improvement `½·gᵀH⁻¹g` is below
1013    /// the outer objective tolerance. `certificate_bound` is the operative
1014    /// (widened) bound the residual actually cleared.
1015    CriterionFlat {
1016        residual_grad_norm: f64,
1017        certificate_bound: f64,
1018    },
1019    /// Every optimized coordinate carried an explicit analytic fixed-point
1020    /// equation and the KKT-projected residual cleared the solver tolerance.
1021    FixedPointStationary {
1022        projected_residual_inf_norm: f64,
1023        certificate_bound: f64,
1024    },
1025    /// Fellner–Schall model-state fixed point (#2235 verdict 2): two
1026    /// consecutive outer evaluations restored the same banked incumbent, so a
1027    /// further outer update provably does not change the fitted state. The
1028    /// analytic first-order certificate is still taken at the incumbent.
1029    RecurrentIncumbent { consecutive_restores: usize },
1030    /// Stationary-at-asymptote (#2348 Inc 1 / #2299 layer 3): the interior
1031    /// (non-railed) coordinates are gradient-stationary, and every coordinate
1032    /// railed at the infinite-/zero-smoothing box bound is certified on a
1033    /// confirmed exponential tail (Thm 2.1) whose fitted model has reached the
1034    /// rail limit to within the estimand tolerance. The typed rail supersedes
1035    /// the generic gradient/criterion-flat verdict for a railed optimum.
1036    AsymptoteStationary { rails: usize },
1037}
1038
1039impl OuterConvergedVia {
1040    /// Stable wire name for termination reports; the enum owns the vocabulary
1041    /// so bindings marshal instead of mapping.
1042    pub fn as_str(&self) -> &'static str {
1043        match self {
1044            Self::GradientStationary => "converged_stationary",
1045            Self::CriterionFlat { .. } => "converged_criterion_flat",
1046            Self::FixedPointStationary { .. } => "converged_fixed_point",
1047            Self::RecurrentIncumbent { .. } => "incumbent_stationary",
1048            Self::AsymptoteStationary { .. } => "converged_asymptote_rail",
1049        }
1050    }
1051}
1052
1053/// Result of a completed outer optimization.
1054#[derive(Clone, Debug)]
1055pub struct OuterResult {
1056    /// Optimized log-smoothing parameters.
1057    pub rho: Array1<f64>,
1058    /// Final objective value.
1059    pub final_value: f64,
1060    /// Total outer iterations across all solver restarts.
1061    pub iterations: usize,
1062    /// Final gradient norm, when the solver computed an actual gradient.
1063    pub final_grad_norm: Option<f64>,
1064    /// Final gradient when the solver is gradient-based.
1065    pub final_gradient: Option<Array1<f64>>,
1066    /// Final Hessian when the solver tracks one.
1067    pub final_hessian: Option<Array2<f64>>,
1068    /// Whether the optimizer converged to a stationary point.
1069    pub converged: bool,
1070    /// Which plan was actually used (may differ from initial if fallback fired).
1071    pub plan_used: OuterPlan,
1072    /// Final trust radius for the internal operator trust-region solver.
1073    ///
1074    /// A non-converged operator-ARC attempt may be restarted by the budget
1075    /// ladder. Restarting only from the last θ but resetting the trust radius
1076    /// is not a warm start: it replays the same rejected large trial steps.
1077    /// Carry this globalization state so retries resume from the scale the
1078    /// previous attempt already learned.
1079    pub operator_trust_radius: Option<f64>,
1080    /// Why the internal operator trust-region solver stopped.
1081    pub operator_stop_reason: Option<OperatorTrustRegionStopReason>,
1082    /// First-order optimality self-audit at the returned point (#934).
1083    ///
1084    /// `None` when no analytic gradient was measured at termination
1085    /// (gradient-free solvers, cache-hit short-circuits, per-atom EFS) or
1086    /// when an audit probe failed to evaluate. Populated once by
1087    /// [`run_outer`] after the solver ladder returns, outside all hot loops.
1088    pub criterion_certificate: Option<OuterCriterionCertificate>,
1089    /// Which certificate concluded a converged run (#2235/#2241). Stamped by
1090    /// [`certify_outer_optimality`] on every certified result (the
1091    /// Fellner–Schall lane pre-stamps `RecurrentIncumbent`, which certification
1092    /// preserves); `None` exactly on non-converged resume checkpoints.
1093    pub converged_via: Option<OuterConvergedVia>,
1094    /// Probe-noise-floor gradient bound measured by the cost-stall guard at a
1095    /// halted stall (#2241): σ̂/Δ, the criterion's evaluation-noise floor over
1096    /// the stall window divided by the radius the accepted steps actually
1097    /// probed. Present only on results rebuilt from a cost-stall exit;
1098    /// [`certify_outer_optimality`] folds it into the stationarity bound so the
1099    /// final re-measured gradient is judged against the same flat certificate
1100    /// the guard granted.
1101    pub flat_noise_grad_bound: Option<f64>,
1102    /// Post-fit PSIS diagnostic for whether sampled smoothing-parameter weights
1103    /// show evidence that plug-in REML/LAML intervals are unreliable. Populated
1104    /// once by [`run_outer`] when the exact rho Hessian is cheap enough to use.
1105    pub rho_uncertainty_diagnostic: Option<crate::rho_uncertainty::RhoUncertaintyDiagnostic>,
1106    /// Reseed point minted by a refused certification whose tail snap CONFIRMED
1107    /// an exponential tail (#2348 Inc 2b). A snap is a waypoint, never a
1108    /// candidate optimum: even an interior coordinate stationary before the
1109    /// snap can move when it is coupled to the tail coordinate (#2358). The
1110    /// plan runner retries ONCE from this point, allowing every coordinate to
1111    /// re-descend or remain on the rail before the natural certificate judges
1112    /// the result.
1113    pub tail_snap_reseed: Option<Array1<f64>>,
1114    /// Saddle-escape reseed point minted by a refused certification whose
1115    /// interior reduced Hessian is a certified strict saddle — small projected
1116    /// gradient, `hessian_psd = Some(false)`, no railed coordinate (#2357). A
1117    /// gradient-only convergence gate (ARC's, or the cost-stall guard's) can
1118    /// ARRIVE at such a saddle with its gradient already below tolerance and
1119    /// stop, even though the certified negative-curvature eigendirection is a
1120    /// strict descent direction the optimizer never took. This point is
1121    /// `ρ + α·v` for the most-negative-curvature eigenvector `v`, stepped off
1122    /// the saddle ridge to a strictly-lower objective; the plan runner reseeds
1123    /// the outer search ONCE from it (reseed gate closed so it cannot recurse),
1124    /// which lets the optimizer descend to the true PSD minimum exactly as an
1125    /// identical warm-started resume does by hand.
1126    pub saddle_escape_reseed: Option<Array1<f64>>,
1127    /// Wrong-rail pull-back reseed point minted by a refused certification whose
1128    /// coordinate sits AT the ρ box bound but whose clean-band probes prove the
1129    /// objective DECREASES as the coordinate moves INWARD (#2392). The outer
1130    /// search drove the coordinate to the wrong bound — its terminal gradient is
1131    /// deep-λ instrument noise, so the trust region never proposed the large
1132    /// inward move — while a drift-band-clean, above-noise-floor run of probes a
1133    /// few e-folds inside carries a pencil constant of the sign OPPOSITE the rail
1134    /// (descent points away from the bound, `∂V/∂ρ > 0` at an upper rail). This
1135    /// point moves that coordinate to its clean-band interior scale, where the
1136    /// gradient is informative again; the plan runner reseeds ONCE (gate closed)
1137    /// and the optimizer descends to the true interior optimum. Gated strictly on
1138    /// the opposite-sign clean-tail proof, so a GENUINE rail (descent toward the
1139    /// bound) never mints it and no real λ→∞ optimum is pulled off its rail.
1140    pub wrong_rail_reseed: Option<Array1<f64>>,
1141    /// Active-set reduction reseed minted by a refused certification whose
1142    /// INTERIOR is not stationary while a coordinate is railed at the ρ box with
1143    /// a deep-λ noise-floor gradient (#2392). The railed coordinate's
1144    /// ill-conditioned Hessian row poisons the joint Newton/ARC steps, so the
1145    /// interior cannot polish; freezing that coordinate at its bound and
1146    /// re-running lets the optimizer converge the interior in the well-conditioned
1147    /// REDUCED space. The reseed carries the frozen box (`bounds`, with
1148    /// `lower[k]==upper[k]==rail` for each frozen coordinate); the plan runner's
1149    /// re-certification under the ORIGINAL bounds then judges every pinned
1150    /// coordinate's KKT sign at the reduced optimum (an inward-feasible-descent
1151    /// gradient unfreezes it — no silent clamping of a coordinate that stops
1152    /// wanting the rail).
1153    pub active_set_reseed: Option<ActiveSetReseed>,
1154}
1155
1156/// An active-set reduction reseed (#2392): re-run the outer search with a set of
1157/// railed coordinates FROZEN at their box bounds so the optimizer polishes the
1158/// interior in the reduced space.
1159#[derive(Clone, Debug)]
1160pub struct ActiveSetReseed {
1161    /// The reseed point: the refused checkpoint with the frozen coordinates
1162    /// pinned at their bounds (`rho[k] == bounds.0[k] == bounds.1[k]`).
1163    pub rho: Array1<f64>,
1164    /// The reduced-space box: `lower[k] == upper[k] == rail` for every frozen
1165    /// coordinate `k`, the original bounds elsewhere.
1166    pub bounds: (Array1<f64>, Array1<f64>),
1167}
1168
1169impl OuterResult {
1170    pub fn new(
1171        rho: Array1<f64>,
1172        final_value: f64,
1173        iterations: usize,
1174        converged: bool,
1175        plan_used: OuterPlan,
1176    ) -> Self {
1177        Self {
1178            rho,
1179            final_value,
1180            iterations,
1181            final_grad_norm: None,
1182            final_gradient: None,
1183            final_hessian: None,
1184            converged,
1185            plan_used,
1186            operator_trust_radius: None,
1187            operator_stop_reason: None,
1188            criterion_certificate: None,
1189            converged_via: None,
1190            flat_noise_grad_bound: None,
1191            rho_uncertainty_diagnostic: None,
1192            tail_snap_reseed: None,
1193            saddle_escape_reseed: None,
1194            wrong_rail_reseed: None,
1195            active_set_reseed: None,
1196        }
1197    }
1198
1199    /// Human-readable rendering of `final_grad_norm` for diagnostics. Returns
1200    /// `"n/a"` when no gradient was measured (gradient-free / cache-hit paths).
1201    pub fn final_grad_norm_report(&self) -> String {
1202        match self.final_grad_norm {
1203            Some(g) => format!("{g:.3e}"),
1204            None => "n/a".to_string(),
1205        }
1206    }
1207}
1208
1209/// Validated evidence that an outer optimization terminated at a finite,
1210/// analytically certified optimum.
1211///
1212/// The inner [`OuterResult`] is private so downstream fit assembly cannot turn
1213/// a status boolean into convergence provenance. Construction consumes the
1214/// optimizer result and revalidates the certificate at the ownership boundary.
1215#[derive(Clone, Debug)]
1216pub struct CertifiedOuterResult {
1217    result: OuterResult,
1218}
1219
1220impl CertifiedOuterResult {
1221    /// The sole constructor is reached from [`OuterProblem::run_certified`]
1222    /// after the optimizer has produced the result.  Keeping this private is
1223    /// load-bearing: `OuterResult` is also a public diagnostic/checkpoint
1224    /// payload, so a public conversion would let downstream code fabricate a
1225    /// certificate-shaped result without ever running an objective.
1226    fn from_optimizer_result(result: OuterResult) -> Result<Self, String> {
1227        if !result.converged {
1228            return Err(format!(
1229                "outer optimization did not converge after {} iterations",
1230                result.iterations
1231            ));
1232        }
1233        if !result.final_value.is_finite() {
1234            return Err(format!(
1235                "outer optimization returned a non-finite objective: {}",
1236                result.final_value
1237            ));
1238        }
1239        if result.rho.iter().any(|value| !value.is_finite()) {
1240            return Err("outer optimization returned non-finite hyperparameters".to_string());
1241        }
1242        if result
1243            .final_grad_norm
1244            .is_some_and(|value| !value.is_finite() || value < 0.0)
1245        {
1246            return Err(format!(
1247                "outer optimization returned an invalid gradient norm: {:?}",
1248                result.final_grad_norm
1249            ));
1250        }
1251        let certificate = result
1252            .criterion_certificate
1253            .as_ref()
1254            .ok_or_else(|| "outer optimization returned no analytic certificate".to_string())?;
1255        if !certificate.certifies() {
1256            return Err(format!(
1257                "outer optimization certificate does not certify: {}",
1258                certificate.summary()
1259            ));
1260        }
1261        if result.converged_via.is_none() {
1262            return Err(
1263                "outer optimization did not retain optimizer-owned termination provenance"
1264                    .to_string(),
1265            );
1266        }
1267        Ok(Self { result })
1268    }
1269
1270    /// Exact optimizer-owned hyperparameter vector covered by the certificate.
1271    pub fn rho(&self) -> &Array1<f64> {
1272        &self.result.rho
1273    }
1274
1275    pub fn iterations(&self) -> usize {
1276        self.result.iterations
1277    }
1278
1279    pub fn final_value(&self) -> f64 {
1280        self.result.final_value
1281    }
1282
1283    pub fn final_grad_norm(&self) -> Option<f64> {
1284        self.result.final_grad_norm
1285    }
1286
1287    /// Exact analytic gradient re-measured by the optimizer-owned terminal
1288    /// certificate. Downstream selected-profile finalizers use this to prove
1289    /// that a retained objective payload is the one certified at `rho()`.
1290    pub fn final_gradient(&self) -> Option<&Array1<f64>> {
1291        self.result.final_gradient.as_ref()
1292    }
1293
1294    pub fn criterion_certificate(&self) -> &OuterCriterionCertificate {
1295        self.result
1296            .criterion_certificate
1297            .as_ref()
1298            .expect("CertifiedOuterResult always owns a validated certificate")
1299    }
1300
1301    /// The analytic outer ρ-Hessian measured at the certified point, when the
1302    /// certification retained one. This is the curvature evidence behind the
1303    /// certificate's PSD verdict — and the `V_ρ = H_ρ⁻¹` input to first-order
1304    /// smoothing-correction inflation (#2346).
1305    pub fn final_hessian(&self) -> Option<&Array2<f64>> {
1306        self.result.final_hessian.as_ref()
1307    }
1308}
1309
1310#[cfg(test)]
1311mod certified_outer_result_tests {
1312    use super::*;
1313
1314    #[test]
1315    fn caller_boolean_and_zero_gradient_cannot_mint_outer_authority() {
1316        let mut fabricated = OuterResult::new(
1317            Array1::from_vec(vec![0.0]),
1318            1.0,
1319            3,
1320            true,
1321            OuterPlan {
1322                solver: Solver::Bfgs,
1323                hessian_source: HessianSource::BfgsApprox,
1324            },
1325        );
1326        fabricated.final_grad_norm = Some(0.0);
1327        fabricated.final_gradient = Some(Array1::from_vec(vec![0.0]));
1328        fabricated.converged_via = Some(OuterConvergedVia::GradientStationary);
1329
1330        let reason = CertifiedOuterResult::from_optimizer_result(fabricated)
1331            .expect_err("caller-written status and gradient must not mint a certificate");
1332        assert!(reason.contains("no analytic certificate"), "{reason}");
1333    }
1334}
1335
1336/// Typed refusal from [`audit_stationary_point`]. The rejected point and every
1337/// analytic certificate field measured before refusal remain available to the
1338/// caller; `source` records why those measurements did not certify.
1339#[derive(Debug)]
1340pub struct OuterStationaryPointRejection {
1341    pub result: OuterResult,
1342    pub source: EstimationError,
1343}
1344
1345impl std::fmt::Display for OuterStationaryPointRejection {
1346    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1347        std::fmt::Display::fmt(&self.source, f)
1348    }
1349}
1350
1351impl std::error::Error for OuterStationaryPointRejection {
1352    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1353        Some(&self.source)
1354    }
1355}
1356
1357/// Apply the shared analytic outer-optimality authority to one caller-supplied
1358/// point without running an optimizer or taking a step.
1359///
1360/// The objective controls whether evaluating that point mutates its profiled
1361/// state. Callers auditing an already-installed inner state must put their
1362/// objective in a frozen evaluation mode before calling this function.
1363/// `iterations == 0` in the returned result is structural: no optimization loop
1364/// exists on this path.
1365pub fn audit_stationary_point(
1366    obj: &mut dyn OuterObjective,
1367    rho: Array1<f64>,
1368    context: &str,
1369) -> Result<OuterResult, OuterStationaryPointRejection> {
1370    let config = OuterConfig::default();
1371    let selected_plan = plan(&obj.capability());
1372    // There is intentionally no independent value-only probe. The analytic
1373    // sample is the authority being audited, and infinity records that no
1374    // optimizer-produced terminal value exists to compare against it.
1375    let mut result = OuterResult::new(rho, f64::INFINITY, 0, false, selected_plan);
1376    match certify_outer_optimality(obj, &config, context, &mut result) {
1377        Ok(certificate) => {
1378            result.criterion_certificate = Some(certificate);
1379            Ok(result)
1380        }
1381        Err(source) => Err(OuterStationaryPointRejection { result, source }),
1382    }
1383}
1384
1385// ─── First-order optimality certificate (#934) ────────────────────────
1386//
1387// The objective↔gradient desync bug genus (#748, #752, #808, #901, …) has a
1388// universal signature: at the returned "optimum" the optimizer claims
1389// convergence while the criterion is not actually stationary there (or the
1390// optimizer stalls and rails λ). The certificate makes the engine check
1391// itself, once, at θ̂, on every generic outer fit — purely from the ANALYTIC
1392// objective, per SPEC rule 2 (finite differences never run outside tests;
1393// the FD gradient oracle now lives in the test-only `fd_audit` module): the
1394// KKT-projected analytic gradient norm against the same score-relative
1395// stationarity bound the outer loop already uses to accept flat-valley
1396// stalls (#1690), a scaled PSD probe of the tracked outer Hessian, and the
1397// λ-rail facts every desync postmortem asks for. It is the runtime
1398// enforcement layer for the criterion-atom architecture (#931).
1399//
1400// A failed certificate REJECTS the fit as typed non-convergence — never a
1401// warn-and-continue diagnostic — so a nonstationary point can never be
1402// minted into a fit (SPEC rule 20).
1403
1404/// Cholesky positive-SEMIdefiniteness probe for the (small, outer-dim) final
1405/// Hessian, with a roundoff-scale diagonal shift. Returns `None` when the
1406/// matrix is empty, non-square, or non-finite; `Some(false)` when the shifted
1407/// matrix has a non-positive pivot — i.e. the curvature is genuinely
1408/// indefinite, not merely semidefinite-within-noise.
1409///
1410/// The shift is `√ε · max(1, max|H_ii|)`: eigenvalues assembled through
1411/// O(‖H‖)-scaled arithmetic carry O(ε·‖H‖) roundoff, so a `√ε`-relative
1412/// margin cleanly separates a true negative direction from accumulated
1413/// floating-point noise on a flat (near-semidefinite) valley.
1414pub(crate) fn certificate_hessian_is_psd(hessian: &Array2<f64>) -> Option<bool> {
1415    let n = hessian.nrows();
1416    if n == 0 || hessian.ncols() != n || hessian.iter().any(|v| !v.is_finite()) {
1417        return None;
1418    }
1419    let max_diag = (0..n).fold(0.0_f64, |acc, j| acc.max(hessian[[j, j]].abs()));
1420    let shift = f64::EPSILON.sqrt() * max_diag.max(1.0);
1421    let mut chol = hessian.clone();
1422    for j in 0..n {
1423        chol[[j, j]] += shift;
1424    }
1425    for j in 0..n {
1426        for k in 0..j {
1427            let l_jk = chol[[j, k]];
1428            for i in j..n {
1429                chol[[i, j]] -= chol[[i, k]] * l_jk;
1430            }
1431        }
1432        let pivot = chol[[j, j]];
1433        if !(pivot > 0.0) || !pivot.is_finite() {
1434            return Some(false);
1435        }
1436        let inv_sqrt = 1.0 / pivot.sqrt();
1437        for i in j..n {
1438            chol[[i, j]] *= inv_sqrt;
1439        }
1440    }
1441    Some(true)
1442}
1443
1444/// PSD verdict of the outer Hessian restricted to its UN-RAILED coordinates
1445/// (#2299 box-KKT reduced-Hessian / critical-cone gate).
1446///
1447/// A coordinate railed at ±`rho_bound` with an outward gradient is at the box-KKT
1448/// constrained optimum: its curvature direction is the flat/indefinite
1449/// infinite-smoothing plateau of a fully-saturated penalty (λ ~ 1e13), carrying
1450/// no feasible descent. Including it makes the FULL Hessian indefinite and used to
1451/// disable the very flatness certificate that exists to handle rails, so an
1452/// honest railed optimum ground to `max_iter` and refused. Judging PSD on the
1453/// INTERIOR (un-railed) sub-block is the standard reduced-Hessian condition: a
1454/// genuinely indefinite *interior* direction still keeps the sub-block non-PSD,
1455/// so this can never over-certify a real saddle. When every coordinate is railed
1456/// the interior is empty — there is no feasible curvature to certify and the rail
1457/// KKT signs are the whole certificate — so the empty sub-block is trivially PSD.
1458/// With no railed coordinate it is exactly [`certificate_hessian_is_psd`].
1459pub(crate) fn certificate_hessian_is_psd_off_railed(
1460    hessian: &Array2<f64>,
1461    railed: &[usize],
1462) -> Option<bool> {
1463    if railed.is_empty() {
1464        return certificate_hessian_is_psd(hessian);
1465    }
1466    let n = hessian.nrows();
1467    let railed_set: std::collections::BTreeSet<usize> = railed.iter().copied().collect();
1468    let interior: Vec<usize> = (0..n).filter(|k| !railed_set.contains(k)).collect();
1469    if interior.is_empty() {
1470        return Some(true);
1471    }
1472    let mut sub = Array2::<f64>::zeros((interior.len(), interior.len()));
1473    for (i, &ri) in interior.iter().enumerate() {
1474        for (j, &rj) in interior.iter().enumerate() {
1475            sub[[i, j]] = hessian[[ri, rj]];
1476        }
1477    }
1478    certificate_hessian_is_psd(&sub)
1479}
1480
1481/// Interior-PSD verdict judged ABOVE the per-coordinate gradient-residue noise
1482/// floor (#2349): PSD of `H + diag(|g|)` restricted to the un-excluded
1483/// coordinates.
1484///
1485/// The assembled ρ-Hessian's tail entries carry the #2298 trace-pair
1486/// cancellation residue: when the `λ²V_λλ` pair cancels to roundoff, the
1487/// surviving diagonal entry is `λV_λ = g_k` — gradient magnitude, corrupted
1488/// sign (the same tie signature the tail-snap candidate band keys on).
1489/// Measured on the #2349 multinomial checkpoint: the sole interior coordinate
1490/// had `g₁ = −1.0228e-3`, `H₁₁ = −1.0216e-3` (ratio 0.999), and that single
1491/// sub-resolution entry was the entire `interior Hessian sub-block not PSD`
1492/// refusal — the full 6×6 spectrum was `[−1.02e-3, 0.135, …, 0.904]`.
1493///
1494/// # Why the floor is safe — instrument resolution, not step economics
1495///
1496/// The residue is `O(|g_k|)`, and the sub-block is extracted AFTER flooring, so
1497/// only the *judged* (un-excluded) coordinates' gradients ever enter: a railed
1498/// coordinate's large `|g|` (measured 1.40 on the #2349 checkpoint) cannot
1499/// inflate the floor. Weyl bounds what remains exactly:
1500///
1501/// ```text
1502///     λ_min(H) + min|g| ≤ λ_min(H + diag|g|) ≤ λ_min(H) + max|g|
1503/// ```
1504///
1505/// so the floor absorbs **at most `max_k |g_k|` over the judged coordinates**.
1506/// Where this verdict can mint, those coordinates have passed gradient
1507/// stationarity, so that is at most the stationarity bound. A negative
1508/// eigenvalue smaller than that is not distinguishable from zero *by the
1509/// instrument that produced it* — the assembled tail entry IS `λV_λ = g`
1510/// (ratio 0.999 as measured) — while a genuine saddle survives untouched: the
1511/// #2357 trace's `λ_min ≈ −0.5` against `|g| ≈ 1e-3` floors to `−0.4973`, and a
1512/// `−1.50e-2` direction still refuses at a `1e-2` bound.
1513///
1514/// ## Do not widen this floor beyond `diag(|g|)`
1515///
1516/// Earlier revisions of this argument (and #2349 rounds 6/7) justified the
1517/// floor by an "exploitable improvement `≲ g²/2|H| ≈ 5e-7`". Both halves are
1518/// wrong and the pair is misleading in the permissive direction:
1519///
1520/// * the quoted number is `g²/2 = 5.23e-7`; the quoted formula evaluates to
1521///   `g²/(2|H|) = 5.12e-4` on the same measured `g = 1.0228e-3`,
1522///   `|H| = 1.0216e-3` — a 979× discrepancy. Since `|H| ≈ g` at exactly the
1523///   point this floor serves, that formula collapses to `≈ g/2`;
1524/// * and `g²/2|H|` is the Newton decrement, which bounds the improvement along
1525///   a direction of POSITIVE curvature. Along curvature `−ε` the model
1526///   `−g·t − ½εt²` is unbounded below, so the quantity it purports to bound
1527///   does not exist in the regime this floor exists for; the step is limited by
1528///   the trust radius, not the curvature.
1529///
1530/// The Weyl bound above is the correct and checkable statement. Anything that
1531/// widens the floor must re-derive against it, not against `g²/2|H|`.
1532pub(crate) fn certificate_hessian_is_psd_off_railed_above_gradient_floor(
1533    hessian: &Array2<f64>,
1534    excluded: &[usize],
1535    gradient: &Array1<f64>,
1536) -> Option<bool> {
1537    let n = hessian.nrows();
1538    if gradient.len() != n {
1539        return certificate_hessian_is_psd_off_railed(hessian, excluded);
1540    }
1541    let mut floored = hessian.clone();
1542    for k in 0..n {
1543        floored[[k, k]] += gradient[k].abs();
1544    }
1545    certificate_hessian_is_psd_off_railed(&floored, excluded)
1546}
1547
1548/// Measure the gradient-residue floor's clearance on the interior sub-block:
1549/// the sub-block's smallest eigenvalue as assembled, the floor it is judged
1550/// against (`max_k |g_k|` over exactly those coordinates), and whether
1551/// `H + diag(|g|)` is PSD there.
1552///
1553/// This RECORDS the verdict; it does not replace the raw measurement. See
1554/// [`certificate_hessian_is_psd_off_railed_above_gradient_floor`] for why the
1555/// Weyl bound makes the floor safe where it can mint, and
1556/// [`crate::model_types::CurvatureFloorClearance`] for why the two facts are
1557/// kept apart.
1558pub(crate) fn interior_curvature_floor_clearance(
1559    hessian: &Array2<f64>,
1560    excluded: &[usize],
1561    gradient: &Array1<f64>,
1562) -> Option<CurvatureFloorClearance> {
1563    use faer::Side;
1564    use gam_linalg::faer_ndarray::FaerEigh;
1565
1566    let n = hessian.nrows();
1567    if n == 0 || hessian.ncols() != n || gradient.len() != n {
1568        return None;
1569    }
1570    let excluded_set: std::collections::BTreeSet<usize> = excluded.iter().copied().collect();
1571    let interior: Vec<usize> = (0..n).filter(|k| !excluded_set.contains(k)).collect();
1572    if interior.is_empty() {
1573        return None;
1574    }
1575    let m = interior.len();
1576    let mut sub = Array2::<f64>::zeros((m, m));
1577    for (i, &ri) in interior.iter().enumerate() {
1578        for (j, &rj) in interior.iter().enumerate() {
1579            sub[[i, j]] = 0.5 * (hessian[[ri, rj]] + hessian[[rj, ri]]);
1580        }
1581    }
1582    if sub.iter().any(|v| !v.is_finite()) {
1583        return None;
1584    }
1585    let interior_min_eigenvalue = sub
1586        .eigh(Side::Lower)
1587        .ok()?
1588        .0
1589        .iter()
1590        .fold(f64::INFINITY, |acc, v| acc.min(*v));
1591    if !interior_min_eigenvalue.is_finite() {
1592        return None;
1593    }
1594    // The floor is the largest gradient among EXACTLY the judged coordinates —
1595    // the excluded ones never enter, so a railed coordinate's large |g| cannot
1596    // inflate it.
1597    let gradient_floor = interior
1598        .iter()
1599        .fold(0.0_f64, |acc, &k| acc.max(gradient[k].abs()));
1600    let cleared = certificate_hessian_is_psd_off_railed_above_gradient_floor(
1601        hessian, excluded, gradient,
1602    ) == Some(true);
1603    Some(CurvatureFloorClearance {
1604        interior_min_eigenvalue,
1605        gradient_floor,
1606        cleared,
1607    })
1608}
1609
1610/// Escape point off a certified strict saddle in the free (un-railed) subspace
1611/// (#2357, generalised to the box-constrained case in #2155).
1612///
1613/// A gradient-only outer convergence gate — ARC's own, or the cost-stall guard's
1614/// — can ARRIVE at a point that is first-order stationary (`‖Pg‖ ≤ bound`) yet
1615/// sits on genuinely indefinite curvature in its INTERIOR (un-railed) directions,
1616/// and stop there because its gradient already cleared tolerance. The mandatory
1617/// analytic certificate then refuses the point as `INDEFINITE CURVATURE AT
1618/// INTERIOR OPTIMUM` — a verdict `certificate_hessian_is_psd_off_railed` reaches
1619/// on the reduced Hessian restricted to the un-railed coordinates, so it fires
1620/// whether or not some other coordinate happens to be railed. Such a point is a
1621/// saddle, not a minimum: the most-negative-curvature eigenvector `v` of that
1622/// reduced Hessian is a strict, box-feasible descent direction the optimizer
1623/// never took. An
1624/// identical warm-started resume escapes it trivially (its fresh cubic step moves
1625/// off the ridge, which is why the resume converges where the cold run refuses);
1626/// this reproduces that escape deterministically by stepping `ρ ± α·v` to a
1627/// strictly-lower objective and handing the point back as a one-shot reseed.
1628///
1629/// Termination is guaranteed: along a direction of negative curvature
1630/// `vᵀHv = λ_min < 0` at a near-stationary gradient,
1631/// `f(ρ ± αv) = f(ρ) ± α(g·v) + ½α²λ_min + o(α²)` strictly decreases for small
1632/// enough `α` once the sign is chosen so the first-order term is non-positive, so
1633/// the finite backtracking below always finds a descending feasible point when
1634/// one exists inside the box.
1635///
1636/// Returns `None` (no reseed; the ordinary refusal proceeds) when the Hessian
1637/// carries no eigen-resolvable negative direction, or no bounded step along it
1638/// clears the box projection with a strict objective decrease. Restores the
1639/// objective's profiled inner state to `rho` before returning either way, so the
1640/// refusal path that follows measures the checkpoint rather than the last probe.
1641fn negative_curvature_escape_point(
1642    obj: &mut dyn OuterObjective,
1643    rho: &Array1<f64>,
1644    gradient: &Array1<f64>,
1645    hessian: &Array2<f64>,
1646    railed: &[usize],
1647    baseline_cost: f64,
1648    bounds: &(Array1<f64>, Array1<f64>),
1649    context: &str,
1650) -> Option<Array1<f64>> {
1651    use faer::Side;
1652    use gam_linalg::faer_ndarray::FaerEigh;
1653
1654    let n = hessian.nrows();
1655    if n == 0 || hessian.ncols() != n || hessian.iter().any(|v| !v.is_finite()) {
1656        return None;
1657    }
1658    // The escape direction lives in the INTERIOR (un-railed) subspace — the exact
1659    // reduced Hessian / critical cone that `certificate_hessian_is_psd_off_railed`
1660    // judges for the PSD verdict. A coordinate railed at a box bound with an
1661    // outward KKT gradient is already at its constrained optimum; its curvature is
1662    // the flat/indefinite infinite-smoothing plateau (λ ~ 1e13) and carries no
1663    // feasible descent. Including it would let the step chase that spurious
1664    // direction and simply re-rail. Restricting to the un-railed block yields a
1665    // feasible descent that holds every rail fixed, so the escape generalises from
1666    // the fully-interior saddle to a box-constrained one whose free-direction
1667    // reduced Hessian is indefinite (#2357 → #2155). With no rail this is exactly
1668    // the full-Hessian eigenproblem as before.
1669    let railed_set: std::collections::BTreeSet<usize> = railed.iter().copied().collect();
1670    let interior: Vec<usize> = (0..n).filter(|k| !railed_set.contains(k)).collect();
1671    if interior.is_empty() {
1672        // Every coordinate is railed: there is no feasible interior direction and
1673        // the rail KKT signs are the whole certificate.
1674        return None;
1675    }
1676    let m = interior.len();
1677    let mut sub = Array2::<f64>::zeros((m, m));
1678    for (i, &ri) in interior.iter().enumerate() {
1679        for (j, &rj) in interior.iter().enumerate() {
1680            sub[[i, j]] = hessian[[ri, rj]];
1681        }
1682    }
1683    let (eigenvalues, eigenvectors) = match sub.eigh(Side::Lower) {
1684        Ok(pair) => pair,
1685        Err(err) => {
1686            log::warn!(
1687                "[CERTIFICATE] {context}: saddle-escape eigendecomposition failed ({err}); \
1688                 refusing at the checkpoint without a reseed"
1689            );
1690            return None;
1691        }
1692    };
1693    // The SAME √ε·‖H‖ margin `certificate_hessian_is_psd` uses to separate a
1694    // genuine negative eigenvalue from O(ε·‖H‖) assembly roundoff: only a truly
1695    // negative direction — not a flat / near-semidefinite one — carries a descent
1696    // the reseed can exploit. Measured on the interior sub-block's diagonal so the
1697    // threshold matches the reduced PSD verdict exactly.
1698    let max_diag = interior
1699        .iter()
1700        .fold(0.0_f64, |acc, &j| acc.max(hessian[[j, j]].abs()));
1701    let neg_margin = f64::EPSILON.sqrt() * max_diag.max(1.0);
1702    let mut min_idx = 0usize;
1703    for k in 1..eigenvalues.len() {
1704        if eigenvalues[k] < eigenvalues[min_idx] {
1705            min_idx = k;
1706        }
1707    }
1708    if !(eigenvalues[min_idx] < -neg_margin) {
1709        return None;
1710    }
1711    let v_sub = eigenvectors.column(min_idx);
1712    let dir_norm = v_sub.dot(&v_sub).sqrt();
1713    if !(dir_norm > 0.0) || !dir_norm.is_finite() {
1714        return None;
1715    }
1716    // Lift the interior eigenvector into the full ρ space, exactly zero on every
1717    // railed coordinate so the backtracking step below holds all rails fixed.
1718    let mut direction = Array1::<f64>::zeros(n);
1719    for (i, &ri) in interior.iter().enumerate() {
1720        direction[ri] = v_sub[i] / dir_norm;
1721    }
1722    // First-order-consistent sign: move against the (tiny) gradient's projection
1723    // onto `v` so the linear term never opposes the curvature descent. With a
1724    // stationary gradient the tie is arbitrary; the opposite sign is tried below
1725    // regardless, which also covers a `v` that projects straight out of the box.
1726    let primary_sign = if gradient.dot(&direction) > 0.0 {
1727        -1.0
1728    } else {
1729        1.0
1730    };
1731    // One e-fold in log-λ is a macroscopic step across the saddle ridge; ARC then
1732    // refines from wherever this lands, so the reseed only needs to leave the
1733    // ridge, not solve the problem. Backtrack so the box-projected point still
1734    // strictly descends.
1735    const ESCAPE_STEP_SCALES: [f64; 5] = [1.0, 0.5, 0.25, 0.125, 0.0625];
1736    // A strict-decrease floor at the objective's roundoff resolution: a reseed
1737    // that only matches the checkpoint to roundoff is not a real escape.
1738    let strict_floor = baseline_cost.abs().max(1.0) * (16.0 * f64::EPSILON);
1739    let mut best: Option<(f64, Array1<f64>)> = None;
1740    for sign in [primary_sign, -primary_sign] {
1741        for &alpha in ESCAPE_STEP_SCALES.iter() {
1742            let mut trial = rho.clone();
1743            for i in 0..n {
1744                trial[i] += sign * alpha * direction[i];
1745            }
1746            let trial = project_to_bounds(&trial, Some(bounds));
1747            // A fully box-clamped trial that lands back on ρ probes nothing.
1748            if outer_theta_bitwise_eq(&trial, rho) {
1749                continue;
1750            }
1751            if let Ok(cost) = obj.eval_cost(&trial)
1752                && cost.is_finite()
1753                && cost < baseline_cost - strict_floor
1754                && best.as_ref().is_none_or(|(c, _)| cost < *c)
1755            {
1756                best = Some((cost, trial));
1757            }
1758        }
1759        if best.is_some() {
1760            break;
1761        }
1762    }
1763    // Restore the profiled inner state to the checkpoint ρ so the refusal path
1764    // that follows measures the checkpoint, not the last probe.
1765    if let Err(err) = obj.eval_cost(rho) {
1766        log::warn!(
1767            "[CERTIFICATE] {context}: failed to restore the objective to the checkpoint \
1768             after saddle-escape probing: {err}"
1769        );
1770    }
1771    best.map(|(cost, point)| {
1772        log::info!(
1773            "[CERTIFICATE] {context}: interior strict saddle (λ_min={:.3e} < 0, |Pg| within \
1774             band); minting a negative-curvature escape reseed (objective {:.6e} → {:.6e}) for \
1775             one retry (#2357)",
1776            eigenvalues[min_idx],
1777            baseline_cost,
1778            cost,
1779        );
1780        point
1781    })
1782}
1783
1784/// Second-order predicted objective decrease of a safeguarded Newton step at a
1785/// flat-valley cost-stall exit (#2253/#2249/#2015).
1786///
1787/// On a flat-valley cost-stall exit the outer criterion has provably stopped
1788/// improving (the cost-stall window fired), yet the re-measured projected
1789/// gradient can sit modestly above the score-relative flat band on a
1790/// weakly-identified small-n fit (measured: |Pg| ≈ 0.072 vs a score-relative
1791/// band ≈ 0.053 on an n=84/p=64 K=1 circle). Whether that residual is genuine
1792/// available descent is a SECOND-ORDER question. The improvement a safeguarded
1793/// Newton step buys is the Newton decrement over two:
1794///
1795///     Δpred = ½ · gᵀ H⁻¹ g,
1796///
1797/// the textbook Newton stopping quantity (Boyd–Vandenberghe §9.5). When `Δpred`
1798/// is below the outer objective tolerance, no step can reduce the criterion by
1799/// more than that tolerance and the point is stationary at the resolution the
1800/// criterion can be optimized — the mathematically correct "no further descent
1801/// possible" criterion.
1802///
1803/// This is curvature-scaled, not a constant: because `H⁻¹` weights each gradient
1804/// component by the inverse eigenvalue, a residual aligned with a NEAR-FLAT
1805/// Hessian eigenvector (a linear ramp that DOES carry real descent) inflates
1806/// `gᵀ H⁻¹ g` toward the roundoff-regularized `|g_flat|² / shift` and is
1807/// REJECTED; only a residual that is small along the well-curved directions and
1808/// nearly orthogonal to the flat ones certifies. An indefinite Hessian never
1809/// reaches here — the certificate's curvature gate (`certificate_hessian_is_psd`)
1810/// rejects a genuinely indefinite point independently, and this factorization
1811/// returns `None` on a non-PSD shifted factor so the caller falls back to the
1812/// gradient-only bound.
1813///
1814/// `hessian` and `grad` are the analytic outer Hessian and the KKT-PROJECTED
1815/// gradient at the certified point. The shift `√ε · max|H_jj|` matches
1816/// [`certificate_hessian_is_psd`] so the definiteness verdict and this decrement
1817/// agree on the same regularized operator. Returns `None` when the shapes are
1818/// malformed, an entry is non-finite, the shifted factor is not PD, or the
1819/// resulting quadratic form is negative (which a PD factor rules out; retained
1820/// as a roundoff guard).
1821pub(crate) fn newton_predicted_decrease(hessian: &Array2<f64>, grad: &Array1<f64>) -> Option<f64> {
1822    let n = hessian.nrows();
1823    if n == 0 || hessian.ncols() != n || grad.len() != n {
1824        return None;
1825    }
1826    if hessian.iter().any(|v| !v.is_finite()) || grad.iter().any(|v| !v.is_finite()) {
1827        return None;
1828    }
1829    let max_diag = (0..n).fold(0.0_f64, |acc, j| acc.max(hessian[[j, j]].abs()));
1830    let shift = f64::EPSILON.sqrt() * max_diag.max(1.0);
1831    // Lower Cholesky factor L of H + shift·I (same regularization the PSD probe
1832    // uses), computed in place.
1833    let mut l = hessian.clone();
1834    for j in 0..n {
1835        l[[j, j]] += shift;
1836    }
1837    for j in 0..n {
1838        for k in 0..j {
1839            let l_jk = l[[j, k]];
1840            for i in j..n {
1841                l[[i, j]] -= l[[i, k]] * l_jk;
1842            }
1843        }
1844        let pivot = l[[j, j]];
1845        if !(pivot > 0.0) || !pivot.is_finite() {
1846            return None;
1847        }
1848        let inv_sqrt = 1.0 / pivot.sqrt();
1849        for i in j..n {
1850            l[[i, j]] *= inv_sqrt;
1851        }
1852    }
1853    // Solve (L Lᵀ) d = g for d = H_s⁻¹ g: forward-substitute L y = g, then
1854    // back-substitute Lᵀ d = y.
1855    let mut y = grad.clone();
1856    for j in 0..n {
1857        let mut s = y[j];
1858        for k in 0..j {
1859            s -= l[[j, k]] * y[k];
1860        }
1861        y[j] = s / l[[j, j]];
1862    }
1863    let mut d = y;
1864    for j in (0..n).rev() {
1865        let mut s = d[j];
1866        for k in (j + 1)..n {
1867            s -= l[[k, j]] * d[k];
1868        }
1869        d[j] = s / l[[j, j]];
1870    }
1871    let quad = grad.dot(&d); // gᵀ H_s⁻¹ g ≥ 0 for a PD factor.
1872    if !quad.is_finite() || quad < 0.0 {
1873        return None;
1874    }
1875    Some(0.5 * quad)
1876}
1877
1878/// Is outer coordinate `k` pinned within [`CERTIFICATE_RAIL_MARGIN`] of either
1879/// of its own box bounds?
1880///
1881/// Factored out so the λ-block REPORT and the θ-wide certificate FACE below
1882/// cannot drift apart about what "railed" means for the same coordinate: they
1883/// differ only in which coordinates they scan, never in the test.
1884fn outer_coordinate_is_railed(theta: &Array1<f64>, k: usize, config: &OuterConfig) -> bool {
1885    let (lo, hi) = match config.bounds.as_ref() {
1886        Some((lo, hi)) if k < lo.len() && k < hi.len() => (lo[k], hi[k]),
1887        Some(_) => return false,
1888        None => (-config.rho_bound, config.rho_bound),
1889    };
1890    (theta[k] - lo).abs() <= CERTIFICATE_RAIL_MARGIN
1891        || (hi - theta[k]).abs() <= CERTIFICATE_RAIL_MARGIN
1892}
1893
1894/// Smoothing coordinates (leading ρ block) railed against the outer box.
1895///
1896/// This is the **report**. `OuterCriterionCertificate::lambdas_railed` indexes
1897/// *smoothing parameters*, and every consumer reads it that way — gam-report's
1898/// "λ railed" warning, the pyffi certificate surface, `is_clean`. It is
1899/// deliberately NOT the set the certificate reasons with; see
1900/// [`certificate_railed_coordinates`].
1901pub(crate) fn certificate_railed_lambdas(
1902    rho: &Array1<f64>,
1903    rho_dim: usize,
1904    config: &OuterConfig,
1905) -> Vec<usize> {
1906    (0..rho_dim.min(rho.len()))
1907        .filter(|&k| outer_coordinate_is_railed(rho, k, config))
1908        .collect()
1909}
1910
1911/// **Every** outer coordinate railed against its own box bound — the ρ block
1912/// *and* the trailing non-ρ blocks that a joint search carries in the same θ
1913/// vector under the same box: the spatial log-κ ψ coordinates and the
1914/// auxiliary coordinates.
1915///
1916/// This is the set every *decision* in [`certify_outer_optimality`] must use,
1917/// and using the λ-only report there instead was a real defect. The active-set
1918/// reasoning at a box-constrained optimum is a statement about coordinates, not
1919/// about what a coordinate happens to parameterize:
1920///
1921/// * the second-order condition only has to hold on the **feasible tangent
1922///   subspace**, so `certificate_hessian_is_psd_off_railed` deletes the railed
1923///   rows and columns. `layout.rho_dim()` is `n_params − psi_dim`, so a ψ
1924///   coordinate pinned on its data-derived κ window stayed *inside* that
1925///   sub-block and its saturated (and, near a window edge, routinely negative)
1926///   curvature row decided `hessian_psd = false` for the whole fit. That is
1927///   precisely the failure the block's own comment says must not happen — "a
1928///   rail-caused indefiniteness would disable the very certificate that exists
1929///   to certify a railed optimum (#2299)" — it was simply never extended past
1930///   the ρ block;
1931/// * the same omission hid the coordinate from the asymptote-rail mint
1932///   (#2348 Inc 1), from tail-snap, from `interior_curvature_floor_clearance`,
1933///   from the #2155 saddle escape, and from the #2392 wrong-rail pull-back and
1934///   active-set reduction. A κ search whose rail is a ψ coordinate could
1935///   therefore never be certified *by construction*, no matter how correct its
1936///   gradient was;
1937/// * and it made the refusal message actively misleading, because
1938///   `project_gradient_vector` DOES project every coordinate against its own
1939///   bound. So `|g|` could collapse to a small `|Pg|` while `railed=[]`
1940///   reported nothing responsible for the collapse — the exact disagreement
1941///   #979 measured from the other side and could not explain.
1942///
1943/// Relaxing nothing: a coordinate near a bound whose gradient still points
1944/// *into* the box keeps its feasible-descent component in `|Pg|`
1945/// ([`project_gradient_vector`] zeros only the outward half), so a genuinely
1946/// unconverged interior direction is still refused.
1947pub(crate) fn certificate_railed_coordinates(
1948    theta: &Array1<f64>,
1949    config: &OuterConfig,
1950) -> Vec<usize> {
1951    (0..theta.len())
1952        .filter(|&k| outer_coordinate_is_railed(theta, k, config))
1953        .collect()
1954}
1955
1956/// Which term of the stationarity bound's `max` chain actually set it.
1957///
1958/// `certify_outer_optimality` does not compute *a* bound; it takes the maximum of
1959/// up to five independently-derived quantities, and until #2458 nothing recorded
1960/// which one won. That is why a `bound=1.000e0` and a `bound=5.68e-6` came out of
1961/// the same message shape and telling them apart required reading this file --
1962/// the emitted number is a DERIVATIVE of a construction-site value, computed
1963/// later, so grepping the construction sites cannot match an observed bound.
1964///
1965/// The rungs are not interchangeable calibrations of one quantity. Only
1966/// [`Self::CurvatureResolvability`] is derived from what a gradient of that size
1967/// does to the criterion: `|Pg|·√(τ/Δpred)` simplifies to `√(2·h·τ)` -- the `|Pg|`
1968/// cancels -- i.e. the gradient magnitude below which the criterion cannot resolve
1969/// descent at all. The others are gradient-magnitude tests, blind to how curvature
1970/// maps a gradient to an objective change, which is exactly what this file's own
1971/// comment at the curvature block already says. Recording the rung is the
1972/// prerequisite for holding every route to the derived one: it makes "which
1973/// machinery did this route happen to have" an observable rather than an
1974/// inference.
1975#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1976pub(crate) enum StationarityBoundSource {
1977    /// `outer_gradient_tolerance(config).threshold(cost, |g|)` -- the raw band.
1978    SolverBand,
1979    /// `flat_valley_converged_grad_bound(cost)`, gated on a `CostStallFlatValley`
1980    /// exit. Saturates at its `1.0` cap (#2456).
1981    FlatValleyScore,
1982    /// The cost-stall guard's measured probe-noise floor `σ̂/Δ` (#2241). Diverges
1983    /// as the step collapses, which is the regime it fires in.
1984    ProbeNoiseFloor,
1985    /// `|Pg|·√(τ/Δpred)` = `√(2·h·τ)` (#2253/#2249/#2015/#2091) -- the only rung
1986    /// with a derivation from the criterion's own resolution.
1987    CurvatureResolvability,
1988    /// Twice the same-ρ spread between the run-recorded and certificate-time
1989    /// gradients (#2299): the measuring instrument's demonstrated noise.
1990    GradientReproducibility,
1991}
1992
1993impl StationarityBoundSource {
1994    pub(crate) fn label(self) -> &'static str {
1995        match self {
1996            Self::SolverBand => "solver-band",
1997            Self::FlatValleyScore => "flat-valley-score",
1998            Self::ProbeNoiseFloor => "probe-noise-floor",
1999            Self::CurvatureResolvability => "curvature-resolvability",
2000            Self::GradientReproducibility => "gradient-reproducibility",
2001        }
2002    }
2003
2004    /// Whether this rung is the derived resolvability standard rather than a
2005    /// gradient-magnitude substitute adopted where that standard was unavailable.
2006    pub(crate) fn is_derived_standard(self) -> bool {
2007        matches!(self, Self::CurvatureResolvability)
2008    }
2009
2010    /// The neutral projection carried on the refusal, so a red states its own
2011    /// rung instead of leaving it to be inferred from the numbers.
2012    pub(crate) fn provenance(self) -> StationarityRung {
2013        StationarityRung {
2014            label: self.label(),
2015            derived_standard: self.is_derived_standard(),
2016        }
2017    }
2018}
2019
2020/// A stationarity bound bundled with the rung that produced it (#2458).
2021///
2022/// The bound and its provenance travelled separately before this: the bound was
2023/// a bare `f64` argument and the rung stayed a local in the certificate block,
2024/// so every refusal outside that block reported a number with no way to say
2025/// which standard it came from. Bundling them makes it impossible to pass one
2026/// without deciding the other.
2027#[derive(Debug, Clone, Copy)]
2028pub(crate) struct StationarityBound {
2029    value: f64,
2030    source: Option<StationarityBoundSource>,
2031}
2032
2033impl StationarityBound {
2034    /// A bound the rung ladder produced, carrying the rung it came from.
2035    pub(crate) fn from_ladder(value: f64, source: StationarityBoundSource) -> Self {
2036        Self {
2037            value,
2038            source: Some(source),
2039        }
2040    }
2041
2042    /// A bound from a route that does not select a ladder rung — a raw config
2043    /// tolerance, or a refusal reached before the ladder is evaluated.
2044    ///
2045    /// This is deliberately not defaulted to [`StationarityBoundSource::SolverBand`]:
2046    /// labelling an unclassified bound with a rung it did not come from would
2047    /// make the ladder look more uniformly applied than it is, which is the
2048    /// exact inference #2458 exists to stop. `rung=unrecorded` in a refusal is a
2049    /// finding — it names a route whose stationarity standard is still unstated.
2050    pub(crate) fn unrecorded(value: f64) -> Self {
2051        Self {
2052            value,
2053            source: None,
2054        }
2055    }
2056
2057    pub(crate) fn value(self) -> f64 {
2058        self.value
2059    }
2060
2061    pub(crate) fn rung(self) -> Option<StationarityRung> {
2062        self.source.map(StationarityBoundSource::provenance)
2063    }
2064}
2065
2066fn outer_nonconvergence_error(
2067    context: &str,
2068    reason: &str,
2069    result: &OuterResult,
2070    projected_grad_norm: Option<f64>,
2071    stationarity_bound: StationarityBound,
2072) -> EstimationError {
2073    // Solver provenance, appended to every outer non-convergence.
2074    //
2075    // The certificate answers "is this point stationary" — and when it is not,
2076    // the next question is always "then why did the search STOP here", which
2077    // the message did not answer. A binomial/logit P-spline (#1575/#1561)
2078    // refuses with `|Pg|=7.5e-1` against a `1.0e-2` bound, PSD Hessian, nothing
2079    // railed, all coordinates 18 e-folds inside the box, "after 7 outer
2080    // iteration(s)" — and the 7 is the whole mystery. `converged` distinguishes
2081    // a solver that CLAIMED convergence (a tolerance desync, and the only case
2082    // the #2273/#2374 resume will retry) from one that ran out of budget;
2083    // `operator_stop_reason` separates a trust-region reject floor from a
2084    // flat-valley cost stall from an iteration budget. All three are already on
2085    // the result and cost nothing to print.
2086    let reason = format!(
2087        "{reason}; solver provenance: claimed_converged={}{}{}",
2088        result.converged,
2089        result
2090            .operator_stop_reason
2091            .map(|stop| format!(", stop_reason={stop:?}"))
2092            .unwrap_or_default(),
2093        result
2094            .converged_via
2095            .map(|via| format!(", converged_via={via:?}"))
2096            .unwrap_or_default(),
2097    );
2098    EstimationError::RemlDidNotConverge {
2099        context: context.to_string(),
2100        reason,
2101        iterations: result.iterations,
2102        final_value: result.final_value,
2103        projected_grad_norm,
2104        stationarity_bound: stationarity_bound.value(),
2105        stationarity_bound_rung: stationarity_bound.rung(),
2106        rho_checkpoint: result.rho.to_vec(),
2107    }
2108}
2109
2110/// Roundoff envelope for two independently assembled values of the same outer
2111/// criterion at the same point.
2112///
2113/// Value-only and derivative-bearing evaluation lanes may use different
2114/// kernels and reduction trees, so bitwise identity is not a valid contract.
2115/// Their relative disagreement must nevertheless stay below the square root of
2116/// machine epsilon: beyond that scale the derivative sample is not evidence
2117/// about the scalar objective the optimizer's value lane ranks.
2118pub fn outer_value_agreement_bound(value_only: f64, derivative_sample: f64) -> f64 {
2119    f64::EPSILON.sqrt() * value_only.abs().max(derivative_sample.abs()).max(1.0)
2120}
2121
2122fn audit_outer_value_agreement(
2123    context: &str,
2124    value_only: f64,
2125    derivative_sample: f64,
2126    result: &mut OuterResult,
2127    projected_grad_norm: Option<f64>,
2128    stationarity_bound: StationarityBound,
2129) -> Result<(), EstimationError> {
2130    let bound = outer_value_agreement_bound(value_only, derivative_sample);
2131    let disagreement = (value_only - derivative_sample).abs();
2132    if disagreement <= bound {
2133        return Ok(());
2134    }
2135
2136    // The value-only lane is the scalar criterion authority. Preserve it on
2137    // the resumable checkpoint rather than the derivative lane's inconsistent
2138    // scalar; no certificate may be attached to this mixed evidence.
2139    result.final_value = value_only;
2140    result.converged = false;
2141    Err(outer_nonconvergence_error(
2142        context,
2143        &format!(
2144            "cost-only value disagrees with analytic-sample value at the same outer point: \
2145             value-only={value_only:.16e}, analytic-sample={derivative_sample:.16e}, \
2146             disagreement={disagreement:.3e}, roundoff bound={bound:.3e}"
2147        ),
2148        result,
2149        projected_grad_norm,
2150        stationarity_bound,
2151    ))
2152}
2153
2154fn certify_fixed_point_optimality(
2155    obj: &mut dyn OuterObjective,
2156    config: &OuterConfig,
2157    context: &str,
2158    result: &mut OuterResult,
2159    fidelity: CertificationFidelity,
2160) -> Result<OuterCriterionCertificate, EstimationError> {
2161    let layout = obj.capability().theta_layout();
2162    // A fixed-point residual is only a certificate for the scalar objective
2163    // when both lanes price that same objective at the same rho. Sample the
2164    // authoritative value lane first; the analytic fixed-point evaluator then
2165    // remains the installed terminal-state owner.
2166    //
2167    // MINT ONLY (#2359), for the same reason as on the analytic path: whether
2168    // the two lanes agree is terminal proof work, not a ranking signal, and on
2169    // this route it is the ONLY thing that distinguishes screening from mint —
2170    // there is no order-four ladder to reserve here.
2171    let value_only = match fidelity {
2172        CertificationFidelity::Screening => None,
2173        CertificationFidelity::Mint => {
2174            let sample = obj
2175                .eval_with_order(&result.rho, OuterEvalOrder::Value)
2176                .map_err(|err| {
2177                    outer_nonconvergence_error(
2178                        context,
2179                        &format!("terminal value-only certificate evaluation failed: {err}"),
2180                        result,
2181                        None,
2182                        StationarityBound::unrecorded(config.tolerance),
2183                    )
2184                })?
2185                .cost;
2186            if !sample.is_finite() {
2187                return Err(outer_nonconvergence_error(
2188                    context,
2189                    "terminal value-only certificate evaluation returned a non-finite objective value",
2190                    result,
2191                    None,
2192                    StationarityBound::unrecorded(config.tolerance),
2193                ));
2194            }
2195            Some(sample)
2196        }
2197    };
2198    let evaluation = obj
2199        .eval_fixed_point_certificate(&result.rho)
2200        .map_err(|err| {
2201            outer_nonconvergence_error(
2202                context,
2203                &format!("analytic fixed-point certificate evaluation failed: {err}"),
2204                result,
2205                None,
2206                StationarityBound::unrecorded(config.tolerance),
2207            )
2208        })?;
2209    if !inner_solve_converged(config.outer_inner_cap.as_ref()) {
2210        return Err(outer_nonconvergence_error(
2211            context,
2212            "terminal fixed-point evidence was evaluated at a non-converged inner state",
2213            result,
2214            None,
2215            StationarityBound::unrecorded(config.tolerance),
2216        ));
2217    }
2218    if evaluation.coordinates.len() != layout.n_params {
2219        return Err(outer_nonconvergence_error(
2220            context,
2221            &format!(
2222                "fixed-point certificate returned {} coordinates for an outer problem of dimension {}",
2223                evaluation.coordinates.len(),
2224                layout.n_params
2225            ),
2226            result,
2227            None,
2228            StationarityBound::unrecorded(config.tolerance),
2229        ));
2230    }
2231    if !evaluation.cost.is_finite() {
2232        return Err(outer_nonconvergence_error(
2233            context,
2234            "fixed-point certificate returned a non-finite objective value",
2235            result,
2236            None,
2237            StationarityBound::unrecorded(config.tolerance),
2238        ));
2239    }
2240    if let Some(value_only) = value_only {
2241        audit_outer_value_agreement(
2242            context,
2243            value_only,
2244            evaluation.cost,
2245            result,
2246            None,
2247            StationarityBound::unrecorded(config.tolerance),
2248        )?;
2249    }
2250
2251    let mut normalized_updates = Vec::with_capacity(layout.n_params);
2252    let mut uncovered = Vec::new();
2253    for (index, coordinate) in evaluation.coordinates.iter().enumerate() {
2254        match coordinate {
2255            FixedPointCoordinateCertificate::Covered { update, scale }
2256                if update.is_finite() && scale.is_finite() && *scale > 0.0 =>
2257            {
2258                normalized_updates.push(*update / *scale);
2259            }
2260            FixedPointCoordinateCertificate::Covered { update, scale } => {
2261                uncovered.push(format!(
2262                    "coordinate {index} has invalid covered residual update={update} scale={scale}"
2263                ));
2264                normalized_updates.push(f64::NAN);
2265            }
2266            FixedPointCoordinateCertificate::Uncovered { reason } => {
2267                uncovered.push(format!("coordinate {index}: {reason}"));
2268                normalized_updates.push(f64::NAN);
2269            }
2270        }
2271    }
2272    if !uncovered.is_empty() {
2273        return Err(outer_nonconvergence_error(
2274            context,
2275            &format!(
2276                "fixed-point certificate lacks root-equivalent analytic coverage: {}",
2277                uncovered.join("; ")
2278            ),
2279            result,
2280            None,
2281            StationarityBound::unrecorded(config.tolerance),
2282        ));
2283    }
2284
2285    let (lower, upper) = outer_bounds_template(config, layout.n_params);
2286    let mut raw_inf = 0.0_f64;
2287    let mut projected_inf = 0.0_f64;
2288    for index in 0..layout.n_params {
2289        let update = normalized_updates[index];
2290        raw_inf = raw_inf.max(update.abs());
2291        // `update` is a signed descent/update direction, the negative of the
2292        // gradient convention used by `projected_gradient_norm`: at a lower
2293        // bound a negative update points out of the box, and at an upper bound
2294        // a positive update does. Only those infeasible multiplier components
2295        // are removed.
2296        let projected = if result.rho[index] <= lower[index] {
2297            update.max(0.0)
2298        } else {
2299            update
2300        };
2301        let projected = if result.rho[index] >= upper[index] {
2302            projected.min(0.0)
2303        } else {
2304            projected
2305        };
2306        projected_inf = projected_inf.max(projected.abs());
2307    }
2308
2309    result.final_value = evaluation.cost;
2310    result.final_grad_norm = None;
2311    result.final_gradient = None;
2312    result.final_hessian = None;
2313    result.converged = false;
2314
2315    let certificate = OuterCriterionCertificate {
2316        stationarity: OuterStationarityCertificate::FixedPoint {
2317            residual_inf_norm: raw_inf,
2318            projected_residual_inf_norm: projected_inf,
2319            bound: config.tolerance,
2320            covered_coordinates: layout.n_params,
2321        },
2322        hessian_psd: None,
2323        lambdas_railed: certificate_railed_lambdas(&result.rho, layout.rho_dim(), config),
2324        curvature_floor: None,
2325    };
2326    result.criterion_certificate = Some(certificate.clone());
2327    if !certificate.certifies() {
2328        return Err(outer_nonconvergence_error(
2329            context,
2330            &certificate.summary(),
2331            result,
2332            Some(projected_inf),
2333            StationarityBound::unrecorded(config.tolerance),
2334        ));
2335    }
2336
2337    result.converged = true;
2338    result.converged_via = match result.converged_via {
2339        Some(via @ OuterConvergedVia::RecurrentIncumbent { .. }) => Some(via),
2340        _ => Some(OuterConvergedVia::FixedPointStationary {
2341            projected_residual_inf_norm: projected_inf,
2342            certificate_bound: config.tolerance,
2343        }),
2344    };
2345    log::info!("[CERTIFICATE] {context}: {}", certificate.summary());
2346    Ok(certificate)
2347}
2348
2349/// Build the mandatory analytic optimality certificate at the returned point.
2350///
2351/// The objective is evaluated at the selected point through both its
2352/// authoritative value-only lane and its analytic derivative lane. The two
2353/// values must agree within their roundoff envelope before the derivative
2354/// sample can certify the scalar objective. Missing, malformed, non-finite, or
2355/// split-objective evidence is non-convergence: an optimizer status bit cannot
2356/// substitute for a stationarity certificate. Exact analytic curvature is
2357/// checked when the objective declares it and can materialize it; BFGS/EFS
2358/// solver geometry is never mistaken for objective curvature.
2359/// Which derivative fidelity a certification pass is allowed to spend.
2360///
2361/// #2359: the generic REML/LAML Hessian consumes the row-family derivative
2362/// ladder through order FOUR while its analytic gradient stops at order three,
2363/// so order four is a mint-time cost, not a per-candidate one. A multi-start
2364/// screens every seed it starts — that screening is a first-order gate
2365/// (stationarity, KKT projection, rail facts), and `curvature_admissible()`
2366/// reads `hessian_psd != Some(false)`, so a `None` curvature verdict certifies
2367/// on stationarity alone. The one order-four evaluation belongs to the winner,
2368/// once, and its verdict is the one that mints.
2369#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2370pub(crate) enum CertificationFidelity {
2371    /// Per-candidate multi-start gate. Never spends order four.
2372    Screening,
2373    /// The single terminal mint audit. Spends order four when the objective
2374    /// declares an analytic Hessian.
2375    Mint,
2376}
2377
2378pub(crate) fn certify_outer_optimality(
2379    obj: &mut dyn OuterObjective,
2380    config: &OuterConfig,
2381    context: &str,
2382    result: &mut OuterResult,
2383) -> Result<OuterCriterionCertificate, EstimationError> {
2384    certify_outer_optimality_with_fidelity(obj, config, context, result, CertificationFidelity::Mint)
2385}
2386
2387pub(crate) fn certify_outer_optimality_with_fidelity(
2388    obj: &mut dyn OuterObjective,
2389    config: &OuterConfig,
2390    context: &str,
2391    result: &mut OuterResult,
2392    fidelity: CertificationFidelity,
2393) -> Result<OuterCriterionCertificate, EstimationError> {
2394    let terminal_cap_guard = config
2395        .outer_inner_cap
2396        .as_ref()
2397        .map(TerminalInnerCapGuard::lift);
2398    if terminal_cap_guard.is_some() || obj.owns_terminal_coefficient_mode() {
2399        // `reset` is deliberately conditional on the presence of the cap
2400        // contract.  Those are the REML/mixture objectives whose search cache
2401        // can contain a coarse inner state; uncapped objectives retain their
2402        // ordinary stateful certification semantics.
2403        //
2404        // The `owns_terminal_coefficient_mode()` disjunct (#2334) closes the
2405        // gap for cap-less objectives that install an owned coefficient mode:
2406        // the certifying re-eval below must start from the same clean baseline
2407        // that `finalize_outer_result` used, so the mode's objective bitwise
2408        // matches the certified `final_value` even when the inner solve is
2409        // bimodal at `rho_star`.
2410        obj.reset();
2411    }
2412    let outcome =
2413        certify_outer_optimality_at_terminal_fidelity(obj, config, context, result, true, fidelity);
2414    drop(terminal_cap_guard);
2415    outcome
2416}
2417
2418fn certify_outer_optimality_at_terminal_fidelity(
2419    obj: &mut dyn OuterObjective,
2420    config: &OuterConfig,
2421    context: &str,
2422    result: &mut OuterResult,
2423    allow_tail_snap: bool,
2424    fidelity: CertificationFidelity,
2425) -> Result<OuterCriterionCertificate, EstimationError> {
2426    let capability = obj.capability();
2427    let layout = capability.theta_layout();
2428    layout
2429        .validate_point_len(&result.rho, "outer certificate point")
2430        .map_err(|err| {
2431            EstimationError::RemlOptimizationFailed(format!(
2432                "{context}: invalid outer certificate point: {err}"
2433            ))
2434        })?;
2435    if result.rho.iter().any(|value| !value.is_finite()) {
2436        return Err(outer_nonconvergence_error(
2437            context,
2438            "the selected checkpoint contains non-finite coordinates",
2439            result,
2440            None,
2441            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2442        ));
2443    }
2444    if layout.n_params == 0 {
2445        let value = obj.eval_cost(&result.rho).map_err(|err| {
2446            outer_nonconvergence_error(
2447                context,
2448                &format!("zero-dimensional final objective evaluation failed: {err}"),
2449                result,
2450                Some(0.0),
2451                StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2452            )
2453        })?;
2454        if !value.is_finite() {
2455            return Err(outer_nonconvergence_error(
2456                context,
2457                "the zero-dimensional final objective is non-finite",
2458                result,
2459                Some(0.0),
2460                StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2461            ));
2462        }
2463        let certificate = OuterCriterionCertificate {
2464            stationarity: OuterStationarityCertificate::AnalyticGradient {
2465                grad_norm: 0.0,
2466                projected_grad_norm: 0.0,
2467                bound: outer_gradient_tolerance(config).abs,
2468            },
2469            hessian_psd: None,
2470            lambdas_railed: Vec::new(),
2471            curvature_floor: None,
2472        };
2473        result.final_value = value;
2474        result.final_grad_norm = Some(0.0);
2475        result.final_gradient = Some(Array1::zeros(0));
2476        result.final_hessian = None;
2477        result.converged = true;
2478        result.converged_via = Some(OuterConvergedVia::GradientStationary);
2479        result.criterion_certificate = Some(certificate.clone());
2480        return Ok(certificate);
2481    }
2482    if matches!(result.plan_used.solver, Solver::Efs | Solver::HybridEfs)
2483        && capability.gradient != Derivative::Analytic
2484    {
2485        return certify_fixed_point_optimality(obj, config, context, result, fidelity);
2486    }
2487    if capability.gradient != Derivative::Analytic {
2488        return Err(outer_nonconvergence_error(
2489            context,
2490            "the objective exposes no analytic gradient for final certification",
2491            result,
2492            None,
2493            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2494        ));
2495    }
2496
2497    // Sample the scalar authority first and leave the derivative-bearing
2498    // evaluator as the terminal state owner. This is one same-rho audit, not a
2499    // finite-difference derivative: it catches a split value/gradient
2500    // implementation without violating the production no-FD contract.
2501    //
2502    // BOTH fidelities pay this, deliberately. It is tempting to reserve it for
2503    // the mint the way order four is reserved (#2359), but the two are not
2504    // alike: order four is evidence the filter does not consume, while the
2505    // value-agreement audit is a REFUSAL GATE on the very number the
2506    // multistart ranks by. `retain_best_outer_checkpoint` orders candidates on
2507    // `final_value`; admitting a candidate whose value lane disagrees with its
2508    // derivative lane lets a desynced candidate win the ranking on a number
2509    // nothing has validated, and mint then refuses the whole fit instead of a
2510    // runner-up carrying it. Pinned by
2511    // `analytic_hessian_candidate_screening_requires_only_first_order_evidence_2414`,
2512    // which asserts screening's orders are exactly [Value, ValueAndGradient].
2513    //
2514    // The EFS/fixed-point route is different and IS gated on fidelity — see
2515    // `certify_fixed_point_optimality`. It returns above this block, and there
2516    // screening and mint are otherwise identical work (no order-four ladder to
2517    // reserve), so running the audit twice buys nothing at all.
2518    let value_only = obj
2519        .eval_with_order(&result.rho, OuterEvalOrder::Value)
2520        .map_err(|err| {
2521            outer_nonconvergence_error(
2522                context,
2523                &format!("terminal value-only certificate evaluation failed: {err}"),
2524                result,
2525                result.final_grad_norm,
2526                StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2527            )
2528        })?
2529        .cost;
2530    if !value_only.is_finite() {
2531        return Err(outer_nonconvergence_error(
2532            context,
2533            "terminal value-only certificate evaluation returned a non-finite objective value",
2534            result,
2535            result.final_grad_norm,
2536            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2537        ));
2538    }
2539
2540    // Order four is reserved for the mint audit (#2359). A screening pass takes
2541    // the same first-order evidence the no-analytic-Hessian path already
2542    // certifies on, so the multi-start keeps its filter without building the
2543    // order-four family tower once per seed.
2544    // One boolean drives BOTH the request below and the requirement at the
2545    // analytic-Hessian block: a pass that does not ask for curvature must not
2546    // then refuse the candidate for not supplying it. Splitting them made every
2547    // screened candidate of an analytic-Hessian objective fail certification
2548    // with "declared analytic curvature but returned none at the final point" —
2549    // a statement about this pass's own eval order, not about the candidate.
2550    let wants_analytic_hessian =
2551        capability.hessian.is_analytic() && matches!(fidelity, CertificationFidelity::Mint);
2552    let order = if wants_analytic_hessian {
2553        OuterEvalOrder::ValueGradientHessian
2554    } else {
2555        OuterEvalOrder::ValueAndGradient
2556    };
2557    let evaluation = obj.eval_with_order(&result.rho, order).map_err(|err| {
2558        outer_nonconvergence_error(
2559            context,
2560            &format!("analytic final-point evaluation failed: {err}"),
2561            result,
2562            result.final_grad_norm,
2563            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2564        )
2565    })?;
2566    if !inner_solve_converged(config.outer_inner_cap.as_ref()) {
2567        return Err(outer_nonconvergence_error(
2568            context,
2569            "terminal analytic evidence was evaluated at a non-converged inner state",
2570            result,
2571            None,
2572            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2573        ));
2574    }
2575    layout
2576        .validate_gradient_len(&evaluation.gradient, "outer certificate gradient")
2577        .map_err(|err| {
2578            outer_nonconvergence_error(
2579                context,
2580                &format!("malformed analytic final gradient: {err}"),
2581                result,
2582                None,
2583                StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2584            )
2585        })?;
2586    if !evaluation.cost.is_finite() || evaluation.gradient.iter().any(|value| !value.is_finite()) {
2587        return Err(outer_nonconvergence_error(
2588            context,
2589            "the analytic final-point value or gradient is non-finite",
2590            result,
2591            None,
2592            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
2593        ));
2594    }
2595
2596    let bounds = outer_bounds_template(config, layout.n_params);
2597    // A penalty creeping toward the ±rho_bound infinite-smoothing ceiling never reaches
2598    // it EXACTLY — each outer step only shrinks the gap, so it lands strictly inside the
2599    // box (the #2299 checkpoint sits at ρ=29.9938, not 30). `certificate_railed_lambdas`
2600    // then flags it railed via `CERTIFICATE_RAIL_MARGIN`, but the exact `x >= upper` /
2601    // `x <= lower` box-KKT projection treats it as INTERIOR and its outward pull inflates
2602    // |Pg| above the (tiny) stationarity bound — the fit refuses a genuine railed optimum.
2603    // Project the stationarity residual with the box endpoints relaxed inward by that SAME
2604    // rail margin, so "railed" means ONE thing to the detector AND the projector: a
2605    // within-tolerance coordinate whose gradient points OUT of the box has its KKT-multiplier
2606    // component removed rather than counted as a stationarity residual (#2299). The
2607    // projection only zeros the OUTWARD half (`.max(0.0)`/`.min(0.0)`), so a coordinate near
2608    // the bound that still has feasible-descent gradient keeps it and is never falsely
2609    // certified.
2610    let rail_projection_bounds = rail_relaxed_bounds(&bounds);
2611    let grad_norm = evaluation.gradient.dot(&evaluation.gradient).sqrt();
2612    // The terminal inner coefficients β(ρ̂), published by the REML bridge on
2613    // every eval (`inner_beta_hint`). Used to scale the estimand tolerance for
2614    // the asymptote-rail certificate (#2348 Inc 1).
2615    let terminal_beta = evaluation.inner_beta_hint.clone();
2616    // KKT-projected gradient VECTOR (not just its norm): the norm feeds the
2617    // stationarity certificate below, and the vector feeds the curvature-scaled
2618    // flat-valley Newton decrement (#2253/#2249/#2015) once the analytic Hessian
2619    // is in hand.
2620    let projected_gradient = project_gradient_vector(
2621        &result.rho,
2622        &evaluation.gradient,
2623        Some(&rail_projection_bounds),
2624    );
2625    let projected_grad_norm = projected_gradient.iter().map(|v| v * v).sum::<f64>().sqrt();
2626    let solver_bound = outer_gradient_tolerance(config).threshold(evaluation.cost, grad_norm);
2627    let mut bound_source = StationarityBoundSource::SolverBand;
2628    let mut stationarity_bound = if matches!(
2629        result.operator_stop_reason,
2630        Some(OperatorTrustRegionStopReason::CostStallFlatValley)
2631    ) {
2632        let flat_valley = flat_valley_converged_grad_bound(evaluation.cost);
2633        if flat_valley > solver_bound {
2634            bound_source = StationarityBoundSource::FlatValleyScore;
2635            flat_valley
2636        } else {
2637            solver_bound
2638        }
2639    } else {
2640        solver_bound
2641    };
2642    // #2241 — a cost-stall exit carries the guard's measured probe-noise-floor
2643    // gradient bound σ̂/Δ. The certificate must judge the re-measured final
2644    // gradient against the same flat band the guard certified, or the guard's
2645    // noise-scale convergence would be granted in the loop and revoked here.
2646    if let Some(noise_bound) = result.flat_noise_grad_bound
2647        && noise_bound.is_finite()
2648    {
2649        if noise_bound > stationarity_bound {
2650            bound_source = StationarityBoundSource::ProbeNoiseFloor;
2651            stationarity_bound = noise_bound;
2652        }
2653    }
2654    audit_outer_value_agreement(
2655        context,
2656        value_only,
2657        evaluation.cost,
2658        result,
2659        Some(projected_grad_norm),
2660        StationarityBound::from_ladder(stationarity_bound, bound_source),
2661    )?;
2662
2663    // The optimizer's own recorded best-iterate evidence, captured before the
2664    // fresh certificate-time measurement overwrites it below. Together with
2665    // `evaluation` this is a SECOND independent measurement of the objective
2666    // at the same ρ — the raw material for the gradient-reproducibility floor
2667    // further down, at zero additional objective evaluations.
2668    let run_recorded_gradient = result.final_gradient.take();
2669    let run_recorded_value = result.final_value;
2670
2671    // Install measured first-order evidence before any fallible curvature
2672    // processing. If curvature is malformed, the retained resume checkpoint
2673    // still carries the exact value/gradient that caused certification to stop.
2674    result.final_value = evaluation.cost;
2675    result.final_grad_norm = Some(projected_grad_norm);
2676    result.final_gradient = Some(evaluation.gradient);
2677    result.converged = false;
2678
2679    let analytic_hessian = if wants_analytic_hessian {
2680        match evaluation.hessian.materialize_dense() {
2681            Ok(Some(hessian)) => {
2682                layout
2683                    .validate_hessian_shape(&hessian, "outer certificate Hessian")
2684                    .map_err(|err| {
2685                        outer_nonconvergence_error(
2686                            context,
2687                            &format!("malformed analytic final Hessian: {err}"),
2688                            result,
2689                            Some(projected_grad_norm),
2690                            StationarityBound::from_ladder(stationarity_bound, bound_source),
2691                        )
2692                    })?;
2693                if hessian.iter().any(|value| !value.is_finite()) {
2694                    return Err(outer_nonconvergence_error(
2695                        context,
2696                        "the analytic final Hessian contains non-finite entries",
2697                        result,
2698                        Some(projected_grad_norm),
2699                        StationarityBound::from_ladder(stationarity_bound, bound_source),
2700                    ));
2701                }
2702                Some(hessian)
2703            }
2704            Ok(None) => {
2705                return Err(outer_nonconvergence_error(
2706                    context,
2707                    "the objective declared analytic curvature but returned none at the final point",
2708                    result,
2709                    Some(projected_grad_norm),
2710                    StationarityBound::from_ladder(stationarity_bound, bound_source),
2711                ));
2712            }
2713            Err(err) => {
2714                return Err(outer_nonconvergence_error(
2715                    context,
2716                    &format!("analytic final Hessian could not be certified: {err}"),
2717                    result,
2718                    Some(projected_grad_norm),
2719                    StationarityBound::from_ladder(stationarity_bound, bound_source),
2720                ));
2721            }
2722        }
2723    } else {
2724        None
2725    };
2726
2727    // Curvature-scaled stationarity (#2253/#2249/#2015/#2091). The re-measured
2728    // projected gradient can sit modestly ABOVE the score-relative / probe-noise
2729    // bands even though NO step reduces the objective by more than the outer
2730    // tolerance — a weakly-identified small-n fit reaches this by a flat-valley
2731    // cost-stall, and an *already-stationary* fit reaches it at iteration 0 when
2732    // the plan search exhausts without stepping (a 2-parameter Gaussian-linear
2733    // REML lands λ→0 at a genuine interior optimum whose |Pg|≈1e-7 sits just above
2734    // an absolute score·1e-9 gradient floor tighter than the REML gradient's
2735    // matrix-factorization round-off). Whether that residual is genuine descent is
2736    // a second-order question the flat bands above cannot answer: they are
2737    // gradient-magnitude tests, blind to how the local curvature maps a gradient
2738    // to an objective change. The Newton decrement `½·gᵀH⁻¹g` (see
2739    // `newton_predicted_decrease`) IS that map — the exact predicted improvement of
2740    // a safeguarded second-order step. When it is below the outer objective
2741    // tolerance, the point is stationary at the resolution the criterion can be
2742    // optimized ("no further descent possible"), independent of HOW the solver
2743    // stopped.
2744    //
2745    // Applied whenever a PSD-along-gradient analytic Hessian is in hand (NOT gated
2746    // to a specific exit reason: the decrement test is the certificate, the exit
2747    // reason is not). It can NEVER wrongly certify a fit with real available
2748    // descent: it only widens when `curvature_grad_bound > stationarity_bound`, so
2749    // a well-identified fit that already clears `solver_bound` is untouched; a
2750    // gradient aligned with a near-flat Hessian direction inflates the decrement
2751    // and is rejected; a globally indefinite Hessian is rejected independently by
2752    // the `hessian_psd` gate inside `certifies()`. The derived widening is a
2753    // genuine, direction-aware curvature-scaled GRADIENT bound — the largest ‖Pg‖
2754    // that, in this gradient's direction under this curvature, still predicts a
2755    // decrease of exactly `objective_tol` — not a constant bump: because the
2756    // decrement scales quadratically with ‖g‖ at fixed direction, that bound is
2757    // `‖Pg‖·√(objective_tol/Δpred)`, which clears the actual ‖Pg‖ iff
2758    // `Δpred ≤ objective_tol`.
2759    if let Some(hessian) = analytic_hessian.as_ref()
2760        && let Some(predicted_decrease) = newton_predicted_decrease(hessian, &projected_gradient)
2761        && predicted_decrease.is_finite()
2762        && predicted_decrease > 0.0
2763    {
2764        // The SAME relative cost floor the cost-stall guard used to declare the
2765        // criterion stalled (run_plan.rs), so certification asserts nothing
2766        // tighter than the loop already proved about this surface.
2767        let objective_tol = outer_rel_cost_floor(config) * (1.0 + evaluation.cost.abs());
2768        let curvature_grad_bound =
2769            projected_grad_norm * (objective_tol / predicted_decrease).sqrt();
2770        if curvature_grad_bound.is_finite() && curvature_grad_bound > stationarity_bound {
2771            log::info!(
2772                "[CERTIFICATE] {context}: curvature-scaled flat-valley bound {curvature_grad_bound:.3e} \
2773                 (|Pg|={projected_grad_norm:.3e}, Newton ½gᵀH⁻¹g={predicted_decrease:.3e} ≤ tol {objective_tol:.3e}) \
2774                 widened from gradient-band {stationarity_bound:.3e}"
2775            );
2776            stationarity_bound = curvature_grad_bound;
2777            bound_source = StationarityBoundSource::CurvatureResolvability;
2778        }
2779    }
2780
2781    // Gradient-reproducibility floor (#2299 fully-saturated smooth). A
2782    // stationarity certificate cannot resolve below the reproducibility of its
2783    // own measuring instrument: at a rail-adjacent optimum (λ ~ 1e12, the term
2784    // collapsed onto its penalty null space, edf saturated) the analytic
2785    // gradient is a difference of enormous canceling log-det terms whose
2786    // evaluation drifts run to run, so |Pg| measures round-off, not slope —
2787    // observed as the SAME ρ returning |g| ∈ {2.5e-3 … 4.5e-2} across
2788    // consecutive evaluations while the objective stays flat to 1e-7.
2789    //
2790    // The certifier already holds TWO independent measurements at this ρ: the
2791    // optimizer's recorded best-iterate gradient (`run_recorded_gradient`) and
2792    // the fresh certificate-time `evaluation` — so the instrument's
2793    // demonstrated noise costs ZERO additional objective evaluations (scripted
2794    // test objectives keep their exact call counts). A REAL residual gradient
2795    // reproduces (spread ≈ 0, no widening — genuine descent can never be
2796    // masked, and a deterministic objective yields bit-identical pairs), while
2797    // cancellation noise decorrelates (spread ~ |Pg|). The widening is gated
2798    // on the two measurements' objective VALUES agreeing to the same relative
2799    // floor the cost-stall guard uses, and the PSD gate below is unchanged.
2800    if projected_grad_norm > stationarity_bound
2801        && let Some(prior_gradient) = run_recorded_gradient.as_ref()
2802        && layout
2803            .validate_gradient_len(prior_gradient, "outer run-recorded gradient")
2804            .is_ok()
2805        && prior_gradient.iter().all(|value| value.is_finite())
2806        && run_recorded_value.is_finite()
2807    {
2808        const GRADIENT_REPRODUCIBILITY_WIDENING: f64 = 2.0;
2809        let objective_tol = config
2810            .rel_cost_tolerance
2811            .unwrap_or(config.tolerance * 1.0e-2)
2812            .max(COST_STALL_REL_TOL_FLOOR)
2813            * (1.0 + evaluation.cost.abs());
2814        let cost_drift = (run_recorded_value - evaluation.cost).abs();
2815        let prior_projected =
2816            project_gradient_vector(&result.rho, prior_gradient, Some(&rail_projection_bounds));
2817        let spread = (&prior_projected - &projected_gradient)
2818            .iter()
2819            .map(|v| v * v)
2820            .sum::<f64>()
2821            .sqrt();
2822        let repro_bound = GRADIENT_REPRODUCIBILITY_WIDENING * spread;
2823        if cost_drift <= objective_tol
2824            && repro_bound.is_finite()
2825            && repro_bound > stationarity_bound
2826            && projected_grad_norm <= repro_bound
2827        {
2828            log::info!(
2829                "[CERTIFICATE] {context}: gradient-reproducibility floor widened the \
2830                 stationarity bound to {repro_bound:.3e} (|Pg|={projected_grad_norm:.3e}, \
2831                 same-ρ spread between the run-recorded and certificate-time gradients \
2832                 {spread:.3e}, cost drift {cost_drift:.3e} ≤ tol {objective_tol:.3e})"
2833            );
2834            stationarity_bound = repro_bound;
2835            bound_source = StationarityBoundSource::GradientReproducibility;
2836        }
2837    }
2838
2839    // #2458 -- the bound's own provenance, emitted UNCONDITIONALLY rather than only
2840    // when a rung happens to widen. A certificate that does not carry which of its
2841    // five terms decided it can only be re-derived from source, never audited; the
2842    // same complaint this file's refusal messages make about the fits they refuse.
2843    // `derived_standard=false` is the actionable bit: it says this verdict rests on
2844    // a gradient-magnitude substitute because the resolvability form was
2845    // unavailable on this route, not because the problem called for it.
2846    log::info!(
2847        "[CERTIFICATE-BOUND] {context}: bound {stationarity_bound:.6e} set by {} \
2848         (derived_standard={}, |Pg|={projected_grad_norm:.6e}, |g|={grad_norm:.6e}, \
2849         solver_band={solver_bound:.6e}, cost={:.6e})",
2850        bound_source.label(),
2851        bound_source.is_derived_standard(),
2852        evaluation.cost,
2853    );
2854
2855    // Large-step flatness certificate (#2299 fully-saturated smooth). After the
2856    // reproducibility floor a coordinate that has collapsed EXACTLY onto its
2857    // penalty null space (λ ~ 1e12, edf saturated) can still carry a projected
2858    // gradient component that is DETERMINISTIC cancellation bias from the
2859    // 1e12-conditioned logdet derivative (≈ ε·κ·scale). Being deterministic it
2860    // reproduces run to run, so the spread-keyed reproducibility floor above
2861    // cannot see it; and the Newton decrement anti-rescues, because the near-null
2862    // Hessian direction inflates gᵀH⁻¹g by design. The decisive question is
2863    // second-order-independent: does the criterion actually MOVE along that
2864    // coordinate at MACROSCOPIC scale? This block answers it directly — it probes
2865    // the objective a full e-fold in λ to either side of a near-null-curvature
2866    // coordinate and, for coordinates whose value is provably flat there, removes
2867    // their measured gradient component (numerical bias, not slope) from the
2868    // projected gradient before the bound test. A coordinate whose large-step
2869    // value MOVES is left untouched, so a genuine pseudologdet ramp still refuses.
2870    //
2871    // Gated as narrowly as possible: it runs only when the certificate would
2872    // OTHERWISE refuse on |Pg|, only with an analytic Hessian that is PSD-within-
2873    // noise in hand, and only probes coordinates whose curvature row is below the
2874    // roundoff floor — so a well-conditioned objective (every scripted mock at its
2875    // certification point) probes nothing and pays zero extra evaluations.
2876    // The coordinates railed at ±rho_bound (the infinite-smoothing ceiling). Their
2877    // saturated curvature direction makes the FULL Hessian indefinite, so the
2878    // flatness certificate below — and the final curvature gate — judge PSD on the
2879    // interior (un-railed) sub-block instead, or a rail-caused indefiniteness would
2880    // disable the very certificate that exists to certify a railed optimum (#2299).
2881    // The FACE the certificate reasons on: every θ coordinate against its own
2882    // bound, ρ and non-ρ alike. See `certificate_railed_coordinates` for why
2883    // the λ-block report cannot be used here.
2884    let certificate_railed = certificate_railed_coordinates(&result.rho, config);
2885    // The λ-block REPORT that ships on the certificate. Same predicate,
2886    // narrower scan, because `lambdas_railed` indexes smoothing parameters.
2887    let railed_lambda_block = certificate_railed_lambdas(&result.rho, layout.rho_dim(), config);
2888
2889    // Typed stationary-at-asymptote rail certificate (#2348 Inc 1, #2299 layer 3,
2890    // #2337 Thm 2.1). Before falling through to the generic gradient/criterion-flat
2891    // verdict, POSITIVELY certify a railed optimum: the interior (non-railed)
2892    // coordinates are gradient-stationary, and each coordinate railed at the
2893    // infinite-/zero-smoothing box bound sits on a confirmed exponential tail whose
2894    // fitted model has already reached the rail limit to within the estimand
2895    // tolerance. This supersedes the untyped `lambdas_railed` flag with a proof that
2896    // the criterion improvement and coefficient travel still available by running to
2897    // the rail are both below tolerance.
2898    //
2899    // Computed in its own statement so the borrow of `analytic_hessian` ends before
2900    // the mint branch moves it onto the result. Gated to a genuinely railed optimum
2901    // with outward pull (`grad_norm` above the stationarity bound) and an analytic
2902    // Hessian: a well-conditioned interior fit, or a coordinate merely resting near a
2903    // bound with a vanishing gradient, probes nothing and keeps its ordinary verdict.
2904    let asymptote_objective_tol = config
2905        .rel_cost_tolerance
2906        .unwrap_or(config.tolerance * 1.0e-2)
2907        .max(COST_STALL_REL_TOL_FLOOR)
2908        * (1.0 + evaluation.cost.abs());
2909    let rail_outcome = match analytic_hessian.as_ref() {
2910        Some(hessian) if !certificate_railed.is_empty() && grad_norm > stationarity_bound => {
2911            Some(try_certify_asymptote_rail(
2912                obj,
2913                &AsymptoteRailInputs {
2914                    rho: &result.rho,
2915                    projected_gradient: &projected_gradient,
2916                    railed: &certificate_railed,
2917                    hessian,
2918                    bounds: &bounds,
2919                    terminal_beta: terminal_beta.as_ref(),
2920                    stationarity_bound,
2921                    objective_tol: asymptote_objective_tol,
2922                    context,
2923                },
2924            )?)
2925        }
2926        _ => None,
2927    };
2928    // A refused railed mint carries its typed decline reason into the final
2929    // refusal summary (mirroring the tail-snap decline note), so a railed
2930    // non-mint names the gate that refused instead of failing silently.
2931    let mut asymptote_rail_note: Option<String> = None;
2932    let mut probes_ran = rail_outcome.is_some();
2933    if let Some(outcome) = rail_outcome {
2934        match outcome {
2935            Err(reason) => asymptote_rail_note = Some(reason),
2936            Ok(minted) => {
2937                let (interior_projected_grad_norm, effective_interior_bound, rails) = minted;
2938                // The tail probes were derivative-bearing evaluations at probe
2939                // ρ's, so the EVALUATOR-side terminal-mode carrier now owns the
2940                // last probe, not the checkpoint (#2155 regression: every
2941                // custom-family at-point mint then failed the bitwise terminal
2942                // theta identity at fit assembly). Re-evaluate at the minted
2943                // point and ship ITS numbers as the terminal facts: the same
2944                // evaluation sets the evaluator carrier, so the optimizer
2945                // certificate and the owned mode are bitwise-identical by
2946                // construction. The certified stationarity facts (interior
2947                // norms, rails) remain the judged ones.
2948                let restored = obj
2949                    .eval_with_order(&result.rho, OuterEvalOrder::ValueAndGradient)
2950                    .map_err(|err| {
2951                        EstimationError::RemlOptimizationFailed(format!(
2952                            "{context}: failed to re-own the certified point after \
2953                             asymptote-rail probing: {err}"
2954                        ))
2955                    })?;
2956                result.final_value = restored.cost;
2957                let restored_projected = project_gradient_vector(
2958                    &result.rho,
2959                    &restored.gradient,
2960                    Some(&rail_projection_bounds),
2961                );
2962                result.final_grad_norm = Some(
2963                    restored_projected
2964                        .iter()
2965                        .map(|v| v * v)
2966                        .sum::<f64>()
2967                        .sqrt(),
2968                );
2969                result.final_gradient = Some(restored.gradient);
2970                let certificate = OuterCriterionCertificate {
2971                    stationarity: OuterStationarityCertificate::AsymptoteRail {
2972                        interior_projected_grad_norm,
2973                        // The bound that admitted the interior: the raw stationarity
2974                        // bound, or the curvature-scaled flat-valley widening when the
2975                        // interior sub-block's Newton decrement is below the loop's
2976                        // cost resolution (shared judgment with the Inc 2c mint).
2977                        bound: effective_interior_bound,
2978                        rails,
2979                    },
2980                    hessian_psd: Some(true),
2981                    lambdas_railed: railed_lambda_block.clone(),
2982                    curvature_floor: None,
2983                };
2984                // Move the certified curvature onto the result; the mint path returns
2985                // immediately, so the fall-through below never observes the move.
2986                result.final_hessian = analytic_hessian;
2987                result.criterion_certificate = Some(certificate.clone());
2988                if !certificate.certifies() {
2989                    result.converged = false;
2990                    return Err(outer_nonconvergence_error(
2991                        context,
2992                        &certificate.summary(),
2993                        result,
2994                        Some(interior_projected_grad_norm),
2995                        StationarityBound::from_ladder(stationarity_bound, bound_source),
2996                    ));
2997                }
2998                result.converged = true;
2999                result.converged_via = Some(OuterConvergedVia::AsymptoteStationary {
3000                    rails: certificate.stationarity.rails().len(),
3001                });
3002                log::info!("[CERTIFICATE] {context}: {}", certificate.summary());
3003                return Ok(certificate);
3004            }
3005        }
3006    }
3007
3008    let mut certified_projected_grad_norm = projected_grad_norm;
3009    if projected_grad_norm > stationarity_bound
3010        && let Some(hessian) = analytic_hessian.as_ref()
3011        && certificate_hessian_is_psd_off_railed(hessian, &certificate_railed) == Some(true)
3012    {
3013        let n = layout.n_params;
3014        // Curvature scale of the analytic outer Hessian: its dominant diagonal,
3015        // the same ‖H‖ scale `certificate_hessian_is_psd` and
3016        // `newton_predicted_decrease` regularize against. A coordinate's curvature
3017        // ROW is indistinguishable from the assembly's roundoff — it has no
3018        // curvature the arithmetic can resolve and has collapsed onto the penalty
3019        // null space — when its largest entry falls below the SAME √ε·‖H‖ margin
3020        // those two probes use to separate a real curvature direction from
3021        // O(ε·‖H‖) accumulation noise. This is the derivation of the threshold:
3022        // NULL_CURVATURE_REL = √ε (machine epsilon's square root, the assembled
3023        // Hessian's relative resolution), scaled by the Hessian's own max-diagonal
3024        // magnitude, floored at 1 exactly as the PSD/Newton shift is.
3025        let max_diag = (0..n).fold(0.0_f64, |acc, j| acc.max(hessian[[j, j]].abs()));
3026        let null_curvature_threshold = f64::EPSILON.sqrt() * max_diag.max(1.0);
3027        // The SAME relative cost floor the cost-stall guard and both widenings
3028        // above use: certification asserts nothing tighter about this surface's
3029        // macroscopic flatness than the loop already proved.
3030        let objective_tol = config
3031            .rel_cost_tolerance
3032            .unwrap_or(config.tolerance * 1.0e-2)
3033            .max(COST_STALL_REL_TOL_FLOOR)
3034            * (1.0 + evaluation.cost.abs());
3035        // One e-fold in log-λ per coordinate (ρ IS log-λ): the +δ/−δ pair spans e²
3036        // in λ, a macroscopic move across which no genuine descent slope can hide.
3037        const LARGE_STEP_DELTA: f64 = 1.0;
3038        let mut saturated_flat: Vec<usize> = Vec::new();
3039        let mut probe_reports: Vec<String> = Vec::new();
3040        let mut probed_any = false;
3041        let mut probe_failed = false;
3042        for k in 0..n {
3043            let row_inf = (0..n).fold(0.0_f64, |acc, j| acc.max(hessian[[k, j]].abs()));
3044            // Only near-null-curvature coordinates the measured gradient actually
3045            // loads on can be responsible for |Pg| exceeding the band; skip every
3046            // other coordinate, so no probe fires on a well-conditioned surface.
3047            if row_inf > null_curvature_threshold || projected_gradient[k] == 0.0 {
3048                continue;
3049            }
3050            let mut plus = result.rho.clone();
3051            plus[k] += LARGE_STEP_DELTA;
3052            let mut minus = result.rho.clone();
3053            minus[k] -= LARGE_STEP_DELTA;
3054            probed_any = true;
3055            let (Ok(cost_plus), Ok(cost_minus)) = (obj.eval_cost(&plus), obj.eval_cost(&minus))
3056            else {
3057                // A failed probe is not evidence of flatness — refuse to classify
3058                // (conservative) and leave |Pg| intact for the bound test.
3059                probe_failed = true;
3060                break;
3061            };
3062            if !cost_plus.is_finite() || !cost_minus.is_finite() {
3063                probe_failed = true;
3064                break;
3065            }
3066            let up = (cost_plus - evaluation.cost).abs();
3067            let down = (cost_minus - evaluation.cost).abs();
3068            if up <= objective_tol && down <= objective_tol {
3069                saturated_flat.push(k);
3070                probe_reports.push(format!("k={k} |ΔV|+={up:.3e} |ΔV|-={down:.3e}"));
3071            }
3072        }
3073        if !probe_failed && !saturated_flat.is_empty() {
3074            // Recompute |Pg| with the provably macroscopically-flat coordinates
3075            // removed: their measured gradient is deterministic cancellation bias,
3076            // not slope. Coordinates that moved keep their component and still count
3077            // against the bound.
3078            let reduced_sq = (0..n)
3079                .filter(|k| !saturated_flat.contains(k))
3080                .map(|k| projected_gradient[k] * projected_gradient[k])
3081                .sum::<f64>();
3082            certified_projected_grad_norm = reduced_sq.sqrt();
3083            let flat_list = saturated_flat
3084                .iter()
3085                .map(usize::to_string)
3086                .collect::<Vec<_>>()
3087                .join(", ");
3088            let probe_summary = probe_reports.join("; ");
3089            log::info!(
3090                "[CERTIFICATE] {context}: large-step flatness certificate classified \
3091                 coordinate(s) [{flat_list}] saturated-flat (curvature row ≤ \
3092                 {null_curvature_threshold:.3e}, probed Δ=±{LARGE_STEP_DELTA} with \
3093                 {probe_summary}, cost-flat to tol {objective_tol:.3e}); projected \
3094                 gradient reduced from {projected_grad_norm:.3e} to \
3095                 {certified_projected_grad_norm:.3e}"
3096            );
3097        }
3098        // `eval_cost` warm-starts the inner solve, so the probes moved the objective
3099        // off the certified point. Restore it to ρ̂ once iff we actually probed, so
3100        // the downstream state (and the rho-uncertainty diagnostic) sees the fitted
3101        // point. A failure to re-evaluate the same ρ that certified moments ago is a
3102        // genuinely broken objective and refuses conservatively.
3103        if probed_any {
3104            obj.eval_cost(&result.rho).map_err(|err| {
3105                outer_nonconvergence_error(
3106                    context,
3107                    &format!(
3108                        "failed to restore the objective to the certified point after \
3109                         flatness probing: {err}"
3110                    ),
3111                    result,
3112                    Some(certified_projected_grad_norm),
3113                    StationarityBound::from_ladder(stationarity_bound, bound_source),
3114                )
3115            })?;
3116        }
3117    }
3118
3119    let certificate = OuterCriterionCertificate {
3120        stationarity: OuterStationarityCertificate::AnalyticGradient {
3121            grad_norm,
3122            projected_grad_norm: certified_projected_grad_norm,
3123            bound: stationarity_bound,
3124        },
3125        // The RAW measurement — unchanged, and what every consumer that asks
3126        // for a genuine PSD certificate keeps receiving.
3127        hessian_psd: analytic_hessian.as_ref().and_then(|hessian| {
3128            certificate_hessian_is_psd_off_railed(hessian, &certificate_railed)
3129        }),
3130        lambdas_railed: railed_lambda_block.clone(),
3131        // The floor's verdict on that same curvature, recorded beside it.
3132        curvature_floor: analytic_hessian.as_ref().and_then(|hessian| {
3133            interior_curvature_floor_clearance(hessian, &certificate_railed, &projected_gradient)
3134        }),
3135    };
3136    // Certify-time tail snap (#2348 Inc 2). About to refuse a point whose
3137    // residual gradient is carried by un-railed coordinates crawling a
3138    // CONFIRMED exponential tail toward the ρ-box (the one-e-fold-per-step
3139    // grind: the loop budget can exhaust strictly inside the box, where the
3140    // Inc 1 railed mint can never fire), snap those coordinates to their box
3141    // bound and publish that point as a one-shot optimization reseed. The
3142    // resumed optimizer lets coupled interior coordinates move before the
3143    // FULL Inc 1 rail discipline judges the result — this path grants nothing
3144    // by itself.
3145    let mut tail_snap_note: Option<String> = None;
3146    if allow_tail_snap
3147        && !certificate.certifies()
3148        && grad_norm > stationarity_bound
3149        && let Some(hessian) = analytic_hessian.as_ref()
3150    {
3151        probes_ran = true;
3152        match try_tail_snap_to_rail(
3153            obj,
3154            &AsymptoteRailInputs {
3155                rho: &result.rho,
3156                projected_gradient: &projected_gradient,
3157                railed: &certificate_railed,
3158                hessian,
3159                bounds: &bounds,
3160                terminal_beta: terminal_beta.as_ref(),
3161                stationarity_bound,
3162                objective_tol: asymptote_objective_tol,
3163                context,
3164            },
3165        )? {
3166            TailSnapOutcome::TailStationaryAtPoint {
3167                rails,
3168                interior_projected_grad_norm,
3169                effective_interior_bound,
3170            } => {
3171                // #2348 Inc 2c: the confirmed tails extrapolate below the bound
3172                // AT the checkpoint — mint the typed asymptote certificate for
3173                // the point as it stands. `hessian_psd` is the interior
3174                // sub-block verdict established before probing (the full
3175                // matrix is expected non-PD from the noise-corrupted tail
3176                // entry); the stored bound is the one that actually certified
3177                // the interior (raw, or the sub-block curvature-scaled
3178                // flat-valley bound).
3179                //
3180                // Re-own the minted point first: the tail probes were
3181                // derivative-bearing evaluations at probe ρ's, so the
3182                // evaluator-side terminal-mode carrier owns the last probe —
3183                // shipping the pre-probe terminal numbers then fails the
3184                // bitwise terminal theta identity at custom-family fit
3185                // assembly (the #2155 all-links regression). One fresh
3186                // evaluation at the checkpoint sets the carrier AND supplies
3187                // the terminal facts, so both sides are bitwise-identical by
3188                // construction.
3189                let restored = obj
3190                    .eval_with_order(&result.rho, OuterEvalOrder::ValueAndGradient)
3191                    .map_err(|err| {
3192                        EstimationError::RemlOptimizationFailed(format!(
3193                            "{context}: failed to re-own the certified point after \
3194                             tail-snap probing: {err}"
3195                        ))
3196                    })?;
3197                result.final_value = restored.cost;
3198                let restored_projected = project_gradient_vector(
3199                    &result.rho,
3200                    &restored.gradient,
3201                    Some(&rail_projection_bounds),
3202                );
3203                result.final_grad_norm = Some(
3204                    restored_projected
3205                        .iter()
3206                        .map(|v| v * v)
3207                        .sum::<f64>()
3208                        .sqrt(),
3209                );
3210                result.final_gradient = Some(restored.gradient);
3211                let certificate = OuterCriterionCertificate {
3212                    stationarity: OuterStationarityCertificate::AsymptoteRail {
3213                        interior_projected_grad_norm,
3214                        bound: effective_interior_bound,
3215                        rails,
3216                    },
3217                    hessian_psd: Some(true),
3218                    lambdas_railed: railed_lambda_block.clone(),
3219                    curvature_floor: None,
3220                };
3221                result.final_hessian = analytic_hessian;
3222                result.criterion_certificate = Some(certificate.clone());
3223                if !certificate.certifies() {
3224                    result.converged = false;
3225                    return Err(outer_nonconvergence_error(
3226                        context,
3227                        &certificate.summary(),
3228                        result,
3229                        Some(interior_projected_grad_norm),
3230                        StationarityBound::unrecorded(effective_interior_bound),
3231                    ));
3232                }
3233                result.converged = true;
3234                result.converged_via = Some(OuterConvergedVia::AsymptoteStationary {
3235                    rails: certificate.stationarity.rails().len(),
3236                });
3237                log::info!(
3238                    "[CERTIFICATE] {context}: tail-stationary at the checkpoint \
3239                     (#2348 Inc 2c): {}",
3240                    certificate.summary()
3241                );
3242                return Ok(certificate);
3243            }
3244            TailSnapOutcome::ConfirmedNeedsReseed(snapped) => {
3245                log::info!(
3246                    "[CERTIFICATE] {context}: confirmed exponential tail on un-railed \
3247                     coordinate(s); publishing the snapped point {snapped} as a waypoint \
3248                     for one re-optimization retry (#2348 Inc 2b / #2358)"
3249                );
3250                tail_snap_note = Some(
3251                    "tail confirmed; retry seeded at the snapped rail waypoint".to_string(),
3252                );
3253                result.tail_snap_reseed = Some(snapped);
3254            }
3255            TailSnapOutcome::Declined(reason) => {
3256                tail_snap_note = Some(reason);
3257            }
3258        }
3259    }
3260    // Install the measured evidence before deciding its verdict.  A rejected
3261    // candidate is retained only as a resumable checkpoint, and that
3262    // checkpoint must carry the actual analytic residual/curvature evidence
3263    // that caused the rejection rather than the optimizer's stale terminal
3264    // status.
3265    result.final_hessian = analytic_hessian;
3266    result.criterion_certificate = Some(certificate.clone());
3267    if !certificate.certifies() {
3268        result.converged = false;
3269        // Mint the #2392 reseeds fresh for THIS refused point: clear any value a
3270        // prior (multistart / pre-polish) certification of a different ρ left on
3271        // the result so the resume loop never consumes a stale pull-back/freeze.
3272        result.wrong_rail_reseed = None;
3273        result.active_set_reseed = None;
3274        // #2357 — saddle escape. The point is first-order stationary
3275        // (`is_stationary`: ‖Pg‖ ≤ bound) yet its INTERIOR reduced Hessian is a
3276        // certified strict saddle (`!curvature_admissible`). A railed coordinate
3277        // no longer waives this: `curvature_admissible` already reads the
3278        // off-railed reduced Hessian, and the escape descends only the free
3279        // (un-railed) directions while holding every rail fixed (#2155). That is
3280        // exactly the case a gradient-only
3281        // convergence gate mis-accepts: it arrived with the gradient already
3282        // below tolerance and stopped, leaving the certified negative-curvature
3283        // eigendirection — a strict descent — untaken. Mint a one-shot reseed
3284        // stepped off the ridge to a strictly-lower objective so the plan runner
3285        // can re-descend to the true PSD minimum, exactly as an identical
3286        // warm-started resume does by hand. Gated by `allow_tail_snap` (the same
3287        // one-shot reseed gate the tail snap rides) so the retry pass — which
3288        // runs with it `false` — can never recurse.
3289        if allow_tail_snap
3290            && certificate.is_stationary()
3291            && !certificate.curvature_admissible()
3292            && let Some(hessian) = result.final_hessian.clone()
3293            && let Some(gradient) = result.final_gradient.clone()
3294        {
3295            let saddle_rho = result.rho.clone();
3296            let baseline_cost = result.final_value;
3297            // `curvature_admissible()` is `false` exactly when the REDUCED
3298            // (off-railed) Hessian is indefinite, so a railed coordinate no
3299            // longer waives the escape: it is passed through and held fixed while
3300            // the step descends the free-direction saddle (#2155). It must be
3301            // held fixed on the SAME face the reduction was taken on — the
3302            // certificate's λ-block report would leave a railed ψ free to be
3303            // stepped out of its box.
3304            result.saddle_escape_reseed = negative_curvature_escape_point(
3305                obj,
3306                &saddle_rho,
3307                &gradient,
3308                &hessian,
3309                &certificate_railed,
3310                baseline_cost,
3311                &bounds,
3312                context,
3313            );
3314        }
3315        // #2392 — wrong-rail pull-back and active-set reduction. A coordinate at
3316        // the ρ box whose deep-λ terminal gradient is instrument noise leaves the
3317        // outer search unable to move it: the trust region's local model is flat
3318        // there. Two evidence-gated one-shot reseeds recover the fit (both gated
3319        // by `allow_tail_snap` so the retry pass cannot recurse):
3320        //   (1) WRONG-RAIL PULL-BACK: the coordinate's clean-band probes (a few
3321        //       e-folds inside, above the noise floor) prove the objective
3322        //       DECREASES inward — it was driven to the wrong bound. Reseed it at
3323        //       its clean-band interior scale so the optimizer descends to the
3324        //       true interior optimum. Fires ONLY on the opposite-sign clean-tail
3325        //       proof, so a genuine λ→∞/λ→0 rail is never pulled off its bound.
3326        //   (2) ACTIVE-SET REDUCTION: no wrong rail, but the INTERIOR is not
3327        //       stationary while a rail is present — the railed coordinate's
3328        //       ill-conditioned Hessian row poisons the joint step. Freeze the
3329        //       rail(s) at their bound and re-run so the interior converges in the
3330        //       reduced space; the plan runner re-certifies the polished point
3331        //       under the ORIGINAL box, so a frozen coordinate whose gradient
3332        //       turns inward there un-freezes (no silent clamping).
3333        // (1) takes precedence: a wrong rail must be pulled back, never frozen.
3334        if allow_tail_snap && !certificate_railed.is_empty() {
3335            let beta_norm = terminal_beta
3336                .as_ref()
3337                .map(|b| b.dot(b).sqrt())
3338                .filter(|v| v.is_finite())
3339                .unwrap_or(0.0);
3340            let mut rail_tol =
3341                AsymptoteTolerances::exp4_rail_bands(ASYMPTOTE_ESTIMAND_REL_TOL * (1.0 + beta_norm));
3342            rail_tol.tail_drift_rel = TAIL_SNAP_DRIFT_REL;
3343            let (lower, upper) = &bounds;
3344            let mut wrong_rail_point: Option<Array1<f64>> = None;
3345            for &k in certificate_railed.iter() {
3346                if k >= result.rho.len() || k >= lower.len() || k >= upper.len() {
3347                    continue;
3348                }
3349                let side = if (upper[k] - result.rho[k]).abs() <= (result.rho[k] - lower[k]).abs() {
3350                    AsymptoteSide::Upper
3351                } else {
3352                    AsymptoteSide::Lower
3353                };
3354                if let Some(target) = detect_wrong_rail_pullback(
3355                    obj,
3356                    &result.rho,
3357                    k,
3358                    side,
3359                    &rail_tol,
3360                    (lower[k], upper[k]),
3361                )? {
3362                    let mut reseed = result.rho.clone();
3363                    reseed[k] = target;
3364                    wrong_rail_point = Some(reseed);
3365                    break;
3366                }
3367            }
3368            if let Some(reseed) = wrong_rail_point {
3369                result.wrong_rail_reseed = Some(reseed);
3370            } else if let Some(hessian) = result.final_hessian.as_ref() {
3371                // Active-set reduction needs curvature to prove that the free
3372                // subspace is genuinely unpolished. Wrong-rail pull-back above
3373                // is a first-order tail-sign proof and deliberately does NOT:
3374                // gradient-only BFGS objectives can rail incorrectly too, and
3375                // withholding a valid pull-back merely because they do not
3376                // materialize H would make recovery depend on solver class.
3377                let interior_indices: Vec<usize> = (0..projected_gradient.len())
3378                    .filter(|k| !certificate_railed.contains(k))
3379                    .collect();
3380                let interior_not_stationary = !interior_indices.is_empty()
3381                    && certify_interior_stationarity(
3382                        &projected_gradient,
3383                        &hessian,
3384                        &interior_indices,
3385                        stationarity_bound,
3386                        asymptote_objective_tol,
3387                    )
3388                    .is_err();
3389                if interior_not_stationary {
3390                    let mut froz_lower = lower.clone();
3391                    let mut froz_upper = upper.clone();
3392                    let mut reseed = result.rho.clone();
3393                    let mut froze_any = false;
3394                    for &k in certificate_railed.iter() {
3395                        if k >= reseed.len() {
3396                            continue;
3397                        }
3398                        let rail = if (upper[k] - reseed[k]).abs() <= (reseed[k] - lower[k]).abs() {
3399                            upper[k]
3400                        } else {
3401                            lower[k]
3402                        };
3403                        reseed[k] = rail;
3404                        froz_lower[k] = rail;
3405                        froz_upper[k] = rail;
3406                        froze_any = true;
3407                    }
3408                    if froze_any {
3409                        result.active_set_reseed = Some(ActiveSetReseed {
3410                            rho: reseed,
3411                            bounds: (froz_lower, froz_upper),
3412                        });
3413                    }
3414                }
3415            }
3416        }
3417        // Carry the railed-mint and tail-snap decline evidence into the
3418        // refusal so a railed or budget-exhausted crawl explains which
3419        // certificate gate refused instead of failing silently.
3420        let mut summary = certificate.summary();
3421        // `summary()` prints `lambdas_railed`, which is the λ-block report. When
3422        // the face the certificate actually reasoned on is wider — a joint
3423        // [ρ, ψ] search with a κ coordinate on its data-derived window — say so,
3424        // or the refusal reads as `railed=[]` while the projector has already
3425        // discarded that coordinate's outward pull and nothing explains where
3426        // `|g|` went (#979).
3427        if certificate_railed.len() != railed_lambda_block.len() {
3428            summary = format!(
3429                "{summary}; outer coordinates railed (theta-wide, incl. non-rho blocks): \
3430                 {certificate_railed:?}"
3431            );
3432        }
3433        if let Some(note) = asymptote_rail_note {
3434            summary = format!("{summary}; asymptote-rail declined: {note}");
3435        }
3436        let summary = match tail_snap_note {
3437            Some(note) => format!("{summary}; tail-snap declined: {note}"),
3438            None => summary,
3439        };
3440        return Err(outer_nonconvergence_error(
3441            context,
3442            &summary,
3443            result,
3444            Some(certified_projected_grad_norm),
3445            StationarityBound::from_ladder(stationarity_bound, bound_source),
3446        ));
3447    }
3448
3449    // #2155 regression, the LAST carrier-stealing path: the rail-mint and
3450    // tail-snap attempts probe with derivative-bearing evaluations, and the
3451    // ORDINARY certificate can still certify after a declined attempt (e.g. a
3452    // KKT-railed projection whose raw gradient norm sits above the bound), so
3453    // this success would ship pre-probe terminal numbers while the evaluator's
3454    // terminal-mode carrier owns the last probe — refusing the bitwise theta
3455    // identity at custom-family fit assembly. Re-own the certified point with
3456    // one fresh evaluation and ship ITS numbers; the mint branches re-own for
3457    // themselves before their early returns, and the judged stationarity facts
3458    // above remain the measured pre-probe ones.
3459    if probes_ran {
3460        let restored = obj
3461            .eval_with_order(&result.rho, OuterEvalOrder::ValueAndGradient)
3462            .map_err(|err| {
3463                EstimationError::RemlOptimizationFailed(format!(
3464                    "{context}: failed to re-own the certified point after                      rail/tail probing: {err}"
3465                ))
3466            })?;
3467        result.final_value = restored.cost;
3468        let restored_projected = project_gradient_vector(
3469            &result.rho,
3470            &restored.gradient,
3471            Some(&rail_projection_bounds),
3472        );
3473        result.final_grad_norm = Some(
3474            restored_projected
3475                .iter()
3476                .map(|v| v * v)
3477                .sum::<f64>()
3478                .sqrt(),
3479        );
3480        result.final_gradient = Some(restored.gradient);
3481    }
3482    result.converged = true;
3483    // #2235/#2241 — record WHICH certificate concluded this run. A
3484    // Fellner–Schall model-state fixed point was pre-stamped by the runner and
3485    // is preserved (this analytic certificate is its corroborating evidence);
3486    // otherwise the verdict is decided by which stationarity band the measured
3487    // projected gradient actually cleared: the solver's own tolerance
3488    // (gradient-stationary) or only the widened flat certificate band
3489    // (criterion-flat, #2241).
3490    result.converged_via = match result.converged_via {
3491        Some(via @ OuterConvergedVia::RecurrentIncumbent { .. }) => Some(via),
3492        _ if certified_projected_grad_norm <= solver_bound => {
3493            Some(OuterConvergedVia::GradientStationary)
3494        }
3495        _ => Some(OuterConvergedVia::CriterionFlat {
3496            residual_grad_norm: certified_projected_grad_norm,
3497            certificate_bound: stationarity_bound,
3498        }),
3499    };
3500    log::info!("[CERTIFICATE] {context}: {}", certificate.summary());
3501    Ok(certificate)
3502}
3503
3504/// Estimand tolerance relative to the fitted coefficient scale for the
3505/// asymptote-rail certificate (#2348 Inc 1): the remaining coefficient travel
3506/// to the rail limit must fall below `ASYMPTOTE_ESTIMAND_REL_TOL·(1 + ‖β‖)` for
3507/// the fitted model to be certified equal to the rail-limit fit.
3508const ASYMPTOTE_ESTIMAND_REL_TOL: f64 = 1.0e-4;
3509
3510/// Number of one-e-fold-in-`ρ` probes stepped back from a railed coordinate
3511/// toward the interior when reconstructing its exponential tail (#2348 Inc 1).
3512/// Enough to span both the finite-difference floor next to the rail (rejected)
3513/// and a confirmable-tail run further in.
3514// 18 e-folds: the window must REACH the finite-difference-clean constant-ĉ
3515// band from a coordinate railed AT the box ceiling. The fused-Hessian
3516// trajectory (#2348) rails fits at ρ=30 that previously stalled mid-box, and
3517// the #2299 fixture's clean band sits 13–16 e-folds inside — the old 12-probe
3518// window (sized for mid-box crawls) stopped one row short of it, so a fully
3519// confirmed tail declined with "no finite-difference-clean tail window". Six
3520// extra value+gradient evals, paid only at certification of railed fits.
3521const ASYMPTOTE_PROBE_COUNT: usize = 18;
3522
3523/// Local confirmation resolution used only when the one-e-fold ladder cannot
3524/// find a clean run. A finite smoothing box can intersect a perfectly regular
3525/// asymptote before three whole e-folds of the leading-order tail are visible;
3526/// half-e-fold probes resolve that band without relaxing any certificate gate.
3527///
3528/// The probes remain equally spaced, which is load-bearing: the estimand
3529/// certificate interprets consecutive coefficient moves as one geometric
3530/// sequence. Six samples cover three e-folds, so the fallback still observes
3531/// curvature over a material interval instead of manufacturing constancy from
3532/// an arbitrarily small neighborhood.
3533const ASYMPTOTE_LOCAL_PROBE_DELTA: f64 = 0.5;
3534const ASYMPTOTE_LOCAL_PROBE_COUNT: usize = 6;
3535
3536/// Read-only inputs to [`try_certify_asymptote_rail`], bundled so the certify
3537/// path passes one borrow rather than a long positional argument list.
3538struct AsymptoteRailInputs<'a> {
3539    rho: &'a Array1<f64>,
3540    projected_gradient: &'a Array1<f64>,
3541    railed: &'a [usize],
3542    hessian: &'a Array2<f64>,
3543    bounds: &'a (Array1<f64>, Array1<f64>),
3544    terminal_beta: Option<&'a Array1<f64>>,
3545    stationarity_bound: f64,
3546    /// The run's relative objective tolerance resolved at the certified cost —
3547    /// the same flat-valley floor the cost-stall guard and the curvature-scaled
3548    /// widening use. The tail-snap interior judgment applies the identical
3549    /// Newton-decrement criterion on the interior SUB-BLOCK (the full-Hessian
3550    /// widening is disabled exactly when a noise-corrupted tail entry makes the
3551    /// full matrix non-PD).
3552    objective_tol: f64,
3553    context: &'a str,
3554}
3555
3556/// Attempt the typed stationary-at-asymptote rail certificate (#2348 Inc 1).
3557///
3558/// Returns `Some((interior_projected_grad_norm, rails))` when the interior
3559/// (non-railed) coordinates are gradient-stationary, the interior Hessian
3560/// sub-block is PSD, and EVERY railed coordinate is certified on a confirmed
3561/// exponential tail whose fitted model has reached the rail limit to within the
3562/// estimand tolerance. Returns `None` (fall through to the generic verdict) on
3563/// any failure — a non-stationary interior, indefinite interior curvature, or
3564/// any railed coordinate whose tail is not confirmable. Never errors on a
3565/// refusal; the only `Err` is a genuinely broken objective that cannot restore
3566/// its inner state to the certified point after probing.
3567fn try_certify_asymptote_rail(
3568    obj: &mut dyn OuterObjective,
3569    inputs: &AsymptoteRailInputs<'_>,
3570) -> Result<Result<(f64, f64, Vec<RailCoordinate>), String>, EstimationError> {
3571    let rho = inputs.rho;
3572    let projected_gradient = inputs.projected_gradient;
3573    let railed = inputs.railed;
3574    // The interior (non-railed) coordinates must be stationary in their own
3575    // right: the asymptote certificate speaks only to the railed directions,
3576    // never rescues a still-descending interior. Judged by the SAME two-stage
3577    // criterion as the Inc 2c at-point mint: the raw bound first, then the
3578    // curvature-scaled flat-valley bound on the interior sub-block — a fit
3579    // whose remaining interior Newton step would improve the cost by less
3580    // than the loop's own cost resolution is at its interior optimum, and the
3581    // residual gradient is the deep-λ instrument noise floor (evaluations
3582    // beside a saturated rail share the rail's logdet noise).
3583    let interior_indices: Vec<usize> = (0..projected_gradient.len())
3584        .filter(|k| !railed.contains(k))
3585        .collect();
3586    let (interior_projected_grad_norm, effective_interior_bound) =
3587        match certify_interior_stationarity(
3588            projected_gradient,
3589            inputs.hessian,
3590            &interior_indices,
3591            inputs.stationarity_bound,
3592            inputs.objective_tol,
3593        ) {
3594            Ok(certified) => certified,
3595            Err(reason) => return Ok(Err(reason)),
3596        };
3597    // The interior sub-block (railed coordinates removed) must be admissible
3598    // curvature for a minimum. A rail-caused indefiniteness in the saturated
3599    // direction is expected and excluded; genuine interior negative curvature is
3600    // not, and refuses the certificate.
3601    if certificate_hessian_is_psd_off_railed_above_gradient_floor(
3602        inputs.hessian,
3603        railed,
3604        projected_gradient,
3605    ) != Some(true)
3606    {
3607        return Ok(Err("interior Hessian sub-block is not PSD".to_string()));
3608    }
3609    let beta_norm = inputs
3610        .terminal_beta
3611        .map(|b| b.dot(b).sqrt())
3612        .filter(|v| v.is_finite())
3613        .unwrap_or(0.0);
3614    let estimand_tol = ASYMPTOTE_ESTIMAND_REL_TOL * (1.0 + beta_norm);
3615    let mut tol = AsymptoteTolerances::exp4_rail_bands(estimand_tol);
3616    // Real REML tails hold ĉ to ~5e-3 relative, not the exp4 synthetic
3617    // characterization's 1e-3 (measured on the #2299 fixture during Inc 2c);
3618    // the tail-snap path already certifies against the widened band, and the
3619    // railed mint must judge the SAME physical tail by the same standard.
3620    tol.tail_drift_rel = TAIL_SNAP_DRIFT_REL;
3621    let (lower, upper) = inputs.bounds;
3622
3623    // #2348 Inc 5 — the ANALYTIC face proof, first resort.
3624    //
3625    // Measuring a tail beside the ρ box asks the criterion for derivative
3626    // information exactly where its logdet pair cancels; and even when it
3627    // succeeds it speaks for ONE coordinate along ONE ray. The analytic route
3628    // forms the λ=∞ limit itself — the null-space-restricted fit, and the
3629    // exact first-order form of the logdet and trace terms there — and its
3630    // positive definiteness proves the whole face against every way of coming
3631    // off it. When the objective cannot form that limit, or the proof does not
3632    // hold, the measured-tail path below is unchanged.
3633    match try_certify_face_analytically(obj, inputs, estimand_tol)? {
3634        Ok((rails, proof)) => {
3635            log::info!(
3636                "[CERTIFICATE] {}: analytic λ=∞ face proof on {} coordinate(s): λ_min(C)={:.6e} \
3637                 > margin {:.3e}, joint pencil ĉ={:.6e}, remaining value gap {:.3e}, estimand \
3638                 travel {:.3e}",
3639                inputs.context,
3640                rails.len(),
3641                proof.min_curvature,
3642                proof.curvature_margin,
3643                proof.joint_tail_constant,
3644                proof.value_gap,
3645                proof.estimand_travel,
3646            );
3647            return Ok(Ok((
3648                interior_projected_grad_norm,
3649                effective_interior_bound,
3650                rails,
3651            )));
3652        }
3653        Err(reason) => log::info!(
3654            "[CERTIFICATE] {}: analytic λ=∞ face proof declined ({reason}); measuring the tail \
3655             instead",
3656            inputs.context,
3657        ),
3658    }
3659
3660    let mut rails: Vec<RailCoordinate> = Vec::new();
3661    let mut decline: Option<String> = None;
3662    let mut probed_any = false;
3663    for &k in railed.iter() {
3664        if k >= rho.len() || k >= lower.len() || k >= upper.len() {
3665            decline = Some(format!("railed coordinate {k} outside the box layout"));
3666            break;
3667        }
3668        // Which rail: the box endpoint the coordinate sits nearest. `Upper`
3669        // (λ → ∞) probes step ρ downward into the tail; `Lower` (λ → 0) step up.
3670        let side = if (upper[k] - rho[k]).abs() <= (rho[k] - lower[k]).abs() {
3671            AsymptoteSide::Upper
3672        } else {
3673            AsymptoteSide::Lower
3674        };
3675        probed_any = true;
3676        match build_and_assess_rail_coordinate(obj, rho, k, side, &tol, (lower[k], upper[k]))? {
3677            Ok(rail) => rails.push(rail),
3678            Err(reason) => {
3679                decline = Some(reason);
3680                break;
3681            }
3682        }
3683    }
3684
3685    // The probes warm-started the inner solve away from ρ̂; restore it so the
3686    // shipped fitted state (and the ρ-uncertainty diagnostic) sees the certified
3687    // point. A failure here is a genuinely broken objective, not a refusal.
3688    if probed_any {
3689        obj.eval_cost(rho).map_err(|err| {
3690            EstimationError::RemlOptimizationFailed(format!(
3691                "{}: failed to restore the objective to the certified point after \
3692                 asymptote-rail probing: {err}",
3693                inputs.context
3694            ))
3695        })?;
3696    }
3697
3698    if let Some(reason) = decline {
3699        return Ok(Err(reason));
3700    }
3701    if rails.is_empty() {
3702        return Ok(Err(
3703            "no railed coordinate produced a certifiable tail".to_string()
3704        ));
3705    }
3706    Ok(Ok((
3707        interior_projected_grad_norm,
3708        effective_interior_bound,
3709        rails,
3710    )))
3711}
3712
3713/// The analytic face law is falsified against production criterion VALUES, so
3714/// the admissible discrepancy is exactly the error sources the comparison is
3715/// made of: the run's own cost resolution (absolute, once per evaluation), the
3716/// law's `O(e^{−ρ})` second-order remainder (relative), and the digits the
3717/// Gram/Schur assembly loses. `FACE_LAW_ERROR_SLACK` widens that budget by the
3718/// factor a two-point difference accumulates — each evaluation carries its own
3719/// resolution error and the remainder enters both the predicted and the
3720/// measured side — so a CORRECT law is never refused by its own error bars,
3721/// while a wrong one (which misses by orders of magnitude, not by slack) still
3722/// is. The falsification only runs where the budget leaves a discriminating
3723/// band; where it does not, the analytic route declines rather than minting
3724/// unfalsifiable evidence.
3725const FACE_LAW_ERROR_SLACK: f64 = 4.0;
3726
3727/// Floor on the falsification band.
3728///
3729/// The derived numerical budget can land many orders below the honest fidelity
3730/// of a closed form that deliberately does not model the criterion's
3731/// stabilization ridge or its reparameterization; holding the law to that
3732/// budget would reject a CORRECT law over a difference that changes no
3733/// decision. What the falsification exists to catch is a structurally wrong law
3734/// — a missing Schur term, the wrong dispersion convention, a sign error — and
3735/// those miss by orders of magnitude, not by slack (measured on a fixture whose
3736/// released directions genuinely earned their cost: 100%). Half the predicted
3737/// drop is the coarsest band that still separates those two worlds.
3738const FACE_LAW_ORDER_BAND: f64 = 0.5;
3739
3740/// Prove the rail face analytically (#2348 Inc 5): ask the objective for the
3741/// exact λ→∞ limit, test the first-order form, and falsify the resulting law
3742/// against the production criterion before minting anything from it.
3743///
3744/// Returns the minted rail coordinates plus the proof, or a human-readable
3745/// decline that the caller logs before falling back to the measured tail.
3746fn try_certify_face_analytically(
3747    obj: &mut dyn OuterObjective,
3748    inputs: &AsymptoteRailInputs<'_>,
3749    estimand_tol: f64,
3750) -> Result<Result<(Vec<RailCoordinate>, RailFaceProof), String>, EstimationError> {
3751    let rho = inputs.rho;
3752    let (lower, upper) = inputs.bounds;
3753    // The analytic limit is the INFINITE-smoothing face. A coordinate railed at
3754    // the zero-smoothing bound is the opposite limit (the penalty leaves the
3755    // model rather than pinning it) and belongs to the measured-tail path.
3756    for &k in inputs.railed.iter() {
3757        if k >= rho.len() || k >= lower.len() || k >= upper.len() {
3758            return Ok(Err("railed coordinate outside the box layout".to_string()));
3759        }
3760        if (upper[k] - rho[k]).abs() > (rho[k] - lower[k]).abs() {
3761            return Ok(Err(format!(
3762                "coordinate {k} rails at the zero-smoothing bound; the analytic face limit \
3763                 covers λ→∞ only"
3764            )));
3765        }
3766    }
3767    let limit = match obj.rail_face_limit(rho, inputs.railed)? {
3768        RailFaceLimitOutcome::Available(limit) => *limit,
3769        // The decline is typed, and the distinction is worth carrying into the
3770        // refusal: "outside this closed form" invites a different one, while
3771        // "the face is unavailable" is a statement about the face.
3772        RailFaceLimitOutcome::OutsideClosedForm { reason } => {
3773            return Ok(Err(format!("outside the analytic closed form: {reason}")));
3774        }
3775        RailFaceLimitOutcome::FaceUnavailable { reason } => {
3776            return Ok(Err(format!("the λ=∞ face is unavailable: {reason}")));
3777        }
3778    };
3779    let proof = match certify_rail_face(&limit) {
3780        RailFaceVerdict::Certified(proof) => proof,
3781        RailFaceVerdict::Refused { reason } => return Ok(Err(reason)),
3782    };
3783    // The face being optimal does not by itself mean the SHIPPED fit is the
3784    // limit fit; the estimand gate is the same one the measured path applies,
3785    // now answered by the exact first-order coefficient offset rather than a
3786    // geometric extrapolation of observed steps.
3787    if !(proof.estimand_travel <= estimand_tol) {
3788        return Ok(Err(format!(
3789            "λ=∞ face proven, but the shipped fit has not reached it: coefficient travel \
3790             {:.3e} > estimand tolerance {estimand_tol:.3e}",
3791            proof.estimand_travel
3792        )));
3793    }
3794    if let Err(reason) = falsify_face_law(obj, inputs, &limit, &proof)? {
3795        return Ok(Err(reason));
3796    }
3797    let rails: Vec<RailCoordinate> = limit
3798        .face
3799        .iter()
3800        .zip(limit.face_rho.iter())
3801        .zip(proof.tail_constants.iter())
3802        .map(|((&index, &rho_k), &tail_constant)| RailCoordinate {
3803            index,
3804            side: AsymptoteSide::Upper,
3805            tail_constant,
3806            // On the tail law the remaining value gap of one coordinate is
3807            // exactly `c_k·e^{−ρ_k}`; a coordinate the rest of the face has
3808            // already pinned reports `c_k = 0` because releasing it does not
3809            // move the criterion at all.
3810            value_gap: tail_constant * (-rho_k).exp(),
3811            estimand_travel_bound: proof.estimand_travel,
3812            // The analytic proof's floor is the eigen-backward-error margin it
3813            // cleared, not a finite-difference noise floor.
3814            noise_margin: proof.curvature_margin,
3815        })
3816        .collect();
3817    Ok(Ok((rails, proof)))
3818}
3819
3820/// Falsify the analytic face law against the production criterion.
3821///
3822/// The law predicts `V(ρ) − V_∞ = ½tr((Σλ_kQᵀS_kQ)⁻¹C)`, so pulling every face
3823/// coordinate back by `Δ` must raise the criterion by exactly
3824/// `gap·(e^{Δ} − 1)`. That is a VALUE comparison — no derivative, no
3825/// cancellation — and it costs two evaluations instead of a probe ladder.
3826///
3827/// `Δ` is not a knob: the measurement error is `resolution/(gap·(e^Δ−1))` and
3828/// the law's own remainder is `O(e^{Δ−ρ})`, so their sum is minimized at
3829/// `Δ* = ½(ln(resolution/gap) + ρ)`, where both equal `√(resolution·e^{−ρ}/gap)`.
3830fn falsify_face_law(
3831    obj: &mut dyn OuterObjective,
3832    inputs: &AsymptoteRailInputs<'_>,
3833    limit: &RailFaceLimit,
3834    proof: &RailFaceProof,
3835) -> Result<Result<(), String>, EstimationError> {
3836    const FACE_LAW_DOMAIN_MARGIN: f64 = 1.0e-6;
3837    let rho = inputs.rho;
3838    let (lower, _) = inputs.bounds;
3839    let gap = proof.value_gap;
3840    let resolution = inputs.objective_tol;
3841    if !(gap > 0.0) || !(resolution > 0.0) {
3842        return Ok(Err(format!(
3843            "the face law carries no resolvable value gap: gap={gap:.3e}, cost resolution \
3844             {resolution:.3e}"
3845        )));
3846    }
3847    let deepest = limit
3848        .face_rho
3849        .iter()
3850        .fold(f64::INFINITY, |acc, v| acc.min(*v));
3851    let ideal = 0.5 * ((resolution / gap).ln() + deepest);
3852    let room = limit
3853        .face
3854        .iter()
3855        .zip(limit.face_rho.iter())
3856        .map(|(&k, &rho_k)| rho_k - lower[k] - FACE_LAW_DOMAIN_MARGIN)
3857        .fold(f64::INFINITY, f64::min);
3858    let delta = ideal.min(room);
3859    // One e-fold is the natural unit of the law being tested; below that the
3860    // predicted change is not a statement about a tail.
3861    if !(delta >= 1.0) || !delta.is_finite() {
3862        return Ok(Err(format!(
3863            "no room inside the box to falsify the face law: Δ={delta:.3e} e-folds"
3864        )));
3865    }
3866    let predicted = gap * (delta.exp() - 1.0);
3867    let measurement_error = resolution / predicted;
3868    let remainder_error = (delta - deepest).exp();
3869    let assembly_error = f64::EPSILON.sqrt() * limit.form_conditioning.sqrt();
3870    let budget = measurement_error + remainder_error + assembly_error;
3871    let admissible = (FACE_LAW_ERROR_SLACK * budget).max(FACE_LAW_ORDER_BAND);
3872    if !(admissible < 1.0) {
3873        return Ok(Err(format!(
3874            "the face law cannot be falsified here: error budget {budget:.3e} (measurement \
3875             {measurement_error:.3e}, remainder {remainder_error:.3e}, assembly \
3876             {assembly_error:.3e}) leaves no discriminating band"
3877        )));
3878    }
3879    let baseline = obj.eval_cost(rho)?;
3880    let mut pulled_back = rho.clone();
3881    for &k in limit.face.iter() {
3882        pulled_back[k] -= delta;
3883    }
3884    let pulled_value = obj.eval_cost(&pulled_back)?;
3885    // Every exit below ships the certified point, so restore it before judging.
3886    obj.eval_cost(rho)?;
3887    if !baseline.is_finite() || !pulled_value.is_finite() {
3888        return Ok(Err(
3889            "the criterion is not finite at the falsification points".to_string()
3890        ));
3891    }
3892    let measured = pulled_value - baseline;
3893    let discrepancy = (predicted - measured).abs() / predicted;
3894    if discrepancy > admissible {
3895        return Ok(Err(format!(
3896            "the analytic face law does not reproduce the criterion: pulling the face back \
3897             {delta:.2} e-folds should raise V by {predicted:.6e}, measured {measured:.6e} \
3898             (relative {discrepancy:.3e} > admissible {admissible:.3e})"
3899        )));
3900    }
3901    Ok(Ok(()))
3902}
3903
3904/// Two-stage interior stationarity judgment shared by the Inc 1 railed mint
3905/// and the Inc 2c at-point mint (#2348): the raw stationarity bound first,
3906/// then the curvature-scaled flat-valley bound on the interior sub-block.
3907///
3908/// The second stage certifies a point whose full interior Newton step would
3909/// improve the objective by less than `objective_tol` — the loop's own cost
3910/// resolution — so the point is cost-indistinguishable from the interior
3911/// optimum and the measured gradient is resolution noise, not slope. Returns
3912/// `Ok((interior_grad_norm, effective_bound))` when certified (the bound
3913/// that admitted the norm: raw, or the curvature-scaled widening); `Err`
3914/// carries the measured evidence when real interior descent remains, so a
3915/// refused mint explains WHICH interior stage failed and by how much.
3916pub(crate) fn certify_interior_stationarity(
3917    gradient: &Array1<f64>,
3918    hessian: &Array2<f64>,
3919    interior_indices: &[usize],
3920    stationarity_bound: f64,
3921    objective_tol: f64,
3922) -> Result<(f64, f64), String> {
3923    let interior_grad_norm = interior_indices
3924        .iter()
3925        .map(|&k| gradient[k] * gradient[k])
3926        .sum::<f64>()
3927        .sqrt();
3928    if interior_grad_norm <= stationarity_bound {
3929        return Ok((interior_grad_norm, stationarity_bound));
3930    }
3931    let m = interior_indices.len();
3932    let mut sub_h = Array2::<f64>::zeros((m, m));
3933    let mut sub_g = Array1::<f64>::zeros(m);
3934    for (i, &ri) in interior_indices.iter().enumerate() {
3935        sub_g[i] = gradient[ri];
3936        for (j, &rj) in interior_indices.iter().enumerate() {
3937            sub_h[[i, j]] = hessian[[ri, rj]];
3938        }
3939    }
3940    match newton_predicted_decrease(&sub_h, &sub_g) {
3941        Some(predicted_decrease) if predicted_decrease.is_finite() && predicted_decrease > 0.0 => {
3942            if predicted_decrease <= objective_tol {
3943                let curvature_grad_bound =
3944                    interior_grad_norm * (objective_tol / predicted_decrease).sqrt();
3945                if curvature_grad_bound.is_finite() && curvature_grad_bound >= interior_grad_norm {
3946                    return Ok((interior_grad_norm, curvature_grad_bound));
3947                }
3948            }
3949            Err(format!(
3950                "interior not stationary: |Pg_int|={interior_grad_norm:.3e} > bound                  {stationarity_bound:.3e}, sub-block Newton decrement                  {predicted_decrease:.3e} > cost resolution {objective_tol:.3e}"
3951            ))
3952        }
3953        _ => Err(format!(
3954            "interior not stationary: |Pg_int|={interior_grad_norm:.3e} > bound              {stationarity_bound:.3e} and the interior sub-block yields no PD Newton              decrement"
3955        )),
3956    }
3957}
3958
3959/// Curvature-tie acceptance band for a certify-time tail-snap candidate
3960/// (#2348 Inc 2). On the #2337 Thm 2.1 exponential tail `V = V_∞ + c·e^{∓ρ}`
3961/// the coordinate's own curvature equals its gradient magnitude EXACTLY
3962/// (`H_kk = c·e^{∓ρ} = |g_k|`, unit decay rate in ρ = log λ), so `H_kk/|g_k| ≈ 1`
3963/// is a zero-cost analytic signature separating a live tail crawl from a
3964/// genuinely unconverged curved coordinate before any probe is spent. The band
3965/// tolerates the `O(e^{∓2ρ})` next-order term and assembly round-off; the
3966/// probing confirmation is the rigorous gate.
3967const TAIL_SNAP_CURVATURE_BAND: (f64, f64) = (0.25, 4.0);
3968
3969/// Certify-time tail snap (#2348 Inc 2): when certification is about to refuse
3970/// a point whose gradient residual is carried entirely by coordinates crawling
3971/// an exponential tail TOWARD the ρ-box (the one-e-fold-per-Newton-step grind
3972/// the asymptote certificate exists to kill — the loop can exhaust its budget
3973/// strictly inside the box, where the Inc 1 railed mint can never fire),
3974/// positively confirm each such coordinate's tail from the current point and
3975/// return the point with those coordinates snapped to their box bound as an
3976/// optimization waypoint. The caller re-runs the outer search from that point;
3977/// only the resulting point is eligible for the Inc 1 rail certificate.
3978///
3979/// Refusal semantics mirror [`try_certify_asymptote_rail`]: any gate failure
3980/// returns `Ok(None)` (fall through to the ordinary refusal); the only `Err` is
3981/// a genuinely broken objective that cannot restore its inner state after
3982/// probing. Gates, in order of cost:
3983/// 1. candidate coordinates = un-railed, `|g_k|` above the stationarity bound,
3984///    positive own-curvature within [`TAIL_SNAP_CURVATURE_BAND`] of `|g_k|`
3985///    (the tail-law tie), with the rail side read from the gradient sign;
3986/// 2. the interior Hessian sub-block (railed + candidates excluded) is PSD;
3987/// 3. every candidate's tail is confirmed by the same probing engine the rail
3988///    mint uses (`CertifiedAtAsymptote` or `OnTailNotYetEquivalent`).
3989/// Outcome of a certify-time tail-snap attempt: a point already stationary on
3990/// its confirmed tail, a confirmed-tail waypoint requiring one optimization
3991/// retry (#2348 Inc 2b / #2358), or a human-readable decline reason carried
3992/// into the refusal summary.
3993#[derive(Debug)]
3994enum TailSnapOutcome {
3995    /// Every candidate's confirmed tail EXTRAPOLATES to a gradient already
3996    /// below the stationarity bound at the CURRENT point (#2348 Inc 2c): the
3997    /// coordinate is tail-stationary where it stands, and the measured local
3998    /// gradient is instrument noise (observed on the #2299 fixture: measured
3999    /// |g|=1.04e-2 at ρ=26.56 vs the clean-band extrapolation ĉ·e^{−ρ} ≈
4000    /// 1.9e-8, 100× below the bound). Mint the AsymptoteRail at this point —
4001    /// no snap, no reseed. `interior_projected_grad_norm` and the
4002    /// `effective_interior_bound` that certified it (the raw stationarity
4003    /// bound, or the interior sub-block's curvature-scaled flat-valley bound —
4004    /// the full-Hessian widening is disabled precisely because the noisy tail
4005    /// entry makes the full matrix non-PD) ride along for the certificate.
4006    TailStationaryAtPoint {
4007        rails: Vec<RailCoordinate>,
4008        interior_projected_grad_norm: f64,
4009        effective_interior_bound: f64,
4010    },
4011    /// Tails confirmed, but the current point is not already
4012    /// tail-stationary. The snapped rail point is only a waypoint: the plan
4013    /// runner must retry ONCE from it so coupled coordinates can reoptimize
4014    /// before certification.
4015    ConfirmedNeedsReseed(Array1<f64>),
4016    Declined(String),
4017}
4018
4019/// Relative drift band for the tail-snap confirmation window, wider than the
4020/// exp4 characterization band (1e-3). The snap's evidentiary strength comes
4021/// from the EXTRAPOLATED-GAP margin, not the band tightness: a 1–2% spread in
4022/// `ĉ` across the clean run moves the extrapolated remaining gradient
4023/// `ĉ·e^{∓ρ}` by the same 1–2%, immaterial against the orders-of-magnitude
4024/// margin the at-point/stationarity decisions demand — while the true tail on
4025/// a REAL fixture still carries visible sub-percent curvature contamination at
4026/// probe depth (measured on #2299: ĉ ∈ {6544, 6565, 6574} over three e-folds,
4027/// drift 4.6e-3, against a wildly swinging noise region above).
4028const TAIL_SNAP_DRIFT_REL: f64 = 1.0e-2;
4029
4030fn try_tail_snap_to_rail(
4031    obj: &mut dyn OuterObjective,
4032    inputs: &AsymptoteRailInputs<'_>,
4033) -> Result<TailSnapOutcome, EstimationError> {
4034    let rho = inputs.rho;
4035    let gradient = inputs.projected_gradient;
4036    let hessian = inputs.hessian;
4037    let (lower, upper) = inputs.bounds;
4038    let n = gradient.len();
4039    if rho.len() != n
4040        || hessian.nrows() != n
4041        || hessian.ncols() != n
4042        || lower.len() < n
4043        || upper.len() < n
4044    {
4045        return Ok(TailSnapOutcome::Declined("shape mismatch".to_string()));
4046    }
4047
4048    let mut candidates: Vec<(usize, AsymptoteSide)> = Vec::new();
4049    let mut rejected: Vec<String> = Vec::new();
4050    for k in 0..n {
4051        if inputs.railed.contains(&k) {
4052            continue;
4053        }
4054        let g_k = gradient[k];
4055        let side = match AsymptoteSide::from_gradient(g_k, inputs.stationarity_bound) {
4056            Some(side) => side,
4057            None => continue,
4058        };
4059        // A tail candidate must be DEEP toward the bound its gradient points
4060        // at — within the probe span of the box. The tail law is an asymptotic
4061        // statement; a coordinate sitting many probe-spans inside the interior
4062        // (every scripted mock optimum, every ordinary unconverged fit) has no
4063        // asymptote to confirm there, and probing it would spend a dozen
4064        // objective evaluations per would-refuse certification for nothing
4065        // (breaking eval-count-asserting harnesses along the way).
4066        let probe_span = ASYMPTOTE_PROBE_COUNT as f64;
4067        let deep_enough = match side {
4068            AsymptoteSide::Upper => upper[k] - rho[k] <= probe_span,
4069            AsymptoteSide::Lower => rho[k] - lower[k] <= probe_span,
4070        };
4071        if !deep_enough {
4072            rejected.push(format!(
4073                "k={k}: ρ={:.2} more than {probe_span:.0} e-folds inside the box",
4074                rho[k]
4075            ));
4076            continue;
4077        }
4078        let h_kk = hessian[[k, k]];
4079        // The tie is judged on |H_kk|/|g_k| — MAGNITUDE only. On the exact
4080        // tail `H_kk = |g_k|` (positive), but the assembled ρ-Hessian's tail
4081        // entry is `λV_λ + λ²V_λλ`, and when the `λ²V_λλ` trace pair cancels
4082        // to roundoff in the deep-smoothing regime (the #2298 rail-cancellation
4083        // class), what survives is `λV_λ = g_k` — magnitude right, SIGN
4084        // flipped (measured on the #2299 fixture: g=-1.040e-2, H_kk=-1.018e-2,
4085        // ratio -0.979). The sign at the tail is exactly the corrupted datum,
4086        // so it cannot gate; the probing confirmation is the rigorous test.
4087        let ratio = h_kk.abs() / g_k.abs();
4088        if !(TAIL_SNAP_CURVATURE_BAND.0..=TAIL_SNAP_CURVATURE_BAND.1).contains(&ratio) {
4089            rejected.push(format!(
4090                "k={k}: g={g_k:.3e} H_kk={h_kk:.3e} |ratio|={ratio:.3e} outside tie band"
4091            ));
4092            continue;
4093        }
4094        candidates.push((k, side));
4095    }
4096    if candidates.is_empty() {
4097        return Ok(TailSnapOutcome::Declined(if rejected.is_empty() {
4098            "no super-bound coordinate".to_string()
4099        } else {
4100            format!(
4101                "no candidate passed the curvature tie ({})",
4102                rejected.join("; ")
4103            )
4104        }));
4105    }
4106
4107    // The curvature left after excluding the railed + candidate directions
4108    // must be admissible for a minimum; a genuinely indefinite interior
4109    // refuses before any probe is spent.
4110    let excluded: Vec<usize> = inputs
4111        .railed
4112        .iter()
4113        .copied()
4114        .chain(candidates.iter().map(|(k, _)| *k))
4115        .collect();
4116    if certificate_hessian_is_psd_off_railed_above_gradient_floor(hessian, &excluded, gradient)
4117        != Some(true)
4118    {
4119        return Ok(TailSnapOutcome::Declined(
4120            "interior Hessian sub-block not PSD".to_string(),
4121        ));
4122    }
4123
4124    let beta_norm = inputs
4125        .terminal_beta
4126        .map(|b| b.dot(b).sqrt())
4127        .filter(|v| v.is_finite())
4128        .unwrap_or(0.0);
4129    let mut tol =
4130        AsymptoteTolerances::exp4_rail_bands(ASYMPTOTE_ESTIMAND_REL_TOL * (1.0 + beta_norm));
4131    tol.tail_drift_rel = TAIL_SNAP_DRIFT_REL;
4132    let mut decline: Option<String> = None;
4133    // Rails for candidates whose confirmed tail extrapolates to an
4134    // already-below-bound gradient at the CURRENT point; when every candidate
4135    // qualifies, the point is minted where it stands (#2348 Inc 2c).
4136    let mut at_point_rails: Vec<RailCoordinate> = Vec::new();
4137    for (k, side) in &candidates {
4138        let verdict = match probe_tail_window(obj, rho, *k, *side, &tol, (lower[*k], upper[*k]))? {
4139            (Some(window), rows) => match assess_coordinate(&window, &tol) {
4140                AsymptoteVerdict::CertifiedAtAsymptote {
4141                    side: assessed_side,
4142                    tail_constant,
4143                    estimand_travel_bound,
4144                    ..
4145                } => {
4146                    // Extrapolate the confirmed tail law to the current point:
4147                    // the TRUE remaining gradient there, immune to the local
4148                    // instrument noise the certificate measured.
4149                    let extrapolated_gap = match assessed_side {
4150                        AsymptoteSide::Upper => tail_constant * (-rho[*k]).exp(),
4151                        AsymptoteSide::Lower => tail_constant * rho[*k].exp(),
4152                    };
4153                    if extrapolated_gap.is_finite() && extrapolated_gap <= inputs.stationarity_bound
4154                    {
4155                        at_point_rails.push(RailCoordinate {
4156                            index: *k,
4157                            side: assessed_side,
4158                            tail_constant,
4159                            value_gap: extrapolated_gap,
4160                            estimand_travel_bound,
4161                            noise_margin: tol.tail_noise_floor,
4162                        });
4163                    }
4164                    None
4165                }
4166                AsymptoteVerdict::OnTailNotYetEquivalent { .. } => None,
4167                AsymptoteVerdict::NoAsymptote { reason } => {
4168                    Some(format!("{reason}; probes: {rows}"))
4169                }
4170            },
4171            (None, rows) => Some(format!(
4172                "no finite-difference-clean tail run; probes: {rows}"
4173            )),
4174        };
4175        if let Some(reason) = verdict {
4176            decline = Some(format!("candidate k={k} tail unconfirmed: {reason}"));
4177            break;
4178        }
4179    }
4180    // #2349 round 7: a multi-coordinate rail face. When a candidate's OWN
4181    // one-dimensional tail law fails and several candidates ride out together,
4182    // the marginal law is the wrong object — overlapping penalties share range
4183    // space, so a lone coordinate's gradient saturates once the others
4184    // dominate the shared term (the measured #2349 ladder swept ĉ₀ across 8
4185    // orders of magnitude). The scalar section along the joint face direction
4186    // has the ordinary exponential tail; certify THAT with the same
4187    // discipline, and mint every face coordinate from the joint law.
4188    // A face confirmed through the JOINT fallback snaps as a WAYPOINT, never a
4189    // candidate optimum: the joint law certifies the direction of the optimum,
4190    // but individual face coordinates can hold interior optima once the others
4191    // sit railed (measured on the #2349 fixture: after snapping the 5-face,
4192    // coordinate 0's own gradient crossed zero near ρ₀ ≈ 7.5 — 4.5 e-folds
4193    // inside its snapped rail — while V dropped 3.86 from the checkpoint). The
4194    // reseed retry re-descends from the snapped point with the rails free to
4195    // hold or relax; a direct re-certification there would refuse exactly that
4196    // relaxation.
4197    if decline.is_some() && candidates.len() >= 2 {
4198        let (window, joint_rows) =
4199            probe_joint_tail_window(obj, rho, &candidates, &tol, (lower, upper))?;
4200        match window.as_ref().map(|w| assess_coordinate(w, &tol)) {
4201            Some(AsymptoteVerdict::CertifiedAtAsymptote {
4202                tail_constant,
4203                estimand_travel_bound,
4204                ..
4205            }) => {
4206                // Extrapolate the joint law back to the checkpoint: the true
4207                // remaining directional gradient there, immune to the local
4208                // instrument noise. All face gradients share one sign
4209                // structure along the face, so the joint gap bounds each
4210                // coordinate's own remaining gradient.
4211                let r0 = candidates
4212                    .iter()
4213                    .map(|(k, side)| match side {
4214                        AsymptoteSide::Upper => rho[*k],
4215                        AsymptoteSide::Lower => -rho[*k],
4216                    })
4217                    .sum::<f64>()
4218                    / candidates.len() as f64;
4219                let joint_gap = tail_constant * (-r0).exp();
4220                if joint_gap.is_finite() && joint_gap <= inputs.stationarity_bound {
4221                    at_point_rails = candidates
4222                        .iter()
4223                        .map(|(k, side)| RailCoordinate {
4224                            index: *k,
4225                            side: *side,
4226                            tail_constant,
4227                            value_gap: joint_gap,
4228                            estimand_travel_bound,
4229                            noise_margin: tol.tail_noise_floor,
4230                        })
4231                        .collect();
4232                }
4233                decline = None;
4234            }
4235            Some(AsymptoteVerdict::OnTailNotYetEquivalent { .. }) => {
4236                // Confirmed on the joint tail; travel not yet settled — the
4237                // face snaps/reseeds below exactly as a confirmed single
4238                // candidate would.
4239                decline = None;
4240            }
4241            Some(AsymptoteVerdict::NoAsymptote { reason }) => {
4242                // A returned window IS the law: it exists only when a
4243                // drift-band-clean, above-noise-floor, uniformly-positive
4244                // pencil-constant run of MIN_TAIL_SAMPLES was found, so the
4245                // only `NoAsymptote` reachable from it is the estimand
4246                // contraction gate — the β-steps in the retained (deep
4247                // interior) rows still move, i.e. the checkpoint is genuinely
4248                // NOT at the face limit yet (measured on the #2349 checkpoint:
4249                // ĉ settled to 34.2 over the last four probes while the crawl
4250                // was still travelling). That is the same state as
4251                // `OnTailNotYetEquivalent`: the law says WHERE the optimum is;
4252                // the snap below reoptimizes from the face, granting nothing
4253                // by itself.
4254                log::info!(
4255                    "[CERTIFICATE] joint {}-coordinate face: pencil-constant run \
4256                     confirmed but estimand not settled at the checkpoint \
4257                     ({reason}); snapping the face for re-optimization",
4258                    candidates.len(),
4259                );
4260                decline = None;
4261            }
4262            None => {
4263                decline = Some(format!(
4264                    "{}; joint {}-coordinate face: no finite-difference-clean run; joint probes: {joint_rows}",
4265                    decline.take().unwrap_or_default(),
4266                    candidates.len(),
4267                ));
4268            }
4269        }
4270    }
4271    // The probes warm-started the inner solve away from the checkpoint; every
4272    // exit below leaves the CURRENT point as the shipped state, so restore it
4273    // before returning. A failure here is a genuinely broken objective.
4274    obj.eval_cost(rho).map_err(|err| {
4275        EstimationError::RemlOptimizationFailed(format!(
4276            "{}: failed to restore the objective to the certified point after \
4277             tail-snap probing: {err}",
4278            inputs.context
4279        ))
4280    })?;
4281    if let Some(reason) = decline {
4282        return Ok(TailSnapOutcome::Declined(reason));
4283    }
4284
4285    let interior_indices: Vec<usize> = (0..n)
4286        .filter(|k| !inputs.railed.contains(k) && !candidates.iter().any(|(c, _)| c == k))
4287        .collect();
4288    // #2348 Inc 2c: every candidate's confirmed tail already extrapolates
4289    // BELOW the stationarity bound at the current point — the fit is
4290    // tail-stationary where it stands and the measured local gradient is
4291    // instrument noise. Judge the interior with the shared two-stage
4292    // criterion (`certify_interior_stationarity`): the raw bound, then the
4293    // curvature-scaled flat-valley bound on the interior SUB-BLOCK (the
4294    // full-Hessian widening is unavailable here exactly because the
4295    // noise-corrupted tail entry makes the full matrix non-PD).
4296    if at_point_rails.len() == candidates.len() {
4297        if let Ok((interior_projected_grad_norm, effective_interior_bound)) =
4298            certify_interior_stationarity(
4299                gradient,
4300                hessian,
4301                &interior_indices,
4302                inputs.stationarity_bound,
4303                inputs.objective_tol,
4304            )
4305        {
4306            return Ok(TailSnapOutcome::TailStationaryAtPoint {
4307                rails: at_point_rails,
4308                interior_projected_grad_norm,
4309                effective_interior_bound,
4310            });
4311        }
4312        // Real interior descent remains: fall through to the reseed path so
4313        // one more optimizer pass polishes it.
4314    }
4315
4316    let mut snapped = rho.clone();
4317    for (k, side) in &candidates {
4318        snapped[*k] = match side {
4319            AsymptoteSide::Upper => upper[*k],
4320            AsymptoteSide::Lower => lower[*k],
4321        };
4322    }
4323
4324    // Tails confirmed, but a finite snap can change every coupled coordinate's
4325    // optimum even when its PRE-snap gradient was stationary (#2358 measured
4326    // the location-scale interior gradient jumping to 0.5). The snap proves a
4327    // direction and supplies a waypoint; only a resumed optimization and its
4328    // subsequent certificate can prove the endpoint.
4329    Ok(TailSnapOutcome::ConfirmedNeedsReseed(snapped))
4330}
4331
4332/// Reconstruct one railed coordinate's exponential tail by probing the analytic
4333/// gradient back from the rail at coarse and, when needed, local resolution;
4334/// locate the longest finite-difference-clean run (rejecting the noise floor
4335/// adjacent to the rail); and assess it against the tail law (#2348 Inc 1 /
4336/// #2337 Thm 2.1). Returns the certified [`RailCoordinate`] or `None` if no
4337/// confirmable tail is found.
4338fn build_and_assess_rail_coordinate(
4339    obj: &mut dyn OuterObjective,
4340    rho: &Array1<f64>,
4341    coord: usize,
4342    side: AsymptoteSide,
4343    tol: &AsymptoteTolerances,
4344    domain: (f64, f64),
4345) -> Result<Result<RailCoordinate, String>, EstimationError> {
4346    let window = match probe_tail_window(obj, rho, coord, side, tol, domain)? {
4347        (Some(window), _) => window,
4348        (None, rows) => {
4349            // #2450: name the floor instead of leaving the reader to find it.
4350            // The criterion ALWAYS carries the soft rho-guard barrier
4351            // (`soft_rho_guard_prior_atom`), and a `log cosh` barrier's gradient
4352            // SATURATES to `w*a` rather than decaying, so once the REML tail
4353            // falls below it, `c_hat = -e^rho * dV/drho` diverges and no tail is
4354            // observable THROUGH the guard at any box width or probe count. That
4355            // is a different failure from a noisy or truncated window, and
4356            // reporting both as "no finite-difference-clean tail window" cost
4357            // real time: it reads as a fixture/conditioning problem when it is a
4358            // property of the objective. Measured: the floor is exactly
4359            // `w*a*tanh(a*rho)` = 1.3324e-7 at rho=30 against a predicted
4360            // 1.3324e-7 (five significant figures, every coordinate).
4361            let guard_floor = crate::estimate::RHO_SOFT_PRIOR_WEIGHT
4362                * (crate::estimate::RHO_SOFT_PRIOR_SHARPNESS / crate::estimate::RHO_BOUND);
4363            return Ok(Err(format!(
4364                "k={coord}: no finite-difference-clean tail window; note the soft \
4365                 rho-guard gradient saturates at w*a={guard_floor:.4e} (#2450), so any \
4366                 tail whose |dV/drho| is at or below that is unobservable through the \
4367                 guard rather than merely unclean; probes {rows}"
4368            )));
4369        }
4370    };
4371    match assess_coordinate(&window, tol) {
4372        AsymptoteVerdict::CertifiedAtAsymptote {
4373            side,
4374            tail_constant,
4375            value_gap,
4376            estimand_travel_bound,
4377        } => Ok(Ok(RailCoordinate {
4378            index: coord,
4379            side,
4380            tail_constant,
4381            value_gap,
4382            estimand_travel_bound,
4383            noise_margin: tol.tail_noise_floor,
4384        })),
4385        other => Ok(Err(format!("k={coord}: tail verdict {other:?}"))),
4386    }
4387}
4388
4389/// Detect a WRONG-RAIL coordinate (#2392): one sitting AT its ρ box bound whose
4390/// clean-band probes prove the objective strictly DECREASES as the coordinate
4391/// moves INWARD — the outer search drove it to the wrong bound. Returns the
4392/// interior ρ to reseed the coordinate at (the deepest drift-clean probe, where
4393/// `|g|` is largest and the descent is most informative) when the proof holds,
4394/// else `None`.
4395///
4396/// # Proof condition (evidence-gated; cannot launder a genuine λ→∞ / λ→0 optimum)
4397///
4398/// Probe [`ASYMPTOTE_PROBE_COUNT`] e-folds inward and require a contiguous run of
4399/// at least [`MIN_TAIL_SAMPLES`] probes that is, at once:
4400/// 1. above the gradient interior floor, `|g| > interior_grad_tol` (so a probe
4401///    whose gradient has decayed into finite-difference cancellation next to the
4402///    rail is excluded rather than read as a settled tail);
4403/// 2. above the pencil-constant noise floor, `|ĉ| > tail_noise_floor`, where
4404///    `ĉ = side.tail_constant(ρ, g)` uses the coordinate's ACTUAL rail side;
4405/// 3. drift-band-clean in `ĉ` within `tail_drift_rel` (the same constant-pencil
4406///    band the genuine tail uses — `run_drift_within_band` keys on `|mean|`, so a
4407///    uniformly-negative run is judged on its magnitude); AND
4408/// 4. `ĉ` uniformly of the sign OPPOSITE a genuine tail — `ĉ < 0` — i.e. the
4409///    descent direction points AWAY from the bound (`∂V/∂ρ > 0` at an upper rail,
4410///    `∂V/∂ρ < 0` at a lower rail).
4411///
4412/// A genuine rail (descent TOWARD the bound) has `ĉ > 0` across the clean run and
4413/// never satisfies (4), so it is never pulled off its rail. This shares every
4414/// tolerance with the genuine asymptote path ([`AsymptoteTolerances`]); the ONLY
4415/// difference is the sign gate in (4).
4416fn detect_wrong_rail_pullback(
4417    obj: &mut dyn OuterObjective,
4418    rho: &Array1<f64>,
4419    coord: usize,
4420    side: AsymptoteSide,
4421    tol: &AsymptoteTolerances,
4422    domain: (f64, f64),
4423) -> Result<Option<f64>, EstimationError> {
4424    const PROBE_DELTA: f64 = 1.0;
4425    const PROBE_DOMAIN_MARGIN: f64 = 1.0e-6;
4426    // Upper rail (ρ → +∞): step ρ DOWN into the interior. Lower rail: step UP.
4427    let sign = match side {
4428        AsymptoteSide::Upper => -1.0,
4429        AsymptoteSide::Lower => 1.0,
4430    };
4431    // rows[r] is probe j=r+1: r=0 is CLOSEST to the rail, increasing r steps
4432    // further into the interior (larger |grad| on a clean run).
4433    let mut rows: Vec<(f64, f64)> = Vec::new();
4434    for j in 1..=ASYMPTOTE_PROBE_COUNT {
4435        let stepped = rho[coord] + sign * (j as f64) * PROBE_DELTA;
4436        if stepped <= domain.0 + PROBE_DOMAIN_MARGIN || stepped >= domain.1 - PROBE_DOMAIN_MARGIN {
4437            break;
4438        }
4439        let mut probe = rho.clone();
4440        probe[coord] = stepped;
4441        let eval = match obj.eval_with_order(&probe, OuterEvalOrder::ValueAndGradient) {
4442            Ok(eval) => eval,
4443            Err(_) => break,
4444        };
4445        if !eval.cost.is_finite() || coord >= eval.gradient.len() || !eval.gradient[coord].is_finite()
4446        {
4447            break;
4448        }
4449        rows.push((stepped, eval.gradient[coord]));
4450    }
4451    if rows.len() < MIN_TAIL_SAMPLES {
4452        return Ok(None);
4453    }
4454    let constants: Vec<f64> = rows
4455        .iter()
4456        .map(|(r, g)| side.tail_constant(*r, *g))
4457        .collect();
4458    // Wrong-rail element-clean: gradient above the interior floor, pencil
4459    // constant above the noise floor IN MAGNITUDE, and of the descent-inward
4460    // (negative) sign. Genuine tails have ĉ > 0 here and are excluded.
4461    let element_clean: Vec<bool> = rows
4462        .iter()
4463        .zip(&constants)
4464        .map(|((_, g), c)| {
4465            c.is_finite() && *c < -tol.tail_noise_floor && g.abs() > tol.interior_grad_tol
4466        })
4467        .collect();
4468    // Longest contiguous element-clean, drift-band-clean run; reseed the
4469    // coordinate at the DEEPEST such probe (largest |g|, closest to the true
4470    // interior optimum the descent points toward).
4471    let mut best: Option<(usize, usize)> = None;
4472    for a in 0..rows.len() {
4473        if !element_clean[a] {
4474            continue;
4475        }
4476        for b in a..rows.len() {
4477            if !element_clean[b] {
4478                break;
4479            }
4480            if b - a + 1 < MIN_TAIL_SAMPLES {
4481                continue;
4482            }
4483            if !run_drift_within_band(&constants[a..=b], tol.tail_drift_rel) {
4484                continue;
4485            }
4486            match best {
4487                Some((ba, bb)) if bb - ba + 1 >= b - a + 1 => {}
4488                _ => best = Some((a, b)),
4489            }
4490        }
4491    }
4492    Ok(best.map(|(_, b)| rows[b].0))
4493}
4494
4495/// Probe one coordinate's tail toward the interior (the shared probing engine
4496/// of [`build_and_assess_rail_coordinate`] and the certify-time tail snap).
4497/// The one-e-fold ladder runs first; if it finds no clean run, a short
4498/// half-e-fold ladder resolves a narrower local band without mixing step sizes
4499/// in one estimand window. Returns the longest finite-difference-clean
4500/// constant-`ĉ` run (newest sample nearest `rho[coord]`), or `None` when neither
4501/// resolution contains at least [`MIN_TAIL_SAMPLES`] clean rows. The second
4502/// element dumps `(ρ, ∂V/∂ρ, ĉ)` evidence for every attempted resolution.
4503fn probe_tail_window(
4504    obj: &mut dyn OuterObjective,
4505    rho: &Array1<f64>,
4506    coord: usize,
4507    side: AsymptoteSide,
4508    tol: &AsymptoteTolerances,
4509    domain: (f64, f64),
4510) -> Result<(Option<AsymptoteWindow>, String), EstimationError> {
4511    let (coarse_window, coarse_rows) = probe_tail_window_at_resolution(
4512        obj,
4513        rho,
4514        coord,
4515        side,
4516        tol,
4517        domain,
4518        (1.0, ASYMPTOTE_PROBE_COUNT),
4519    )?;
4520    if coarse_window.is_some() {
4521        return Ok((coarse_window, coarse_rows));
4522    }
4523
4524    // The coarse ladder is deliberately retained as the first pass: railed
4525    // dense REML fits can have several e-folds of cancellation noise beside
4526    // the box followed by a clean band far inside it. The local pass addresses
4527    // the complementary geometry exposed by #2358, where a modest finite box
4528    // contains a narrow but regular tail and unit steps skip over it.
4529    let (local_window, local_rows) = probe_tail_window_at_resolution(
4530        obj,
4531        rho,
4532        coord,
4533        side,
4534        tol,
4535        domain,
4536        (
4537            ASYMPTOTE_LOCAL_PROBE_DELTA,
4538            ASYMPTOTE_LOCAL_PROBE_COUNT,
4539        ),
4540    )?;
4541    Ok((
4542        local_window,
4543        format!("coarse[{coarse_rows}] local[{local_rows}]"),
4544    ))
4545}
4546
4547/// Probe a single equally-spaced resolution of one coordinate's tail.
4548///
4549/// Keeping each returned window at one resolution is essential for
4550/// [`assess_coordinate`]: its coefficient-travel bound estimates a geometric
4551/// ratio from consecutive steps, which is only meaningful when their `Δρ`
4552/// values are identical.
4553fn probe_tail_window_at_resolution(
4554    obj: &mut dyn OuterObjective,
4555    rho: &Array1<f64>,
4556    coord: usize,
4557    side: AsymptoteSide,
4558    tol: &AsymptoteTolerances,
4559    domain: (f64, f64),
4560    resolution: (f64, usize),
4561) -> Result<(Option<AsymptoteWindow>, String), EstimationError> {
4562    let (probe_delta, probe_count) = resolution;
4563    // Strictly-inside guard for probes against the probed coordinate's own box
4564    // interval (#2388). The ρ-gradient assembly freezes any coordinate at (or
4565    // within 1e-8 of) its recorded upper bound to the #197 KKT projection — a
4566    // literal 0.0 — so a probe at or past a box bound samples the frozen-axis
4567    // convention, not the criterion's tail: a fabricated hard-zero tail that
4568    // the drift band can never confirm. Out-of-box points are outside the
4569    // λ-selection domain altogether; they are not evidence for or against a
4570    // tail, so the ladder stops at the last strictly-in-domain probe.
4571    const PROBE_DOMAIN_MARGIN: f64 = 1.0e-6;
4572    // Upper rail (ρ → +∞): step ρ DOWN into the tail. Lower rail: step UP.
4573    let sign = match side {
4574        AsymptoteSide::Upper => -1.0,
4575        AsymptoteSide::Lower => 1.0,
4576    };
4577    // rows[r] corresponds to probe j=r+1: r=0 is the point CLOSEST to the rail,
4578    // increasing r steps further into the interior (larger |grad|).
4579    let mut rows: Vec<(f64, f64, Option<Array1<f64>>)> = Vec::new();
4580    for j in 1..=probe_count {
4581        let stepped = rho[coord] + sign * (j as f64) * probe_delta;
4582        if stepped <= domain.0 + PROBE_DOMAIN_MARGIN || stepped >= domain.1 - PROBE_DOMAIN_MARGIN {
4583            break;
4584        }
4585        let mut probe = rho.clone();
4586        probe[coord] = stepped;
4587        let eval = match obj.eval_with_order(&probe, OuterEvalOrder::ValueAndGradient) {
4588            Ok(eval) => eval,
4589            // A failed probe is not evidence against a tail; stop probing and
4590            // assess whatever clean run the earlier probes established.
4591            Err(_) => break,
4592        };
4593        if !eval.cost.is_finite()
4594            || coord >= eval.gradient.len()
4595            || !eval.gradient[coord].is_finite()
4596        {
4597            break;
4598        }
4599        rows.push((probe[coord], eval.gradient[coord], eval.inner_beta_hint));
4600    }
4601    let rows_summary = rows
4602        .iter()
4603        .map(|(r, g, _)| {
4604            format!(
4605                "(ρ={r:.2}, g={g:.3e}, ĉ={:.3e})",
4606                side.tail_constant(*r, *g)
4607            )
4608        })
4609        .collect::<Vec<_>>()
4610        .join(" ");
4611    if rows.len() < MIN_TAIL_SAMPLES {
4612        return Ok((None, rows_summary));
4613    }
4614
4615    // Per-row pencil constant ĉ and the element-clean predicate: ĉ above the
4616    // noise floor AND the gradient above the interior floor (so a row adjacent to
4617    // the rail, whose gradient has decayed into finite-difference cancellation, is
4618    // excluded rather than mistaken for a settled tail).
4619    let constants: Vec<f64> = rows
4620        .iter()
4621        .map(|(r, g, _)| side.tail_constant(*r, *g))
4622        .collect();
4623    let element_clean: Vec<bool> = rows
4624        .iter()
4625        .zip(&constants)
4626        .map(|((_, g, _), c)| {
4627            c.is_finite() && *c > tol.tail_noise_floor && g.abs() > tol.interior_grad_tol
4628        })
4629        .collect();
4630
4631    // Longest contiguous run that is element-clean AND holds ĉ within the drift
4632    // band; ties broken toward the rail (smallest start) for the most settled
4633    // estimand.
4634    let mut best: Option<(usize, usize)> = None;
4635    for a in 0..rows.len() {
4636        if !element_clean[a] {
4637            continue;
4638        }
4639        for b in a..rows.len() {
4640            if !element_clean[b] {
4641                break;
4642            }
4643            if b - a + 1 < MIN_TAIL_SAMPLES {
4644                continue;
4645            }
4646            if !run_drift_within_band(&constants[a..=b], tol.tail_drift_rel) {
4647                continue;
4648            }
4649            let len = b - a + 1;
4650            match best {
4651                Some((ba, bb)) if bb - ba + 1 >= len => {}
4652                _ => best = Some((a, b)),
4653            }
4654        }
4655    }
4656    let (a, b) = match best {
4657        Some(run) => run,
4658        None => return Ok((None, rows_summary)),
4659    };
4660
4661    // Build the window oldest → newest: newest (window `latest`) is the row
4662    // CLOSEST to the rail (r=a). A sample's coefficient move is ‖β(r) − β(r+1)‖,
4663    // the step from the next-farther retained row toward the rail.
4664    let mut window = AsymptoteWindow::with_capacity(b - a + 1);
4665    for r in (a..=b).rev() {
4666        let (rho_r, grad_r, beta_r) = &rows[r];
4667        let coef_step_norm = match (beta_r, rows.get(r + 1).map(|row| &row.2)) {
4668            (Some(cur), Some(Some(farther))) if cur.len() == farther.len() => {
4669                (cur - farther).iter().map(|v| v * v).sum::<f64>().sqrt()
4670            }
4671            _ => 0.0,
4672        };
4673        window.push(AsymptoteSample {
4674            rho: *rho_r,
4675            grad: *grad_r,
4676            coef_step_norm,
4677        });
4678    }
4679
4680    Ok((Some(window), rows_summary))
4681}
4682
4683/// Probe a JOINT multi-coordinate rail face (#2349 round 7 / #2348): step every
4684/// face coordinate one e-fold toward the interior TOGETHER and assess the
4685/// directional gradient along the outward face direction against the same
4686/// exponential tail law, noise floor, and drift band as the single-coordinate
4687/// window.
4688///
4689/// Why a joint law exists where the per-coordinate laws fail: for OVERLAPPING
4690/// penalties (e.g. the multinomial per-class family's coalesced pseudo-logdet
4691/// `½log|Σ_s λ_s M_s|₊`) several λs ride to ∞ on one face and share range
4692/// space. Moving ONE coordinate down leaves the shared term dominated by the
4693/// others, so that coordinate's own gradient saturates and its per-probe pencil
4694/// constant `ĉ_k = |g_k|e^{ρ_k}` sweeps orders of magnitude — measured on the
4695/// #2349 checkpoint: ĉ₀ spanning 4.5e2 → 1.0e-6 over the ladder, an honest
4696/// refusal of a law that genuinely does not hold marginally. Along the face
4697/// direction `u` (`u_k = +1` toward an upper rail, `−1` toward a lower rail)
4698/// the shared term moves coherently and the scalar objective section
4699/// `t ↦ V(ρ + t·u)` has the ordinary one-dimensional exponential tail; its
4700/// pencil constant is assessed with the pseudo-coordinate `r = mean_k(u_k ρ_k)`
4701/// and the directional derivative `g_u = Σ_{k∈face} u_k g_k = dV/dt`.
4702///
4703/// The window it returns speaks the [`assess_coordinate`] conventions
4704/// verbatim: on a genuine face `g_u < 0` at every interior probe (descent runs
4705/// outward), so the verdict side is `Upper` in the pseudo-coordinate
4706/// regardless of the mix of physical sides, and `ĉ = −e^{r}·g_u` recovers the
4707/// joint tail constant. Per-coordinate rails minted from it keep their own
4708/// physical [`AsymptoteSide`].
4709fn probe_joint_tail_window(
4710    obj: &mut dyn OuterObjective,
4711    rho: &Array1<f64>,
4712    face: &[(usize, AsymptoteSide)],
4713    tol: &AsymptoteTolerances,
4714    bounds: (&Array1<f64>, &Array1<f64>),
4715) -> Result<(Option<AsymptoteWindow>, String), EstimationError> {
4716    const PROBE_DELTA: f64 = 1.0;
4717    const PROBE_DOMAIN_MARGIN: f64 = 1.0e-6;
4718    let (lower, upper) = bounds;
4719    // Outward unit direction of the face; probes step INWARD (−u).
4720    let direction: Vec<(usize, f64)> = face
4721        .iter()
4722        .map(|(k, side)| {
4723            (
4724                *k,
4725                match side {
4726                    AsymptoteSide::Upper => 1.0,
4727                    AsymptoteSide::Lower => -1.0,
4728                },
4729            )
4730        })
4731        .collect();
4732    let r0 = direction
4733        .iter()
4734        .map(|(k, u)| u * rho[*k])
4735        .sum::<f64>()
4736        / direction.len() as f64;
4737    let mut rows: Vec<(f64, f64, Option<Array1<f64>>)> = Vec::new();
4738    for j in 1..=ASYMPTOTE_PROBE_COUNT {
4739        let step = (j as f64) * PROBE_DELTA;
4740        let mut probe = rho.clone();
4741        let mut in_domain = true;
4742        for (k, u) in &direction {
4743            let stepped = rho[*k] - u * step;
4744            if stepped <= lower[*k] + PROBE_DOMAIN_MARGIN
4745                || stepped >= upper[*k] - PROBE_DOMAIN_MARGIN
4746            {
4747                in_domain = false;
4748                break;
4749            }
4750            probe[*k] = stepped;
4751        }
4752        if !in_domain {
4753            break;
4754        }
4755        let eval = match obj.eval_with_order(&probe, OuterEvalOrder::ValueAndGradient) {
4756            Ok(eval) => eval,
4757            Err(_) => break,
4758        };
4759        if !eval.cost.is_finite() {
4760            break;
4761        }
4762        let mut g_u = 0.0;
4763        let mut finite = true;
4764        for (k, u) in &direction {
4765            match eval.gradient.get(*k) {
4766                Some(g) if g.is_finite() => g_u += u * g,
4767                _ => {
4768                    finite = false;
4769                    break;
4770                }
4771            }
4772        }
4773        if !finite {
4774            break;
4775        }
4776        rows.push((r0 - step, g_u, eval.inner_beta_hint));
4777    }
4778    let rows_summary = rows
4779        .iter()
4780        .map(|(r, g, _)| {
4781            format!(
4782                "(r={r:.2}, dV/dt={g:.3e}, ĉ={:.3e})",
4783                AsymptoteSide::Upper.tail_constant(*r, *g)
4784            )
4785        })
4786        .collect::<Vec<_>>()
4787        .join(" ");
4788    if rows.len() < MIN_TAIL_SAMPLES {
4789        return Ok((None, rows_summary));
4790    }
4791    let constants: Vec<f64> = rows
4792        .iter()
4793        .map(|(r, g, _)| AsymptoteSide::Upper.tail_constant(*r, *g))
4794        .collect();
4795    let element_clean: Vec<bool> = rows
4796        .iter()
4797        .zip(&constants)
4798        .map(|((_, g, _), c)| {
4799            c.is_finite() && *c > tol.tail_noise_floor && g.abs() > tol.interior_grad_tol
4800        })
4801        .collect();
4802    let mut best: Option<(usize, usize)> = None;
4803    for a in 0..rows.len() {
4804        if !element_clean[a] {
4805            continue;
4806        }
4807        for b in a..rows.len() {
4808            if !element_clean[b] {
4809                break;
4810            }
4811            if b - a + 1 < MIN_TAIL_SAMPLES {
4812                continue;
4813            }
4814            if !run_drift_within_band(&constants[a..=b], tol.tail_drift_rel) {
4815                continue;
4816            }
4817            let len = b - a + 1;
4818            match best {
4819                Some((ba, bb)) if bb - ba + 1 >= len => {}
4820                _ => best = Some((a, b)),
4821            }
4822        }
4823    }
4824    let (a, b) = match best {
4825        Some(run) => run,
4826        None => return Ok((None, rows_summary)),
4827    };
4828    let mut window = AsymptoteWindow::with_capacity(b - a + 1);
4829    for r in (a..=b).rev() {
4830        let (rho_r, grad_r, beta_r) = &rows[r];
4831        let coef_step_norm = match (beta_r, rows.get(r + 1).map(|row| &row.2)) {
4832            (Some(cur), Some(Some(farther))) if cur.len() == farther.len() => {
4833                (cur - farther).iter().map(|v| v * v).sum::<f64>().sqrt()
4834            }
4835            _ => 0.0,
4836        };
4837        window.push(AsymptoteSample {
4838            rho: *rho_r,
4839            grad: *grad_r,
4840            coef_step_norm,
4841        });
4842    }
4843    Ok((Some(window), rows_summary))
4844}
4845
4846/// Whether a run of pencil constants holds constant within the relative drift
4847/// band `(max − min)/|mean| ≤ band` (deterministic, ordered).
4848fn run_drift_within_band(constants: &[f64], band: f64) -> bool {
4849    if constants.len() < MIN_TAIL_SAMPLES {
4850        return false;
4851    }
4852    let mut sum = 0.0_f64;
4853    let mut lo = f64::INFINITY;
4854    let mut hi = f64::NEG_INFINITY;
4855    for &c in constants {
4856        if !c.is_finite() {
4857            return false;
4858        }
4859        sum += c;
4860        lo = lo.min(c);
4861        hi = hi.max(c);
4862    }
4863    let mean = sum / constants.len() as f64;
4864    if !(mean.abs() > 0.0) {
4865        return false;
4866    }
4867    (hi - lo) / mean.abs() <= band
4868}
4869
4870pub(crate) fn compute_rho_uncertainty_diagnostic(
4871    obj: &mut dyn OuterObjective,
4872    config: &OuterConfig,
4873    context: &str,
4874    result: &mut OuterResult,
4875) -> crate::rho_uncertainty::RhoUncertaintyDiagnostic {
4876    let terminal_cap_guard = config
4877        .outer_inner_cap
4878        .as_ref()
4879        .map(TerminalInnerCapGuard::lift);
4880    // Do not reset here. The diagnostic intentionally runs before terminal
4881    // installation and certification; the certificate must remain the final
4882    // owner of objective state. Holding cap=0 ensures proposal evaluations use
4883    // terminal fidelity, and the selected point is reinstalled immediately
4884    // afterward before the mint audit.
4885    let diagnostic =
4886        compute_rho_uncertainty_diagnostic_at_terminal_fidelity(obj, config, context, result);
4887    drop(terminal_cap_guard);
4888    diagnostic
4889}
4890
4891fn compute_rho_uncertainty_diagnostic_at_terminal_fidelity(
4892    obj: &mut dyn OuterObjective,
4893    config: &OuterConfig,
4894    context: &str,
4895    result: &mut OuterResult,
4896) -> crate::rho_uncertainty::RhoUncertaintyDiagnostic {
4897    let cap = obj.capability();
4898    let layout = cap.theta_layout();
4899    let rho_dim = layout.rho_dim();
4900    let gate = crate::rho_uncertainty::RhoUncertaintyCostGate {
4901        sample_count: 32,
4902        problem_size: config.rho_uncertainty_problem_size,
4903    };
4904    if let Err(reason) = crate::rho_uncertainty::cost_gate_allows(rho_dim, gate) {
4905        return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(reason, 0);
4906    }
4907    if result.rho.len() != layout.n_params {
4908        return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(
4909            format!(
4910                "final outer point length {} does not match objective dimension {}",
4911                result.rho.len(),
4912                layout.n_params
4913            ),
4914            0,
4915        );
4916    }
4917    // The ρ-uncertainty diagnostic needs the EXACT outer Hessian, but it runs
4918    // BEFORE terminal certification so that the certificate remains the final
4919    // owner of objective state. Under the optimize-3/certify-4 protocol (#2359)
4920    // this diagnostic may therefore consume only curvature the SEARCH already
4921    // retained. It must never trigger its own `ValueGradientHessian` evaluation:
4922    // a gradient-only search has deliberately reserved that one order-four pass
4923    // for the mint gate. Such a search skips this optional diagnostic; the
4924    // terminal certificate still computes and persists exact curvature.
4925    if !cap.hessian.is_analytic() {
4926        return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(
4927            "outer Hessian is not analytic; rho-uncertainty diagnostic needs exact curvature",
4928            0,
4929        );
4930    }
4931    if result.plan_used.hessian_source != HessianSource::Analytic {
4932        return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(
4933            "search did not use exact outer curvature; order-four work is reserved for the terminal certificate",
4934            0,
4935        );
4936    }
4937
4938    let hessian = match result.final_hessian.as_ref() {
4939        Some(hessian) => hessian.clone(),
4940        None => {
4941            return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(
4942                "search retained no exact outer Hessian; order-four work is reserved for the terminal certificate",
4943                0,
4944            );
4945        }
4946    };
4947    if hessian.nrows() != layout.n_params || hessian.ncols() != layout.n_params {
4948        return crate::rho_uncertainty::RhoUncertaintyDiagnostic::skipped(
4949            format!(
4950                "exact outer Hessian shape {}x{} does not match objective dimension {}",
4951                hessian.nrows(),
4952                hessian.ncols(),
4953                layout.n_params
4954            ),
4955            1,
4956        );
4957    }
4958    let mut hessian_rho = Array2::<f64>::zeros((rho_dim, rho_dim));
4959    for row in 0..rho_dim {
4960        for col in 0..rho_dim {
4961            hessian_rho[[row, col]] = hessian[[row, col]];
4962        }
4963    }
4964    let rho_hat = result.rho.slice(ndarray::s![..rho_dim]).to_owned();
4965    let theta_hat = result.rho.clone();
4966    let cost_hat = result.final_value;
4967    let diagnostic = {
4968        let mut served_hat_cost = false;
4969        let mut criterion = |rho: &Array1<f64>| -> Option<f64> {
4970            let is_hat = rho.len() == rho_hat.len()
4971                && rho
4972                    .iter()
4973                    .zip(rho_hat.iter())
4974                    .all(|(&left, &right)| left.to_bits() == right.to_bits());
4975            if is_hat && !served_hat_cost {
4976                served_hat_cost = true;
4977                return Some(cost_hat);
4978            }
4979            let mut theta = theta_hat.clone();
4980            for idx in 0..rho_dim {
4981                theta[idx] = rho[idx];
4982            }
4983            obj.eval_cost(&theta).ok()
4984        };
4985        crate::rho_uncertainty::rho_uncertainty_diagnostic(
4986            &rho_hat,
4987            &hessian_rho,
4988            gate,
4989            &mut criterion,
4990        )
4991    };
4992    match &diagnostic.status {
4993        crate::rho_uncertainty::RhoUncertaintyStatus::NoEvidenceOfHeavyTails => {
4994            log::info!(
4995                "[RHO uncertainty] {context}: no heavy-tail evidence at sampled rho proposals k_hat={:.3} evals={}",
4996                diagnostic.k_hat.unwrap_or(f64::NAN),
4997                diagnostic.n_evaluations,
4998            );
4999        }
5000        crate::rho_uncertainty::RhoUncertaintyStatus::HeavyTailsDetected { k_hat } => {
5001            log::warn!(
5002                "[RHO uncertainty] {context}: heavy rho-importance tail detected k_hat={:.3} evals={}",
5003                k_hat,
5004                diagnostic.n_evaluations,
5005            );
5006        }
5007        crate::rho_uncertainty::RhoUncertaintyStatus::Skipped { reason } => {
5008            log::info!("[RHO uncertainty] {context}: skipped ({reason})");
5009        }
5010    }
5011    diagnostic
5012}
5013
5014#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5015pub enum OperatorTrustRegionStopReason {
5016    Converged,
5017    RejectFloor,
5018    IterationBudget,
5019    /// The objective stopped changing on a criterion-flat surface. The
5020    /// in-loop guard may already have certified the score-relative residual or
5021    /// may have returned a non-stationary floor; either way the final analytic
5022    /// certificate needs this provenance to reproduce the guard's derived
5023    /// stationarity band exactly.
5024    CostStallFlatValley,
5025    /// Family returned a non-operator Hessian mid-flight after routing into
5026    /// the operator path. Best-effort `x_k` returned with this reason; the
5027    /// caller should consider re-fitting under a different solver class
5028    /// (e.g. BFGS gradient-only) instead of trusting the partial result.
5029    RoutingMismatch,
5030}
5031
5032/// Run the outer smoothing-parameter optimization.
5033///
5034/// This is the single entry point that replaces the scattered optimizer wiring
5035/// across estimate.rs, joint.rs, and custom_family.rs. It:
5036///
5037/// 1. Queries and canonicalizes the objective's capability declaration.
5038/// 2. Calls `plan()` to select solver + hessian source.
5039/// 3. Logs the plan and the analytic derivative capabilities it will consume.
5040/// 4. Generates seed candidates.
5041/// 5. Runs the chosen solver on candidates in heuristic order up to budget.
5042/// 6. If the configured fallback policy allows it, re-plans with degraded
5043///    capabilities chosen centrally inside outer_strategy and retries.
5044/// 7. Returns the best result (including which plan was actually used).
5045///
5046/// Do not wrap `run_outer` calls in try/catch with ad-hoc solver recovery.
5047/// Callers should declare only the primary capability and, at most, whether
5048/// automatic fallback is enabled at all.
5049///
5050/// Bound on the certify-last checkpoint-resume loop (#2273/#2374). When a
5051/// solver CLAIMS convergence but the mandatory analytic certificate refuses,
5052/// the loop re-runs the outer search seeded AT the refused checkpoint (with a
5053/// fresh metric for gradient-only outers, since `final_hessian` is `None`)
5054/// while each resume strictly reduces the objective — real descent the claim
5055/// left unexploited. #2273 introduced this as a SINGLE retry for the
5056/// stale-tolerance desync (one reseed re-anchors the in-loop tolerance to the
5057/// terminal cost scale and certifies). #2374 generalized it to a
5058/// progress-bounded loop: a gradient-only `opt::Bfgs` outer in log-λ space can
5059/// exit its flat-valley `StallPolicy` at `‖g‖∞ ≤ tol·(1 + ‖ρ‖∞)` — a gate
5060/// inflated ~10× by a railed coordinate — reporting `Ok(converged)` at a
5061/// checkpoint whose projected gradient the un-inflated certificate correctly
5062/// rejects, and a single fresh-metric reseed rarely lands the optimum in one
5063/// hop (the transformation-survival LAML of #2373 needed two). This bound caps
5064/// how many such reseeds are attempted before the honest non-convergence is
5065/// surfaced; a fit that certifies on the first pass never enters the loop, and
5066/// a reseed that fails to reduce the objective (a genuine non-stationary floor
5067/// a fresh metric cannot escape) stops the loop immediately regardless of the
5068/// remaining budget.
5069const OUTER_CERTIFY_RESUME_BUDGET: usize = 16;
5070
5071/// Max interior strict-saddle escape resumes (#2357/#2155). A genuine saddle is
5072/// cleared in one escape; the small cap keeps a pathological non-convergent
5073/// objective (e.g. a bimodal inner solve, #2363) from re-escaping a family of
5074/// shallow saddles until the general resume budget is spent.
5075pub(crate) const OUTER_SADDLE_ESCAPE_BUDGET: usize = 3;
5076
5077/// Roundoff-relative scale below which a certify-last reseed's objective
5078/// reduction is numerical noise rather than exploited descent (#2374). A
5079/// fresh-metric BFGS restart seeded AT the refused checkpoint can only reduce
5080/// the objective from that checkpoint, so `retried == prior` (to roundoff)
5081/// means the restart found no descent — a genuine stationary floor — while a
5082/// false flat-valley stall yields a reduction orders of magnitude above this
5083/// scale. The progress gate MUST anchor on roundoff, not the much larger
5084/// cost-stall relative floor: a flat valley crawls out in per-reseed steps far
5085/// smaller than `rel_cost·(1 + |cost|)` (the transformation-survival LAML moves
5086/// ~4e-5 relative per reseed), and gating on that coarser floor stops the crawl
5087/// after a single hop and refuses a well-posed fit.
5088const CERTIFY_RESUME_PROGRESS_REL: f64 = 32.0 * f64::EPSILON;
5089
5090pub(crate) fn run_outer(
5091    obj: &mut dyn OuterObjective,
5092    config: &OuterConfig,
5093    context: &str,
5094) -> Result<OuterResult, EstimationError> {
5095    // Permutation-invariant outer search (#1538/#1539). When the caller has
5096    // supplied per-coordinate structural keys that induce a non-identity
5097    // canonical order, run the ENTIRE outer pipeline (seeding, multistart,
5098    // optimization, and the #934 certificate / uncertainty audits) in that
5099    // canonical layout against a permuting wrapper, then map the result back to
5100    // the native layout. Seeding/tie-breaking then see byte-identical
5101    // coordinates for every term order, so both orders select the same λ̂.
5102    if let Some(keys) = config.rho_canonical_keys.as_ref()
5103        && let Some(perm) = canonical_permutation(keys)
5104    {
5105        let canonical_config = canonicalize_outer_config(config, &perm);
5106        let mut canonical_obj = CanonicalizedObjective::new(obj, perm.clone());
5107        let result = run_outer(&mut canonical_obj, &canonical_config, context)?;
5108        return Ok(outer_result_to_native(result, &perm));
5109    }
5110    let mut result = run_outer_uncertified(obj, config, context)?;
5111    if obj.begin_exact_polish() {
5112        // A sampled outer-derivative pilot is an optimization stage, never a
5113        // certifiable objective. Continue from its best checkpoint on the
5114        // family's exact full-data measure before the mandatory analytic
5115        // certificate. This transition is unconditional whenever the family
5116        // reports that a sample actually ran, so convergence before a nominal
5117        // phase budget cannot strand the optimizer on the stochastic surface
5118        // (#979: matrix-free TR stopped after 6 evaluations while the family
5119        // waited for a 12-evaluation counter).
5120        let pilot_iterations = result.iterations;
5121        let mut exact_config = config.clone();
5122        exact_config.initial_rho = Some(result.rho.clone());
5123        exact_config.heuristic_lambdas = None;
5124        exact_config.seed_config.max_seeds = 1;
5125        exact_config.seed_config.seed_budget = 1;
5126        exact_config.screen_initial_rho = false;
5127        exact_config.operator_initial_trust_radius = result.operator_trust_radius;
5128        exact_config.warm_start_outer_hessian = result.final_hessian.clone();
5129        log::info!(
5130            "[OUTER] {context}: sampled derivative pilot completed after {} iteration(s); \
5131             continuing from its checkpoint on the exact full-data measure",
5132            pilot_iterations,
5133        );
5134        let mut polished = run_outer_uncertified(obj, &exact_config, context)?;
5135        polished.iterations = polished.iterations.saturating_add(pilot_iterations);
5136        result = polished;
5137    }
5138    // Mandatory analytic optimality certificate (#934): once at the selected
5139    // point, outside every hot loop, for every solver path and every iteration
5140    // budget. Missing or failed evidence is typed non-convergence; there is no
5141    // max-iteration or logging-level bypass.
5142    //
5143    // #2273 STALE-TOLERANCE DESYNC RETRY. The solver's in-loop convergence
5144    // threshold is resolved ONCE from the SEED's cost scale
5145    // (`rel_cost·(1+|seed_cost|)`), while this certificate re-derives the
5146    // same formula at the terminal point's own (often far smaller) cost — on
5147    // a perfectly-separated binomial the score plunges between the
5148    // oversmoothed heuristic seed and the first accepted step, so the solver
5149    // can declare victory against a bound orders of magnitude looser than
5150    // the one that then refuses it here (measured: |g|=8.1e-1 accepted
5151    // in-loop vs bound 8.3e-3 at certification, 'NOT STATIONARY after 1
5152    // outer iteration'; the pass/fail pattern was non-monotone in n because
5153    // it tracked the seed-to-terminus cost ratio, not identifiability). The
5154    // desync exists precisely because the tolerance anchor differs from the
5155    // terminus, so ONE re-run seeded AT the refused checkpoint removes it by
5156    // construction: the retry's seed cost IS the certificate's cost, its
5157    // in-loop bound equals the certificate bound, and the solver either
5158    // genuinely closes the remaining gradient gap or exhausts its budget and
5159    // takes the same typed refusal as before. Bounded to a single retry;
5160    // only fires when the solver CLAIMED convergence (a budget-exhausted
5161    // result is not a desync — its refusal is genuine).
5162    // CERTIFICATION-LAST FIT OWNERSHIP. The uncertainty diagnostic evaluates
5163    // proposal points after theta-hat and the terminal reinstallation
5164    // re-evaluates at `result.rho`, so any certificate measured BEFORE them
5165    // describes a state the caller never receives: on a nonconvex profile the
5166    // certificate-time inner mode and the finally-installed inner mode can sit
5167    // in different coefficient basins (measured on the cause-specific survival
5168    // gate as a stable bitwise mismatch, terminal 9.1931e2 vs certified
5169    // 9.1671e2, because the two paths prime the inner solve under different
5170    // eval orders). Running the diagnostic and the terminal installation
5171    // FIRST and certifying LAST makes the certificate's own evaluation the
5172    // final objective-state installer, so the sealed terminal identity fit
5173    // assembly binds against IS the certified evidence — bitwise, by
5174    // construction, independent of basin multiplicity.
5175    let certify_diagnose_and_install = |obj: &mut dyn OuterObjective,
5176                                        result: &mut OuterResult|
5177     -> Result<OuterCriterionCertificate, EstimationError> {
5178        result.rho_uncertainty_diagnostic = Some(compute_rho_uncertainty_diagnostic(
5179            obj, config, context, result,
5180        ));
5181        // Reinstall the selected point under cap=0 so the certificate below
5182        // measures the full-fidelity state belonging to `result.rho`, not
5183        // the diagnostic's final proposal (seeding beta alone does not
5184        // restore weights, factors, or link state). Reset forces a real
5185        // installation instead of an LRU value hit.
5186        let terminal_cap_guard = config
5187            .outer_inner_cap
5188            .as_ref()
5189            .map(TerminalInnerCapGuard::lift);
5190        // Reset is conditional on the cap contract, mirroring
5191        // `certify_outer_optimality`'s own doctrine: REML/mixture
5192        // objectives with a cap can hold a coarse search cache that must
5193        // not be installed as terminal state, while uncapped stateful
5194        // objectives (reactive-domain entries among them) retain the very
5195        // state their evaluation at `result.rho` depends on — an
5196        // unconditional reset here wiped it and made the certification
5197        // evaluation non-finite on the reactive fixture.
5198        //
5199        // OR-in the terminal-coefficient-mode ownership signal (#2334):
5200        // objectives that install an owned coefficient mode here but hold
5201        // their inner cap in a different field (custom families) leave
5202        // `outer_inner_cap` `None`, so the cap gate alone never fires and
5203        // `finalize` here could land in a different inner basin than the
5204        // certifying re-eval below — a spurious bitwise bind failure on a
5205        // bimodal inner solve. Forcing the reset for mode-owning objectives
5206        // makes both installations start from the same clean baseline.
5207        if terminal_cap_guard.is_some() || obj.owns_terminal_coefficient_mode() {
5208            obj.reset();
5209        }
5210        let terminal_installation = obj.finalize_outer_result(&result.rho, &result.plan_used);
5211        let terminal_inner_converged = inner_solve_converged(config.outer_inner_cap.as_ref());
5212        drop(terminal_cap_guard);
5213        terminal_installation?;
5214        if !terminal_inner_converged {
5215            return Err(outer_nonconvergence_error(
5216                context,
5217                "final outer state installation did not converge at full inner fidelity",
5218                result,
5219                result.final_grad_norm,
5220                StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
5221            ));
5222        }
5223        certify_outer_optimality(obj, config, context, result)
5224    };
5225    // Certify-last checkpoint-resume loop (#2273 stale-tolerance desync,
5226    // generalized by #2374). A solver that CLAIMS convergence but fails the
5227    // mandatory analytic certificate is re-run once per iteration seeded AT the
5228    // refused checkpoint — re-anchoring the in-loop tolerance to the terminal
5229    // cost scale and, for gradient-only outers (`final_hessian == None`),
5230    // restarting `opt::Bfgs` with a fresh inverse-Hessian metric that breaks the
5231    // flat-valley `StallPolicy` false stop the accumulated metric crawled into.
5232    // Looping (rather than the original single retry) matters because that stall
5233    // gate is inflated by `(1 + ‖ρ‖∞)` in log-λ space, so one fresh-metric
5234    // reseed rarely lands the optimum in a single hop. The loop stops the moment
5235    // certification passes; it also stops — regardless of remaining budget —
5236    // when a reseed fails to strictly reduce the objective, because a point that
5237    // a fresh-metric restart cannot improve is a genuine non-stationary floor
5238    // (or a true flat valley), not an exploitable false stall, and further
5239    // reseeds would only re-derive the same refusal. A result that never claimed
5240    // convergence (e.g. a budget-exhausted `MaxIterationsReached`) is refused
5241    // immediately with no reseed: its non-convergence is genuine.
5242    let mut resumes_remaining = OUTER_CERTIFY_RESUME_BUDGET;
5243    // Interior strict-saddle escapes are bounded separately and tightly: a real
5244    // saddle is cleared in one hop, so a handful of attempts is ample, while a
5245    // non-convergent bimodal-inner grind (#2155/#2363) is cut off well before it
5246    // exhausts the general resume budget (#2357).
5247    let mut saddle_escapes_remaining: usize = OUTER_SADDLE_ESCAPE_BUDGET;
5248    let certificate = loop {
5249        let claimed_converged = result.converged;
5250        match certify_diagnose_and_install(obj, &mut result) {
5251            Ok(certificate) => break certificate,
5252            Err(refusal) => {
5253                // #2357/#2155 — interior strict-saddle escape. When the refusal
5254                // is a first-order-stationary point whose reduced (off-railed)
5255                // Hessian is indefinite, the certificate publishes a
5256                // negative-curvature reseed stepped strictly BELOW the saddle
5257                // (`negative_curvature_escape_point`). Reseeding the resume at the
5258                // refused checkpoint itself would re-descend straight back to that
5259                // zero-gradient saddle — the #2273/#2374 stale-tolerance resume
5260                // anchors the tolerance and breaks flat-valley stalls, but it
5261                // cannot break a genuine saddle. Seed at the escape point instead,
5262                // off the ridge, and start from a FRESH outer metric so the
5263                // saddle's indefinite curvature is not transferred into the
5264                // restart. This is the run_outer-level consumer of the reseed that
5265                // the multistart-loop consumer (`run_outer_with_plan`) mints only
5266                // when a per-seed claim is already stationary; the terminal
5267                // certificate is where stationarity is reached for the binomial
5268                // link-wiggle families, so without this the reseed was minted and
5269                // then dropped.
5270                let saddle_escape_reseed = result.saddle_escape_reseed.take();
5271                let resume_from_saddle_escape = saddle_escape_reseed.is_some();
5272                // #2348 Inc 2b, completed (#2349 round 8): a confirmed-tail
5273                // snap that needs a re-descent publishes the snapped face as
5274                // `tail_snap_reseed` — previously minted and then DROPPED
5275                // (declared, set, never consumed), so every ConfirmedNeedsReseed
5276                // outcome fell through to the plain refusal. The joint tail law
5277                // is first-order evidence of WHERE the optimum is, so the retry
5278                // is warranted regardless of the solver's convergence claim,
5279                // exactly like the saddle-escape reseed (measured on the #2349
5280                // fixture: the face snap descends 3.86 with |Pg| dropping
5281                // 2.05 → 0.35; the retry lets over-snapped coordinates relax
5282                // back to their interior optima while the rest hold the rail).
5283                let tail_snap_reseed = if resume_from_saddle_escape {
5284                    result.tail_snap_reseed.take();
5285                    None
5286                } else {
5287                    result.tail_snap_reseed.take()
5288                };
5289                let resume_from_tail_snap = tail_snap_reseed.is_some();
5290                // #2392 — wrong-rail pull-back and active-set reduction reseeds,
5291                // consumed with LOWER precedence than the saddle/tail-snap
5292                // reseeds. A higher-precedence reseed DROPS them (take-and-discard)
5293                // so no stale reseed leaks into a later iteration, exactly as the
5294                // saddle escape drops a co-minted tail snap above. Both are
5295                // first-order evidence (a proven inward descent / a poisoned-rail
5296                // interior), so — like the tail snap — they fire regardless of the
5297                // solver's convergence claim.
5298                let higher_precedence_reseed = resume_from_saddle_escape || resume_from_tail_snap;
5299                let wrong_rail_reseed = if higher_precedence_reseed {
5300                    result.wrong_rail_reseed.take();
5301                    None
5302                } else {
5303                    result.wrong_rail_reseed.take()
5304                };
5305                let resume_from_wrong_rail = wrong_rail_reseed.is_some();
5306                let active_set_reseed = if higher_precedence_reseed || resume_from_wrong_rail {
5307                    result.active_set_reseed.take();
5308                    None
5309                } else {
5310                    result.active_set_reseed.take()
5311                };
5312                let resume_from_active_set = active_set_reseed.is_some();
5313                let active_set_rho = active_set_reseed.as_ref().map(|a| a.rho.clone());
5314                let active_set_bounds = active_set_reseed.map(|a| a.bounds);
5315                // A published reseed means the refused point IS first-order
5316                // stationary (the escape mint gate requires `is_stationary`), so
5317                // it is a genuine saddle escapable regardless of whether the
5318                // solver "claimed" convergence: for exact-Hessian link-wiggle
5319                // families the terminal certificate — not the in-loop gate — is
5320                // where stationarity is first reached, so they arrive here with
5321                // `converged == false` yet stationary. The #2273/#2374
5322                // stale-tolerance resume, which reseeds AT the refused checkpoint,
5323                // still requires a genuine convergence claim (a budget-exhausted
5324                // non-stationary iterate has no desync to remove).
5325                if (!claimed_converged
5326                    && !resume_from_saddle_escape
5327                    && !resume_from_tail_snap
5328                    && !resume_from_wrong_rail
5329                    && !resume_from_active_set)
5330                    || resumes_remaining == 0
5331                    || (resume_from_saddle_escape && saddle_escapes_remaining == 0)
5332                {
5333                    return Err(refusal);
5334                }
5335                resumes_remaining -= 1;
5336                if resume_from_saddle_escape {
5337                    // Genuine strict saddles are cleared in one escape (the fresh
5338                    // ARC step off the ridge descends straight to the PSD
5339                    // minimum). A SMALL cap stops a pathological objective — e.g. a
5340                    // bimodal inner solve whose warm re-descent keeps reporting a
5341                    // phantom improvement that the cold certificate cannot
5342                    // reproduce (#2155 / #2363) — from burning the whole resume
5343                    // budget re-escaping a family of shallow saddles that never
5344                    // certifies. Past the cap the honest refusal is taken.
5345                    saddle_escapes_remaining -= 1;
5346                }
5347                let prior_iterations = result.iterations;
5348                let prior_value = result.final_value;
5349                log::info!(
5350                    "[OUTER] {context}: analytic certification refused after \
5351                     {prior_iterations} iteration(s) (final_value={prior_value:.6e}); re-running \
5352                     seeded {} so the in-loop tolerance anchors to the terminal cost scale \
5353                     ({resumes_remaining} resume(s) left after this one; #2273/#2374/#2155)",
5354                    if resume_from_saddle_escape {
5355                        "off the negative-curvature saddle ridge"
5356                    } else if resume_from_tail_snap {
5357                        "at the confirmed-tail snapped face"
5358                    } else if resume_from_wrong_rail {
5359                        "at the wrong-rail coordinate's clean-band interior scale"
5360                    } else if resume_from_active_set {
5361                        "with the poisoned rail frozen so the interior polishes in the reduced box"
5362                    } else {
5363                        "at the refused checkpoint"
5364                    }
5365                );
5366                let mut retry_cfg = config.clone();
5367                retry_cfg.initial_rho = Some(
5368                    saddle_escape_reseed
5369                        .or(tail_snap_reseed)
5370                        .or(wrong_rail_reseed)
5371                        .or(active_set_rho)
5372                        .unwrap_or_else(|| result.rho.clone()),
5373                );
5374                // Active-set reduction (#2392): the polish runs in the REDUCED
5375                // (frozen) box so the interior converges without the railed
5376                // coordinate's ill-conditioned Hessian row poisoning the step. The
5377                // loop re-certifies the polished point under the ORIGINAL box at
5378                // the top of the next iteration (`certify_diagnose_and_install`
5379                // captures the original `config`), so a frozen coordinate whose
5380                // gradient turns inward there un-freezes through the wrong-rail
5381                // path — no silent clamping — while a genuine rail certifies with
5382                // the interior now stationary. `config.clone()` reset each
5383                // iteration, so the frozen box never persists past this run.
5384                if let Some(frozen_bounds) = active_set_bounds {
5385                    retry_cfg.bounds = Some(frozen_bounds);
5386                }
5387                retry_cfg.heuristic_lambdas = None;
5388                retry_cfg.seed_config.max_seeds = 1;
5389                retry_cfg.seed_config.seed_budget = 1;
5390                retry_cfg.screen_initial_rho = false;
5391                // Every reseed kind lands at a genuinely different point, so the
5392                // refused checkpoint's metric (trust radius, outer Hessian)
5393                // must not be transferred into the restart.
5394                let fresh_metric = resume_from_saddle_escape
5395                    || resume_from_tail_snap
5396                    || resume_from_wrong_rail
5397                    || resume_from_active_set;
5398                retry_cfg.operator_initial_trust_radius = if fresh_metric {
5399                    None
5400                } else {
5401                    result.operator_trust_radius
5402                };
5403                retry_cfg.warm_start_outer_hessian = if fresh_metric {
5404                    None
5405                } else {
5406                    result.final_hessian.clone()
5407                };
5408                obj.reset();
5409                match run_outer_uncertified(obj, &retry_cfg, context) {
5410                    Ok(mut retried) => {
5411                        retried.iterations = retried.iterations.saturating_add(prior_iterations);
5412                        // Progress gate. A fresh-metric reseed seeded AT the
5413                        // checkpoint can only descend from it, so a reduction at
5414                        // roundoff scale means it found no descent — a genuine
5415                        // stationary floor — while a false flat-valley stall
5416                        // yields a reduction orders of magnitude larger. Gate on
5417                        // roundoff (NOT the coarser cost-stall floor) so a valley
5418                        // that crawls out in tiny per-reseed steps is not cut off
5419                        // after one hop; stop only when a reseed truly stalls, so
5420                        // the next iteration certifies the best point once more
5421                        // and takes the honest refusal.
5422                        let improved = certify_resume_made_progress(
5423                            prior_value,
5424                            retried.final_value,
5425                            CERTIFY_RESUME_PROGRESS_REL,
5426                        );
5427                        result = retried;
5428                        if !improved {
5429                            resumes_remaining = 0;
5430                        }
5431                    }
5432                    // The reseed could not even run (e.g. the checkpoint is a
5433                    // hard refusal wall for the objective): surface the
5434                    // certification refusal from the point we started this
5435                    // iteration at, which carries the checkpoint evidence.
5436                    Err(_) => return Err(refusal),
5437                }
5438            }
5439        }
5440    };
5441    result.criterion_certificate = Some(certificate);
5442    Ok(result)
5443}
5444
5445/// Build a CANONICAL-order copy of an [`OuterConfig`] for the
5446/// permutation-invariant outer search (#1538/#1539).
5447///
5448/// `perm[c]` is the native coordinate at canonical slot `c`. Every
5449/// per-coordinate config field (initial ρ seed, heuristic-λ seed, per-axis
5450/// bounds, transferred warm Hessian) is reordered native→canonical so the
5451/// optimizer's seeding and multistart operate entirely in canonical space;
5452/// scalar fields are copied verbatim. `rho_canonical_keys` is cleared so the
5453/// recursive [`run_outer`] frame runs the normal (identity-order) pipeline on
5454/// the already-canonical objective.
5455fn canonicalize_outer_config(config: &OuterConfig, perm: &[usize]) -> OuterConfig {
5456    // Permute a per-coordinate slice native→canonical; pass through any length
5457    // that does not match the permutation (defensive — should not occur).
5458    let permute_vec = |v: &[f64]| -> Vec<f64> {
5459        if v.len() == perm.len() {
5460            perm.iter().map(|&i| v[i]).collect()
5461        } else {
5462            v.to_vec()
5463        }
5464    };
5465    let permute_arr = |a: &Array1<f64>| -> Array1<f64> {
5466        if a.len() == perm.len() {
5467            Array1::from_iter(perm.iter().map(|&i| a[i]))
5468        } else {
5469            a.clone()
5470        }
5471    };
5472    let mut canonical = config.clone();
5473    canonical.rho_canonical_keys = None;
5474    if let Some(initial) = config.initial_rho.as_ref() {
5475        canonical.initial_rho = Some(permute_arr(initial));
5476    }
5477    if let Some(bound) = config.initial_inner_seed.as_ref() {
5478        canonical.initial_inner_seed = Some(BoundInnerSeed {
5479            theta: permute_arr(&bound.theta),
5480            beta: bound.beta.clone(),
5481        });
5482    }
5483    if let Some(h) = config.heuristic_lambdas.as_ref() {
5484        canonical.heuristic_lambdas = Some(permute_vec(h));
5485    }
5486    if let Some((lower, upper)) = config.bounds.as_ref() {
5487        canonical.bounds = Some((permute_arr(lower), permute_arr(upper)));
5488    }
5489    // A transferred dense outer Hessian is in native coordinate order; permute
5490    // it into canonical order so the BFGS warm metric stays aligned. (None on
5491    // the cold-start canonicalized path, so this is usually a no-op.)
5492    if let Some(h) = config.warm_start_outer_hessian.as_ref()
5493        && h.nrows() == perm.len()
5494        && h.ncols() == perm.len()
5495    {
5496        let mut hc = Array2::<f64>::zeros((perm.len(), perm.len()));
5497        for (a, &ia) in perm.iter().enumerate() {
5498            for (b, &ib) in perm.iter().enumerate() {
5499                hc[[a, b]] = h[[ia, ib]];
5500            }
5501        }
5502        canonical.warm_start_outer_hessian = Some(hc);
5503    }
5504    canonical
5505}
5506
5507/// The solver ladder behind [`run_outer`], without the #934 self-audit.
5508pub(crate) fn run_outer_uncertified(
5509    obj: &mut dyn OuterObjective,
5510    config: &OuterConfig,
5511    context: &str,
5512) -> Result<OuterResult, EstimationError> {
5513    let cap = primary_capability_for_config(obj.capability(), config, context);
5514    cap.validate_layout(context)?;
5515    // #2370: reject a degenerate / inverted ρ-box up front, as a typed error.
5516    // Every downstream stage — the per-atom EFS path below and
5517    // `run_outer_with_plan` — projects seeds against these bounds with
5518    // `f64::clamp`, whose `min > max` (or NaN) precondition panics *inside the
5519    // Rust boundary* and surfaces as an opaque `GamError: ... panicked` across
5520    // the FFI, violating the fail-loudly contract. The configured box can invert
5521    // whenever an independently-derived upper bound drifts below the lower wall
5522    // (e.g. the custom-family effective-df ceiling vs. `rho_lower_bound`).
5523    // Validating the *effective* template here — the same one every consumer
5524    // reads — turns any such inversion into `EstimationError::InvalidInput`
5525    // regardless of how the bounds were constructed.
5526    {
5527        let (bound_lo, bound_hi) = outer_bounds_template(config, cap.n_params);
5528        for i in 0..bound_lo.len() {
5529            if !(bound_lo[i].is_finite() && bound_hi[i].is_finite()) {
5530                return Err(EstimationError::InvalidInput(format!(
5531                    "{context}: outer rho bounds are non-finite at coordinate {i}: \
5532                     lower={}, upper={}",
5533                    bound_lo[i], bound_hi[i]
5534                )));
5535            }
5536
5537            // Report a collapsed interval with BOTH walls. `outer_bounds` below
5538            // is the backstop and rejects the same condition, but its message
5539            // names only the coordinate. The panic this guard replaced printed
5540            // `min = -10.0, max = -11.855421656441532`, and those two numbers
5541            // are what made #2370 diagnosable from a bug report alone: they
5542            // identify WHICH pair of independently-derived bounds drifted, and
5543            // by how much. A typed error must not be a weaker diagnostic than
5544            // the panic it replaced.
5545            //
5546            // Two tests constrain this string: `inverted_rho_box_is_a_typed_
5547            // error_not_a_clamp_panic_2370` greps for the word "bound", and
5548            // `the_inverted_box_refusal_carries_both_bound_values_2370` pins
5549            // both numeric walls. Keep both when rewording.
5550            if bound_lo[i] > bound_hi[i] {
5551                return Err(EstimationError::InvalidInput(format!(
5552                    "{context}: outer rho bounds are inverted at coordinate {i}: \
5553                     lower bound {} exceeds upper bound {}",
5554                    bound_lo[i], bound_hi[i]
5555                )));
5556            }
5557        }
5558        outer_bounds(&bound_lo, &bound_hi)
5559            .map_err(|err| EstimationError::InvalidInput(format!("{context}: {err}")))?;
5560    }
5561    if let Some(initial_rho) = config.initial_rho.as_ref() {
5562        cap.theta_layout()
5563            .validate_point_len(initial_rho, "initial outer seed")
5564            .map_err(|err| match err {
5565                ObjectiveEvalError::Recoverable { message }
5566                | ObjectiveEvalError::Fatal { message } => {
5567                    EstimationError::RemlOptimizationFailed(format!("{context}: {message}"))
5568                }
5569            })?;
5570    }
5571    // Frontier ρ-scaling auto-switch (#986): at per-atom-EFS-eligible frontier
5572    // rho dimension the decoupled per-atom fixed point is the primary outer
5573    // iteration; everything else falls through to the dense / standard path
5574    // below. Routed here so every entry point inherits it (magic by default).
5575    if let Some(result) = run_per_atom_efs_if_frontier(obj, config, context)? {
5576        if result.converged {
5577            return Ok(result);
5578        }
5579        return Err(outer_nonconvergence_error(
5580            context,
5581            "per-atom EFS exhausted its iteration budget before the fixed-point step converged",
5582            &result,
5583            None,
5584            StationarityBound::unrecorded(outer_gradient_tolerance(config).abs),
5585        ));
5586    }
5587
5588    if cap.n_params == 0 {
5589        let cost = obj.eval_cost(&Array1::zeros(0))?;
5590        let the_plan = plan(&cap);
5591        return Ok(outer_result_with_gradient_norm(
5592            Array1::zeros(0),
5593            cost,
5594            0,
5595            Some(0.0),
5596            true,
5597            the_plan,
5598        ));
5599    }
5600
5601    // Build the ordered list of capabilities to attempt: primary first, then
5602    // any centrally-derived degraded capabilities. Aux direct-search has no
5603    // degraded ladder — a single attempt either succeeds or the failure is
5604    // surfaced to the caller.
5605    let fallback_attempts = match config.fallback_policy {
5606        FallbackPolicy::Automatic => automatic_fallback_attempts(&cap),
5607        FallbackPolicy::Disabled => Vec::new(),
5608    };
5609    let mut attempts: Vec<OuterCapability> = Vec::with_capacity(1 + fallback_attempts.len());
5610    attempts.push(cap.clone());
5611    for degraded in fallback_attempts {
5612        attempts.push(degraded);
5613    }
5614
5615    let mut last_error: Option<EstimationError> = None;
5616    let mut best_checkpoint: Option<OuterResult> = None;
5617
5618    for (attempt_idx, attempt_cap) in attempts.iter().enumerate() {
5619        let the_plan = plan(attempt_cap);
5620        if attempt_idx > 0 {
5621            log::debug!("[OUTER] {context}: primary plan failed; falling back to {the_plan}");
5622        }
5623        log_plan(context, attempt_cap, &the_plan);
5624
5625        obj.reset();
5626
5627        // ARC budget-exhaustion retry: when an Arc attempt runs out of
5628        // outer iterations, reseed a fresh Arc run from the previous
5629        // attempt's last ρ and trust radius. Inner caches (PIRLS LRU,
5630        // eval bundle, warm-start predictor, adaptive signals) are wiped
5631        // by `obj.reset()`; the operator-TR's Cauchy/Newton/CG state has
5632        // no resume API and is not preserved. The lever that changes for
5633        // the resumed run is the inner-PIRLS cap (uncapped via the
5634        // feedback handle), not `max_iter` — empirically the prior stall
5635        // was an inner-tolerance / model-fidelity issue, not an outer
5636        // budget shortfall, and doubling `max_iter` only replays the
5637        // same trajectory byte-for-byte. The retry is gated on observed
5638        // `‖g‖` progress so trajectories that made no headway fall
5639        // through to the degraded plan instead of replaying.
5640        let mut arc_retries_left: u32 = if matches!(the_plan.solver, Solver::Arc) {
5641            2
5642        } else {
5643            0
5644        };
5645        let mut retry_config: Option<OuterConfig> = None;
5646        // Tracks the previous ARC attempt's terminal `‖g‖`. The retry
5647        // gate compares attempt-over-attempt: if a retry didn't move
5648        // the gradient norm, the trajectory replayed (same seed, same
5649        // trust radius, cold caches, deterministic optimizer) and
5650        // further retries cannot help. First retry is unconditional
5651        // (no prior attempt to compare against).
5652        let mut prev_attempt_grad_norm: Option<f64> = None;
5653
5654        let outcome = loop {
5655            // Bind the active config by cloning into a local owned value so
5656            // subsequent retry-config assignment does not collide with the
5657            // borrow used inside this iteration body.
5658            let active_config_owned: OuterConfig =
5659                retry_config.clone().unwrap_or_else(|| config.clone());
5660            let active_config: &OuterConfig = &active_config_owned;
5661            match run_outer_with_plan(obj, active_config, context, attempt_cap, &the_plan, true) {
5662                Ok(PlanRunOutcome::Converged(result)) => break Ok(result),
5663                Ok(PlanRunOutcome::Exhausted(result)) => {
5664                    if arc_retries_left == 0
5665                        || matches!(
5666                            result.operator_stop_reason,
5667                            Some(
5668                                OperatorTrustRegionStopReason::RejectFloor
5669                                    // #1690: a flat-valley cost-stall is a CONVERGED
5670                                    // cost plateau over the whole stall window, not a
5671                                    // budget shortfall. The ARC retry only reseeds
5672                                    // from the same last ρ with a reset trust radius
5673                                    // and the same deterministic operator state, so it
5674                                    // replays the identical trajectory and re-halts at
5675                                    // the same valley floor with the same |g| (verified
5676                                    // on the #1690 Gamma repro: two retries, each
5677                                    // returning |g|=0.3646 byte-for-byte). Treat it
5678                                    // like `RejectFloor` and stop — the genuine
5679                                    // stationarity verdict is reconciled downstream
5680                                    // against the authoritative shipped-β gradient
5681                                    // (`optimizer.rs`), and a non-stationary floor is
5682                                    // still reported non-converged. This skips the
5683                                    // wasted full-trajectory replay that dominated the
5684                                    // count-family slowdown.
5685                                    | OperatorTrustRegionStopReason::CostStallFlatValley
5686                            )
5687                        )
5688                    {
5689                        break Ok(result);
5690                    }
5691                    // Gate the retry on attempt-over-attempt `‖g‖`
5692                    // progress. The first retry is unconditional (no
5693                    // prior attempt). Subsequent retries fall through
5694                    // to the degraded plan when the gradient norm did
5695                    // not materially shrink — the deterministic
5696                    // optimizer with the same seed and trust radius
5697                    // would replay the same trajectory.
5698                    let Some(cur_grad_norm) = result.final_grad_norm else {
5699                        log::info!(
5700                            "[OUTER] {context}: ARC attempt exhausted budget at \
5701                             iter={} cost={:.6e} without a final gradient norm; \
5702                             falling through to degraded plan",
5703                            result.iterations,
5704                            result.final_value,
5705                        );
5706                        break Ok(result);
5707                    };
5708                    if let Some(prev_g) = prev_attempt_grad_norm {
5709                        let progressed = cur_grad_norm.is_finite()
5710                            && prev_g.is_finite()
5711                            && cur_grad_norm < 0.5 * prev_g;
5712                        if !progressed {
5713                            log::info!(
5714                                "[OUTER] {context}: ARC retry stalled at \
5715                                 iter={} cost={:.6e} |g|={:.6e} (prev |g|={:.6e}); \
5716                                 deterministic replay suspected, falling through \
5717                                 to degraded plan",
5718                                result.iterations,
5719                                result.final_value,
5720                                cur_grad_norm,
5721                                prev_g,
5722                            );
5723                            break Ok(result);
5724                        }
5725                    }
5726                    let next_trust_radius =
5727                        sanitized_operator_trust_restart_radius(result.operator_trust_radius);
5728                    log::info!(
5729                        "[OUTER] {context}: ARC attempt exhausted budget at \
5730                         iter={} cost={:.6e} |g|={:.6e}; resuming from last \
5731                         rho + trust_radius={:?}, inner-PIRLS uncapped \
5732                         (objective caches wiped; operator-TR Cauchy/Newton \
5733                         state is not resumable)",
5734                        result.iterations,
5735                        result.final_value,
5736                        cur_grad_norm,
5737                        next_trust_radius,
5738                    );
5739                    // Snapshot the cap-feedback handle before we
5740                    // reassign `retry_config` (which currently backs
5741                    // `active_config`'s borrow). `InnerProgressFeedback`
5742                    // is an Arc-wrapper bundle, so the clone is cheap.
5743                    let cap_feedback = active_config.outer_inner_cap.clone();
5744                    let mut next = active_config.clone();
5745                    prev_attempt_grad_norm = Some(cur_grad_norm);
5746                    next.initial_rho = Some(result.rho.clone());
5747                    next.operator_initial_trust_radius = next_trust_radius;
5748                    retry_config = Some(next);
5749                    arc_retries_left -= 1;
5750                    obj.reset();
5751                    // Lift any inner-PIRLS cap for the resumed run. The
5752                    // schedule's cold-start ladder (3/5/10) would
5753                    // re-coarsen exactly the inner solves whose tolerance
5754                    // is suspected to have starved the prior trajectory.
5755                    // The next outer iter consumes ρ near a near-stationary
5756                    // point where exact β / gradient / Hessian is the
5757                    // load-bearing input to the operator-TR geometry.
5758                    if let Some(feedback) = cap_feedback.as_ref() {
5759                        feedback.cap.store(0, Ordering::Relaxed);
5760                    }
5761                }
5762                Err(e) => break Err(e),
5763            }
5764        };
5765
5766        match outcome {
5767            Ok(result) => {
5768                if result.converged {
5769                    return Ok(result);
5770                }
5771
5772                let improves_checkpoint = result.final_value.is_finite()
5773                    && best_checkpoint.as_ref().is_none_or(|checkpoint| {
5774                        !checkpoint.final_value.is_finite()
5775                            || result.final_value < checkpoint.final_value
5776                    });
5777                if improves_checkpoint {
5778                    best_checkpoint = Some(result);
5779                }
5780
5781                let message = format!(
5782                    "{context}: attempt {} (plan={the_plan}) exhausted without convergence",
5783                    attempt_idx + 1
5784                );
5785                log::debug!("[OUTER] {message}; trying degraded fallback plan");
5786                last_error = Some(EstimationError::RemlOptimizationFailed(message));
5787            }
5788            Err(e) => {
5789                if e.is_fatal_outer_evaluation() {
5790                    return Err(e);
5791                }
5792                log::debug!(
5793                    "[OUTER] {context}: attempt {} (plan={the_plan}) failed: {e}",
5794                    attempt_idx + 1
5795                );
5796                last_error = Some(e);
5797            }
5798        }
5799    }
5800
5801    if let Some(checkpoint) = best_checkpoint {
5802        // The solver ladder produced no result that its OWN internal
5803        // (raw-gradient) convergence test accepted — but that test cannot see a
5804        // railed or already-stationary optimum. At a smoothing parameter railed to
5805        // the ρ box floor (λ→0, e.g. an exact linear fit or a separated smooth),
5806        // the RAW gradient stays large along the railed axis — it "wants" to push
5807        // past the boundary — so the solver reports non-convergence and can take
5808        // zero steps, even though the KKT-PROJECTED gradient (which zeroes
5809        // outward-railed axes) is stationary and no feasible step reduces the
5810        // objective. Only the mandatory analytic certificate in `run_outer`
5811        // computes that projected gradient AND the curvature-scaled flat-valley
5812        // bound (½·gᵀH⁻¹g ≤ objective_tol), so IT, not this raw-gradient ladder, is
5813        // the sole authority on stationarity. Hand it the best finite checkpoint:
5814        // `certify_outer_optimality` mints iff the point is genuinely stationary
5815        // (interior, railed, or flat-valley) and returns typed non-convergence
5816        // otherwise, so a truly divergent fit is still rejected there.
5817        return Ok(checkpoint);
5818    }
5819
5820    Err(last_error.unwrap_or_else(|| {
5821        EstimationError::RemlOptimizationFailed(format!("all plan attempts exhausted ({context})"))
5822    }))
5823}
5824
5825// ─── Frontier ρ-scaling auto-switch (issue #986) ─────────────────────────
5826//
5827// ARD-per-atom assigns one smoothing coordinate per dictionary atom, so the
5828// ρ-vector reaches 10^4–10^5 coordinates. A dense outer quasi-Newton over that
5829// materializes an O(K²) Hessian and is impossible at scale. When the ρ-dimension
5830// is frontier-scale AND every coordinate is penalty-like with a working
5831// fixed-point hook, route the PRIMARY outer iteration to the per-atom decoupled
5832// EFS path (`crate::estimate::reml::per_atom_efs`) instead of the dense
5833// ARC/BFGS lane. The decision is auto-derived from the coordinate count alone —
5834// there is no flag — and it is additive: the dense path is unchanged for small K
5835// and for any objective that is not per-atom-EFS-eligible.
5836
5837/// Whether this capability is in the frontier ρ-scaling regime where the
5838/// per-atom decoupled EFS primary should take over from the dense outer.
5839///
5840/// Delegates the eligibility decision to
5841/// [`crate::estimate::reml::per_atom_efs::per_atom_efs_eligible`], which
5842/// requires all-penalty-like coordinates, a working `eval_efs` hook,
5843/// fixed-point not disabled, and a frontier-scale ρ-dimension. This is the
5844/// single auto-switch predicate; `plan` keeps selecting the
5845/// dense or standard-EFS solver for everything below the frontier threshold.
5846pub fn is_per_atom_efs_frontier(cap: &OuterCapability) -> bool {
5847    crate::estimate::reml::per_atom_efs::per_atom_efs_eligible(cap)
5848}
5849
5850/// Auto-switch entry point: when `cap` is frontier-scale per-atom-EFS-eligible,
5851/// run the per-atom decoupled EFS primary and return its [`OuterResult`];
5852/// otherwise return `Ok(None)` so the caller falls through to the existing dense
5853/// / standard-EFS path via [`OuterProblem::run`] / [`run_outer`].
5854///
5855/// Builds the same bounded seed and tolerance/budget the standard plan path
5856/// uses, picks the seed (initial-ρ if supplied, else the first generated
5857/// candidate — the per-atom fixed point is a contraction near the optimum and
5858/// does not need the multi-seed cascade the dense path runs for its non-convex
5859/// quasi-Newton surface), then drives the per-atom EFS loop. The shared-border
5860/// topology defaults to disjoint (every atom owns a private penalty block — the
5861/// common ARD-per-atom case); callers with a known arrow-border overlap can run
5862/// the module's `run_per_atom_efs` directly with a populated
5863/// `SharedBorderTopology`.
5864///
5865/// Additive: this function neither mutates nor bypasses the dense path; it is
5866/// the pre-dispatch shortcut [`run_outer`] calls before the dense ladder.
5867pub(crate) fn run_per_atom_efs_if_frontier(
5868    obj: &mut dyn OuterObjective,
5869    config: &OuterConfig,
5870    context: &str,
5871) -> Result<Option<OuterResult>, EstimationError> {
5872    let cap = primary_capability_for_config(obj.capability(), config, context);
5873    cap.validate_layout(context)?;
5874    if !is_per_atom_efs_frontier(&cap) {
5875        return Ok(None);
5876    }
5877
5878    let the_plan = plan(&cap);
5879    let rho_dim = cap.theta_layout().rho_dim();
5880
5881    let (lower, upper) = outer_bounds_template(config, cap.n_params);
5882
5883    // Seed: cache/explicit initial ρ if present, otherwise the first generated
5884    // candidate. The per-atom multiplicative fixed point is locally
5885    // contractive, so a single seed suffices; the heavy multi-seed cascade
5886    // exists for the dense quasi-Newton's non-convex surface, not for EFS.
5887    let seed = match config.initial_rho.as_ref() {
5888        Some(initial) if initial.len() == cap.n_params => initial.clone(),
5889        _ => {
5890            let generated = crate::seeding::generate_rho_candidates(
5891                cap.n_params,
5892                config.heuristic_lambdas.as_deref(),
5893                &config.seed_config,
5894            )?;
5895            match generated.into_iter().next() {
5896                Some(first) => first,
5897                None => Array1::<f64>::zeros(cap.n_params),
5898            }
5899        }
5900    };
5901
5902    log::info!(
5903        "[OUTER] {context}: frontier ρ-scaling (rho_dim={rho_dim}) → per-atom decoupled EFS primary"
5904    );
5905
5906    let pa_cfg = crate::estimate::reml::per_atom_efs::PerAtomEfsConfig::new(
5907        config.tolerance,
5908        config.max_iter,
5909        lower,
5910        upper,
5911    );
5912    let topology = crate::estimate::reml::per_atom_efs::SharedBorderTopology::disjoint(rho_dim);
5913
5914    obj.reset();
5915    install_matching_initial_inner_seed(obj, config, &seed, context)?;
5916    let result =
5917        crate::estimate::reml::per_atom_efs::run_per_atom_efs(obj, &seed, &pa_cfg, &topology)?;
5918    Ok(Some(result.into_outer_result(the_plan)))
5919}
5920
5921#[cfg(test)]
5922#[path = "inverted_rho_box_tests.rs"]
5923mod inverted_rho_box_tests;
5924
5925pub(crate) fn outer_bounds(lo: &Array1<f64>, hi: &Array1<f64>) -> Result<Bounds, EstimationError> {
5926    Bounds::new(lo.clone(), hi.clone(), 1e-6).map_err(|err| {
5927        EstimationError::InvalidInput(format!("outer rho bounds are invalid: {err}"))
5928    })
5929}
5930
5931pub(crate) fn outer_bounds_template(config: &OuterConfig, n: usize) -> (Array1<f64>, Array1<f64>) {
5932    config.bounds.clone().unwrap_or_else(|| {
5933        (
5934            Array1::<f64>::from_elem(n, -config.rho_bound),
5935            Array1::<f64>::from_elem(n, config.rho_bound),
5936        )
5937    })
5938}
5939
5940/// Intersect typed objective-domain faces with the caller's configured search
5941/// box. The resulting box is stored back on `config`, making it the one source
5942/// consumed by seed projection, continuation entry, every solver, and terminal
5943/// projected-stationarity certification.
5944pub(super) fn install_objective_domain(
5945    config: &mut OuterConfig,
5946    n_params: usize,
5947    objective_lower: Option<Array1<f64>>,
5948    objective_upper: Option<Array1<f64>>,
5949) -> Result<(), EstimationError> {
5950    let (mut lower, mut upper) = outer_bounds_template(config, n_params);
5951    if lower.len() != n_params || upper.len() != n_params {
5952        return Err(EstimationError::InvalidInput(format!(
5953            "outer configured bounds dimension mismatch: parameters={n_params}, lower={}, upper={}",
5954            lower.len(),
5955            upper.len(),
5956        )));
5957    }
5958    if let Some(domain) = objective_lower.as_ref()
5959        && domain.len() != n_params
5960    {
5961        return Err(EstimationError::InvalidInput(format!(
5962            "outer objective-domain lower-bound dimension mismatch: parameters={n_params}, lower={}",
5963            domain.len()
5964        )));
5965    }
5966    if let Some(domain) = objective_upper.as_ref()
5967        && domain.len() != n_params
5968    {
5969        return Err(EstimationError::InvalidInput(format!(
5970            "outer objective-domain upper-bound dimension mismatch: parameters={n_params}, upper={}",
5971            domain.len()
5972        )));
5973    }
5974    for index in 0..n_params {
5975        if let Some(domain) = objective_lower.as_ref() {
5976            let value = domain[index];
5977            if !value.is_finite() {
5978                return Err(EstimationError::InvalidInput(format!(
5979                    "outer objective-domain lower bound[{index}] must be finite; got {value}"
5980                )));
5981            }
5982            lower[index] = lower[index].max(value);
5983        }
5984        if let Some(domain) = objective_upper.as_ref() {
5985            let value = domain[index];
5986            if !value.is_finite() {
5987                return Err(EstimationError::InvalidInput(format!(
5988                    "outer objective-domain upper bound[{index}] must be finite; got {value}"
5989                )));
5990            }
5991            upper[index] = upper[index].min(value);
5992        }
5993        if !(lower[index].is_finite() && upper[index].is_finite() && lower[index] < upper[index]) {
5994            return Err(EstimationError::InvalidInput(format!(
5995                "outer objective-domain intersection is empty or non-finite at coordinate {index}: lower={}, upper={}",
5996                lower[index], upper[index]
5997            )));
5998        }
5999    }
6000    config.bounds = Some((lower, upper));
6001    Ok(())
6002}
6003
6004pub(crate) fn outer_tolerance(value: f64) -> Result<Tolerance, EstimationError> {
6005    Tolerance::new(value)
6006        .map_err(|err| EstimationError::InvalidInput(format!("outer tolerance is invalid: {err}")))
6007}
6008
6009/// The relative cost floor shared by the cost-stall guard, the curvature-scaled
6010/// flat-valley certificate, and the certify-last resume progress gate: nothing
6011/// tighter than what the in-loop stall detector already proved about the
6012/// surface. `rel_cost_tolerance` when set, else a small fraction of the absolute
6013/// tolerance, never below `COST_STALL_REL_TOL_FLOOR`.
6014pub(crate) fn outer_rel_cost_floor(config: &OuterConfig) -> f64 {
6015    config
6016        .rel_cost_tolerance
6017        .unwrap_or(config.tolerance * 1.0e-2)
6018        .max(COST_STALL_REL_TOL_FLOOR)
6019}
6020
6021/// Whether a certify-last checkpoint reseed (#2273/#2374) exploited real descent.
6022///
6023/// A reseed that does not strictly reduce the outer objective past the shared
6024/// relative cost floor `rel_cost_floor·(1 + min(|prior|, |retried|))` is at a
6025/// genuine non-stationary floor (or a true flat valley) a fresh metric cannot
6026/// escape, so the resume loop must stop rather than spend its remaining budget
6027/// re-deriving the same refusal. Anchoring the floor on the SMALLER of the two
6028/// costs keeps a tiny uphill wobble from a metric restart from reading as
6029/// progress, and a non-finite retried value is never progress.
6030pub(crate) fn certify_resume_made_progress(
6031    prior_value: f64,
6032    retried_value: f64,
6033    rel_cost_floor: f64,
6034) -> bool {
6035    let floor = rel_cost_floor * (1.0 + prior_value.abs().min(retried_value.abs()));
6036    retried_value.is_finite() && retried_value < prior_value - floor
6037}
6038
6039pub(crate) fn outer_gradient_tolerance(config: &OuterConfig) -> GradientTolerance {
6040    let abs = config
6041        .objective_scale
6042        // A matrix-factorization REML/LAML score cannot resolve relative
6043        // perturbations below the forward-error scale √ε. Requiring a smaller
6044        // absolute residual made gradient-only / operator-curvature objectives
6045        // impossible to certify unless an unrelated Hessian or probe-noise
6046        // rescue happened to be available (#2269). This is the arithmetic
6047        // resolution of the declared objective scale, not a fitted tolerance.
6048        .map(|scale| config.tolerance.max(scale * f64::EPSILON.sqrt()))
6049        .unwrap_or(config.tolerance);
6050    GradientTolerance {
6051        abs,
6052        rel_initial_grad: None,
6053        rel_cost: Some(config.rel_cost_tolerance.unwrap_or(config.tolerance)),
6054        projected: true,
6055    }
6056}
6057
6058pub(crate) fn outer_max_iterations(value: usize) -> Result<MaxIterations, EstimationError> {
6059    MaxIterations::new(value)
6060        .map_err(|err| EstimationError::InvalidInput(format!("outer max_iter is invalid: {err}")))
6061}
6062
6063pub(crate) fn sanitized_operator_trust_restart_radius(radius: Option<f64>) -> Option<f64> {
6064    radius
6065        .filter(|value| value.is_finite() && *value > 0.0)
6066        .map(|value| value.max(OPERATOR_TRUST_RESTART_RADIUS_FLOOR))
6067}
6068
6069pub(crate) fn bfgs_axis_step_caps(
6070    config: &OuterConfig,
6071    layout: OuterThetaLayout,
6072) -> Option<Array1<f64>> {
6073    if config.bfgs_step_cap.is_none() && config.bfgs_step_cap_psi.is_none() {
6074        return None;
6075    }
6076    let mut caps = Array1::from_elem(layout.n_params, f64::INFINITY);
6077    if let Some(cap) = config.bfgs_step_cap {
6078        for i in 0..layout.rho_dim() {
6079            caps[i] = cap;
6080        }
6081    }
6082    if let Some(cap) = config.bfgs_step_cap_psi {
6083        for i in layout.rho_dim()..layout.n_params {
6084            caps[i] = cap;
6085        }
6086    }
6087    Some(caps)
6088}
6089
6090pub(crate) enum FixedPointOuterRunError {
6091    SeedRejected(EstimationError),
6092    ImmediateFallback(EstimationError),
6093    Failed(EstimationError),
6094}
6095
6096pub(crate) fn run_fixed_point_outer_solver(
6097    obj: &mut dyn OuterObjective,
6098    layout: OuterThetaLayout,
6099    barrier_config: Option<BarrierConfig>,
6100    config: &OuterConfig,
6101    context: &str,
6102    seed: &Array1<f64>,
6103    the_plan: OuterPlan,
6104    label: &str,
6105    failure_prefix: &str,
6106) -> Result<OuterResult, FixedPointOuterRunError> {
6107    // Shared publication slot for the recurrent-restored-incumbent stop
6108    // (#2235 verdict 2): the bridge is moved into the driver, so the streak
6109    // count comes back through this cell and is stamped onto the returned
6110    // `OuterResult` below.
6111    let recurrent_incumbent_exit = Arc::new(Mutex::new(None));
6112    let mut objective = OuterFixedPointBridge {
6113        obj,
6114        layout,
6115        barrier_config,
6116        fixed_point_tolerance: config.tolerance,
6117        consecutive_psi_zero_iters: 0,
6118        last_restored_incumbent_streak: None,
6119        recurrent_incumbent_exit: Arc::clone(&recurrent_incumbent_exit),
6120    };
6121    let seed_sample = match objective.eval_step(seed) {
6122        Ok(sample) => sample,
6123        Err(ObjectiveEvalError::Recoverable { message }) => {
6124            let err = EstimationError::RemlOptimizationFailed(message);
6125            if requests_immediate_first_order_fallback(&err.to_string()) {
6126                return Err(FixedPointOuterRunError::ImmediateFallback(err));
6127            }
6128            return Err(FixedPointOuterRunError::SeedRejected(err));
6129        }
6130        Err(ObjectiveEvalError::Fatal { message }) => {
6131            return Err(FixedPointOuterRunError::Failed(
6132                EstimationError::fatal_outer_evaluation(
6133                    "outer fixed-point seed evaluation",
6134                    EstimationError::RemlOptimizationFailed(message),
6135                ),
6136            ));
6137        }
6138    };
6139    let (lo, hi) = outer_bounds_template(config, layout.n_params);
6140    let bounds = outer_bounds(&lo, &hi).map_err(FixedPointOuterRunError::Failed)?;
6141    let tol = outer_tolerance(config.tolerance).map_err(FixedPointOuterRunError::Failed)?;
6142    let max_iter =
6143        outer_max_iterations(config.max_iter).map_err(FixedPointOuterRunError::Failed)?;
6144    let mut optimizer = FixedPoint::new(seed.clone(), objective)
6145        // Seed validation already paid the complete EFS inner solve. Reuse that
6146        // exact sample so iteration zero neither repeats the expensive solve nor
6147        // mistakes two evaluations at the identical rho for recurrent incumbent
6148        // evidence (#2241).
6149        .with_initial_sample(seed.clone(), seed_sample)
6150        .with_bounds(bounds)
6151        .with_tolerance(tol)
6152        .with_max_iterations(max_iter);
6153    match optimizer.run() {
6154        Ok(sol) => {
6155            let mut result = solution_into_outer_result(sol, true, the_plan);
6156            // Stamp the model-state fixed-point stop when the bridge published
6157            // one; `None` means the walk stopped through the ordinary
6158            // step-norm test instead.
6159            if let Some(consecutive_restores) =
6160                recurrent_incumbent_exit.lock().ok().and_then(|slot| *slot)
6161            {
6162                result.converged_via = Some(OuterConvergedVia::RecurrentIncumbent {
6163                    consecutive_restores,
6164                });
6165            }
6166            Ok(result)
6167        }
6168        Err(FixedPointError::MaxIterationsReached { last_solution }) => {
6169            log::warn!(
6170                "[OUTER warning] {context}: {label} hit max_iter={} at final_value={:.6e} step_norm={:.3e}",
6171                config.max_iter,
6172                last_solution.final_value,
6173                last_solution.final_gradient_norm.unwrap_or(f64::NAN),
6174            );
6175            Ok(solution_into_outer_result(*last_solution, false, the_plan))
6176        }
6177        Err(FixedPointError::ObjectiveFailed { message })
6178            if requests_immediate_first_order_fallback(&message) =>
6179        {
6180            // The bridge raises `EFS_FIRST_ORDER_FALLBACK_MARKER` when the
6181            // fixed-point step is not a descent direction it can rescue — a
6182            // ψ-stagnation streak, or a step every halving rejected on both
6183            // the full vector and the ρ/τ-only fallback. That marker is a
6184            // ROUTING REQUEST ("abandon the fixed point, run the joint
6185            // gradient solver that enforces ∇_ψ V = 0"), not a defect: the
6186            // ladder `automatic_fallback_attempts` builds for an
6187            // analytic-gradient EFS/HybridEFS primary is exactly the
6188            // `disable_fixed_point` BFGS plan it is asking for.
6189            //
6190            // The seed evaluation above already honours it. Every LATER
6191            // iteration reached this arm instead, where the blanket
6192            // `fatal_outer_evaluation` classification short-circuits both
6193            // `run_outer_with_plan`'s own marker check and the attempt loop in
6194            // `run_outer_with_strategy` — so a HybridEFS search that descended
6195            // and then asked to hand over died fatally with the fallback plan
6196            // never attempted. Carry the same recoverable routing the seed
6197            // path uses, so the request is honoured wherever it is raised.
6198            Err(FixedPointOuterRunError::ImmediateFallback(
6199                EstimationError::RemlOptimizationFailed(message),
6200            ))
6201        }
6202        Err(FixedPointError::ObjectiveFailed { message }) => Err(FixedPointOuterRunError::Failed(
6203            EstimationError::fatal_outer_evaluation(
6204                "outer fixed-point evaluation",
6205                EstimationError::RemlOptimizationFailed(message),
6206            ),
6207        )),
6208        Err(e) => Err(FixedPointOuterRunError::Failed(
6209            EstimationError::RemlOptimizationFailed(format!("{failure_prefix}: {e:?}")),
6210        )),
6211    }
6212}
6213
6214#[cfg(test)]
6215mod asymptote_rail_certify_tests {
6216    use super::*;
6217    use ndarray::array;
6218
6219    /// Build a one-coordinate UPPER-rail tail-law objective: at ρ its gradient is
6220    /// `−c·e^{−ρ}` (so `ĉ = −e^{ρ}·grad = c` is constant) and its published inner
6221    /// β is `a·e^{−ρ}` (so consecutive-probe `‖Δβ‖` contracts geometrically).
6222    /// `drift_amp` ramps `ĉ` with ρ to model the finite-difference noise regime
6223    /// (a non-constant pencil constant that no drift band can confirm).
6224    fn upper_tail_objective(c: f64, a: f64, drift_amp: f64) -> impl OuterObjective {
6225        let problem = OuterProblem::new(1).with_gradient(Derivative::Analytic);
6226        problem.build_objective(
6227            (),
6228            move |_: &mut (), rho: &Array1<f64>| {
6229                let r = rho[0];
6230                let c_eff = c + drift_amp * r;
6231                Ok((c_eff * (-r).exp()).abs())
6232            },
6233            move |_: &mut (), rho: &Array1<f64>| {
6234                let r = rho[0];
6235                let c_eff = c + drift_amp * r;
6236                Ok(OuterEval {
6237                    cost: (c_eff * (-r).exp()).abs(),
6238                    gradient: array![-c_eff * (-r).exp()],
6239                    hessian: HessianValue::Unavailable,
6240                    inner_beta_hint: Some(array![a * (-r).exp()]),
6241                })
6242            },
6243            None::<fn(&mut ())>,
6244            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6245        )
6246    }
6247
6248    /// An exact upper-rail exponential tail is certified: the reconstructed
6249    /// pencil constant is `c`, and the value-gap / estimand-travel are finite.
6250    #[test]
6251    fn asymptote_rail_mints_on_exact_tail_law() {
6252        let mut obj = upper_tail_objective(6723.0, 1.0, 0.0);
6253        let rho = array![29.9];
6254        let tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6255        let rail = build_and_assess_rail_coordinate(
6256            &mut obj,
6257            &rho,
6258            0,
6259            AsymptoteSide::Upper,
6260            &tol,
6261            (f64::NEG_INFINITY, f64::INFINITY),
6262        )
6263        .expect("probing the tail-law objective must not error")
6264        .expect("an exact exponential tail must certify a rail");
6265        assert_eq!(rail.index, 0);
6266        assert_eq!(rail.side, AsymptoteSide::Upper);
6267        assert!(
6268            (rail.tail_constant - 6723.0).abs() / 6723.0 < 1.0e-6,
6269            "recovered ĉ={} should equal c=6723",
6270            rail.tail_constant,
6271        );
6272        assert!(rail.value_gap.is_finite() && rail.value_gap >= 0.0);
6273        assert!(rail.estimand_travel_bound.is_finite() && rail.estimand_travel_bound >= 0.0);
6274    }
6275
6276    /// A drifting pencil constant (finite-difference noise regime) never
6277    /// certifies: no finite-difference-clean run of the required length exists.
6278    #[test]
6279    fn asymptote_rail_refuses_on_drifting_constant() {
6280        let mut obj = upper_tail_objective(6723.0, 1.0, 3000.0);
6281        let rho = array![29.9];
6282        let tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6283        let verdict = build_and_assess_rail_coordinate(
6284            &mut obj,
6285            &rho,
6286            0,
6287            AsymptoteSide::Upper,
6288            &tol,
6289            (f64::NEG_INFINITY, f64::INFINITY),
6290        )
6291        .expect("probing must not error");
6292        assert!(
6293            verdict.is_err(),
6294            "a drifting ĉ must not certify a tail, got {verdict:?}",
6295        );
6296    }
6297
6298    /// #2358: a finite smoothing box can expose fewer than three whole
6299    /// e-folds of the leading-order tail even though the compactified
6300    /// criterion is already regular there. For
6301    ///
6302    /// `V(ρ) = c·e⁻ρ + (d/2)·e⁻²ρ`,
6303    ///
6304    /// the pencil constant is `ĉ(ρ) = c + d·e⁻ρ`: the ordinary asymptotic law
6305    /// plus its first vanishing correction. Unit probes from ρ=10 step into
6306    /// enough correction curvature that no three-row clean run exists; the
6307    /// equal-spaced half-e-fold fallback resolves the local tail without
6308    /// changing the drift, estimand, sign, or noise gates.
6309    #[test]
6310    fn tail_probe_resolves_narrow_regular_band_before_finite_box_2358() {
6311        let (c, d, a) = (7.1_f64, 400.0_f64, 1.0e-3_f64);
6312        let problem = OuterProblem::new(1).with_gradient(Derivative::Analytic);
6313        let mut obj = problem.build_objective(
6314            (),
6315            move |_: &mut (), rho: &Array1<f64>| {
6316                let tau = (-rho[0]).exp();
6317                Ok(c * tau + 0.5 * d * tau * tau)
6318            },
6319            move |_: &mut (), rho: &Array1<f64>| {
6320                let tau = (-rho[0]).exp();
6321                Ok(OuterEval {
6322                    cost: c * tau + 0.5 * d * tau * tau,
6323                    gradient: array![-c * tau - d * tau * tau],
6324                    hessian: HessianValue::Unavailable,
6325                    inner_beta_hint: Some(array![a * tau]),
6326                })
6327            },
6328            None::<fn(&mut ())>,
6329            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6330        );
6331        let rho = array![10.0];
6332        let mut tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6333        tol.tail_drift_rel = TAIL_SNAP_DRIFT_REL;
6334
6335        let (coarse, coarse_rows) = probe_tail_window_at_resolution(
6336            &mut obj,
6337            &rho,
6338            0,
6339            AsymptoteSide::Upper,
6340            &tol,
6341            (-10.0, 10.5),
6342            (1.0, ASYMPTOTE_PROBE_COUNT),
6343        )
6344        .expect("coarse probing must not error");
6345        assert!(
6346            coarse.is_none(),
6347            "unit probes must not manufacture a pure tail through the curved band: {coarse_rows}"
6348        );
6349
6350        let (window, rows) = probe_tail_window(
6351            &mut obj,
6352            &rho,
6353            0,
6354            AsymptoteSide::Upper,
6355            &tol,
6356            (-10.0, 10.5),
6357        )
6358        .expect("multi-resolution probing must not error");
6359        let window = window.unwrap_or_else(|| {
6360            panic!("the half-e-fold fallback must resolve the regular tail: {rows}")
6361        });
6362        assert!(
6363            matches!(
6364                assess_coordinate(&window, &tol),
6365                AsymptoteVerdict::CertifiedAtAsymptote { .. }
6366            ),
6367            "the resolved tail must pass the unchanged asymptote gates"
6368        );
6369    }
6370
6371    /// #2358: pre-snap interior stationarity cannot authorize direct
6372    /// certification at the rail. The second coordinate is stationary at the
6373    /// checkpoint but its mode depends on the tail coordinate, so moving the
6374    /// first coordinate changes the second coordinate's optimum. A confirmed
6375    /// snap must therefore publish a re-optimization waypoint even though the
6376    /// pre-snap interior gradient is exactly zero.
6377    #[test]
6378    fn coupled_coordinate_stationary_before_snap_still_reseeds_2358() {
6379        let c = 10.0_f64;
6380        let problem = OuterProblem::new(2).with_gradient(Derivative::Analytic);
6381        let mut obj = problem.build_objective(
6382            (),
6383            move |_: &mut (), rho: &Array1<f64>| {
6384                let tau = (-rho[0]).exp();
6385                let coupled = rho[1] - tau;
6386                Ok(c * tau + 0.5 * coupled * coupled)
6387            },
6388            move |_: &mut (), rho: &Array1<f64>| {
6389                let tau = (-rho[0]).exp();
6390                Ok(OuterEval {
6391                    cost: c * tau + 0.5 * (rho[1] - tau).powi(2),
6392                    gradient: array![
6393                        -c * tau + (rho[1] - tau) * tau,
6394                        rho[1] - tau
6395                    ],
6396                    hessian: HessianValue::Unavailable,
6397                    inner_beta_hint: Some(array![1.0e-3 * tau]),
6398                })
6399            },
6400            None::<fn(&mut ())>,
6401            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6402        );
6403        let rho = array![8.0, (-8.0_f64).exp()];
6404        let tail_gradient = -c * (-rho[0]).exp();
6405        let gradient = array![tail_gradient, 0.0];
6406        let hessian = array![[tail_gradient.abs(), 0.0], [0.0, 1.0]];
6407        let bounds = (Array1::from_elem(2, -12.0), Array1::from_elem(2, 12.0));
6408
6409        let outcome = try_tail_snap_to_rail(
6410            &mut obj,
6411            &AsymptoteRailInputs {
6412                rho: &rho,
6413                projected_gradient: &gradient,
6414                railed: &[],
6415                hessian: &hessian,
6416                bounds: &bounds,
6417                terminal_beta: None,
6418                stationarity_bound: 1.0e-3,
6419                objective_tol: 1.0e-8,
6420                context: "coupled pre-snap stationarity guard",
6421            },
6422        )
6423        .expect("tail snap must not error");
6424        match outcome {
6425            TailSnapOutcome::ConfirmedNeedsReseed(snapped) => {
6426                assert_eq!(snapped, array![12.0, (-8.0_f64).exp()]);
6427            }
6428            other => panic!(
6429                "a coupled coordinate stationary only before the snap must reoptimize, got {other:?}"
6430            ),
6431        }
6432    }
6433
6434    /// #2392 wrong-rail pull-back FIRES: a coordinate sitting at the UPPER bound
6435    /// whose clean-band probes carry a POSITIVE gradient (`∂V/∂ρ > 0`, so the
6436    /// pencil constant `ĉ = −e^{ρ}·g < 0` — descent points INWARD, away from the
6437    /// bound) was driven to the wrong rail. `detect_wrong_rail_pullback` returns
6438    /// an interior reseed target strictly below the coordinate's current ρ.
6439    #[test]
6440    fn wrong_rail_pullback_fires_on_inward_descent_2392() {
6441        // V(ρ) = −c·e^{−ρ} ⇒ ∂V/∂ρ = +c·e^{−ρ} > 0: the descent runs ρ DOWN, away
6442        // from the upper rail, and ĉ_upper = −e^{ρ}·(c·e^{−ρ}) = −c < 0 uniformly.
6443        let c = 6723.0;
6444        let problem = OuterProblem::new(1).with_gradient(Derivative::Analytic);
6445        let mut obj = problem.build_objective(
6446            (),
6447            move |_: &mut (), rho: &Array1<f64>| Ok(-c * (-rho[0]).exp()),
6448            move |_: &mut (), rho: &Array1<f64>| {
6449                Ok(OuterEval {
6450                    cost: -c * (-rho[0]).exp(),
6451                    gradient: array![c * (-rho[0]).exp()],
6452                    hessian: HessianValue::Unavailable,
6453                    inner_beta_hint: Some(array![(-rho[0]).exp()]),
6454                })
6455            },
6456            None::<fn(&mut ())>,
6457            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6458        );
6459        let rho = array![29.9];
6460        let tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6461        let target = detect_wrong_rail_pullback(
6462            &mut obj,
6463            &rho,
6464            0,
6465            AsymptoteSide::Upper,
6466            &tol,
6467            (-30.0, 30.0),
6468        )
6469        .expect("probing the wrong-rail objective must not error")
6470        .expect("an inward-descent rail must publish a pull-back target");
6471        assert!(
6472            target < rho[0] && target.is_finite(),
6473            "the reseed must move the coordinate INWARD (ρ down), got {target}",
6474        );
6475    }
6476
6477    /// #2392 wrong-rail pull-back does NOT fire on a GENUINE upper-rail tail:
6478    /// `∂V/∂ρ < 0` ⇒ `ĉ > 0` ⇒ descent runs TOWARD the bound (a real λ→∞ optimum),
6479    /// which must never be pulled off its rail.
6480    #[test]
6481    fn wrong_rail_pullback_refuses_a_genuine_upper_tail_2392() {
6482        let mut obj = upper_tail_objective(6723.0, 1.0, 0.0);
6483        let rho = array![29.9];
6484        let tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6485        let verdict = detect_wrong_rail_pullback(
6486            &mut obj,
6487            &rho,
6488            0,
6489            AsymptoteSide::Upper,
6490            &tol,
6491            (-30.0, 30.0),
6492        )
6493        .expect("probing must not error");
6494        assert!(
6495            verdict.is_none(),
6496            "a genuine λ→∞ tail (ĉ>0) must not be pulled off its rail, got {verdict:?}",
6497        );
6498    }
6499
6500    /// #2349: the interior-PSD gate must judge curvature above the
6501    /// gradient-residue noise floor. Fixture = the measured multinomial
6502    /// checkpoint shape: excluded tail candidates {0}, interior coordinate 1
6503    /// gradient-stationary (|g| = 1.0228e-3) with the corrupted tie-signature
6504    /// diagonal H₁₁ = −1.0216e-3 ≈ −|g₁| (the #2298 trace-pair residue — the
6505    /// entire measured 6×6 spectrum was PSD except this one sub-resolution
6506    /// entry). The raw gate refuses on the residue; the floored gate
6507    /// certifies; a GENUINE interior saddle (λ_min = −0.5 against the same
6508    /// tiny gradient) still refuses under the floor.
6509    #[test]
6510    fn interior_psd_gate_floors_tail_residue_but_keeps_genuine_saddles_2349() {
6511        let hessian = array![[0.2828, 0.0004], [0.0004, -1.0216e-3]];
6512        let gradient = array![-1.057, -1.0228e-3];
6513        let excluded = [0usize];
6514        assert_eq!(
6515            certificate_hessian_is_psd_off_railed(&hessian, &excluded),
6516            Some(false),
6517            "raw gate must see the corrupted sub-resolution entry as indefinite"
6518        );
6519        assert_eq!(
6520            certificate_hessian_is_psd_off_railed_above_gradient_floor(
6521                &hessian, &excluded, &gradient
6522            ),
6523            Some(true),
6524            "the gradient floor must absorb the O(|g|) trace-pair residue"
6525        );
6526        let saddle = array![[0.2828, 0.0004], [0.0004, -0.5]];
6527        assert_eq!(
6528            certificate_hessian_is_psd_off_railed_above_gradient_floor(
6529                &saddle, &excluded, &gradient
6530            ),
6531            Some(false),
6532            "a genuine interior saddle dwarfs the bound-scale floor and refuses"
6533        );
6534    }
6535
6536    /// THE GUARANTEE, not an instance of it. Weyl bounds the floored spectrum by
6537    /// `λ_min(H) + min|g| ≤ λ_min(H + diag|g|) ≤ λ_min(H) + max|g|`, so the floor
6538    /// can absorb AT MOST `max_k |g_k|` over the JUDGED coordinates. Therefore
6539    /// any interior spectrum whose most negative direction exceeds that floor
6540    /// must still refuse — for every such spectrum, not merely for the one
6541    /// saddle that happened to be measured.
6542    ///
6543    /// Swept over curvatures spanning six orders and gradients spanning four,
6544    /// including the pair where they are within a factor of two of each other
6545    /// (the regime the floor exists to serve, and the only place the verdict is
6546    /// genuinely close). The excluded coordinate carries a deliberately huge
6547    /// gradient: the sub-block is extracted AFTER flooring, so it must never
6548    /// reach the floor.
6549    #[test]
6550    fn gradient_floor_absorbs_at_most_max_interior_gradient_weyl_bound() {
6551        let excluded = [0usize];
6552        for &lambda_min in &[-5.0e-1, -1.5e-2, -1.0e-3, -1.0e-5, -1.0e-7] {
6553            for &g_interior in &[1.0e-7, 1.0e-5, 1.0e-3, 1.0e-2] {
6554                // The railed coordinate's gradient is four orders above every
6555                // interior one; if it ever entered the floor the sweep would
6556                // certify everything.
6557                let gradient = array![-1.4017, g_interior];
6558                let hessian = array![[0.2828, 0.0004], [0.0004, lambda_min]];
6559                let floored = certificate_hessian_is_psd_off_railed_above_gradient_floor(
6560                    &hessian, &excluded, &gradient,
6561                );
6562                if g_interior < lambda_min.abs() {
6563                    assert_eq!(
6564                        floored,
6565                        Some(false),
6566                        "Weyl: max|g_int|={g_interior:.1e} < |λ_min|={:.1e} means the floored \
6567                         sub-block is still indefinite, so the gate MUST refuse",
6568                        lambda_min.abs()
6569                    );
6570                }
6571                // And the recorded clearance must report the same verdict
6572                // against the same floor, so the certificate's evidence and its
6573                // gate can never disagree.
6574                let clearance =
6575                    interior_curvature_floor_clearance(&hessian, &excluded, &gradient)
6576                        .expect("a finite 1×1 interior sub-block has a clearance");
6577                assert_eq!(
6578                    clearance.gradient_floor, g_interior,
6579                    "the floor must be the largest JUDGED gradient — the excluded \
6580                     coordinate's 1.4017 must never enter it"
6581                );
6582                assert!(
6583                    (clearance.interior_min_eigenvalue - lambda_min).abs()
6584                        <= 1.0e-12 * lambda_min.abs(),
6585                    "recorded λ_min {} should be the interior sub-block's own {lambda_min}",
6586                    clearance.interior_min_eigenvalue
6587                );
6588                assert_eq!(
6589                    Some(clearance.cleared),
6590                    floored,
6591                    "the recorded verdict and the gate must be the same judgment"
6592                );
6593            }
6594        }
6595    }
6596
6597    /// Joint-face objective `V(ρ) = c·e^{−(ρ₀+ρ₁)/2}` — the algebraic skeleton
6598    /// of an OVERLAPPING-penalty λ→∞ face (the coalesced pseudo-logdet's
6599    /// shared range space couples the two coordinates, so each marginal
6600    /// gradient `g_k = −(c/2)e^{−(ρ₀+ρ₁)/2}` decays in the JOINT coordinate
6601    /// only). Along either single coordinate the pencil constant
6602    /// `ĉ_k = |g_k|e^{ρ_k}` sweeps a factor `e^{1/2}` per e-fold — far outside
6603    /// any drift band — while along the face direction it is exactly constant.
6604    fn joint_face_objective(c: f64, a: f64) -> impl OuterObjective {
6605        let problem = OuterProblem::new(2).with_gradient(Derivative::Analytic);
6606        problem.build_objective(
6607            (),
6608            move |_: &mut (), rho: &Array1<f64>| Ok(c * (-(rho[0] + rho[1]) / 2.0).exp()),
6609            move |_: &mut (), rho: &Array1<f64>| {
6610                let v = c * (-(rho[0] + rho[1]) / 2.0).exp();
6611                Ok(OuterEval {
6612                    cost: v,
6613                    gradient: array![-0.5 * v, -0.5 * v],
6614                    hessian: HessianValue::Unavailable,
6615                    inner_beta_hint: Some(array![a * (-(rho[0] + rho[1]) / 2.0).exp()]),
6616                })
6617            },
6618            None::<fn(&mut ())>,
6619            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6620        )
6621    }
6622
6623    /// #2349 round 7: the joint multi-coordinate rail face. The marginal
6624    /// single-coordinate tail law honestly fails on an overlapping-penalty
6625    /// face (measured on the multinomial checkpoint: ĉ₀ swept 8 orders of
6626    /// magnitude), so tail-snap must fall back to the joint face direction,
6627    /// certify the one-dimensional joint law there, and snap the whole face.
6628    #[test]
6629    fn joint_face_tail_certifies_where_single_coordinate_law_drifts_2349() {
6630        let c = 1.2 * (7.5_f64).exp();
6631        let rho = array![8.0, 7.0];
6632        let tol = {
6633            let mut t = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6634            t.tail_drift_rel = TAIL_SNAP_DRIFT_REL;
6635            t
6636        };
6637        let bounds = (Array1::from_elem(2, -12.0), Array1::from_elem(2, 12.0));
6638
6639        // The marginal law must genuinely fail first — otherwise this test
6640        // would pass vacuously with the joint path never exercised.
6641        let mut obj = joint_face_objective(c, 1.0e-9);
6642        let (single_window, _) = probe_tail_window(
6643            &mut obj,
6644            &rho,
6645            0,
6646            AsymptoteSide::Upper,
6647            &tol,
6648            (bounds.0[0], bounds.1[0]),
6649        )
6650        .expect("single-coordinate probing must not error");
6651        assert!(
6652            single_window.is_none(),
6653            "the marginal pencil constant drifts e^(1/2) per e-fold and must not \
6654             produce a finite-difference-clean run"
6655        );
6656
6657        // The joint window recovers the exact face constant.
6658        let (joint_window, _) = probe_joint_tail_window(
6659            &mut obj,
6660            &rho,
6661            &[(0, AsymptoteSide::Upper), (1, AsymptoteSide::Upper)],
6662            &tol,
6663            (&bounds.0, &bounds.1),
6664        )
6665        .expect("joint probing must not error");
6666        let window = joint_window.expect("the joint face law is exactly exponential");
6667        match assess_coordinate(&window, &tol) {
6668            AsymptoteVerdict::CertifiedAtAsymptote { tail_constant, .. } => {
6669                assert!(
6670                    (tail_constant - c).abs() / c < 1.0e-6,
6671                    "joint pencil constant must recover c: got {tail_constant}, want {c}"
6672                );
6673            }
6674            other => panic!("joint face must certify, got {other:?}"),
6675        }
6676
6677        // End-to-end: tail-snap declines the marginal law, falls back to the
6678        // joint face, and snaps BOTH coordinates to their upper rails.
6679        let g = -0.5 * c * (-7.5_f64).exp();
6680        let gradient = array![g, g];
6681        let hessian = array![[g.abs(), 0.0], [0.0, g.abs()]];
6682        let outcome = try_tail_snap_to_rail(
6683            &mut obj,
6684            &AsymptoteRailInputs {
6685                rho: &rho,
6686                projected_gradient: &gradient,
6687                railed: &[],
6688                hessian: &hessian,
6689                bounds: &bounds,
6690                terminal_beta: None,
6691                stationarity_bound: 1.0e-3,
6692                objective_tol: 1.0e-8,
6693                context: "joint-face guard test",
6694            },
6695        )
6696        .expect("tail snap must not error");
6697        match outcome {
6698            TailSnapOutcome::ConfirmedNeedsReseed(snapped) => {
6699                assert_eq!(
6700                    snapped,
6701                    array![12.0, 12.0],
6702                    "both face coordinates must snap to their upper rails"
6703                );
6704            }
6705            other => panic!(
6706                "the joint face must confirm and publish a reseed waypoint, got {other:?}"
6707            ),
6708        }
6709    }
6710
6711    /// #2349 e2e shape: the joint pencil-constant run confirms (measured on
6712    /// the multinomial checkpoint: ĉ settling 62.7 → … → 34.2) while the
6713    /// coefficient steps in the retained deep-interior rows are NOT yet
6714    /// geometrically contracting — the crawl was cut mid-travel. A confirmed
6715    /// law with an unsettled estimand must SNAP the face for re-optimization
6716    /// (the single-coordinate `OnTailNotYetEquivalent` semantics), not
6717    /// decline.
6718    #[test]
6719    fn joint_face_with_unsettled_estimand_snaps_for_reoptimization_2349() {
6720        let c = 1.2 * (7.5_f64).exp();
6721        // Non-contracting coefficient hints: constant per-probe steps (β moves
6722        // linearly in r), so coef_step_ratio has q = 1 and the estimand gate
6723        // refuses while the pencil constant is exact.
6724        let problem = OuterProblem::new(2).with_gradient(Derivative::Analytic);
6725        let mut obj = problem.build_objective(
6726            (),
6727            move |_: &mut (), rho: &Array1<f64>| Ok(c * (-(rho[0] + rho[1]) / 2.0).exp()),
6728            move |_: &mut (), rho: &Array1<f64>| {
6729                let v = c * (-(rho[0] + rho[1]) / 2.0).exp();
6730                Ok(OuterEval {
6731                    cost: v,
6732                    gradient: array![-0.5 * v, -0.5 * v],
6733                    hessian: HessianValue::Unavailable,
6734                    inner_beta_hint: Some(array![0.1 * (rho[0] + rho[1])]),
6735                })
6736            },
6737            None::<fn(&mut ())>,
6738            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6739        );
6740        let rho = array![8.0, 7.0];
6741        let g = -0.5 * c * (-7.5_f64).exp();
6742        let gradient = array![g, g];
6743        let hessian = array![[g.abs(), 0.0], [0.0, g.abs()]];
6744        let bounds = (Array1::from_elem(2, -12.0), Array1::from_elem(2, 12.0));
6745        let outcome = try_tail_snap_to_rail(
6746            &mut obj,
6747            &AsymptoteRailInputs {
6748                rho: &rho,
6749                projected_gradient: &gradient,
6750                railed: &[],
6751                hessian: &hessian,
6752                bounds: &bounds,
6753                terminal_beta: None,
6754                stationarity_bound: 1.0e-3,
6755                objective_tol: 1.0e-8,
6756                context: "joint-face unsettled-estimand guard test",
6757            },
6758        )
6759        .expect("tail snap must not error");
6760        match outcome {
6761            TailSnapOutcome::ConfirmedNeedsReseed(snapped) => {
6762                assert_eq!(
6763                    snapped,
6764                    array![12.0, 12.0],
6765                    "a confirmed joint law with unsettled estimand must snap the face"
6766                );
6767            }
6768            other => panic!("expected a face snap, got {other:?}"),
6769        }
6770    }
6771
6772    /// A pair of super-bound coordinates that do NOT share a face (independent
6773    /// laws with strongly drifting joint section) must still decline — the
6774    /// joint fallback cannot manufacture a certificate where no joint law
6775    /// holds.
6776    #[test]
6777    fn joint_face_fallback_refuses_a_non_face_2349() {
6778        // V = c₀·e^{−ρ₀} + drift·ρ₀·e^{−ρ₀} + c₁·e^{−2ρ₁}: coordinate 0's own
6779        // law is corrupted by the drift term and coordinate 1 decays at a
6780        // DIFFERENT exponential rate, so neither the marginals nor the joint
6781        // direction carry a constant pencil.
6782        let problem = OuterProblem::new(2).with_gradient(Derivative::Analytic);
6783        let (c0, drift, c1) = (3.0e3, 2.0e3, 5.0e2);
6784        let mut obj = problem.build_objective(
6785            (),
6786            move |_: &mut (), rho: &Array1<f64>| {
6787                Ok((c0 + drift * rho[0]) * (-rho[0]).exp() + c1 * (-2.0 * rho[1]).exp())
6788            },
6789            move |_: &mut (), rho: &Array1<f64>| {
6790                let e0 = (-rho[0]).exp();
6791                let e1 = (-2.0 * rho[1]).exp();
6792                Ok(OuterEval {
6793                    cost: (c0 + drift * rho[0]) * e0 + c1 * e1,
6794                    gradient: array![
6795                        drift * e0 - (c0 + drift * rho[0]) * e0,
6796                        -2.0 * c1 * e1
6797                    ],
6798                    hessian: HessianValue::Unavailable,
6799                    inner_beta_hint: Some(array![1.0e-9 * e0]),
6800                })
6801            },
6802            None::<fn(&mut ())>,
6803            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6804        );
6805        let rho = array![8.0, 7.0];
6806        let g0 = drift * (-8.0_f64).exp() - (c0 + drift * 8.0) * (-8.0_f64).exp();
6807        let g1 = -2.0 * c1 * (-14.0_f64).exp();
6808        let gradient = array![g0, g1];
6809        let hessian = array![[g0.abs(), 0.0], [0.0, g1.abs()]];
6810        let bounds = (Array1::from_elem(2, -12.0), Array1::from_elem(2, 12.0));
6811        let outcome = try_tail_snap_to_rail(
6812            &mut obj,
6813            &AsymptoteRailInputs {
6814                rho: &rho,
6815                projected_gradient: &gradient,
6816                railed: &[],
6817                hessian: &hessian,
6818                bounds: &bounds,
6819                terminal_beta: None,
6820                stationarity_bound: 1.0e-9,
6821                objective_tol: 1.0e-8,
6822                context: "non-face guard test",
6823            },
6824        )
6825        .expect("tail snap must not error");
6826        match outcome {
6827            TailSnapOutcome::Declined(reason) => {
6828                assert!(
6829                    reason.contains("joint 2-coordinate face"),
6830                    "the decline must carry the joint-face evidence, got: {reason}"
6831                );
6832            }
6833            other => panic!("a non-face must decline, got {other:?}"),
6834        }
6835    }
6836
6837    /// #2388: the tail-probe ladder must never step the probed coordinate
6838    /// outside its own box interval. Past a box bound the ρ-gradient assembly
6839    /// reports the #197 frozen-axis projection — a literal `0.0` — so an
6840    /// out-of-box probe fabricates a hard-zero tail row (`1.531e0 → 0.000e0` in
6841    /// one e-fold in the #2388 evidence) that the drift band can never confirm,
6842    /// and the fit refuses. The ladder must stop at the last strictly-in-domain
6843    /// probe, and the in-domain rows alone must still confirm an exact tail.
6844    #[test]
6845    fn tail_probe_ladder_never_leaves_the_coordinate_box_2388() {
6846        let c = 6723.0_f64;
6847        // Deep enough that the in-domain ladder keeps a healthy-gradient run
6848        // (probes at |g| below the interior floor are rightly judged unclean),
6849        // shallow enough that the 18-probe ladder would cross it without the
6850        // domain clip.
6851        let box_lower = 12.0_f64;
6852        let probed = std::sync::Arc::new(std::sync::Mutex::new(Vec::<f64>::new()));
6853        let probed_in_eval = std::sync::Arc::clone(&probed);
6854        let problem = OuterProblem::new(1).with_gradient(Derivative::Analytic);
6855        let mut obj = problem.build_objective(
6856            (),
6857            move |_: &mut (), rho: &Array1<f64>| Ok((c * (-rho[0]).exp()).abs()),
6858            move |_: &mut (), rho: &Array1<f64>| {
6859                let r = rho[0];
6860                probed_in_eval.lock().expect("probe log").push(r);
6861                // Below the box the assembly's frozen-axis convention reports a
6862                // fabricated zero gradient — exactly the #2388 evidence shape.
6863                let grad = if r <= box_lower + 1.0e-8 {
6864                    0.0
6865                } else {
6866                    -c * (-r).exp()
6867                };
6868                Ok(OuterEval {
6869                    cost: (c * (-r).exp()).abs(),
6870                    gradient: array![grad],
6871                    hessian: HessianValue::Unavailable,
6872                    inner_beta_hint: Some(array![(-r).exp()]),
6873                })
6874            },
6875            None::<fn(&mut ())>,
6876            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6877        );
6878        let rho = array![29.9];
6879        let tol = AsymptoteTolerances::exp4_rail_bands(1.0e-2);
6880        let rail = build_and_assess_rail_coordinate(
6881            &mut obj,
6882            &rho,
6883            0,
6884            AsymptoteSide::Upper,
6885            &tol,
6886            (box_lower, 30.0),
6887        )
6888        .expect("probing must not error")
6889        .expect("the in-domain rows alone must certify the exact tail");
6890        assert!(
6891            (rail.tail_constant - c).abs() / c < 1.0e-6,
6892            "recovered ĉ={} should equal c={c}",
6893            rail.tail_constant,
6894        );
6895        let seen = probed.lock().expect("probe log").clone();
6896        assert!(
6897            !seen.is_empty() && seen.iter().all(|&r| r > box_lower),
6898            "no probe may leave the λ-selection domain (lower bound {box_lower}): {seen:?}",
6899        );
6900    }
6901
6902    /// Build a two-coordinate objective: coordinate 0 follows the upper-rail tail
6903    /// law; coordinate 1 (interior) is gradient-flat.
6904    fn upper_tail_with_interior(c: f64, a: f64) -> impl OuterObjective {
6905        let problem = OuterProblem::new(2).with_gradient(Derivative::Analytic);
6906        problem.build_objective(
6907            (),
6908            move |_: &mut (), rho: &Array1<f64>| Ok((c * (-rho[0]).exp()).abs()),
6909            move |_: &mut (), rho: &Array1<f64>| {
6910                let r = rho[0];
6911                Ok(OuterEval {
6912                    cost: (c * (-r).exp()).abs(),
6913                    gradient: array![-c * (-r).exp(), 0.0],
6914                    hessian: HessianValue::Unavailable,
6915                    inner_beta_hint: Some(array![a * (-r).exp(), 0.0]),
6916                })
6917            },
6918            None::<fn(&mut ())>,
6919            None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
6920        )
6921    }
6922
6923    /// The interior-PSD gate is load-bearing: with a positive-definite interior
6924    /// sub-block the confirmed tail mints, but a genuinely indefinite interior
6925    /// curvature refuses the rail certificate even though the tail is clean.
6926    #[test]
6927    fn asymptote_rail_requires_psd_interior_sub_block() {
6928        let rho = array![29.9, 0.0];
6929        let projected = array![0.0, 0.0];
6930        let bounds = (array![-30.0, -30.0], array![30.0, 30.0]);
6931        let railed = [0usize];
6932
6933        let mut obj = upper_tail_with_interior(6723.0, 1.0);
6934        let hessian_psd = array![[1.0, 0.0], [0.0, 2.0]];
6935        let inputs_psd = AsymptoteRailInputs {
6936            rho: &rho,
6937            projected_gradient: &projected,
6938            railed: &railed,
6939            hessian: &hessian_psd,
6940            bounds: &bounds,
6941            terminal_beta: None,
6942            stationarity_bound: 1.0e-6,
6943            objective_tol: 1.0e-5,
6944            context: "asymptote-rail psd test",
6945        };
6946        let minted = try_certify_asymptote_rail(&mut obj, &inputs_psd)
6947            .expect("certification must not error");
6948        let (interior_norm, effective_bound, rails) =
6949            minted.expect("PSD interior + confirmed tail must mint");
6950        assert!(interior_norm <= 1.0e-6);
6951        assert!(
6952            effective_bound >= interior_norm,
6953            "the admitting bound must cover the interior norm"
6954        );
6955        assert_eq!(rails.len(), 1);
6956        assert_eq!(rails[0].index, 0);
6957
6958        let hessian_indefinite = array![[1.0, 0.0], [0.0, -2.0]];
6959        let inputs_indefinite = AsymptoteRailInputs {
6960            hessian: &hessian_indefinite,
6961            ..inputs_psd
6962        };
6963        let refused = try_certify_asymptote_rail(&mut obj, &inputs_indefinite)
6964            .expect("certification must not error");
6965        assert!(
6966            refused.is_err(),
6967            "indefinite interior curvature must refuse the rail certificate, got {refused:?}",
6968        );
6969        let reason = refused.unwrap_err();
6970        assert!(
6971            reason.contains("not PSD") || reason.contains("interior"),
6972            "the decline must name the refusing gate, got: {reason}"
6973        );
6974    }
6975}
6976
6977#[cfg(test)]
6978mod certify_resume_progress_tests {
6979    //! Unit coverage for the certify-last checkpoint-resume progress gate
6980    //! (#2374). The generalized loop keeps reseeding at the refused checkpoint
6981    //! only while each reseed exploits real descent; `certify_resume_made_progress`
6982    //! is the exact predicate that decides "real descent" vs "genuine floor", so
6983    //! pinning it directly pins the loop's termination contract independent of the
6984    //! solver dynamics that produce the reseeds.
6985    use super::{
6986        CERTIFY_RESUME_PROGRESS_REL, OuterConfig, certify_resume_made_progress,
6987        outer_rel_cost_floor,
6988    };
6989
6990    fn config_with_rel_cost(rel_cost: Option<f64>, tolerance: f64) -> OuterConfig {
6991        OuterConfig {
6992            tolerance,
6993            rel_cost_tolerance: rel_cost,
6994            ..OuterConfig::default()
6995        }
6996    }
6997
6998    #[test]
6999    fn rel_cost_floor_prefers_explicit_then_scaled_tolerance_never_below_hard_floor() {
7000        // Explicit relative tolerance wins verbatim.
7001        let explicit = config_with_rel_cost(Some(1.0e-3), 1.0e-5);
7002        assert_eq!(outer_rel_cost_floor(&explicit), 1.0e-3);
7003        // Absent, it derives from a small fraction of the absolute tolerance.
7004        let derived = config_with_rel_cost(None, 1.0e-2);
7005        assert!((outer_rel_cost_floor(&derived) - 1.0e-4).abs() <= 1.0e-16);
7006        // But never below the shared hard floor, however tight the tolerances.
7007        let tiny = config_with_rel_cost(Some(1.0e-30), 1.0e-30);
7008        assert_eq!(outer_rel_cost_floor(&tiny), super::COST_STALL_REL_TOL_FLOOR);
7009    }
7010
7011    // ── Helper math (arbitrary floor) ────────────────────────────────────
7012
7013    #[test]
7014    fn strict_descent_past_the_floor_is_progress() {
7015        let floor = 1.0e-4;
7016        // A drop far larger than floor·(1+|cost|)≈0.034 at cost scale ~1e2.
7017        assert!(certify_resume_made_progress(342.0, 300.0, floor));
7018        // A drop of many orders is trivially progress.
7019        assert!(certify_resume_made_progress(1.0e6, 1.0e3, floor));
7020    }
7021
7022    #[test]
7023    fn flat_or_uphill_reseed_is_not_progress() {
7024        let floor = 1.0e-4;
7025        // Exactly equal: no descent.
7026        assert!(!certify_resume_made_progress(100.0, 100.0, floor));
7027        // Uphill: a metric restart that landed worse is never progress.
7028        assert!(!certify_resume_made_progress(100.0, 100.5, floor));
7029        // A reduction SMALLER than the passed floor is within the flat band.
7030        let cost = 1.0e4;
7031        let sub_floor = floor * (1.0 + cost) * 0.5;
7032        assert!(!certify_resume_made_progress(cost, cost - sub_floor, floor));
7033    }
7034
7035    #[test]
7036    fn floor_anchors_on_the_smaller_cost_magnitude() {
7037        // With prior≈0 and a large-magnitude retried, anchoring on the smaller
7038        // (prior) magnitude keeps the floor tight so a genuine tiny descent near a
7039        // small optimum still registers, rather than being swamped by |retried|.
7040        let floor = 1.0e-4;
7041        // prior tiny-positive, retried strictly below it by more than floor·(1+0):
7042        assert!(certify_resume_made_progress(1.0e-2, 1.0e-3, floor));
7043    }
7044
7045    #[test]
7046    fn non_finite_retried_is_never_progress() {
7047        let floor = 1.0e-4;
7048        assert!(!certify_resume_made_progress(100.0, f64::NAN, floor));
7049        assert!(!certify_resume_made_progress(100.0, f64::INFINITY, floor));
7050        assert!(!certify_resume_made_progress(100.0, f64::NEG_INFINITY, floor));
7051    }
7052
7053    // ── Production gate (roundoff floor) ─────────────────────────────────
7054    //
7055    // These pin the ACTUAL gate the loop runs (`CERTIFY_RESUME_PROGRESS_REL`),
7056    // which must admit the tiny per-reseed descent a flat valley crawls out in
7057    // and reject only numerical noise — the exact distinction the earlier
7058    // cost-stall-floor gate got wrong (#2374: it stopped the survival LAML crawl
7059    // after one hop and refused a well-posed fit).
7060
7061    #[test]
7062    fn roundoff_gate_admits_the_tiny_flat_valley_crawl_step() {
7063        let rel = CERTIFY_RESUME_PROGRESS_REL;
7064        // The transformation-survival LAML moves ~4e-5 relative per reseed:
7065        // cost 342.0730 → 342.0580 is ~4.4e-5 relative, far above roundoff.
7066        assert!(certify_resume_made_progress(342.0730, 342.0580, rel));
7067        // Even a 1e-6 relative step at cost ~455 (the two-smooth cohort scale)
7068        // is real descent under the roundoff gate — the coarse cost-stall floor
7069        // (~1e-6·456 ≈ 4.6e-4) would have wrongly rejected it.
7070        assert!(certify_resume_made_progress(455.40, 455.40 - 5.0e-4, rel));
7071    }
7072
7073    #[test]
7074    fn roundoff_gate_rejects_noise_and_non_descent() {
7075        let rel = CERTIFY_RESUME_PROGRESS_REL;
7076        // A bitwise-identical reseed (genuine floor: BFGS found no descent from
7077        // the checkpoint) is not progress.
7078        assert!(!certify_resume_made_progress(455.40, 455.40, rel));
7079        // A reduction at the roundoff scale is noise, not descent: a few ULPs at
7080        // cost ~455 sits below CERTIFY_RESUME_PROGRESS_REL·(1+455).
7081        let noise = 4.0 * f64::EPSILON * (1.0 + 455.40);
7082        assert!(!certify_resume_made_progress(455.40, 455.40 - noise, rel));
7083        // Uphill / non-finite are never progress.
7084        assert!(!certify_resume_made_progress(455.40, 455.41, rel));
7085        assert!(!certify_resume_made_progress(455.40, f64::NAN, rel));
7086    }
7087}