Repository navigation
Restrict deferred init to SCC-lowered steady-state problems - #176
ChrisRackauckas-Claude wants to merge 6 commits into
Conversation
…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
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
Independent review (Devin CLI 3000.11.3, model fusion-claude-opus-5-5-high-sidekick-swe-2-medium): MERGE, risk low. Full reviewVERDICT: MERGE Scope: PR #176 at c6413ce, fixing #172. The only production change is a new Blocking findingsNone. Non-blocking findings
What I ranAll 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
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 |
Please ignore until reviewed by @ChrisRackauckas.
Restrict deferred initialization to
SteadyStateProblems with SCC lowerings sosolve!(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_valuesandparameter_valuesexpose 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 andSSRootfind,DynamicSS, andSICNM.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~/.juliaare read-only fallbacks). Full logs are in the job'sscratch/directory.Failing before
With the takeover head (
79c3d42792287c0f24806ec8a1824774b13d000f) source and the newtest/init.jl: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 withgit show <revision>:src/solve.jl, ran the same tests/probe, and restored the repaired file:Master control tail:
First rejected implementation (round-1 probe, both stored and callable lowerings):
Passing after
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, andSICNM.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 rerunningPkg.test()'s environment-construction wrapper.All exited 0. Docs tail:
The first docs attempt failed because the scratch environment lacked the docs-declared direct dependency
OrdinaryDiffEqRosenbrock. Adding it withPkg.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.jlpassed 56 assertions andCore/scc.jlpassed 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. TheDynamicSS(Tsit5())initialization block remains a separate case. This follow-up changes onlytest/scc.jl.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:
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.jl56/56 andCore/scc.jl496/496 on all three Core configurations, and QA 37/37. The separate Dependabot Auto-merge workflow again reports the pre-existingstartup_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
SCCNonlinearProbleminitialization and explicit nonlinear-algorithm initialization are outside this change.Known limitations / follow-ups (not fixed here):
init(prob, Tsit5())on an SCC-lowered problem returns a deferred object, andNonSolverErrorappears only atsolve!. Master raisedFieldErroratinit.init(prob, NewtonRaphson())on SCC lowerings still raises a closure-arityMethodError, as it does on master.init(prob, DynamicSS())still builds NonlinearSolve's default polyalgorithm cache (master behavior), while the SCC path honorsDynamicSS.__init(::SteadyStateProblem, ::Nothing)method shadows NonlinearSolve's method forSteadyStateProblem.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 duringsolve!, 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
🤖 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)
Risk assessment (independent review, Codex gpt-6.1-sol, head c6413ce)
__inithook, changing dispatch for existingSteadyStateProbleminitialization and introducing the SCC deferred-object contract). Other matched criteria: L1, L2, L6, ML2, ML8; none sets a higher level.SteadyStateProblem, particularly stored/callable SCC lowerings with the default solver,SSRootfind,DynamicSS, andSICNM. 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.git diff origin/HEAD...HEAD, and relevant dependency dispatch.git diff --check origin/HEAD...HEADpassed; checkout status remained clean. Used scratch source archives of head and default branch471a4a039f637459ff8625cc832f20a7b85f4f49, 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, andtimeout 3600throughout.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.jlextracts the committed SCC additions with their helpers, the changed MTK testset, and unchangedtest/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. Seescratch/head.log.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 withFieldError: type SCCNonlinearProblem has no field u0. That same test passed on head. Seescratch/base.log.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. PositionalDynamicSSdirect/cached roots on head were both[1.0000000000165905]. Seescratch/keywords-head.logandscratch/keywords-base.log. Commands above abbreviate absolute paths relative to this run directory; the actual Julia executable was<local path>.init.jl56/56 andscc.jl496/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.[1, 2, cbrt(3)], alongside direct/deferred comparisons.🤖 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.