Skip to content

[Tech Debt]: Introduce Central Package Management (CPM) and a deliberate dependency-version policy #328

Description

@antoineatstariongroup

Summary

Adopt Central Package Management (CPM) — a single Directory.Packages.props
that owns every dependency version — codify a dependency-version policy that
keeps redistributable-library floors low, and exclude the deliberately-floored
packages from the outdated-package CI check
so they stop generating recurring
"NuGet Package Issues Detected" issues.

Motivation

Each of the ~22 .csproj files carries its own Version="…" per PackageReference:

  1. Duplication / drift risk. The test stack (NUnit 4.6.1, NUnit3TestAdapter 6.2.0,
    NUnit.Console 3.22.0, Microsoft.NET.Test.Sdk 18.6.0, coverlet.* 10.0.1,
    Microsoft.Extensions.Logging.Console 10.0.9) is repeated in every test project.

  2. Library floors are too high. The redistributable libraries multi-target
    netstandard2.1;net10.0 and pin runtime-era versions that become a minimum
    floor for every downstream consumer
    (the floor bites hardest on the
    netstandard2.1 target; on net10.0 these are in-box/unified). These abstraction
    packages have been API-stable since 6.0 and NuGet unifies to the consuming app's
    version anyway, so the high floor only narrows compatibility.

  3. The outdated-check fights the policy. .github/workflows/nuget-reference-check.yml
    runs dotnet list package --outdated daily and opens/updates a "NuGet Package
    Issues Detected" issue. Once we intentionally floor a package, it is by design
    "outdated" forever, so the check would nag continuously unless excluded.

Packages to floor (exhaustive, from current dependencies)

Only stable framework-abstraction packages referenced by redistributable
libraries
are floored. Suggested floor: latest LTS (e.g. 8.0.x); final
version at implementer discretion, provided the APIs used still resolve.

Package Referenced by (library) Current Action
Microsoft.Extensions.Logging.Abstractions SysML2.NET, SysML2.NET.Serializer.TextualNotation 10.0.9 Floor to LTS
System.Collections.Immutable SysML2.NET, SysML2.NET.Serializer.TextualNotation 10.0.9 Floor to LTS
System.IO.Pipelines SysML2.NET.Serializer.MessagePack 10.0.9 Floor to LTS (note: MessagePack's own transitive floor wins if higher)

Proposed approach

  1. Add Directory.Packages.props at the repo root (<ManagePackageVersionsCentrally>true</…>, one <PackageVersion> per package).
  2. Strip Version="…" from every <PackageReference>.
  3. Floor the three packages in the table above to an LTS version.
  4. Extend IGNORE_PACKAGES in .github/workflows/nuget-reference-check.yml with those three floored packages so they no longer trigger the outdated issue — while remaining covered by the --deprecated and --vulnerable steps (which do not use the ignore filter).

Dependency-version policy

  • Redistributable libraries (SysML2.NET, .Serializer.*, .Dal, .REST,
    .Kpar, .Extensions, .PIM): reference the lowest version providing the APIs
    used
    . Keep stable framework abstractions (Microsoft.Extensions.*,
    System.Collections.Immutable, System.IO.Pipelines, …) at an LTS floor; do
    not chase majors.
  • Applications & test projects (SysML2.NET.Viewer, all *.Tests): keep current.
  • Bump a library dependency only when (a) a required new API needs it, or (b) a
    CVE affects that specific package. Serialization/crypto packages track current.

CI: exclude floored packages from the outdated check (not from security)

  • Add the three floored packages to IGNORE_PACKAGES in nuget-reference-check.yml
    (the regex on line ~33). This suppresses only the outdated signal.
  • Do NOT exclude them from --deprecated or --vulnerable — a floored package
    with a CVE must still surface.
  • Keep the floored/ignored list as a single source of truth: list the floored
    packages once (e.g. a comment block in Directory.Packages.props) and mirror
    them in the workflow's IGNORE_PACKAGES, so the two never drift.

Scope / tasks

  • Add Directory.Packages.props centralizing all versions.
  • Remove Version= from every PackageReference.
  • Floor Microsoft.Extensions.Logging.Abstractions, System.Collections.Immutable, and System.IO.Pipelines to an LTS version (per the table).
  • Extend IGNORE_PACKAGES in .github/workflows/nuget-reference-check.yml with those three packages (outdated check only).
  • Document the dependency-version policy + the floored/ignored list (single source of truth) in README.md, CLAUDE.md, and the project wiki.
  • dotnet restore + dotnet build + full dotnet test green; CodeQuality.yml unaffected; nuget-reference-check.yml produces no recurring outdated issue for floored packages.

Out of scope

  • Mass-bumping application/test package versions.
  • Changing target frameworks.
  • Weakening the deprecated/vulnerable checks (those stay strict on every package).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions