Every Dependabot NuGet PR fails Darling whole-tree guards on restore, before a single test runs, because Dependabot updates Directory.Packages.props and cannot regenerate the packages.lock.json files that go with it.
NU1004: Mismatch between the requestedVersion of a lock file dependency marked as
CentralTransitive and the version specified in the central package management file.
Lock file version [4.0.100.11, ), central package management version [4.0.100.12, ).
NU1004: The packages lock file is inconsistent with the project dependencies so restore
can't be run in locked mode.
Currently red on #3130 and #3131.
dev is consistent — this is created by the change, not present in the tree
|
Directory.Packages.props |
Darling.Tests/packages.lock.json |
dev |
AWSSDK.PI 4.0.100.11 |
[4.0.100.11, ), resolved 4.0.100.11 |
So the nightly and the release path are unaffected — a nightly built from dev succeeds, and every merge today went 8/8 including that guard. Both Dependabot PRs change exactly one file, Directory.Packages.props, leaving nine lock files pinned to the old version.
Scope, measured
Nine packages.lock.json files, four live and five under deprecated/:
Darling/Darling.Tests Lite deprecated/Dashboard
Darling/PerformanceMonitor.Darling.Viewer Lite.Tests deprecated/Dashboard.Tests
deprecated/Installer
deprecated/Installer.Core
deprecated/Installer.Tests
--locked-mode is passed explicitly on eight restore invocations across three jobs (build.yml lines 296–301, 761, 1109). This is not implicit CI behaviour — it is a deliberate choice, made eight times.
Volume is ~1–2 PRs per week, not a flood: Dependabot runs weekly on Mondays with minor and patch grouped into one PR, majors deliberately separate, limit 10. With CPM each bump is one line.
Recommended direction: automate the regeneration. Do NOT relax locked mode.
Relaxing RestoreLockedMode is the tempting option and should be refused. CPM already pins direct versions; the lock files pin the transitive closure, which is the part nobody reviews and the part that can drift into a build shipping to production boxes. Eight explicit flags is a decision. Making Dependabot green by deleting the guarantee inverts it for convenience.
Instead: a workflow on Dependabot PRs that runs dotnet restore --force-evaluate across the nine projects and commits the updated lock files back to the branch. Preserves the guarantee, removes the recurring human step, and is the standard pattern for CPM + lock files + Dependabot in .NET.
One hazard to design around rather than discover: pushing to a PR branch needs write permission, and Dependabot PRs run with a restricted token — so this wants workflow_run or pull_request_target. The latter runs with repo write against PR code, which is a real footgun for fork PRs and bounded here because Dependabot branches are repo-internal. build.yml already documents its own workflow_dispatch recursion guard, so the mechanics are familiar in this repo; follow that precedent for the loop guard.
Rejected alternatives, with reasons:
- Regenerate manually per PR. Works, mechanical, ~weekly. Rejected as the primary answer because the failure mode is a red PR sitting unnoticed — which is the current state.
- Relax
RestoreLockedMode. Trades a real reproducibility guarantee for convenience.
- Delete the lock files. Same trade, larger.
Immediate, independent of the long-term fix
Both open PRs need one dotnet restore --force-evaluate and a commit. That unblocks them today whichever direction is chosen.
Acceptance criteria
- a Dependabot NuGet PR reaches
Darling whole-tree guards with restore succeeding, without any --locked-mode flag being removed;
- the nine lock files stay consistent with
Directory.Packages.props on dev;
- a PR that changes
Directory.Packages.props by hand and forgets the lock files still fails — the guarantee must survive the automation, or it has been traded rather than kept.
The third arm is the one that matters: an automation that regenerates unconditionally would make the guard unable to catch a genuine mismatch.
Two observations, not part of this fix
Five of the nine lock files are under deprecated/, and two of them — Installer.Tests, Dashboard.Tests — are restored in locked mode by CI at lines 298–299. Deprecated projects are still gating builds. Possibly worth pruning; a separate decision.
#3131 is a major bump (BlackwellSystems.Gcf 0.2.1 → 1.0.0). The Dependabot config deliberately keeps majors out of the group so a breaking change arrives on its own PR rather than buried in a batch — so that one wants reading on its merits, separately from the lockfile mechanics.
Every Dependabot NuGet PR fails
Darling whole-tree guardson restore, before a single test runs, because Dependabot updatesDirectory.Packages.propsand cannot regenerate thepackages.lock.jsonfiles that go with it.Currently red on #3130 and #3131.
devis consistent — this is created by the change, not present in the treeDirectory.Packages.propsDarling.Tests/packages.lock.jsondevAWSSDK.PI4.0.100.11[4.0.100.11, ), resolved4.0.100.11So the nightly and the release path are unaffected — a nightly built from
devsucceeds, and every merge today went 8/8 including that guard. Both Dependabot PRs change exactly one file,Directory.Packages.props, leaving nine lock files pinned to the old version.Scope, measured
Nine
packages.lock.jsonfiles, four live and five underdeprecated/:--locked-modeis passed explicitly on eight restore invocations across three jobs (build.ymllines 296–301, 761, 1109). This is not implicit CI behaviour — it is a deliberate choice, made eight times.Volume is ~1–2 PRs per week, not a flood: Dependabot runs weekly on Mondays with minor and patch grouped into one PR, majors deliberately separate, limit 10. With CPM each bump is one line.
Recommended direction: automate the regeneration. Do NOT relax locked mode.
Relaxing
RestoreLockedModeis the tempting option and should be refused. CPM already pins direct versions; the lock files pin the transitive closure, which is the part nobody reviews and the part that can drift into a build shipping to production boxes. Eight explicit flags is a decision. Making Dependabot green by deleting the guarantee inverts it for convenience.Instead: a workflow on Dependabot PRs that runs
dotnet restore --force-evaluateacross the nine projects and commits the updated lock files back to the branch. Preserves the guarantee, removes the recurring human step, and is the standard pattern for CPM + lock files + Dependabot in .NET.One hazard to design around rather than discover: pushing to a PR branch needs write permission, and Dependabot PRs run with a restricted token — so this wants
workflow_runorpull_request_target. The latter runs with repo write against PR code, which is a real footgun for fork PRs and bounded here because Dependabot branches are repo-internal.build.ymlalready documents its ownworkflow_dispatchrecursion guard, so the mechanics are familiar in this repo; follow that precedent for the loop guard.Rejected alternatives, with reasons:
RestoreLockedMode. Trades a real reproducibility guarantee for convenience.Immediate, independent of the long-term fix
Both open PRs need one
dotnet restore --force-evaluateand a commit. That unblocks them today whichever direction is chosen.Acceptance criteria
Darling whole-tree guardswith restore succeeding, without any--locked-modeflag being removed;Directory.Packages.propsondev;Directory.Packages.propsby hand and forgets the lock files still fails — the guarantee must survive the automation, or it has been traded rather than kept.The third arm is the one that matters: an automation that regenerates unconditionally would make the guard unable to catch a genuine mismatch.
Two observations, not part of this fix
Five of the nine lock files are under
deprecated/, and two of them —Installer.Tests,Dashboard.Tests— are restored in locked mode by CI at lines 298–299. Deprecated projects are still gating builds. Possibly worth pruning; a separate decision.#3131 is a major bump (
BlackwellSystems.Gcf 0.2.1 → 1.0.0). The Dependabot config deliberately keeps majors out of the group so a breaking change arrives on its own PR rather than buried in a batch — so that one wants reading on its merits, separately from the lockfile mechanics.