Skip to content

Access full_cache, resize_non_user_cache!, AutoDePSpecialize and SciMLOperators from their owners - #4168

Merged
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:cleanup/explicit-imports-via-owners
Aug 8, 2026
Merged

Access full_cache, resize_non_user_cache!, AutoDePSpecialize and SciMLOperators from their owners#4168
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:cleanup/explicit-imports-via-owners

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Aug 8, 2026

Copy link
Copy Markdown
Member

Please ignore until reviewed by @ChrisRackauckas.

What changed and why

full_cache and resize_non_user_cache! are defined in and exported by SciMLBase (src/integrator_interface.jl:147 / :162; export block at src/SciMLBase.jl:2077/:2079); AutoDePSpecialize is defined in SciMLBase and declared public there (src/SciMLBase.jl:2234, public since 3.39.0); the SciMLOperators module name is owned by SciMLOperators. OrdinaryDiffEqCore — and, for SciMLOperators, SciMLBase — merely re-exports these. 14 sublibraries reached them through the re-exporter, which fails ExplicitImports' owner/public checks in every QA lane that runs them.

This applies the same transformation #4167 did for OrdinaryDiffEqBDF: move the name into the import SciMLBase: list, and change OrdinaryDiffEqCore.AutoDePSpecialize to SciMLBase.AutoDePSpecialize. Import lines only — no behaviour change, no new dependency, no compat bump. 44 added lines, 41 removed, 0 comment lines, 14 files.

Branched off master, not off #4167 — the two touch disjoint files, so there is no ordering requirement and either can merge first.

Affected sublibraries (re-derived, not inherited)

I re-derived the list by parsing every lib/OrdinaryDiffEq*/src/<Name>.jl import block rather than trusting a handed-down list, then cross-checked each name's owner and publicness against SciMLBase 3.39.0's sources. Result: 14 siblings besides BDF, and 12 of them have a QA lane with explicit_imports = true.

sublibrary full_cache AutoDePSpecialize other EI lane
AdamsBashforthMoulton yes yes
ExponentialRK yes yes
HighOrderRK yes yes
Linear yes SciMLOperators yes
LowStorageRK yes yes yes
Multirate yes no
Newmark yes no
RKN yes yes
Rosenbrock yes yes resize_non_user_cache! yes
SDIRK yes yes yes
SSPRK yes yes yes
StabilizedRK yes yes
Tsit5 yes yes yes
Verner yes yes yes

Two names beyond full_cache/AutoDePSpecialize turned up, and both are included because without them the affected lane cannot go green:

  • resize_non_user_cache! in Rosenbrock — SciMLBase-owned, exported, imported from OrdinaryDiffEqCore, and absent from Rosenbrock's ignore list. Confirmed by the baseline lane, which names it alongside full_cache.
  • SciMLOperators in Linear — owned by SciMLOperators, reached via using SciMLBase: SciMLBase, SciMLOperators, SplitFunction. Routed through the existing using SciMLOperators: line instead. This one is worth flagging: SciMLBase 3.40.0 deliberately dropped @reexport using SciMLOperators in SciML/SciMLBase#1472 ("Make strict QA owner-contract clean"), so this PR moves OrdinaryDiffEqLinear in the same direction SciMLBase itself went.

Multirate and Newmark have a test/qa/ directory containing only allocation_tests.jl — no qa.jl, hence no ExplicitImports checks. They are fixed at the source level; there is no lane to show a before/after on, so their evidence is a clean GROUP=ALL run instead.

Compat and dependency verification

All 14 already have SciMLBase in [deps] and already pin SciMLBase = "3.39", so AutoDePSpecialize is public at the pinned floor everywhere. No compat bump and no new dependency were needed. Checked mechanically:

sublib                   SciMLBase in [deps]  SciMLBase compat   >=3.39?
AdamsBashforthMoulton    True                 3.39               True
ExponentialRK            True                 3.39               True
HighOrderRK              True                 3.39               True
Linear                   True                 3.39               True
LowStorageRK             True                 3.39               True
Multirate                True                 3.39               True
Newmark                  True                 3.39               True
RKN                      True                 3.39               True
Rosenbrock               True                 3.39               True
SDIRK                    True                 3.39               True
SSPRK                    True                 3.39               True
StabilizedRK             True                 3.39               True
Tsit5                    True                 3.39               True
Verner                   True                 3.39               True

Verification

Julia 1.12.6. Baselines were run against a separate clean checkout of unmodified master (7b1ad0368), so before/after are independent trees rather than a stash.

ExplicitImports before → after — all 12 lanes run

rollup is the ExplicitImports testset line (pass [fail] [error] total). "target" counts the four checks this PR addresses: all_explicit_imports_via_owners, all_explicit_imports_are_public, all_qualified_accesses_via_owners, all_qualified_accesses_are_public.

sublibrary before rollup before target names flagged before after rollup after target
AdamsBashforthMoulton 4 2 6 2/4 pass, 2 ERROR full_cache 6 6 4/4 pass
ExponentialRK 4 2 6 2/4 pass, 2 ERROR full_cache 6 6 4/4 pass
HighOrderRK 4 2 6 2/4 pass, 2 ERROR full_cache 6 6 4/4 pass
Linear 4 2 6 2/4 pass, 2 ERROR SciMLOperators, full_cache 6 6 4/4 pass
LowStorageRK 2 4 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache 6 6 4/4 pass
RKN 4 2 6 2/4 pass, 2 ERROR full_cache 6 6 4/4 pass
SSPRK 2 4 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache 6 6 4/4 pass
StabilizedRK 4 2 6 2/4 pass, 2 ERROR full_cache 6 6 4/4 pass
Tsit5 2 4 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache 6 6 4/4 pass
Verner 2 4 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache 6 6 4/4 pass
Rosenbrock 1 5 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache, resize_non_user_cache!, + Cartesian, lorenz_pref, lorenz_pref_params 4 2 6 3/4 pass, 1 ERROR
SDIRK 2 4 6 0/4 pass, 4 ERROR AutoDePSpecialize, full_cache, + lorenz_pref, lorenz_pref_params, strip_cache 5 1 6 3/4 pass, 1 ERROR

Ten of twelve reach 4/4. Rosenbrock and SDIRK reach 3/4, not 4/4 — read that carefully rather than assuming a clean sweep. In both, all_qualified_accesses_are_public stays red on names this PR does not touch and which are simply missing from those two packages' own ignore lists: lorenz_pref / lorenz_pref_params (OrdinaryDiffEqCore precompile-workload internals — note Tsit5's qa.jl does ignore them), plus Cartesian (a Base internal, in Rosenbrock) and strip_cache (in SDIRK). Rosenbrock additionally keeps a pre-existing no_stale_explicit_imports error on WOperator and _reshape. Per the brief I did not add ignore entries to paper over any of these; they want their own PR (either make the name public at the owner, or add a documented ignore).

The exact baseline diagnostic, e.g. for Tsit5:

all_explicit_imports_via_owners: Error During Test
  ExplicitImportsFromNonOwnerException
  - `full_cache` has owner `SciMLBase` but it was imported from `OrdinaryDiffEqCore`
    at lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl:12:5
all_qualified_accesses_via_owners: Error During Test
  QualifiedAccessesFromNonOwnerException
  - `AutoDePSpecialize` has owner `SciMLBase` but it was accessed from `OrdinaryDiffEqCore`
    at lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl:72:49

Aqua totals, and nothing else moved

Whole-Aqua counts, showing the errors clearing while Allocation and JET stay byte-identical:

sublibrary Aqua before Aqua after Allocation before → after JET before → after
Tsit5 15 pass, 1 fail, 4 error 19 pass, 1 fail, 0 error 1 11 1 1 pass 2 broken1 pass 2 broken
HighOrderRK 17 pass, 1 fail, 2 error 19 pass, 1 fail, 0 error 4 44 4 1 11 1
LowStorageRK 15 pass, 1 fail, 4 error 19 pass, 1 fail, 0 error 38 3838 38 1 11 1
RKN 17 pass, 1 fail, 2 error 19 pass, 1 fail, 0 error 17 broken17 broken 1 11 1
SSPRK 15 pass, 1 fail, 4 error 19 pass, 1 fail, 0 error 16 pass 2 broken16 pass 2 broken 1 pass 22 broken1 pass 22 broken
StabilizedRK 17 pass, 1 fail, 2 error 19 pass, 1 fail, 0 error 13 broken13 broken 27 2727 27
Verner 15 pass, 1 fail, 4 error 19 pass, 1 fail, 0 error 8 88 8 1 11 1

Every row's total is 20. The surviving 1 fail in all of them is the docstring issue described below.

The QA lanes remain RED overall — for reasons that are not this PR

  1. public API has docstrings, Evaluated: isempty([:SciMLBase]) fails in every one of these lanes, identically before and after. Known master failure, fixed in Exempt reexported external modules from the API docstring check SciMLTesting.jl#45. Do not read a red QA lane on this PR as a regression — the signal is the ExplicitImports subtree and the Aqua error column.

  2. AllocCheck aborts stopped the QA lane before Aqua in AdamsBashforthMoulton, ExponentialRK and Linear when I ran it. A parallel investigation established the root cause and it is not a code regression: a bare Pkg.test() uses --check-bounds=yes, while SciML's Sublibrary CI passes --check-bounds=auto, and the AB3 allocation sites only survive under =yes. CI has never seen these. See AllocCheck allocation testsets disagree between CI (--check-bounds=auto) and local Pkg.test() (--check-bounds=yes) #4172 and the fix in Keep AB3's history-slot updates allocation-free (fixes the local ABM GROUP=QA failure) #4171.

  3. UndefVarError: MatrixOperator fails GROUP=Core in Linear and ExponentialRK, on clean master too. Cause: SciMLBase 3.40.0 dropped @reexport using SciMLOperators (SciML/SciMLBase#1472); those test files use MatrixOperator without importing it. Fix in Import SciMLOperators names explicitly in tests (SciMLBase 3.40 dropped the re-export) #4170.

Where an abort hid the Aqua testset, I obtained the ExplicitImports result by running that sublibrary's own test/qa/qa.jl directly in its QA env — the same run_qa call with the same ei_kwargs, just without the two preceding testsets. This harness was cross-validated against the full lane on four sublibraries where both reached Aqua (HighOrderRK 4 2 6, LowStorageRK 2 4 6, RKN 4 2 6, SSPRK 2 4 6) and agreed exactly.

Main test groups

GROUP=ALL (Core + QA) on the branch:

  • Multirate — exit 0, fully green. MREEF, MRAB 16/16, MRI-GARK 57/57, MIS 7/7; Allocation 2 broken.
  • Newmark — exit 0, fully green. All functional testsets pass; Allocation 2 broken; JET 1 1.
  • AdamsBashforthMoulton — ABM Convergence 24/24, Adams Variable Coefficients 16/16, ABM Discontinuity Restart 211/211. Allocation 1 fail, 12 broken, byte-identical to master (issue AllocCheck allocation testsets disagree between CI (--check-bounds=auto) and local Pkg.test() (--check-bounds=yes) #4172 above).
  • HighOrderRK — High Order ERK Convergence 2/2; Allocation 4/4; JET 1/1.
  • Tsit5 — Allocation 1/1; JET 1 pass, 2 broken.
  • SDIRKConvergence 102 pass / 2 broken on the master baseline (49 minutes); the branch's own SDIRK convergence run did not finish before I stopped the batch, see below.

Multirate and Newmark are precisely the two sublibraries with no ExplicitImports lane, so their clean exit 0 is the evidence that their import move is sound.

Formatting / spelling

Runic.main(["--check", "--diff", <the 14 files>]) → exit 0 locally (Runic 1.7.0). typos <the 14 files> → exit 0 locally (typos-cli 1.47.0, honouring the repo .typos.toml).

CI agrees on the rebased head: format-check success, Runic Suggestions success, Spell Check success, Downgrade success, Documentation success. The remaining test matrices were still running when I wrote this.

What I did NOT verify

  • Full GROUP=ALL functional runs for Rosenbrock and SDIRK on the branch. Their convergence suites run ~50 minutes each and I stopped the batch before they completed; their ExplicitImports numbers above come from the qa.jl harness. RKN, SSPRK, StabilizedRK, Verner, LowStorageRK completed their GROUP=ALL lanes (Aqua table above), but I have not tabulated their functional testset counts here.
  • GPU groups — Linear, LowStorageRK, Rosenbrock and StabilizedRK have a GROUP=GPU; not run, no GPU on this machine.
  • Downstream packages — not run.
  • Docs build — now covered: CI's Documentation workflow passes on the rebased head. (The pre-rebase run failed on Cannot resolve @ref for DummyControllerCache in docs/src/devtools/internals/public_api.md, which is the pre-existing failure Fix docs build: unlink the unresolvable DummyControllerCache @ref #4164 fixed on master; the rebase picked that fix up.)
  • julia pre — the QA lanes are gated on isempty(VERSION.prerelease) anyway — and the other allowed-to-fail jobs.

Worth pushing back on

  • full_cache is imported but never used outside the module header in 11 of the 14 (only Rosenbrock and SDIRK define methods on it). Deleting the import would arguably be cleaner than moving it; I moved it to stay consistent with the merged BDF change in Access full_cache and AutoDePSpecialize from SciMLBase in OrdinaryDiffEqBDF #4167. Say the word and I will delete instead.
  • SciMLOperators (Linear) and resize_non_user_cache! (Rosenbrock) are scope beyond the two names in the original report. Same defect class, and the affected lanes cannot go green without them, but it is a judgement call.
  • Multirate, Newmark, RKIP and SIMDRK have further non-owner imports of public names that I deliberately left alone (alg_order, isadaptive, initialize!, SplitFunction reached via OrdinaryDiffEqCore). None of those four has an ExplicitImports lane, so a fix there is unverifiable by CI and belongs in its own PR.
  • Rosenbrock's and SDIRK's residual all_qualified_accesses_are_public failures (lorenz_pref, lorenz_pref_params, Cartesian, strip_cache) are left red on purpose rather than silenced with ignore entries.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F75XsVeZ94QH3PmCuq6QUF

…LOperators from their owners

SciMLBase owns and publicly declares `full_cache` and `resize_non_user_cache!`
(both `export`ed) and `AutoDePSpecialize` (`public` since 3.39.0);
OrdinaryDiffEqCore only re-exports them. SciMLOperators owns the
`SciMLOperators` module name, which OrdinaryDiffEqLinear reached through
SciMLBase. Import and access these through their owners in the 14 sublibraries
that reached them via a re-exporter, matching the OrdinaryDiffEqBDF change in
 SciML#4167.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude
ChrisRackauckas-Claude force-pushed the cleanup/explicit-imports-via-owners branch from de6c961 to fcb8ddd Compare August 8, 2026 12:24
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

Rebased onto current master, which now contains #4167 (the BDF counterpart of this change) and #4171 (the AB3 allocation fix). Two consequences for the evidence in the description:

Runic --check --diff and typos re-run clean on the rebased diff.

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

CI triage — all four current failures are pre-existing on master, none are from this PR

Green, and matching my local runs: format-check, Runic Suggestions, Spell Check, Downgrade, Documentation.

Failing:

job cause pre-existing?
lib/OrdinaryDiffEqLinear / Julia lts / Tests - Core UndefVarError: MatrixOperator at linear_method_tests.jl:6 yes — SciMLBase 3.40.0 dropped @reexport using SciMLOperators (SciML/SciMLBase#1472); fix in #4170
lib/OrdinaryDiffEqExponentialRK / Julia lts / Tests - Core same, at linear_nonlinear_krylov_tests.jl:21 yes — same, #4170
lib/OrdinaryDiffEqExponentialRK / Julia pre / Tests - Core same yes — and julia pre is allowed-to-fail
lib/OrdinaryDiffEqAdamsBashforthMoulton [Threaded] / Julia 1 precompilation failure of OrdinaryDiffEqLowOrderRK yes — see below

The Threaded one is worth spelling out because it is a hard precompile error rather than a test failure, so it could easily be mistaken for a breakage introduced here. It is not: this PR touches neither OrdinaryDiffEqLowOrderRK nor OrdinaryDiffEqCore, and the error reproduces byte-identically on an unmodified master checkout at 7b1ad0368:

$ cd lib/OrdinaryDiffEqAdamsBashforthMoulton
$ GROUP=Threaded julia +1.12 --project -e 'using Pkg; Pkg.test()'
WARNING: Imported binding OrdinaryDiffEqCore.du_cache was undeclared at import time during import to OrdinaryDiffEqLowOrderRK.
WARNING: Imported binding OrdinaryDiffEqCore.u_cache was undeclared at import time during import to OrdinaryDiffEqLowOrderRK.
ERROR: LoadError: invalid method definition in OrdinaryDiffEqLowOrderRK: exported function OrdinaryDiffEqCore.u_cache does not exist
ERROR: LoadError: Failed to precompile OrdinaryDiffEqLowOrderRK [1344f307-1e59-4825-a18e-ace9aa3fa4c6]
exit 1

It is Julia-version-sensitive — ABM's Core group passes on Julia lts (1.10) in this same CI run and the failure appears only on Julia 1 (1.12) — which points at Julia 1.12's stricter binding-at-import rules rather than any repo commit. OrdinaryDiffEqLowOrderRK imports u_cache/du_cache from SciMLBase correctly at src/OrdinaryDiffEqLowOrderRK.jl:20, and OrdinaryDiffEqCore neither imports nor exports those names, so something is emitting an export/GlobalRef against the wrong module. Handed off for its own investigation; it needs a separate fix and is out of scope here.

I have not re-run the remaining test matrices to completion — they were still in flight. If anything fails beyond the four above, treat it as unexplained and worth a look rather than assuming it is also pre-existing.

@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review August 8, 2026 12:41
@ChrisRackauckas
ChrisRackauckas merged commit 920cf80 into SciML:master Aug 8, 2026
153 of 204 checks passed
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

CI independently reproduces the ExplicitImports result

The first touched sublibrary whose QA lane finished on CI is OrdinaryDiffEqVerner, and it matches my local before/after exactly:

  Quality Assurance                            |   19     1     20  28.3s
    ExplicitImports                            |    6            6  13.6s
      public API has docstrings                |          1      1   1.5s
public API has docstrings: Test Failed at SciMLTesting.jl:1205
   Evaluated: isempty([:SciMLBase])

ExplicitImports | 6 6 — all six checks pass, including the four this PR targets, against a baseline of 2 4 6 (two passing, four erroring). The lane is still red overall, and the only reason is the isempty([:SciMLBase]) docstring check fixed by SciML/SciMLTesting.jl#45. That is exactly the outcome the description predicts.

Two corroborating data points that this red-lane behaviour is repo-wide and not introduced here: lib/GlobalDiffEq [QA] and lib/OrdinaryDiffEqStabilizedIRK [QA] also fail, and neither is touched by this PR.

One correction to my earlier triage comment: lib/OrdinaryDiffEqExponentialRK [QA] fails on CI at test/qa/allocation_tests.jl:8 with an Error, i.e. the AllocCheck abort happens on CI too, not only locally. So that particular one is not explained by the local-vs-CI --check-bounds divergence in #4172 — it is a separate pre-existing breakage in the ExponentialRK/Linear allocation test bodies (the same pair, at :8 and :7). It stops the lane before Aqua, which is why those two have no CI-side ExplicitImports numbers; their before/after in the description comes from running qa.jl directly.

The remaining QA lanes were still in flight.

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

CI-side confirmation: ExplicitImports results for every completed QA lane

The QA lanes have now run on CI. Extracting the ExplicitImports testset line from each completed job:

sublibrary ExplicitImports Quality Assurance EI errors docstring fail
AdamsBashforthMoulton 6 6 19 1 20 0 yes
HighOrderRK 6 6 19 1 20 0 yes
LowStorageRK 6 6 19 1 20 0 yes
RKN 6 6 19 1 20 0 yes
SSPRK 6 6 19 1 20 0 yes
StabilizedRK 6 6 19 1 20 0 yes
Tsit5 6 6 19 1 20 0 yes
Verner 6 6 19 1 20 0 yes
Rosenbrock 4 2 6 17 1 2 20 1 yes
Linear (lane aborts at allocation_tests.jl:7)
ExponentialRK (lane aborts at allocation_tests.jl:8)
SDIRK (still running)

Eight of the touched sublibraries reach ExplicitImports | 6 6 on CI — every check green — against baselines of 2 4 6 or 4 2 6. Rosenbrock lands on 4 2 6 with exactly one residual EI error, which is precisely what the description predicts (3 of the 4 target checks fixed; all_qualified_accesses_are_public still red on lorenz_pref / lorenz_pref_params / Cartesian, none of which this PR touches). CI agrees with my local numbers in every case.

Controls — untouched packages, same red lane:

sublibrary ExplicitImports note
BDF 6 6 already fixed by #4167
Nordsieck 6 6 not touched here
StabilizedIRK 6 6 not touched here
DelayDiffEq 4 2 6 2 pre-existing EI errors, not touched here
GlobalDiffEq 5 1 6 1 pre-existing EI error, not touched here

Every one of these fails its lane too, all on public API has docstrings / isempty([:SciMLBase]). That is the SciMLTesting issue (SciML/SciMLTesting.jl#45), it affects packages this PR never touches, and it is why a red QA lane here is not a signal about this change. The lanes that pass outright — Multirate, Newmark, Default — are exactly the ones with no qa.jl, hence no docstring check.

One upgrade over the description: AdamsBashforthMoulton's lane now reaches Aqua on CI and reports 6 6 directly, because #4171 landed and the rebase picked it up. Its numbers no longer depend on the qa.jl harness.

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

Correction: SDIRK's [QA] lane is green, but that is not confirmation

Closing the loop on the one row left open in the table above. lib/OrdinaryDiffEqSDIRK [QA] / Julia 1 finished as success — but it should not be read as this PR's fix being verified on CI for SDIRK, because that lane runs no QA tests at all.

lib/OrdinaryDiffEqSDIRK/test/runtests.jl calls activate_qa_env() and then includes nothing; test/qa/allocation_tests.jl, test/qa/jet.jl and test/qa/qa.jl are never included, while the four functional testsets run ungated. The job log confirms it — under GROUP: QA it ran only Tableau consistency, Stage predictors, Convergence and DAE tests, with no Quality Assurance / ExplicitImports subtree at all.

Filed separately as #4177. I scanned every lib/*/test/runtests.jl for the same shape and SDIRK is the only one affected, so the other rows in the table above are unaffected.

Consequence for this PR: the SDIRK before/after numbers in the description come from running qa/qa.jl directly, and that remains the only ExplicitImports evidence that exists for SDIRK anywhere — CI has never produced any. Those numbers stand: 2 4 65 1 6, i.e. 3 of the 4 target checks fixed, with all_qualified_accesses_are_public still erroring on the pre-existing lorenz_pref / lorenz_pref_params / strip_cache.

Final tally for the 12 EI lanes, CI-confirmed where CI actually runs the checks:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants