Skip to content

docs: fix linkcheck and cross-reference CI failures#942

Merged
ChrisRackauckas merged 3 commits into
SciML:masterfrom
ChrisRackauckas-Claude:cr-claude/fix-docs-ci
May 28, 2026
Merged

docs: fix linkcheck and cross-reference CI failures#942
ChrisRackauckas merged 3 commits into
SciML:masterfrom
ChrisRackauckas-Claude:cr-claude/fix-docs-ci

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented May 27, 2026

Copy link
Copy Markdown
Contributor

Important

This PR was opened by an agent and should be ignored until reviewed by @ChrisRackauckas.

Summary

Fixes two of the three Documentation-build failures on master.

  • docs/make.jl — add https://iopscience.iop.org/article/10.1088/1757-899X/1276/1/012010/ to linkcheck_ignore. IOP returns a 302 to a PerimeterX bot validator from CI runners, so linkcheck fails.
  • docs/src/solvers/bracketing_solvers.md[modAB](@ref)[ModAB](@ref). The exported binding is uppercase ModAB (lib/BracketingNonlinearSolve/src/BracketingNonlinearSolve.jl), so the cross-reference could not resolve.

Not included (separate issue)

The third failure — the @example block in docs/src/tutorials/large_systems.md:322-337 tripping NoFunctionWrapperFoundError when DenseSparsityDetector(AutoForwardDiff()) runs the wrapped function with DI's FixTail-tagged ForwardDiff duals — is a deeper FunctionWrappers/ForwardDiff problem and is out of scope for this docs PR. It is tracked separately. Docs CI will still fail on that example block until it is resolved.

Verification (Julia 1.12.6)

  • Docs build no longer reports Cannot resolve @ref for modAB.
  • linkcheck_ignore entry matches the exact failing URL from the CI log (linkcheck itself not re-run locally — slow).

🤖 Generated with Claude Code

ChrisRackauckas and others added 2 commits May 27, 2026 13:37
The Documentation workflow on master was failing with three independent
errors, all addressed here:

1. **linkcheck** — `https://iopscience.iop.org/article/10.1088/1757-899X/1276/1/012010/`
   returns a 302 to a PerimeterX bot validator from GitHub Actions runners.
   Added the URL to the existing `linkcheck_ignore` list in `docs/make.jl`.

2. **cross_references** — `docs/src/solvers/bracketing_solvers.md` referenced
   `[`modAB`](@ref)` but the exported binding (per commits `e856faf` /
   `1da0421`) is `ModAB` (uppercase). Fixed the casing.

3. **example_block** — the `@example ill_conditioned_nlprob` block at
   `docs/src/tutorials/large_systems.md:322-337` tripped
   `NoFunctionWrapperFoundError` (`No matching function wrapper was found!`)
   when running
   `solve(prob_brusselator_2d_approx_di, NewtonRaphson())` against a
   `NonlinearFunction` whose `sparsity` was
   `DifferentiationInterface.DenseSparsityDetector(AutoForwardDiff(); atol=1e-4)`.

   Root cause: `maybe_wrap_nonlinear_f` wraps IIP problem functions with a
   `FunctionWrappersWrapper` whose signatures are keyed off
   `ForwardDiff.Dual{Tag{NonlinearSolveTag, Float64}, ...}`.
   `DenseSparsityDetector{AutoForwardDiff}` runs the wrapped function with
   ForwardDiff duals whose tag is generated by DI
   (`Tag{DifferentiationInterface.FixTail{NonlinearFunction{...}}, Float64}`),
   not `NonlinearSolveTag`. Those duals are *isbits*, so FWW's
   `AllowNonIsBits` fallback does not kick in, and the dispatch trips
   `NoFunctionWrapperFoundError`. (Tracer-based detectors happen to work
   because Tracer types are non-isbits and hit the `AllowNonIsBits`
   fallback.)

   Fix: extend the same "skip wrapping in incompatible contexts" pattern
   introduced by SciML#940 (Enzyme reverse-mode) to the sparsity-detector path.
   In `maybe_wrap_nonlinear_f`, when `prob.f.sparsity` is a non-`NoSparsityDetector`
   `AbstractSparsityDetector`, return the raw function unwrapped. The
   autospecialize gain is also less significant on the sparse path (per-color
   Jacobian columns are small), so this is the right tradeoff.

   Test added in `lib/NonlinearSolveBase/test/runtests.jl` asserting that
   `maybe_wrap_nonlinear_f` wraps under `NoSparsityDetector` (the default)
   and skips when an `AbstractSparsityDetector` is supplied.

Verified locally (Julia 1.12.6):
- `Pkg.test("NonlinearSolveBase")`: 40/40 pass (+3 new test cases).
- Standalone repro of the docs example_block: both the
  TracerSparsityDetector and DenseSparsityDetector+AutoForwardDiff variants
  now `solve` successfully (`retcode = Success`). Without the fix the
  DenseSparsityDetector variant trips `NoFunctionWrapperFoundError`.
- Full docs build with `julia +1.12 --project=docs -e 'include("docs/make.jl")'`
  (with `linkcheck = false` locally to skip the slow linkcheck pass) runs
  end-to-end through `Populate: populating indices.` /
  `RenderDocument: rendering document.` / `HTMLWriter: rendering HTML
  pages.` with no `Cannot resolve @ref`, no `failed to run @example
  block`, and no `makedocs encountered errors`. The `linkcheck = false`
  override is local-only and is not in the committed diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
The prior version skipped FunctionWrappers wrapping for *any*
`AbstractSparsityDetector` other than `NoSparsityDetector`. This is
overbroad: Tracer/Symbolics-style detectors emit non-isbits eltypes
(`Tracer`, `Num`, …) which `FunctionWrappersWrappers`' `AllowNonIsBits`
fallback already handles correctly — wrapping works for them. Only
`DI.DenseSparsityDetector` is the actual failure mode, because it runs
the user function with isbits ForwardDiff duals carrying DI's own
`FixTail`-tagged Tag, for which no wrapper signature is pre-built and
which bypasses `AllowNonIsBits`.

Narrow the predicate to `prob.f.sparsity isa DI.DenseSparsityDetector`
so Tracer/Symbolics paths keep the AutoSpecialize precompile benefit.

The test now exercises three cases: default (wraps), `DenseSparsityDetector`
(does not wrap — the regression), and an `AbstractSparsityDetector`
proxy for Tracer/Symbolics (wraps). Locally verified that
`NLS.solve(prob_brusselator_2d_approx_di, NewtonRaphson())` from
docs/src/tutorials/large_systems.md returns `ReturnCode.Success` and
that the new testset passes 4/4 on Julia 1.12.6.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor Author

Narrowed maybe_wrap_nonlinear_f skip predicate from AbstractSparsityDetector && !NoSparsityDetector to just DI.DenseSparsityDetector (fc732ed). Reason: Tracer/Symbolics-style detectors work fine with the wrap via FWW's AllowNonIsBits fallback — only DenseSparsityDetector (DI's FixTail-tagged isbits duals) breaks it. Narrowing keeps the AutoSpecialize precompile benefit for Tracer/Symbolics paths.

Test now exercises three cases (default, DenseSparsityDetector, non-Dense AbstractSparsityDetector proxy) — all 4 assertions pass locally on Julia 1.12.6, and the brusselator repro returns ReturnCode.Success.

The FunctionWrappers/ForwardDiff `NoFunctionWrapperFoundError` triggered
by `DenseSparsityDetector(AutoForwardDiff())` is a separate, deeper issue
that shouldn't be addressed in a docs-CI PR. Restore autospecialize.jl
and its test to master; this PR now only carries the linkcheck and
cross-reference fixes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude ChrisRackauckas-Claude changed the title docs: fix three CI failures (linkcheck, cross_references, example_block) docs: fix linkcheck and cross-reference CI failures May 28, 2026
@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review May 28, 2026 17:44
@ChrisRackauckas ChrisRackauckas merged commit b27afb0 into SciML:master May 28, 2026
9 of 10 checks passed
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