Skip to main content

gam_solve/rho_optimizer/
run.rs

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