From f6a02bc3d80d15e4f5d1f480af7cce55b1b6015a Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Thu, 25 Jun 2026 06:14:05 -0400 Subject: [PATCH 1/4] QA: run_qa v1.6 form + ExplicitImports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert test/qa/qa.jl from a hand-rolled Aqua testset to SciMLTesting's run_qa (v1.6) with ExplicitImports enabled. The bespoke JET `@test_opt` constructor type-stability checks stay in test/qa/jet_tests.jl (run_qa's `JET.test_package` error analysis does not subsume them); run_qa keeps its JET off via `jet = false` so loading JET in jet_tests.jl does not auto-enable it. ExplicitImports findings resolved: - no_implicit_imports: add SciMLBase.DiscreteProblem to the explicit imports (was used implicitly). - no_stale_explicit_imports: drop genuinely-unused imports NonlinearLeastSquaresProblem, init, reinit!, solve! (SciMLBase) and ldiv! (LinearAlgebra) — each was only ever accessed in qualified/extended form (SciMLBase.reinit! etc.) or not at all. derivative_discontinuity! is kept and ignored: it is imported inside the @static-if SciMLBase v2/v3 rename shim and used bare on v3, which the static scan cannot see through. - all_qualified_accesses_via_owners: change SciMLBase.copyto! to bare copyto! in the manifold projection (copyto! is Base's, already imported from LinearAlgebra). - Remaining other-package non-public qualified accesses / explicit imports ignored via ei_kwargs (SciMLBase / LinearAlgebra / Base / DiffEqBase internals; several are `public` on 1.11+ but flagged on the LTS). test/qa/Project.toml: add SciMLTesting (compat "1.6"); ExplicitImports comes transitively via SciMLTesting; Aqua and JET stay direct deps (Aqua's ambiguities child-proc and the bespoke JET check need them). Verified locally against released SciMLTesting 1.6.0: QA group green on both lanes (Julia 1.12: jet_tests 15/15, qa.jl 17/17; Julia 1.10 LTS: jet_tests 1 broken [JET-skip-on-LTS, preserved], qa.jl 17/17). Full Core lane green on 1.12 (manifold 25/25, domain 19/19, terminatesteadystate 11/11). Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/DiffEqCallbacks.jl | 10 ++++---- src/manifold.jl | 2 +- test/qa/Project.toml | 2 ++ test/qa/qa.jl | 52 ++++++++++++++++++++++++++++++------------ 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/DiffEqCallbacks.jl b/src/DiffEqCallbacks.jl index 0d6c4818..6ef84eb6 100644 --- a/src/DiffEqCallbacks.jl +++ b/src/DiffEqCallbacks.jl @@ -4,16 +4,16 @@ using ConcreteStructs: @concrete using DataStructures: DataStructures, BinaryMaxHeap, BinaryMinHeap using DiffEqBase: DiffEqBase, get_tstops, get_tstops_array, get_tstops_max using DifferentiationInterface: DifferentiationInterface, Constant -using LinearAlgebra: LinearAlgebra, adjoint, axpy!, copyto!, diagind, mul!, ldiv! +using LinearAlgebra: LinearAlgebra, adjoint, axpy!, copyto!, diagind, mul! using Markdown: @doc_str using PrecompileTools: PrecompileTools using RecipesBase: @recipe using RecursiveArrayTools: RecursiveArrayTools, DiffEqArray, copyat_or_push! -using SciMLBase: SciMLBase, CallbackSet, DiscreteCallback, NonlinearFunction, - NonlinearLeastSquaresProblem, NonlinearProblem, RODEProblem, +using SciMLBase: SciMLBase, CallbackSet, DiscreteCallback, DiscreteProblem, + NonlinearFunction, NonlinearProblem, RODEProblem, ReturnCode, SDEProblem, add_tstop!, check_error, get_du, - get_proposed_dt, get_tmp_cache, init, reinit!, - set_proposed_dt!, solve!, terminate! + get_proposed_dt, get_tmp_cache, + set_proposed_dt!, terminate! using StaticArraysCore: StaticArraysCore # SciMLBase v3 renamed `u_modified!` → `derivative_discontinuity!` (with diff --git a/src/manifold.jl b/src/manifold.jl index 6b927183..20cab184 100644 --- a/src/manifold.jl +++ b/src/manifold.jl @@ -114,7 +114,7 @@ function (proj::ManifoldProjection)(integrator) return end - return SciMLBase.copyto!(integrator.u, u) + return copyto!(integrator.u, u) end function initialize_manifold_projection(cb, u, t, integrator) diff --git a/test/qa/Project.toml b/test/qa/Project.toml index cb4fd96e..9c6e0602 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -2,9 +2,11 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Aqua = "0.8" JET = "0.9, 0.10, 0.11" +SciMLTesting = "1.6" Test = "1" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index e0c6d60d..b9df2d29 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,14 +1,38 @@ -using DiffEqCallbacks, Aqua -@testset "Aqua" begin - Aqua.find_persistent_tasks_deps(DiffEqCallbacks) - Aqua.test_ambiguities(DiffEqCallbacks, recursive = false) - Aqua.test_deps_compat(DiffEqCallbacks) - Aqua.test_piracies( - DiffEqCallbacks, - treat_as_own = [] - ) - Aqua.test_project_extras(DiffEqCallbacks) - Aqua.test_stale_deps(DiffEqCallbacks) - Aqua.test_unbound_args(DiffEqCallbacks) - Aqua.test_undefined_exports(DiffEqCallbacks) -end +using SciMLTesting, DiffEqCallbacks, Test + +run_qa( + DiffEqCallbacks; + explicit_imports = true, + # JET is covered by the curated `@test_opt` constructor type-stability checks in + # jet_tests.jl (which `run_qa`'s `JET.test_package` error analysis does not + # subsume); keep `run_qa`'s JET off so loading JET there does not auto-enable it. + jet = false, + ei_kwargs = (; + # `derivative_discontinuity!` is imported via `using SciMLBase:` inside a + # `@static if isdefined(SciMLBase, :derivative_discontinuity!)` block (the + # SciMLBase v2/v3 rename shim); ExplicitImports' static scan flags the import + # as stale because the `else` branch also binds the name as a `const`, but it + # is used bare on SciMLBase v3. + no_stale_explicit_imports = (; ignore = (:derivative_discontinuity!,)), + # Other packages' non-public names accessed in qualified form; go public as + # those packages release. The `Success`/`ConvergenceFailure`/`InitialFailure`/ + # `successful_retcode`/`Iterators.reverse` group is `public` in its owning module + # on Julia 1.11+ but flagged on the LTS (1.10, no `public` keyword), so it must + # be ignored for the QA lane's lts run. + all_qualified_accesses_are_public = (; + ignore = ( + :AbstractDEProblem, :AbstractODEIntegrator, :INITIALIZE_DEFAULT, + :_unwrap_val, :alg_order, :isadaptive, :numargs, # SciMLBase internals + :successful_retcode, # SciMLBase (public on 1.11+) + :Success, :ConvergenceFailure, :InitialFailure, # SciMLBase.ReturnCode (public on 1.11+) + :QRCompactWY, # LinearAlgebra internal + :RefValue, :depwarn, # Base internals + :reverse, # Base.Iterators (public on 1.11+) + ), + ), + # DiffEqBase internals imported explicitly; go public as DiffEqBase releases. + all_explicit_imports_are_public = (; + ignore = (:get_tstops, :get_tstops_array, :get_tstops_max), + ), + ), +) From f71c76f0cf9c89b0ee7f1ccd9920258e334ffc70 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 26 Jun 2026 15:05:28 -0400 Subject: [PATCH 2/4] QA: trim redundant public-API EI ignores (SciMLTesting 1.7 + released base libs) SciMLTesting 1.7.0 runs the two public-API ExplicitImports checks (check_all_qualified_accesses_are_public / check_all_explicit_imports_are_public) only on Julia >= 1.11 and skips them on the LTS, and SciMLBase 3.24.0 made several formerly-internal names public. With those released, the per-name public-API ignore-lists in test/qa/qa.jl are largely redundant. Drop the entries that are now public on the registered releases (verified on Julia 1.12 against SciMLBase 3.24.0): - all_qualified_accesses_are_public: remove numargs, successful_retcode, Success, ConvergenceFailure, InitialFailure (SciMLBase), depwarn (Base), reverse (Base.Iterators). Keep only what the public checks still flag against the registered releases: - all_qualified_accesses_are_public: AbstractDEProblem, AbstractODEIntegrator, INITIALIZE_DEFAULT, _unwrap_val, alg_order, isadaptive (SciMLBase 3.24.0, still non-public), QRCompactWY (LinearAlgebra), RefValue (Base). - all_explicit_imports_are_public: get_tstops, get_tstops_array, get_tstops_max (DiffEqBase 7.5.7, still non-public). The no_stale_explicit_imports ignore (derivative_discontinuity!) is unchanged. qa/Project.toml needs no compat change: SciMLTesting="1.6" already admits 1.7, and the base-lib floors transitively admit the released versions. Verified locally against registered releases (SciMLTesting 1.7.0, SciMLBase 3.24.0, DiffEqBase 7.5.7, ExplicitImports 1.15.0): - Julia 1.12 (public checks run): QA group 32/32 pass. - Julia 1.10 LTS (public checks skipped): QA group 15 pass + 1 broken (pre-existing JET-skip-on-LTS marker), 0 fail. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- test/qa/qa.jl | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/test/qa/qa.jl b/test/qa/qa.jl index b9df2d29..c40cf452 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -14,20 +14,15 @@ run_qa( # as stale because the `else` branch also binds the name as a `const`, but it # is used bare on SciMLBase v3. no_stale_explicit_imports = (; ignore = (:derivative_discontinuity!,)), - # Other packages' non-public names accessed in qualified form; go public as - # those packages release. The `Success`/`ConvergenceFailure`/`InitialFailure`/ - # `successful_retcode`/`Iterators.reverse` group is `public` in its owning module - # on Julia 1.11+ but flagged on the LTS (1.10, no `public` keyword), so it must - # be ignored for the QA lane's lts run. + # Names that are still non-public in their owning module on the released + # versions (verified on Julia 1.12 / SciMLBase 3.24.0, DiffEqBase 7.5.7, + # LinearAlgebra+Base stdlib): go public as those packages release. all_qualified_accesses_are_public = (; ignore = ( :AbstractDEProblem, :AbstractODEIntegrator, :INITIALIZE_DEFAULT, - :_unwrap_val, :alg_order, :isadaptive, :numargs, # SciMLBase internals - :successful_retcode, # SciMLBase (public on 1.11+) - :Success, :ConvergenceFailure, :InitialFailure, # SciMLBase.ReturnCode (public on 1.11+) - :QRCompactWY, # LinearAlgebra internal - :RefValue, :depwarn, # Base internals - :reverse, # Base.Iterators (public on 1.11+) + :_unwrap_val, :alg_order, :isadaptive, # SciMLBase internals + :QRCompactWY, # LinearAlgebra internal + :RefValue, # Base internal ), ), # DiffEqBase internals imported explicitly; go public as DiffEqBase releases. From c0d327d649f94453e86db41d5d0cddea3f79730e Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sat, 27 Jun 2026 00:00:08 -0400 Subject: [PATCH 3/4] QA: migrate DiffEqBase.X -> SciMLBase.X callers; strip now-public EI ignores DiffEqBase 7.6.0 / SciMLBase 3.27.0 make the previously-internal names public, so the public-API ExplicitImports ignores can be trimmed and the qualified-access callers pointed at the owning module (SciMLBase): - src: rewrite `DiffEqBase.isinplace/addsteps!/get_du!/DiscreteProblem` (all SciMLBase-owned, now public, identity-equal re-exports) to `SciMLBase.X`; drop the now-unused `DiffEqBase` module self-binding from the import (only the DiffEqBase-own `get_tstops*` are still used bare); fix the PresetTimeCallback docstring to `SciMLBase.INITIALIZE_DEFAULT`. - qa.jl: empty `all_explicit_imports_are_public` (get_tstops* now public in DiffEqBase 7.6.0) and drop `AbstractDEProblem/alg_order/isadaptive` from `all_qualified_accesses_are_public` (now public in SciMLBase 3.27.0). Survivors kept (verified still non-public on Julia 1.12 / SciMLBase 3.27.0, DiffEqBase 7.6.0, stdlib): AbstractODEIntegrator, INITIALIZE_DEFAULT, _unwrap_val (SciMLBase), QRCompactWY (LinearAlgebra), RefValue (Base). Verified: QA group 17/17 on Julia 1.12 (public-API checks run), 15/15 on Julia 1.10 (public-API checks gated off by SciMLTesting 1.7); 0 fail/error. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/DiffEqCallbacks.jl | 2 +- src/function_caller.jl | 2 +- src/integrating.jl | 2 +- src/integrating_GK_affect.jl | 2 +- src/integrating_GK_sum.jl | 2 +- src/integrating_sum.jl | 2 +- src/preset_time.jl | 2 +- src/saving.jl | 4 ++-- src/terminatesteadystate.jl | 10 +++++----- test/qa/qa.jl | 17 ++++++----------- 10 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/DiffEqCallbacks.jl b/src/DiffEqCallbacks.jl index 6ef84eb6..43c9c4bd 100644 --- a/src/DiffEqCallbacks.jl +++ b/src/DiffEqCallbacks.jl @@ -2,7 +2,7 @@ module DiffEqCallbacks using ConcreteStructs: @concrete using DataStructures: DataStructures, BinaryMaxHeap, BinaryMinHeap -using DiffEqBase: DiffEqBase, get_tstops, get_tstops_array, get_tstops_max +using DiffEqBase: get_tstops, get_tstops_array, get_tstops_max using DifferentiationInterface: DifferentiationInterface, Constant using LinearAlgebra: LinearAlgebra, adjoint, axpy!, copyto!, diagind, mul! using Markdown: @doc_str diff --git a/src/function_caller.jl b/src/function_caller.jl index 2cdb98ce..32efd7cf 100644 --- a/src/function_caller.jl +++ b/src/function_caller.jl @@ -19,7 +19,7 @@ function (affect!::FunctionCallingAffect)(integrator, force_func = false) if curt != integrator.t # If Date: Mon, 29 Jun 2026 06:32:23 -0400 Subject: [PATCH 4/4] QA: eliminate fixable EI exceptions (migrate/local-define), keep only stdlib internals ExplicitImports exceptions in test/qa/qa.jl reduced from 6 to 2 by fixing the root cause instead of ignoring: - derivative_discontinuity! (no_stale_explicit_imports ignore): the v2/v3 rename shim used `using SciMLBase: derivative_discontinuity!` on one branch and a `const ... = SciMLBase.u_modified!` on the other, which EI flagged as a stale import. Replaced with a single `const` bound to whichever public name the loaded SciMLBase provides; behavior is identical on both v2 (u_modified!) and v3 (derivative_discontinuity!), both of which are public. Drops the ignore. - AbstractODEIntegrator (all_qualified_accesses_are_public ignore): now public in SciMLBase 3.30.0 and already accessed via the public owner SciMLBase; ignore is redundant and dropped. - INITIALIZE_DEFAULT: defined a local no-op `INITIALIZE_DEFAULT(cb,u,t,integrator) = derivative_discontinuity!(integrator, false)` matching SciMLBase's non-public const (no identity comparison exists for it anywhere in SciMLBase/DiffEqBase/ OrdinaryDiffEqCore, so a local binding is behavior-preserving) and use it as the PresetTimeCallback default. Drops the ignore. - _unwrap_val: defined a local `_unwrap_val` (the leading-underscore SciMLBase internal that will not be made public) reproducing its exact behavior, used in manifold.jl. Drops the ignore. Remaining 2 ignores are genuinely-irreducible concrete stdlib internal types with no public spelling: LinearAlgebra.QRCompactWY (dispatch target of fact_successful) and Base.RefValue (concrete Ref type in a parametric NamedTuple alias). No new direct deps: all migrations went to local definitions or to already-imported public SciMLBase API. Verified on Julia 1.12 / SciMLBase 3.30.0 / SciMLTesting 1.7.0: QA group 17/17 pass; print_explicit_imports reports only the 2 stdlib internals. Co-Authored-By: Chris Rackauckas --- src/DiffEqCallbacks.jl | 22 ++++++++++++++++++---- src/manifold.jl | 2 +- src/preset_time.jl | 4 ++-- test/qa/qa.jl | 21 +++++++++------------ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/DiffEqCallbacks.jl b/src/DiffEqCallbacks.jl index 43c9c4bd..407fa71e 100644 --- a/src/DiffEqCallbacks.jl +++ b/src/DiffEqCallbacks.jl @@ -18,16 +18,30 @@ using StaticArraysCore: StaticArraysCore # SciMLBase v3 renamed `u_modified!` → `derivative_discontinuity!` (with # an `@deprecate` on the old name). Support both SciMLBase v2 and v3 by -# aliasing to whichever name the loaded SciMLBase provides. -@static if isdefined(SciMLBase, :derivative_discontinuity!) - using SciMLBase: derivative_discontinuity! +# binding a const to whichever name the loaded SciMLBase provides. Both +# `derivative_discontinuity!` and `u_modified!` are public in their +# respective SciMLBase versions, so the qualified access is to public API; a +# `const` (rather than a `using` import on one branch) keeps the name a single +# local binding and avoids a stale-import false positive. +const derivative_discontinuity! = if isdefined(SciMLBase, :derivative_discontinuity!) + SciMLBase.derivative_discontinuity! else - const derivative_discontinuity! = SciMLBase.u_modified! + SciMLBase.u_modified! end const DI = DifferentiationInterface true_condition(u, t, integrator) = true +# Local reproduction of SciMLBase's `_unwrap_val` (a leading-underscore internal +# that will not be made public): pull the value out of a `Val`, pass anything +# else through unchanged. +_unwrap_val(B) = B +_unwrap_val(::Val{B}) where {B} = B + +# No-op default `initialize` for `DiscreteCallback`, matching SciMLBase's +# (non-public) `INITIALIZE_DEFAULT`: reset the derivative-discontinuity flag. +INITIALIZE_DEFAULT(cb, u, t, integrator) = derivative_discontinuity!(integrator, false) + include("functor_helpers.jl") include("autoabstol.jl") include("manifold.jl") diff --git a/src/manifold.jl b/src/manifold.jl index 20cab184..0382703d 100644 --- a/src/manifold.jl +++ b/src/manifold.jl @@ -152,7 +152,7 @@ export ManifoldProjection # wrapper for non-autonomous functions function wrap_autonomous_function(autonomous::Union{Val{true}, Val{false}}, g) g === nothing && return nothing - return TypedNonAutonomousFunction{SciMLBase._unwrap_val(autonomous)}(g, nothing) + return TypedNonAutonomousFunction{_unwrap_val(autonomous)}(g, nothing) end function wrap_autonomous_function(autonomous::Union{Bool, Nothing}, g) g === nothing && return nothing diff --git a/src/preset_time.jl b/src/preset_time.jl index d9aa58eb..9bc8fbb1 100644 --- a/src/preset_time.jl +++ b/src/preset_time.jl @@ -34,7 +34,7 @@ end """ ```julia PresetTimeCallback(tstops, user_affect!; - initialize = SciMLBase.INITIALIZE_DEFAULT, + initialize = INITIALIZE_DEFAULT, filter_tstops = true, kwargs...) ``` @@ -55,7 +55,7 @@ automatic. """ function PresetTimeCallback( tstops, user_affect!; - initialize = SciMLBase.INITIALIZE_DEFAULT, + initialize = INITIALIZE_DEFAULT, filter_tstops = true, sort_inplace = false, kwargs... ) diff --git a/test/qa/qa.jl b/test/qa/qa.jl index c99924bc..82ff1c5d 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -8,20 +8,17 @@ run_qa( # subsume); keep `run_qa`'s JET off so loading JET there does not auto-enable it. jet = false, ei_kwargs = (; - # `derivative_discontinuity!` is imported via `using SciMLBase:` inside a - # `@static if isdefined(SciMLBase, :derivative_discontinuity!)` block (the - # SciMLBase v2/v3 rename shim); ExplicitImports' static scan flags the import - # as stale because the `else` branch also binds the name as a `const`, but it - # is used bare on SciMLBase v3. - no_stale_explicit_imports = (; ignore = (:derivative_discontinuity!,)), - # Names still non-public in their owning module on the released versions - # (verified on Julia 1.12 / SciMLBase 3.27.0, DiffEqBase 7.6.0, LinearAlgebra + - # Base stdlib): they go public as those packages release. + # The only remaining non-public qualified accesses are to concrete stdlib + # types used for method dispatch, for which there is no public spelling + # (verified on Julia 1.12): + # `LinearAlgebra.QRCompactWY` — the concrete result type of `qr(A)` for a + # dense matrix; `fact_successful` dispatches on it to read `.factors`. + # `Base.RefValue` — the concrete type behind `Ref`; used in a + # parametric `NamedTuple` type alias where the abstract `Ref` will not do. all_qualified_accesses_are_public = (; ignore = ( - :AbstractODEIntegrator, :INITIALIZE_DEFAULT, :_unwrap_val, # SciMLBase internals - :QRCompactWY, # LinearAlgebra internal - :RefValue, # Base internal + :QRCompactWY, # LinearAlgebra internal concrete factorization type + :RefValue, # Base internal concrete Ref type ), ), ),