Skip to content

Restrict deferred init to SCC-lowered steady-state problems - #176

Draft
ChrisRackauckas-Claude wants to merge 6 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/172-init-scc-lowering
Draft

ChrisRackauckas-Claude wants to merge 6 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/172-init-scc-lowering

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Please ignore until reviewed by @ChrisRackauckas.

Restrict deferred initialization to SteadyStateProblems with SCC lowerings so solve!(init(prob, DynamicSS(...))) preserves the requested algorithm and attracting root. Ordinary problems and non-SCC lowerings retain master's nonlinear caches, including state updates, aliasing, symbolic indexing, reinit!, step!, and direct-solve keyword merging. Callable lowerings are materialized once during initialization.

The SCC object is deliberately a deferred solve, not a reusable integrator: each solve! creates fresh numerical caches using the materialized lowering. state_values and parameter_values expose original initial data by reference; solved values and symbolic indexing belong to the returned solution. The deferred object does not support stepping, reinitialization, or symbolic indexing. This contract is documented in the algorithm docstrings and rendered documentation. Supported SCC initialization paths are the default solver and SSRootfind, DynamicSS, and SICNM.

Closes #172. Please ignore this draft until reviewed by @ChrisRackauckas.

Verification

Julia 1.12.7; SciMLBase 3.57.0, NonlinearSolve 4.32.0, NonlinearSolveBase 2.54.1, ModelingToolkit 11.45.3. Tests use a scratch copy of the review's locked test environment, with this checkout developed into it. JET and Documenter were added to that scratch environment with preserve=Pkg.PRESERVE_ALL; existing dependency versions stayed unchanged. No repository dependency or version changes.

Commands below run from the repository root with JULIA=julia, TMPDIR=<job>/tmp, and a job-local first depot (the previous reviews' depots and ~/.julia are read-only fallbacks). Full logs are in the job's scratch/ directory.

Failing before

With the takeover head (79c3d42792287c0f24806ec8a1824774b13d000f) source and the new test/init.jl:

$JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv -e 'using Test; @testset "round 2 regressions" begin include("test/init.jl"); end'
Test Summary:       | Pass  Fail  Error  Total     Time
round 2 regressions |   18    14     18     50  1m28.6s

Failures cover stale cache state, missing symbolic indexing/reinitialization, changed default aliasing, and loss of stored maxiters=0. The tests also exercise stepping after reinitialization and call-site overrides.

Source-only negative controls saved the repaired src/solve.jl, replaced it with git show <revision>:src/solve.jl, ran the same tests/probe, and restored the repaired file:

git show origin/master:src/solve.jl > src/solve.jl
$JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv -e 'using Test; @testset "master controls" begin include("test/init.jl"); include("../scratch/probe.jl"); end'
git show 2170ff995c4dd1271ef6b7905313dd8c4a26e205:src/solve.jl > src/solve.jl
$JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv ../scratch/probe.jl

Master control tail:

FieldError: type SCCNonlinearProblem has no field `u0`
Test Summary:                      | Pass  Error  Total     Time
master controls                    |   56      1     57  2m08.2s
  non-SCC cache compatibility      |   48            48    52.3s
  non-SCC lowering solver keywords |    4             4    21.4s
  non-SCC lowering solver keywords |    4             4     0.4s
  adversarial cache semantics      |           1      1    12.4s

First rejected implementation (round-1 probe, both stored and callable lowerings):

ROOT builder=false direct=[1.000000000016591] Success cached=[2.0000000000000036] Success alg=NonlinearSolvePolyAlgorithm
ROOT builder=true direct=[1.000000000016591] Success cached=[2.0000000000000036] Success alg=NonlinearSolvePolyAlgorithm
Test Summary:               | Pass  Fail  Total     Time
adversarial cache semantics |    2     2      4  1m12.4s

Passing after

$JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv -e 'using Test; @testset "repaired initialization" begin include("test/init.jl"); include("../scratch/probe.jl"); include("../scratch/mtk_probe.jl"); end'
ROOT builder=false direct=[1.000000000016591] Success cached=[1.000000000016591] Success alg=DynamicSS
ROOT builder=true direct=[1.000000000016591] Success cached=[1.000000000016591] Success alg=DynamicSS
NON-SCC lowering calls=1
MTK direct raw=[1.0, 1.4422495703000229] cached raw=[1.0, 1.4422495703000229]
MTK direct symbolic=[1.0, 2.0, 1.4422495703000229] cached symbolic=[1.0, 2.0, 1.4422495703000229]
Test Summary:           | Pass  Total      Time
repaired initialization |   62     62  10m03.4s

The probes are reused from review round 1; their end-to-end assertions are also covered in the committed test/scc.jl. The committed regressions additionally cover repeated deferred solves and the initial-data contract for the default solver, SSRootfind, DynamicSS, and SICNM.

The full Core group passed 2,920 assertions through the package's unchanged test/runtests.jl / SciMLTesting runner. QA passed 37 assertions. This uses the already-resolved scratch test environment rather than rerunning Pkg.test()'s environment-construction wrapper.

GROUP=Core $JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv test/runtests.jl
GROUP=QA $JULIA +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv test/runtests.jl
Test Summary: | Pass  Total     Time
Core/core.jl  | 2322   2322  2m14.7s
Test Summary:                | Pass  Total  Time
Core/developer_interfaces.jl |    5      5  0.5s
Test Summary: | Pass  Total   Time
Core/init.jl  |   56     56  59.7s
Test Summary:               | Pass  Total  Time
Core/precompile_workload.jl |    8      8  6.2s
Test Summary: | Pass  Total     Time
Core/scc.jl   |  496    496  6m32.7s
Test Summary: | Pass  Total     Time
Core/sicnm.jl |   33     33  1m45.4s
Test Summary: | Pass  Total     Time
QA/qa.jl      |   37     37  1m31.0s
$JULIA +1.12 --compiled-modules=existing --project=../scratch/testenv docs/make.jl
$JULIA +1.12 --project=@runic -e 'using Runic; exit(Runic.main(ARGS))' -- --check src/solve.jl src/algorithms.jl src/SteadyStateDiffEq.jl test/scc.jl test/init.jl
typos src/solve.jl src/algorithms.jl src/SteadyStateDiffEq.jl test/scc.jl test/init.jl docs/src/index.md
git diff --check

All exited 0. Docs tail:

[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: ExpandTemplates: expanding markdown templates.
[ Info: CrossReferences: building cross-references.
[ Info: CheckDocument: running document checks.
[ Info: Populate: populating indices.
[ Info: RenderDocument: rendering document.
[ Info: HTMLWriter: rendering HTML pages.
[ Info: Automatic `version="2.18.0"` for inventory from ../Project.toml
┌ Warning: Documenter could not auto-detect the building environment. Skipping deployment.
└ @ Documenter ~/.julia/packages/Documenter/13nbQ/src/deployconfig.jl:95

The first docs attempt failed because the scratch environment lacked the docs-declared direct dependency OrdinaryDiffEqRosenbrock. Adding it with Pkg.add("OrdinaryDiffEqRosenbrock"; preserve=Pkg.PRESERVE_ALL) changed no resolved versions; the unchanged docs build then passed. No doctests or checks were disabled.

GitHub checks on the reviewed commit

All 13 PR checks passed on 30cd58ebc867ca58a272ebdff5f6afc038c6e9a5: release/LTS/32-bit Core, QA, documentation, downgrade compatibility, formatting, spelling, and the benchmark jobs. I also read the completed test logs: Core/init.jl passed 56 assertions and Core/scc.jl passed 496 assertions on all three tested Core configurations; QA passed 37.

The separate Dependabot Auto-merge workflow has a startup_failure, also present on both previous PR heads. It is not a failing code check and was not modified here.

Validation after the required review edit

Restored the original solve(prob, DynamicSS(); abstol = 1.0e-10, reltol = 1.0e-10) line and its assertions unchanged. The DynamicSS(Tsit5()) initialization block remains a separate case. This follow-up changes only test/scc.jl.

source ../scratch/env.sh
julia +1.12 --compiled-modules=existing --check-bounds=yes --project=../scratch/testenv -e 'include("test/scc.jl"); flush(stdout); ENV["GROUP"] = "Core"; include("test/runtests.jl")'
julia +1.12 --project=@runic -e 'using Runic; exit(Runic.main(ARGS))' -- --check test/scc.jl
typos test/scc.jl
git diff --check

All commands exited 0. The standalone SCC run passed 496 assertions (including all nine in the restored default-solve/Tsit5-init testset); the Core group passed 2,920 assertions. Core output tail:

Test Summary: | Pass  Total     Time
Core/core.jl  | 2322   2322  1m44.5s
Test Summary:                | Pass  Total  Time
Core/developer_interfaces.jl |    5      5  0.4s
Test Summary: | Pass  Total   Time
Core/init.jl  |   56     56  43.7s
Test Summary:               | Pass  Total  Time
Core/precompile_workload.jl |    8      8  5.7s
Test Summary: | Pass  Total     Time
Core/scc.jl   |  496    496  3m00.9s
Test Summary: | Pass  Total     Time
Core/sicnm.jl |   33     33  1m43.1s

QA and docs were not rerun locally for this test-only follow-up; the previous passing results above apply to the unchanged production source and documentation. Follow-up commit: c6413ce. All 13 PR checks passed on this commit, including release/LTS/32-bit Core, QA, documentation, downgrade, formatting, spelling, and benchmarks. Completed test logs confirm Core/init.jl 56/56 and Core/scc.jl 496/496 on all three Core configurations, and QA 37/37. The separate Dependabot Auto-merge workflow again reports the pre-existing startup_failure.

Limits and review points

Not verified locally: the complete downstream SciMLBase symbolic-indexing group, minimum dependency versions, Julia versions other than 1.12.7, other operating systems, or downstream/GPU suites. Direct SCCNonlinearProblem initialization and explicit nonlinear-algorithm initialization are outside this change.

Known limitations / follow-ups (not fixed here):

  • Errors can surface late: init(prob, Tsit5()) on an SCC-lowered problem returns a deferred object, and NonSolverError appears only at solve!. Master raised FieldError at init.
  • init(prob, NewtonRaphson()) on SCC lowerings still raises a closure-arity MethodError, as it does on master.
  • Without SCC, init(prob, DynamicSS()) still builds NonlinearSolve's default polyalgorithm cache (master behavior), while the SCC path honors DynamicSS.
  • The new __init(::SteadyStateProblem, ::Nothing) method shadows NonlinearSolve's method for SteadyStateProblem.

The SCC deferred-cache contract distinguishes initial-data access on the cache from solved-data access on its solution. The existing default-ODE-algorithm solve(prob, DynamicSS()) test and all its assertions are preserved unchanged, with the Tsit5 initialization case tested separately. No assertion is skipped, silenced, or weakened. The non-SCC callable-count test now expects materialization at initialization and none during solve!, consistent with restoring the regular solver cache.

Independent review artifacts (local): <local dir>. The review verdict was MERGE, with the default-algorithm coverage restoration required before handoff.

Links

Risk assessment

  • Risk: low
  • Blast radius: SCC-lowered steady-state initialization; ordinary initialization and direct solve dispatch are preserved. No new exported names, dependencies, or version bumps.
  • Evidence: failing-before/passing-after results above, non-SCC master controls, DynamicSS multiple-root checks, and MTK raw/symbolic solution comparisons.
  • Independent review: Claude Code (Opus 5.5) rated it low, medium-high confidence: ordinary paths identical to master; SCC init matches solve (multiple-root DynamicSS case fixed for both lowerings); new tests fail on master and on the previous head; Core and QA pass; known limitations listed
  • Merge: needs human review — the requested default-algorithm coverage restoration is a follow-up commit after the independent review. Keep as draft for @ChrisRackauckas; do not merge.

🤖 AI-assisted original implementation: Cursor Agent CLI 2026.10.01-14929f9, model auto; transcript: /log.txt. Escalation fix: Codex CLI 0.160.0, model gpt-6-astra; local session transcript: /log.txt.

Independent review: Devin Fusion (fusion-claude-opus-5-5-high-sidekick-swe-2-medium) rated it low, verdict MERGE: #176 (comment)

🤖 Automated comment from an AI agent running as @ChrisRackauckas — not written or reviewed by Chris.

Risk assessment (independent review, Codex gpt-6.1-sol, head c6413ce)

  • Verdict: MERGE
  • Rating: Codex gpt-6.1-sol rated it medium (M1) at head c6413ce
  • Risk: medium (M1: adds a specialized method of SciMLBase's public __init hook, changing dispatch for existing SteadyStateProblem initialization and introducing the SCC deferred-object contract). Other matched criteria: L1, L2, L6, ML2, ML8; none sets a higher level.
  • Blast radius: Initialization of SteadyStateProblem, particularly stored/callable SCC lowerings with the default solver, SSRootfind, DynamicSS, and SICNM. Non-SCC initialization forwards to the same nonlinear-cache implementation as the base. Direct solving and explicit nonlinear-algorithm initialization have no production-code changes.
  • Evidence: Read the supplied metadata, linked issue, full git diff origin/HEAD...HEAD, and relevant dependency dispatch. git diff --check origin/HEAD...HEAD passed; checkout status remained clean. Used scratch source archives of head and default branch 471a4a039f637459ff8625cc832f20a7b85f4f49, with identical copied dependency manifests except the developed package path. Julia 1.12.7, SciMLBase 3.57.0, NonlinearSolve 4.32.0, NonlinearSolveBase 2.54.1; requested depot, four threads, sequential Julia processes, and timeout 3600 throughout.
    • Head: julia --compiled-modules=existing --check-bounds=yes --project=scratch/headenv -e 'using Test; @testset "PR 176 targeted head regressions" begin include("scratch/regressions.jl"); include("scratch/dispatch_probe.jl"); end'. regressions.jl extracts the committed SCC additions with their helpers, the changed MTK testset, and unchanged test/init.jl. All 145 committed assertions passed: SCC additions 80, MTK 9, non-SCC controls 56. The overall exploratory command exited 1 with 149 passed, 0 failed, 1 errored, solely because the extra keyword-algorithm probe exposed the pre-existing limitation described below. See scratch/head.log.
    • Base: julia --compiled-modules=existing --compile=min --check-bounds=yes --project=scratch/baseenv scratch/base_regressions.jl. All 56 non-SCC assertions passed; the exact committed multiple-root SCC initialization test then errored with FieldError: type SCCNonlinearProblem has no field u0. That same test passed on head. See scratch/base.log.
    • Both revisions: julia --compiled-modules=existing --compile=min --check-bounds=yes --project=scratch/{head,base}env scratch/keyword_probe.jl. Diagnostic output confirms positional initialization changes from error to success for all three algorithms; keyword/stored-algorithm variants fail on both revisions. Positional DynamicSS direct/cached roots on head were both [1.0000000000165905]. See scratch/keywords-head.log and scratch/keywords-base.log. Commands above abbreviate absolute paths relative to this run directory; the actual Julia executable was <local path>.
    • Read current-head CI results and completed test logs: all 13 reported checks passed; release/LTS/32-bit logs each show init.jl 56/56 and scc.jl 496/496, with QA 37/37. No assertions were deleted, skipped, or loosened. No dependencies or new public names were added; the private cache's interface is documented in algorithm docstrings and the rendered manual. New dependency accesses use public hooks; the repaired erroring paths do not constitute a SemVer breaking change.
    • G1: pass — analytic references include the attracting root 1 of the cubic, the linear equilibrium 2, and the MTK equilibrium [1, 2, cbrt(3)], alongside direct/deferred comparisons.
    • G2: not applicable — no GPU kernels, AD rules, Reactant tracing, or MPI implementation paths change.
    • G3: pass — repeated solves, one-time callable materialization, initial-data identity/state, and non-SCC state updates, reinitialization, stepping, and symbolic indexing are tested and passed.
  • Merge: merge — no blocking finding in this scoped fix. Medium risk requires Chris's decision; this is not an automatic-merge authorization.

🤖 Posted by an AI agent — harness: Codex CLI 0.162.1 · model: gpt-6.1-sol
Conversation: local headless review run (no public session URL); transcript kept by the fleet master.

ChrisRackauckas and others added 5 commits October 2, 2026 02:32
…al states.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-cursor/log.txt on amdci2.julia.csail.mit.edu
…esidual.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-cursor/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-cursor/log.txt on amdci2.julia.csail.mit.edu
…oot flows.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-cursor/log.txt on amdci2.julia.csail.mit.edu
Preserve ordinary nonlinear cache interfaces and master solve keyword merging.
Materialize SCC lowerings once and document the deferred cache contract.
Add regressions for cache reuse, solver options, and repeated SCC solves.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.160.0
Agent-Model: gpt-6-astra
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-codex/log.txt on amdci2.julia.csail.mit.edu
@ChrisRackauckas-Claude ChrisRackauckas-Claude changed the title init on SCC-lowered SteadyStateProblem uses unlowered residual Restrict deferred init to SCC-lowered steady-state problems Oct 2, 2026
Keep the original default-ODE-algorithm solve and its assertions unchanged,
with the explicit Tsit5 initialization case tested separately.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.160.0
Agent-Model: gpt-6-astra
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/ibd/SteadyStateDiffEq.jl/jobs/172-codex/log.txt on amdci2.julia.csail.mit.edu
@ChrisRackauckas

Copy link
Copy Markdown
Member

🤖 Automated comment from an AI agent running as @ChrisRackauckas — not written or reviewed by Chris.

Independent review (Devin CLI 3000.11.3, model fusion-claude-opus-5-5-high-sidekick-swe-2-medium): MERGE, risk low.

Full review

VERDICT: MERGE
RISK: low

Scope: PR #176 at c6413ce, fixing #172. The only production change is a new SciMLBase.__init(::SteadyStateProblem, ::Nothing, args...) method (src/solve.jl:132). When NonlinearProblem(prob) is not an SCCNonlinearProblem, it does exactly what NonlinearSolve's __init(::AbstractSteadyStateProblem, ::Nothing, ...) does. When it is one, it returns a SteadyStateDeferSolveCache whose solve! calls solve(prob_with_materialized_lowering, alg, ...). The SCC case raised FieldError before this PR, so no working code path changes behaviour.

Blocking findings

None.

Non-blocking findings

  1. This is a design decision on a question the issue left to maintainers. (From reading.) Issue 172 explicitly asks "What should init return for an SCC-lowered steady-state problem?" The PR answers with a new non-integrator type that has supertype Any. Its getindex, step!, reinit! and .u all fail with MethodError/FieldError; I confirmed that by running probe3 (P7). The docs and docstrings state this limitation. Two facts for the maintainer:

  2. What init does now depends on whether the problem was SCC-lowered. (Confirmed by running, probe2 P6.) I used f = -(u-1)(u-2)(u-3) with u0 = 1.8 and DynamicSS(Tsit5(); tspan=100):

    • solve: 1.0 (attracting root).
    • solve!(init(...)) without a lowering: 2.0. NonlinearSolve's polyalgorithm silently ignores DynamicSS; that behaviour comes from master.
    • Same problem with an SCC lowering, through the PR: 1.0.

    So the same ModelingToolkit model gives init(prob, DynamicSS()) different semantics (and roots) depending on whether structural simplification produced an SCC lowering. The PR body and docs (docs/src/index.md: "Problems without an SCC lowering use the regular nonlinear solver caches") acknowledge this, but it is a real inconsistency to weigh against Add __init for DynamicSS/SICNM so init() doesn't fall through to NonlinearSolve's default #173.

  3. src/solve.jl:139-142: the branch has no effect. Both arms result in solve(cache.prob, args...; kwargs...), because solve! re-prepends alg. Storing alg separately only affects the alg field. Simplify to __defer_solve_cache(prob, nothing, args...), or drop the alg field.

  4. Assertions that cannot fail or prove little. (From reading.)

    • test/scc.jl:508: @test length(state_values(integ)) == length(prob.u0) is tautological, because state_values(cache) is defined as state_values(cache.prob) and cache.prob is a remake of prob with the same u0.
    • test/scc.jl:282: @test NonlinearProblem(prob) === sccprob tests SciMLBase materialization, not this PR.

    The meaningful assertions in those testsets (cached.u ≈ direct.u, the multi-root ≈ [1.0] check, calls[] == 1, cached.alg isa DynamicSS) are sound. The expected values are analytic (roots 1, 2, cbrt(3)), not taken from the code's own output.

  5. Method shadowing. (From reading.) The new method is more specific than NonlinearSolve's __init(::AbstractSteadyStateProblem, ::Nothing), so a future change there (for example a guard like the closed Guard against infinite recursion when NonlinearProblem(prob) makes no progress NonlinearSolve.jl#1327) would silently not apply to SteadyStateProblem. Aqua's piracy check passes because SciMLTesting treats __init/__solve as own (_standard_aqua_kwargs), and the package already overrides solve(::SteadyStateProblem, ...) the same way. The PR body discloses this.

  6. Errors now surface late. (Confirmed by running, probe3.) init(prob, Tsit5()) on an SCC problem returns a deferred cache, and NonSolverError appears only at solve!. The PR body discloses this. Raising NonSolverError eagerly in __init when args is non-empty and first(args) is not a SteadyStateDiffEqAlgorithm would be cheap.

  7. Pre-existing bug, not this PR's: solve(prob; alg = DynamicSS(...)) with the algorithm passed as a keyword, on an SCC-lowered problem, throws FieldError: SCCNonlinearProblem has no field u0. init(prob; alg=...) returns a deferred cache, and its solve! hits the same error (probe P2). Worth a separate issue against the solve(::SteadyStateProblem, ...) override, which reads only get(kwargs, :alg, ...) before it is forwarded.

What I ran

All with Julia 1.12.7. Resolved versions: SciMLBase 3.57.0, NonlinearSolve 4.32.0, NonlinearSolveBase 2.54.1, SCCNonlinearSolve 1.15.4, ModelingToolkit 11.45.3, OrdinaryDiffEq 7.8.1. Logs are in scratch/.

  • PR's test files at the PR head (confirmed): test/init.jl 56/56 passed; test/scc.jl 496/496 passed. These match the PR body.
  • The same test files against an origin/master worktree (735cb01) (confirmed):
    • test/init.jl passed 56/56. These are regression guards that already hold on master, as the body says.
    • test/scc.jl gave 415 pass and 9 errors, all FieldError: SCCNonlinearProblem has no field u0. They are in the four new SCC init testsets and in the MTK DynamicSS block. So the new tests fail before the fix and pass after.
  • GROUP=QA test/runtests.jl: 36 pass, 1 error (Aqua persistent_tasks: "Unable to locate 'Scratch', a dependency of 'GPUCompiler'"). Master gives the identical result in the same env, so this comes from the environment, not the PR. Piracy, ambiguities, ExplicitImports and JET all passed.
  • Runic --check src test: exit 0. typos on the changed files: exit 0.
  • Adversarial probes (scratch/probe.jl, probe2.jl, probe3.jl; output in probe_head.txt, probe2_head.txt, probe3_head.txt):
    • P1: u0 = [2.5] override with a callable SCC lowering gives 3.0 from both init and solve.
    • P3: repeated solve! on a stored lowering, for DynamicSS/SSRootfind/SICNM/default. Every result is identical to direct solve, and the block u0 is unmutated (stays [1.8]).
    • P4: save_idxs passes through.
    • P5: in-place SCC lowering works with all four algorithm choices.
    • P6 and P7: as described in the non-blocking findings above.

What I did not verify


🤖 Posted by an AI agent — harness: Devin CLI 3000.11.3 (review), Claude Code 2.1.285 (posting) · model: fusion-claude-opus-5-5-high-sidekick-swe-2-medium
Conversation: local Claude session 3c311569-dda6-4687-bc9f-65febb212c33 (fleet master)

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.

init(::SteadyStateProblem) fails on SCC-lowered problems (lowered_problem): SCCNonlinearProblem has no field u0

3 participants