Skip to content

SmrtHub Central Package Version Policy v1.0

Authoritative governance for NuGet dependency version management across all SmrtHub .NET projects.

1. Purpose

Establish a single, deterministic, auditable mechanism for specifying and evolving third‑party and first‑party NuGet package versions. Prevents version drift, reduces restore unpredictability, and enables safe, batched upgrades.

2. Scope

Applies to every C#/.NET project (.csproj) in the repository (applications, libraries, tools, test projects) that consumes NuGet packages. Excludes Python dependencies, native toolchain assets, or ad‑hoc local project references.

3. Core Mechanism

SmrtHub uses .NET Central Package Management (CPM): - A single root file: Directory.Packages.props (repository root) - Exact pins via <PackageVersion Include="Package" Version="X.Y.Z" /> - Project files list <PackageReference Include="Package" /> without Version attributes - The property <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> lives in the central file - Any attempt to add a Version inside a project triggers NU1008 (enforcement signal)

4. Design Principles

Principle Explanation
Determinism First Exact versions (no floating ranges) for reproducible builds & diagnostics.
Stable Before Preview Prefer latest stable unless a preview/rc is required (platform constraints).
Minimal Noise No redundant imports; rely on MSBuild automatic discovery at repo root.
Explicit Exceptions Pre-release packages documented inline until replaced.
Single Source of Truth Only one authoritative location for versions.
Commented Intent Lower-bound intent (future range considerations) captured as comments, never enforced via ranges today.

5. File Location & Discovery

/Directory.Packages.props must reside at the repository root so MSBuild auto‑loads it without manual <Import> statements. Manual re‑imports cause MSB4011 warnings and are prohibited.

6. Allowed Version Forms

Form Allowed Rationale
Exact numeric (e.g. 13.0.4) Yes Deterministic pin
Pre-release semantic (e.g. 10.0.0-rc.1.25451.107) Yes (document) Platform / dependency wave alignment
Version ranges [a,b) No (for now) Increases complexity / non-determinism
Floating * Never Breaks reproducibility
Relative / auto (e.g. 8.*) Never Hidden drift

7. Update Workflow

Step Action
1 Identify candidate package & target version (prefer stable)
2 Edit Directory.Packages.props – change the Version attribute
3 Run dotnet restore (or build script) locally
4 Address any new analyzer / API warnings introduced
5 Run test suite (unit + integration where applicable)
6 Commit with message: deps: bump <PackageName> to <Version>
7 Include changelog / security notes if major or security-related

8. Adding a New Dependency

  1. Add a new <PackageVersion Include="Package" Version="X.Y.Z" /> in sorted alphabetical order (case-insensitive) within the central file.
  2. Add <PackageReference Include="Package" /> to the consuming project(s).
  3. Restore & build.
  4. If transitive conflicts arise, resolve by explicitly adding other required PackageVersion pins.

9. Removing a Dependency

  1. Remove all <PackageReference Include="Package" /> entries.
  2. Delete its <PackageVersion> line from the central file.
  3. Restore & confirm no other project reintroduces it transitively (use dotnet list <project>.csproj package --include-transitive).

10. Pre-release Governance

Scenario Guideline
Required platform (e.g., WinAppSDK wave) Pin pre-release with full qualifier
Experimental adoption Justify in PR description + plan to revisit stable replacement
Aging pre-release (> 2 stable cycles) Review and migrate or drop

11. Enforcement Signals

Error / Warning Meaning Action
NU1008 Inline Version present while CPM enabled Remove Version attribute
MSB4011 Duplicate import of central file Remove manual <Import>
NU1604 No inclusive lower bound (historical issue) Caused by CPM not applied – ensure root file in place
Vulnerability warnings (NU19xx) Known CVE in pinned version Upgrade or document temporary hold reason

12. Anti-Patterns (Prohibited)

Anti-Pattern Why Disallowed
Multiple Directory.Packages.props Fragmentation / ambiguity
Project-specific downgrades Silent divergence, potential runtime mismatch
Floating or wildcard versions Non-repeatable builds
Manual import once discovery works Redundant noise (MSB4011)
Ranges for "future proofing" Encourages unnoticed drift

13. Comment Conventions

Lower-bound intent is recorded as:

<PackageVersion Include="Serilog" Version="4.3.0" /> <!-- lower-bound: [4.3.0,) -->
These comments are informational only; tooling may later parse them if range mode is adopted.

14. SmrtHub Runtime Identifier (RID) Guard Interaction

The SmrtHub project enforces explicit -r usage through the build system. This is orthogonal to CPM but influences build invocation. Building SmrtHub requires an explicit RID (win-x64 or win-arm64). The build system handles this automatically, but for manual builds:

# Using build script (recommended)
.\Tools\Clean-Build\BuildApps.ps1 -Configuration Debug -RuntimeIdentifier win-x64

# Or direct dotnet command
dotnet build <your-app>.csproj -r win-x64 -c Debug

15. Bulk Upgrade Playbook

  1. Export current dependency inventory:
    dotnet list .\SmrtApps\SmrtHub.sln package --include-transitive > .\Tools\Reports\deps-before.txt
    
  2. Update one or a logical cluster (e.g., Serilog family) at a time.
  3. Restore & run tests.
  4. Compare new tree:
    dotnet list SmrtApps/SmrtHub.sln package --include-transitive > _reports/deps-after.txt
    
  5. Diff for unexpected additions / version regressions.
  6. Commit with a cohesive message.

16. Risk Mitigation & Rollback

Risk Mitigation Rollback
Breaking API Use feature branches & tests Revert the specific <PackageVersion> line
Transitive vulnerability Upgrade direct dep first Pin explicit transitive version if required
Hidden drift (manual version added) NU1008 stops build Remove offending attribute

17. Tooling Enhancements (Future Consideration)

  • Pre-commit hook to block inline Version=" additions
  • Script to validate alphabetical ordering & duplicate detection
  • Report generator diffing previous vs current dependency graph

18. Change Management

Change Type Action Version Bump of This Policy
Add package Update central file Patch if doc adjusted
Replace pre-release with stable Update entry Patch
Introduce ranges Major (would alter determinism stance) Major
Add enforcement tooling Document Minor

19. Example Directory.Packages.props (Extract)

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <!-- Logging -->
    <PackageVersion Include="Serilog" Version="4.3.0" /> <!-- lower-bound: [4.3.0,) -->
    <PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" /> <!-- lower-bound: [6.0.0,) -->
    <PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" /> <!-- lower-bound: [7.0.0,) -->

    <!-- Windows UI -->
    <PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.4.231115000" />
    <PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />

    <!-- Testing -->
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
    <PackageVersion Include="xunit" Version="2.6.2" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
  </ItemGroup>
</Project>

20. Verification Checklist

  • No Version=" in any <PackageReference>
  • Directory.Packages.props loads once (no MSB4011)
  • New/changed versions justified in PR description
  • Tests pass locally
  • Vulnerability warnings (NU19xx) acknowledged or resolved

Maintainers: Build / Runtime Engineering Initial Release: v1.0