Skip to content

Fix: don't develop a dependency's test-only [sources] transitively on Julia <1.11#98

Merged
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-transitive-test-only-sources-1228
Jun 16, 2026
Merged

Fix: don't develop a dependency's test-only [sources] transitively on Julia <1.11#98
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-transitive-test-only-sources-1228

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown

Summary

Fixes the bug tracked in SciML/Optimization.jl#1228: every Optimization.jl sublibrary's QA group fails on Julia lts (<1.11) with Aqua Stale dependencies and missing-deps-compat findings for OptimizationLBFGSB and OptimizationManopt, even in sublibraries that have nothing to do with those packages. QA on Julia 1 (>=1.11) is green.

Where the bug lived

The tests.yml reusable workflow's "Develop in-repo [sources] path deps" step (run on Julia <1.11 only) walks the [sources] graph transitively and Pkg.develops every path source it finds. Crucially, when it recursed into an already-developed dependency, it followed that dependency's test-only [sources] too — sources whose names live in [extras]/[targets].test, not in [deps].

OptimizationBase declares [sources] for its own test-only deps OptimizationLBFGSB/OptimizationManopt (so its own test suite resolves on <1.11). Any sublibrary that legitimately sources OptimizationBase (≈26 of them) therefore had OptimizationLBFGSB/OptimizationManopt Pkg.develop-ed into its environment as phantom direct deps. Pkg.develop writes them into the active Project.toml's [deps], and Aqua (run against that sublib) then flags them as stale / missing-compat. On Julia >=1.11 the whole helper is a no-op (VERSION < v"1.11.0-DEV.0"), which is exactly why QA-Julia-1 is green and QA-Julia-lts fails.

This bug is in SciML/.github (the project model tests.yml, which grouped-tests.yml and sublibrary-project-tests.yml both delegate to). It needs a v1 retag to reach consumers. (SciMLTesting.jl's develop_sources! has the same transitive-walk shape for the folder model, but Optimization.jl uses the .github project model; that's a separate follow-up if desired.)

The fix

  • Extracted the [sources] walk into scripts/develop_sources.jl (collect_source_paths is a pure, env-mutation-free function; develop_sources activates + develops). tests.yml now checks out SciML/.github at dotgithub-ref (default v1, matching the sibling workflows) and calls the script — one tested source of truth instead of an untested inline block.
  • When recursing into a dependency, only follow [sources] entries that are also that dependency's runtime [deps]. A dependency's test-only sources are never developed into the package-under-test's env.
  • The package-under-test itself (root of the walk) is exempt: its own test-only [sources] are still developed, because its own test suite legitimately needs them (e.g. testing OptimizationBase directly still develops LBFGSB/Manopt).
  • Does not silence Aqua — the phantom deps are never introduced in the first place.

Local verification (Julia 1.10, both directions)

Reproduced against a real Optimization.jl checkout by replicating the workflow's develop step, then running Aqua's stale-deps + deps-compat checks against OptimizationCMAEvolutionStrategy.

(a) Bug reproduced (old, buggy helper): develop step injects OptimizationLBFGSB + OptimizationManopt into CMAES's [deps]; Aqua fails exactly as in the issue:

Stale dependencies: Evaluated: isempty(Base.PkgId[OptimizationLBFGSB […], OptimizationManopt […]])
OptimizationCMAEvolutionStrategy does not declare a compat entry for the following deps:
  OptimizationLBFGSB […]
  OptimizationManopt […]
3 passed, 2 failed

(a) Fix works: with scripts/develop_sources.jl, only OptimizationBase is developed; CMAES's [deps] stays {CMAEvolutionStrategy, OptimizationBase, Reexport, SciMLBase} (no phantom deps); the same Aqua stale-deps + deps-compat checks now pass 5/5, exit 0.

(b) No regression (legitimate transitive runtime developing still works): built a synthetic monorepo Top → Mid → Leaf where Mid runtime-sources Leaf (in [deps]) and test-only-sources TestOnly (only in [extras]/[targets].test). With the fix, developing Top develops the full runtime chain {Mid, Leaf} (precompiles + loads; Top.top_marker() returns through Mid → Leaf), while TestOnly is correctly excluded from Top's manifest. The old helper, by contrast, leaks TestOnly in — confirming the fixture genuinely discriminates the two behaviors.

Owning-repo test suite: julia test/runtests.jl passes on Julia 1.10 and 1.12 (exit 0). Added 3 testsets asserting (1) a dependency's test-only [sources] are excluded while the runtime transitive chain is developed, (2) the root package's own test-only [sources] ARE still developed, (3) no-[sources] → nothing developed. actionlint is clean on the modified tests.yml.

Deploy note

This change is in SciML/.github reusables, so it requires a v1 retag to take effect for consumers (Optimization.jl and the rest of the fleet).

Fixes SciML/Optimization.jl#1228

Please ignore until reviewed by @ChrisRackauckas.

ChrisRackauckas and others added 2 commits June 16, 2026 05:51
….11)

The tests.yml "Develop in-repo [sources] path deps" step walked the
[sources] graph transitively on Julia <1.11. When the package-under-test
sources an in-repo dependency that itself declares test-only [sources]
(names in [extras]/[targets].test, not [deps]), those test-only path deps
were Pkg.develop-ed into the active environment as phantom direct deps.
Aqua's stale-deps and deps-compat checks then failed.

This is what makes every Optimization.jl sublibrary's QA group fail on
Julia lts: OptimizationBase's test-only [sources] (OptimizationLBFGSB,
OptimizationManopt) were pulled into ~26 dependent sublibraries' envs.
QA on Julia >=1.11 is green because the whole helper is a no-op there.

Fix: extract the walk into scripts/develop_sources.jl and, when recursing
into an already-developed dependency, only follow [sources] entries that are
also that dependency's runtime [deps]. The package-under-test itself (the
root of the walk) is exempt, so its own test-only [sources] are still
developed for its own test suite. tests.yml now checks out SciML/.github
(at dotgithub-ref, default v1, matching the sibling workflows) and calls the
script, giving a single tested source of truth.

Adds test/runtests.jl coverage asserting a dependency's test-only [sources]
are excluded while the runtime transitive chain (and the root's own
test-only sources) are still developed.

Fixes SciML/Optimization.jl#1228

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The actionlint+shellcheck job uses a docker:// action, but `runs-on:
ubuntu-latest` lets it land on the self-hosted pool (which squats
`ubuntu-latest` and cannot pull/run Docker images) -> intermittent
"Docker pull failed with exit code 1". Self-hosted runners do not carry
the `ubuntu-24.04` label, so pinning forces a GitHub-hosted runner where
Docker works. The Julia script-tests job is left on ubuntu-latest (no
Docker; self-hosted is fine).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review June 16, 2026 11:47
@ChrisRackauckas ChrisRackauckas merged commit c9c3a9a into SciML:master Jun 16, 2026
2 checks passed
ChrisRackauckas added a commit that referenced this pull request Jun 17, 2026
…s monorepo sublibrary CI)

The "Develop in-repo [sources]" step (added in #98) runs with
`shell: julia {0}`, which writes the body to a temp file under RUNNER_TEMP
and executes it from there. Julia's `include` resolves a RELATIVE path
against the including file's directory (RUNNER_TEMP), not GITHUB_WORKSPACE
where `.sciml-dotgithub` is checked out -- so the relative
`include(joinpath(".sciml-dotgithub", ...))` failed with
`SystemError: opening file ".../_temp/.sciml-dotgithub/scripts/develop_sources.jl"`.

This broke every monorepo's sublibrary CI (project != '.'/'@.') the moment
v1.15.1 was retagged (e.g. ModelingToolkit Sublibrary CI). Anchor the
include at ENV["GITHUB_WORKSPACE"] so it resolves regardless of the temp
script's location.

Verified by simulating the step (julia temp-script in RUNNER_TEMP, run from
a third cwd, .sciml-dotgithub under GITHUB_WORKSPACE): the relative form
reproduces the SystemError; the GITHUB_WORKSPACE-anchored form loads
develop_sources cleanly.

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.

Sublibrary QA-lts fails: OptimizationBase test-only [sources] (LBFGSB/Manopt) transitively developed into every dependent sublibrary on Julia < 1.11

2 participants