Activate a scratch copy of the group env so QA runs stop rewriting the repo's Project.toml - #48
Merged
Merged
Conversation
`activate_group_env` activated the group's git-tracked directory and then `Pkg.develop`ed into it, so every QA run rewrote a tracked `Project.toml` (new `[deps]` entry, normalized `[sources]`/`[compat]`). Copy the env's project/manifest/preferences to a temporary directory and activate that instead; relative `path` entries are rewritten to absolute paths so a copy outside the repo still resolves its in-repo siblings. `sandbox = false` keeps the old in-place behavior. Closes #46 Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
ChrisRackauckas
marked this pull request as ready for review
August 9, 2026 11:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #46.
Please ignore until reviewed by @ChrisRackauckas.
What changed and why
activate_group_envactivated the group env in the repo under test — a git-tracked directory — and thenPkg.developed into it.Pkg.developrewrites the project it acts on, so every QA run left the working tree dirty: a new[deps]entry for eachparentthat was not already listed, plus Pkg's normalization of[sources]and[compat]. The injected dep lands with no matching[sources]entry (the dev path lives only in the gitignored manifest), so committing that churn silently points a monorepo QA env at the registered release of the package the repo is testing.The fix copies the env (
Project.toml,Manifest.toml,LocalPreferences.toml, and theJulia*variants) into a temporary directory and activates the copy, soPkg.develop/Pkg.instantiatenever write into the repo. Relativepathentries —[sources]in the project, developed entries in the manifest — are rewritten to absolute paths, since the copy no longer sits at the env's original depth ("../../../OrdinaryDiffEqCore"would otherwise resolve outside the repo). The copy is memoized per group dir per process, so re-activating the same env in one run reuses the resolved state;sandbox = falserestores the old in-place behavior.Consequence worth flagging:
dirname(Base.active_project())is now a temp dir rather thangroup_dir. Test bodies that locate files with@__DIR__(all the ones I looked at) are unaffected; anything resolving paths against the active project would be. Documented in the docstring and README.Reproduction on unmodified main
Fresh clone of SciML/OrdinaryDiffEq.jl at 9d23061 (clean tree), Julia 1.12.6, SciMLTesting main at 1796019 (
v2.6.3) dev'd into a driver env, running the call OrdinaryDiffEqBDF'sruntests.jlmakes:Discriminating test
New testset
activate_group_env leaves the group env's Project.toml untouched: a fake monorepo (root package, sublibrary, unregistered sibling pinned by a relative[sources]path that escapes the env directory), activated with the two-parent call, asserting the trackedProject.tomlis byte-identical afterwards, noManifest.tomlis dropped into the env, and the sandbox still resolves the sibling by path.Because reverting
src/also removes thesandboxkwarg that another testset now uses, the clean before/after below runs the new testset verbatim as a standalone script against the same package checkout,src/SciMLTesting.jlreverted to main and then restored. The full-suite numbers for both states follow.Before the fix (
git checkout origin/main -- src/SciMLTesting.jl):After the fix:
Test suite
julia --project=. -e 'using Pkg; Pkg.test()', Julia 1.12.6, withsrc/reverted to main (the three activation testsets fail; the error is the not-yet-existingsandboxkwarg):With the fix, Julia 1.12.6:
With the fix, Julia 1.11.9:
With the fix, Julia 1.10.11 (LTS — the
develop_sources![sources]backport path; fewer tests because the 1.11+-gated ones do not run):Downstream verification
Throwaway clone of SciML/OrdinaryDiffEq.jl at 9d23061. Where the lane needed the patched SciMLTesting, the pin was committed first, so
git status --porcelainmeasures only harness churn.A full
GROUP=QAPkg.test()lane, Julia 1.12.6,lib/OrdinaryDiffEqBDF, patched SciMLTesting v2.7.0 pinned by[sources]. The lane passes and the tree stays clean:The same lane against the unpatched baseline (registered SciMLTesting v2.6.2, same commit,
[sources]pin reverted) dirties the tree with exactly the diff from #46:(That baseline run also fails
public API has docstringson:SciMLBase— unrelated to this PR; it is what #45 already fixed on main, which is why the patched run passes it.)Full disclosure on flakiness: the first patched run of this lane failed one check, Aqua's
Persistent tasks, which took 4m14s while ~200 other Julia processes were on this box; Aqua builds its own wrapper env (Pkg.generate+Pkg.develop) independent of the active project and fails when precompilation exceedstmax = 10s. The re-run quoted above passes it. The baseline run passed it in 16.3s under lighter load.The sandbox that absorbed the churn during that run, for illustration — this is what used to be written into the repo:
A second full lane on the LTS reproduces the bug and shows the class is wider than one dep.
GROUP=QAPkg.test(), Julia 1.10.11,lib/OrdinaryDiffEqSIMDRK, registered SciMLTesting v2.6.2 (Testing OrdinaryDiffEqSIMDRK tests passed, tree dirty afterwards):On the LTS the
[sources]backport walks the graph, soDiffEqBaseis injected as well. Repeating that same SIMDRK activation on Julia 1.10.11 with the patched SciMLTesting v2.7.0 ([sources]is ignored on 1.10, so the pin is aPkg.developin a driver env) leaves the tree clean:Sandboxing does not change Pkg's validation. A group env whose
[sources]names a package missing from[deps]/[extras]is rejected identically either way (found while wiring the pin above):Alternatives, and why they lose
Both of the narrower options in the issue were checked rather than assumed:
finally. It does not just leave a window — it breaks the lane.activate_group_envreturns before the group's test files run, so restoring the pre-develop[deps]makes the developed parent unloadable. Verified directly: develop a package into an env, restore the originalProject.toml, thenusing P→ArgumentError: Package P not found in current path.[deps]leaves the file byte-identical), so this would help the no-op case — but the case that actually mutates is the one where the parent genuinely must be added. In OrdinaryDiffEq's sublibrary QA envs the umbrellaOrdinaryDiffEqis not in[deps], and developing it is the whole point of the lane, so this alternative cannot fix the reported bug.Also checked
Every group env in OrdinaryDiffEq (
qa, rootAD/Downstream/ODEInterfaceRegression) that goes throughactivate_group_envgets the fix, as does DiffEqDevTools' QA env;run_tests'envgroup specs route through the same function.Hand-rolled helpers still living in the repos bypass SciMLTesting entirely and are unaffected by this PR: OrdinaryDiffEqDifferentiation's
activate_sparse_env/activate_modelingtoolkit_env, DiffEqBase'sactivate_static_env, and the variousactivate_gpu_envs all do their ownPkg.activate+Pkg.develop. Thesparse/modelingtoolkit/gpuenvs already list their parent in[deps], so they leave the file alone;lib/DiffEqBase/test/static/Project.tomldoes not list DiffEqBase, soactivate_static_envhas the same defect — the fix is to migrate those helpers toactivate_group_env, which is a separate OrdinaryDiffEq PR.Version
2.6.3 → 2.7.0.
sandboxis a new public keyword argument and the default behavior of a public function changes (the activated project is a copy), so this is a minor bump, not a patch. 2.6.3 is not yet registered (General has 2.6.2).Not verified
Pkg.activatein the repos anyway and are untouched by this PR.Manifest.tomls: I rewrite relative manifestpathentries when copying, which the OrdinaryDiffEq lane does exercise for a generated manifest, but no repo I checked commits one.Reviewer, push back on
develop = false, instantiate = false(a pure activation writes nothing, so the copy is not strictly needed there). I chose the simpler invariant "the working tree is never written" over a conditional one.