From f0f73d4833e8d50454a2a98064203e9c6bf680bb Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Thu, 25 Jun 2026 06:28:21 -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 the hand-rolled JET-only QA group (test/qa/jet_tests.jl) to the SciMLTesting 1.6 run_qa form with ExplicitImports enabled. test/qa/qa.jl: - run_qa(PDEBase; explicit_imports = true) — Aqua + JET + ExplicitImports. - Aqua: treat_as_own = [PDEBase.symbolic_discretize] (PDEBase extends SciMLBase.symbolic_discretize on a PDESystem as its discretization entry point); deps_compat check_extras = false (folder-model test deps live in test/qa/Project.toml, root [extras] are vestigial). - ExplicitImports ignore-lists for re-exporter/non-public names owned by ModelingToolkitBase / TermInterface / SymbolicUtils / Symbolics / SciMLBase. - ei_broken = (:no_implicit_imports,): PDEBase's surface rests on heavy `using ModelingToolkit / Symbolics / SymbolicUtils / SciMLBase / DomainSets`; making each implicitly used name explicit is a large refactor tracked separately. src/PDEBase.jl: - Remove 8 stale (unused) explicit imports flagged by check_no_stale_explicit_imports: parameters, varmap_to_vars, solve_for, expand_derivatives, diff2term, variable, Postwalk, symtype. - Remove the phantom export `pde_substitute_filter` (exported but never defined — Aqua undefined_exports failure; only pde_substitute exists). test/qa/Project.toml: - Add Aqua as a direct dep (Aqua.test_ambiguities spawns a child process that `import Aqua`s, so it must be a direct dep, not transitive via SciMLTesting). - Drop Symbolics / SymbolicUtils (were only used by the old jet_tests.jl). - SciMLTesting compat -> "1.6". Verified locally on Julia LTS against released SciMLTesting 1.6.0: QA group 16 Pass / 1 Broken (no_implicit_imports) / 0 Fail / 0 Error; Core group alloc_tests 12/12 pass. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/PDEBase.jl | 10 ++++---- test/qa/Project.toml | 8 +++--- test/qa/jet_tests.jl | 60 -------------------------------------------- test/qa/qa.jl | 58 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 70 deletions(-) delete mode 100644 test/qa/jet_tests.jl create mode 100644 test/qa/qa.jl diff --git a/src/PDEBase.jl b/src/PDEBase.jl index 551032b..5fbd600 100644 --- a/src/PDEBase.jl +++ b/src/PDEBase.jl @@ -5,14 +5,14 @@ using SciMLBase: AbstractDiscretization, AbstractDiscretizationMetadata using ModelingToolkit using ModelingToolkit: get_unknowns, ProblemTypeCtx, get_ps, get_bcs, get_dvs, - parameters, varmap_to_vars, get_eqs, get_iv, + get_eqs, get_iv, get_domain, get_ivs, get_systems, get_connector_type, get_metadata, get_gui_metadata using Symbolics, SymbolicUtils -using Symbolics: unwrap, solve_for, expand_derivatives, diff2term, setname, rename, variable -using SymbolicUtils: operation, arguments, Chain, Prewalk, Postwalk, maketerm, metadata, - symtype, operation, iscall, arguments, getmetadata, unwrap_const, substitute +using Symbolics: unwrap, setname, rename +using SymbolicUtils: operation, arguments, Chain, Prewalk, maketerm, metadata, + iscall, getmetadata, unwrap_const, substitute using SymbolicIndexingInterface: is_time_dependent using DomainSets @@ -47,7 +47,7 @@ export AbstractBoundary, AbstractTruncatingBoundary, AbstractInterfaceBoundary, export get_time export count_differentials, differential_order, has_derivatives, find_derivative, d_orders, - subs_alleqs!, get_depvars, getvars, pde_substitute, pde_substitute_filter, + subs_alleqs!, get_depvars, getvars, pde_substitute, get_all_depvars, split_terms, split_additive_terms, subsmatch, ex2term, safe_unwrap, recursive_unwrap, flatten_vardict, filter_interfaces, isperiodic, isinterface, haslowerupper, has_interfaces, isupper diff --git a/test/qa/Project.toml b/test/qa/Project.toml index f5d58dd..c41c251 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -1,19 +1,17 @@ [deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" PDEBase = "a7812802-0625-4b9e-961c-d332478797e5" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" -SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b" -Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [sources] PDEBase = {path = "../.."} [compat] +Aqua = "0.8" JET = "0.9, 0.10, 0.11" SafeTestsets = "0.0.1, 0.1, 1" -SciMLTesting = "1" -SymbolicUtils = "4" -Symbolics = "7" +SciMLTesting = "1.6" Test = "1" diff --git a/test/qa/jet_tests.jl b/test/qa/jet_tests.jl deleted file mode 100644 index 5bd2815..0000000 --- a/test/qa/jet_tests.jl +++ /dev/null @@ -1,60 +0,0 @@ -using JET -using PDEBase -using Test -import Symbolics -using SymbolicUtils: operation - -@testset "JET static analysis" begin - # Test core symbolic utility functions for type stability - # JET reports from dependencies (Symbolics, SymbolicUtils) are filtered - # via target_modules to avoid noise from transitive symbolic-stack issues. - @eval Symbolics.@variables x y t - @eval Symbolics.@variables u(..) - - x_sym = Symbolics.unwrap(x) - u_term = Symbolics.unwrap(u(x, y, t)) - depvar_ops = [operation(u_term)] - - Dx = Symbolics.Differential(x) - term = Symbolics.unwrap(Dx(u(x, y, t))) - - @testset "safe_unwrap" begin - rep = JET.report_call( - PDEBase.safe_unwrap, (typeof(u(x, y, t)),); - target_modules = (PDEBase,) - ) - @test length(JET.get_reports(rep)) == 0 - end - - @testset "has_derivatives" begin - rep = JET.report_call( - PDEBase.has_derivatives, (typeof(term),); - target_modules = (PDEBase,) - ) - @test length(JET.get_reports(rep)) == 0 - end - - @testset "count_differentials" begin - rep = JET.report_call( - PDEBase.count_differentials, (typeof(term), typeof(x_sym)); - target_modules = (PDEBase,) - ) - @test length(JET.get_reports(rep)) == 0 - end - - @testset "find_derivative" begin - rep = JET.report_call( - PDEBase.find_derivative, (typeof(term), typeof(operation(u_term))); - target_modules = (PDEBase,) - ) - @test length(JET.get_reports(rep)) == 0 - end - - @testset "recursive_unwrap" begin - rep = JET.report_call( - PDEBase.recursive_unwrap, (typeof(term),); - target_modules = (PDEBase,) - ) - @test length(JET.get_reports(rep)) == 0 - end -end diff --git a/test/qa/qa.jl b/test/qa/qa.jl new file mode 100644 index 0000000..45cb90d --- /dev/null +++ b/test/qa/qa.jl @@ -0,0 +1,58 @@ +using SciMLTesting, PDEBase, Test +using JET + +run_qa( + PDEBase; + explicit_imports = true, + # symbolic_discretize(::PDESystem, ::AbstractDiscretization) extends + # SciMLBase.symbolic_discretize as PDEBase's discretization entry point; the + # function is conceptually owned by the discretization stack PDEBase implements. + aqua_kwargs = (; + piracies = (; treat_as_own = [PDEBase.symbolic_discretize]), + deps_compat = (; check_extras = false), + ), + ei_kwargs = (; + all_explicit_imports_via_owners = (; + ignore = ( + # re-exported by ModelingToolkit; owner ModelingToolkitBase + :ProblemTypeCtx, :get_bcs, :get_connector_type, :get_domain, + :get_dvs, :get_eqs, :get_gui_metadata, :get_iv, :get_ivs, + :get_metadata, :get_ps, :get_systems, :get_unknowns, + # re-exported by SymbolicUtils; owner TermInterface + :maketerm, :metadata, + # re-exported by Symbolics; owner SymbolicUtils + :unwrap, + ), + ), + all_qualified_accesses_via_owners = (; + ignore = ( + :ExtraVariablesSystemException, # ModelingToolkit re-export; owner ModelingToolkitBase + :unwrap, # Symbolics re-export; owner SymbolicUtils + ), + ), + all_qualified_accesses_are_public = (; + ignore = ( + :Arr, # Symbolics non-public + :ExtraVariablesSystemException, # ModelingToolkit non-public + :NullParameters, # SciMLBase non-public + :unwrap, # Symbolics non-public + :value, # Symbolics non-public + ), + ), + all_explicit_imports_are_public = (; + ignore = ( + :AbstractDiscretization, :AbstractDiscretizationMetadata, # SciMLBase non-public + :Chain, :Prewalk, :maketerm, :metadata, # SymbolicUtils non-public + # ModelingToolkit non-public + :ProblemTypeCtx, :get_bcs, :get_connector_type, :get_domain, + :get_dvs, :get_eqs, :get_gui_metadata, :get_iv, :get_ivs, + :get_metadata, :get_ps, :get_systems, :get_unknowns, + :rename, :setname, :unwrap, # Symbolics non-public + ), + ), + ), + # PDEBase's public surface rests on heavy `using ModelingToolkit / Symbolics / + # SymbolicUtils / SciMLBase / DomainSets`; making each implicitly used name + # explicit is a large, risky refactor tracked separately. See the QA PR. + ei_broken = (:no_implicit_imports,), +) From 8813093d2a672a099bb0e721bc9101a783997696 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Thu, 25 Jun 2026 10:58:53 -0400 Subject: [PATCH 2/4] Fix latent issequal typo + undefined-local JET reports in parse_boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QA conversion to `run_qa` runs full `JET.report_package(mode=:typo)` instead of the old 5 hand-picked `report_call`s, which never traversed `parse_boundaries.jl`. On Julia 1.12 this surfaced 9 JET reports: - `isperiodic`: `issequal` is not defined — a genuine typo for `isequal` (present since the package's first commit). Calling `isperiodic` would throw `UndefVarError`. Fixed to `isequal`. - `parse_bcs`: `local u_, u__, x_, x__` left the bindings unassigned on paths JET cannot prove are unreachable, yielding 8 "may be undefined" reports. Initializing them to `nothing` makes them definitely-assigned without changing behavior (they are only read inside `if isinterface`, which is set true only in the same branches that assign real values). After the fix, `JET.report_package(PDEBase; mode=:typo)` reports 0 errors and the QA group passes on Julia 1.12.6 (16 Pass | 1 Broken | 0 Fail). Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/parse_boundaries.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parse_boundaries.jl b/src/parse_boundaries.jl index 2d3c3ec..8ce22e1 100644 --- a/src/parse_boundaries.jl +++ b/src/parse_boundaries.jl @@ -187,7 +187,7 @@ function isperiodic( ) where {b1u, b1u2, b2u, b2u2} us_equal = isequal(operation(b1.u), operation(b2.u2)) && isequal(operation(b2.u), operation(b1.u2)) - xs_equal = issequal(b1.x, b2.x2) && isequal(b1.x2, b2.x) + xs_equal = isequal(b1.x, b2.x2) && isequal(b1.x2, b2.x) return us_equal && xs_equal end @@ -311,7 +311,7 @@ function parse_bcs(bcs, v::VariableMap, orders) terms = split_terms(bc) # * Assume that the BC is defined on the edge of the domain # Check whether the bc is on the lower boundary, or periodic, we don't care which depvar/var - local u_, u__, x_, x__ + u_ = u__ = x_ = x__ = nothing isinterface = false interface_orders = [] for term in terms, r in flatten_vardict(lower_boundary_rules) From 8f2756932279bdb15604aa65e7dc6d52e6973c04 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 26 Jun 2026 16:21:58 -0400 Subject: [PATCH 3/4] QA: prune now-public EI ignores (SciMLTesting 1.7 + base-lib make-public) SciMLTesting 1.7 runs the public-API ExplicitImports checks (all_qualified_accesses_are_public / all_explicit_imports_are_public) only on Julia >= 1.11, and the base-lib make-public releases (SciMLBase 3.24, CommonSolve 0.2.9, Symbolics 7.28, SymbolicUtils 4.36, ModelingToolkit 11.29, ArrayInterface 7.26) made many previously-internal names public. Empty both public-API ignore-lists, then restore only the names still flagged as non-public on Julia 1.12 against the registered releases: - all_qualified_accesses_are_public: keep ExtraVariablesSystemException (ModelingToolkit); drop Arr, NullParameters, unwrap, value (now public). - all_explicit_imports_are_public: keep AbstractDiscretization, AbstractDiscretizationMetadata (SciMLBase); Chain, Prewalk, maketerm, metadata (SymbolicUtils); ProblemTypeCtx (ModelingToolkit); rename, setname (Symbolics). Drop the 12 get_* names and unwrap (now public). Verified: Julia 1.12 QA group green (16 pass, 1 broken=no_implicit_imports, 0 fail/error) with the minimal lists; Julia 1.10 QA group green (14 pass, 1 broken, 0 fail/error) with public checks skipped. The *_via_owners lists and ei_broken(no_implicit_imports) are unchanged. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- test/qa/qa.jl | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 45cb90d..193ab68 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -32,22 +32,15 @@ run_qa( ), all_qualified_accesses_are_public = (; ignore = ( - :Arr, # Symbolics non-public :ExtraVariablesSystemException, # ModelingToolkit non-public - :NullParameters, # SciMLBase non-public - :unwrap, # Symbolics non-public - :value, # Symbolics non-public ), ), all_explicit_imports_are_public = (; ignore = ( :AbstractDiscretization, :AbstractDiscretizationMetadata, # SciMLBase non-public :Chain, :Prewalk, :maketerm, :metadata, # SymbolicUtils non-public - # ModelingToolkit non-public - :ProblemTypeCtx, :get_bcs, :get_connector_type, :get_domain, - :get_dvs, :get_eqs, :get_gui_metadata, :get_iv, :get_ivs, - :get_metadata, :get_ps, :get_systems, :get_unknowns, - :rename, :setname, :unwrap, # Symbolics non-public + :ProblemTypeCtx, # ModelingToolkit non-public + :rename, :setname, # Symbolics non-public ), ), ), From 6d45b94d551a6e2956e5a34ae5e6774646adf2de Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 28 Jun 2026 10:39:11 -0400 Subject: [PATCH 4/4] QA: thorough EI ignore re-clean (drop stale incl via_owners, migrate non-public re-exports) Co-Authored-By: Chris Rackauckas --- test/qa/qa.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 193ab68..9e81973 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -27,7 +27,6 @@ run_qa( all_qualified_accesses_via_owners = (; ignore = ( :ExtraVariablesSystemException, # ModelingToolkit re-export; owner ModelingToolkitBase - :unwrap, # Symbolics re-export; owner SymbolicUtils ), ), all_qualified_accesses_are_public = (;