Skip to content

Fix Downgrade (Core) and Aqua/JET QA failures#58

Draft
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:fix-qa-and-downgrade-20260619
Draft

Fix Downgrade (Core) and Aqua/JET QA failures#58
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:fix-qa-and-downgrade-20260619

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the Downgrade (Core) check and the Aqua method-ambiguity / unbound-type-parameter / deps-compat and JET sub-checks of the QA jobs on main. All fixes were reproduced and verified locally on the failing Julia versions before committing.

1. Downgrade (Core) — SteadyStateDiffEq compat floor

The downgrade job failed precompiling SteadyStateDiffEq with UndefVarError: AbstractNonlinearTerminationMode not defined (its solve.jl:70 references SciMLBase.AbstractNonlinearTerminationMode). The old floor SteadyStateDiffEq = "1, 2" let the downgrade resolver pick a SteadyStateDiffEq paired with a SciMLBase too old to define that symbol. Raised to SteadyStateDiffEq = "2.5", which forces a SciMLBase floor (resolved 2.99.0) that defines it. Also added the missing SparseArrays = "1" compat (fixes the Aqua deps-compat failure) and raised the DiffEqBase floor to 6.140 for downgrade resolvability.

2. QA / Aqua — method ambiguity + unbound type parameters

pairedindices(::DefaultIndexHandler{N}, ::NTuple{N,T}, ::CartesianIndex{N}) had a T<:Number/T<:AbstractVector pair that was ambiguous at N == 0 (NTuple{0,T} === Tuple{} leaves T free) and an AbstractVector fallback with unbound M/T. Rewrote the two methods using Tuple{T, Vararg{T}} (so T is always bound) plus an explicit zero-dimensional method, and dropped the unused type params on the dimension-mismatch fallback.

3. QA / JET — NullParameters

NullParameters is not exported from DiffEqBase, so the bare default-arg references in build_rhs.jl / build_rhs_ss.jl were undefined bindings. Qualified as DiffEqBase.NullParameters(). This also clears the JET iterate(::Nothing) cascade that stemmed from the ambiguous/unbound pairedindices methods.

Verification (run locally)

  • Downgrade Core, Julia 1.10 (lts) with the =floor-rewritten compat: telegraph 17/17, feedbackloop 12/12, birthdeath2D 18/18, tests passed. (CI: Downgrade (Core) is now green.)
  • Core, Julia 1.12 (1): telegraph 17/17, feedbackloop 12/12, birthdeath2D 18/18, tests passed.
  • Aqua test_ambiguities / test_unbound_args (1/1) / test_deps_compat (4/4), and JET test_package(...; target_defined_modules=true) (1/1): all pass on Julia 1.12 against the package project.
  • Runic-formatted all changed .jl files (runic --check clean).

Remaining QA failure (upstream Catalyst — not fixable here)

The Aqua test_undefined_exports sub-check is still red. The undefined exports — CartesianGridReJ, infimum, iscall, params, supremum — are all inherited via @reexport using Catalyst; FiniteStateProjection's own exports (FSPSystem, DefaultIndexHandler, SteadyState) are all defined.

This is conclusively an upstream Catalyst bug, not an FSP defect. Catalyst itself fails the same Aqua check: running the equivalent of Aqua.test_undefined_exports against Catalyst directly reports [:CartesianGridReJ, :infimum, :params, :supremum] as undefined exports of Catalyst. FSP inherits those four plus iscall (the extra one is a @reexport double-hop: iscall is using-imported into Catalyst from TermInterface, so it is isdefined(Catalyst, :iscall) but is not re-bound in FSP).

  • CartesianGridReJ (uppercase J) is a literal export typo in Catalystsrc/Catalyst.jl exports CartesianGridReJ while the type defined in JumpProcesses (and used everywhere else in Catalyst) is CartesianGridRej (lowercase j). The uppercase-J symbol is defined in no module in the dependency tree, so it cannot be made isdefined in FSP without inventing a fake binding. The typo is present on Catalyst 15.0.11 (the latest 15.x) and on Catalyst master.
  • infimum, supremum, params are using-imported-then-exported by Catalyst from ModelingToolkit / Symbolics / DomainSets and do not propagate transitive bindings through @reexport using Catalyst.

Bumping to Catalyst 16.2 does not fix this (it yields a different set of undefined re-exports and additionally breaks FSP's Core tests — see the dependabot Catalyst-16.2 PR, whose Core jobs are red). Making this check green requires an upstream Catalyst fix (at minimum, fixing the CartesianGridReJ -> CartesianGridRej export typo). It cannot be fixed inside FiniteStateProjection without disabling/excluding the check or fabricating a binding.

Note on the Core (julia pre) CI job

On a later CI run this PR shows 3 failing asserts in birthdeath2D.jl (steady-state marginal/permutation tests, atol=1e-4) on the julia pre channel (1.13.0-rc1). This is not a regression from this PR: the same job was green on main, the resolved dependency set is byte-identical between the two runs (same SteadyStateDiffEq 2.11.0, NonlinearSolve 4.16.0, Catalyst 15.0.11, SciMLBase 2.153.1), and locally on 1.13.0-rc1 with that exact resolved environment birthdeath2D passes 18/18 (reproduced twice). The failures are borderline-tolerance numerical drift in the SSRootfind steady-state solve on the Julia release candidate, not a deterministic FSP change.

This PR makes Downgrade fully green and reduces QA from 5 failing Aqua/JET sub-checks to the single upstream-blocked test_undefined_exports check.

Please ignore until reviewed by @ChrisRackauckas.

🤖 Generated with Claude Code

Downgrade (Core): raise SteadyStateDiffEq compat floor to 2.5. The old
"1, 2" floor let the downgrade resolver pick a SteadyStateDiffEq whose
solve.jl references SciMLBase.AbstractNonlinearTerminationMode against a
SciMLBase too old to define it, failing precompilation with
`UndefVarError: AbstractNonlinearTerminationMode not defined`. 2.5 forces a
SciMLBase floor (resolved 2.99) that defines the symbol. Also add the
missing SparseArrays compat entry (Aqua deps_compat) and raise the
DiffEqBase floor to 6.140 for downgrade resolvability.

QA / Aqua method-ambiguity + unbound-type-parameter: rewrite the
`pairedindices(::DefaultIndexHandler{N}, ::NTuple{N,T}, ...)` methods using
`Tuple{T, Vararg{T}}` (so T is always bound; NTuple{0,T} === Tuple{} left T
free) and add an explicit zero-dimensional method, removing both the
Number/AbstractVector ambiguity at NTuple{0} and the unbound M/T params in
the dimension-mismatch fallback.

QA / JET: qualify the NullParameters default argument as
`DiffEqBase.NullParameters()` in build_rhs.jl / build_rhs_ss.jl
(NullParameters is not exported from DiffEqBase, so the bare reference was an
undefined-binding error). This also clears the cascade of JET
`iterate(::Nothing)` reports that stemmed from the ambiguous/unbound
pairedindices methods.

Verified locally:
- Downgrade Core on Julia 1.10 (lts) with =floor-rewritten compat: telegraph
  17/17, feedbackloop 12/12, birthdeath2D 18/18, tests passed.
- Core on Julia 1.12 ("1"): 17/17, 12/12, 18/18, tests passed.
- Aqua ambiguities/unbound/deps_compat: pass. JET.test_package: pass.

Remaining QA undefined-exports failure (CartesianGridReJ, infimum, iscall,
params, supremum) is inherited via `@reexport using Catalyst` and is an
upstream Catalyst export bug (Catalyst exports CartesianGridReJ but
JumpProcesses defines CartesianGridRej; the others come from MTK/Symbolics
re-exports). Not fixable from within FiniteStateProjection without disabling
the check; needs an upstream Catalyst release.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants