[quality-improver] 3 of 69 central PackageVersion entries in Directory.Packages.props have zero PackageReference anywhere in the repo
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Refactor
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- csharp
- Domain
- build-system
Research direction
Start in Directory.Packages.props and confirm the PackageVersion entries for Microsoft.TestPlatform.TranslationLayer (line 98), Microsoft.TestPlatform (line 124) and Newtonsoft.Json (line 132) have no matching PackageReference by running the grep given in the issue. Delete those three entries, then run a full restore/build to confirm CPM still resolves. Done means the entries are gone and the restore succeeds. The CI lint script in Task 2 is a separate, larger piece of work.
Written by the indexing model from the issue text.
Description
🎯 Repository Quality Improvement Report — Central Package Management Hygiene
Analysis Date: 2026-10-09
Focus Area: central-package-management-dead-entries (custom)
Strategy Type: Custom
Executive Summary
The repository's Directory.Packages.props centralises NuGet versions for every packable and test project via Central Package Management (CPM). Cross-referencing all 69 <PackageVersion Include="..."> entries against every <PackageReference Include="..."> usage across all 243 .csproj/.props/.targets files in the repo (excluding bin/, obj/, artifacts/) surfaces 3 entries with no corresponding PackageReference anywhere: Microsoft.TestPlatform.TranslationLayer, Microsoft.TestPlatform (the bare package name, distinct from Microsoft.TestPlatform.ObjectModel, .Filter.Source, and .TestHost, all of which are referenced), and Newtonsoft.Json.
This isn't a functional bug — CPM silently tolerates unused PackageVersion entries, and the build succeeds either way. But it is maintenance debt: each dead entry still gets tracked by Dependabot/Darc, still needs manual eyes during version-bump reviews, and misleads a reader auditing "what does this repo actually depend on" (for example, the prior dependency-health audit in #9091 treated the registry's 54-then-69 entries as the live dependency surface without flagging that a few were already dead). None of the three were referenced via GlobalPackageReference, a wildcard import, or any transitive-pinning mechanism — Directory.Build.props/.targets at every level (root, src/, test/) were checked and contain no such references.
Findings
Confirmed dead central package entries (zero PackageReference matches repo-wide):
| Entry (Directory.Packages.props line) | Version pin | PackageReference matches found |
|---|---|---|
Microsoft.TestPlatform.TranslationLayer (line 98) |
$(MicrosoftNETTestSdkVersion) |
0 |
Microsoft.TestPlatform (line 124) |
$(MicrosoftNETTestSdkVersion) |
0 |
Newtonsoft.Json (line 132) |
13.0.3 |
0 |
For contrast, sibling/similarly-named packages in the same file are actively referenced and should not be touched:
Microsoft.TestPlatform.ObjectModel→ used insrc/Adapter/MSTest.TestAdapter,src/Platform/Microsoft.Testing.Extensions.VSTestBridge,samples/public/UwpVSTestApp,test/IntegrationTests/PlatformServices.Desktop.IntegrationTests.Microsoft.TestPlatform.Filter.Source→ used insrc/Adapter/MSTest.TestAdapterandsrc/Platform/Microsoft.Testing.Extensions.VSTestBridge.Microsoft.TestPlatform.TestHost→ used insamples/public/WinUIVSTestAppandsamples/public/UwpVSTestApp.
Method: parsed every <PackageVersion Include="X"> name from Directory.Packages.props, then searched the concatenated text of all .csproj/.props/.targets files (excluding build output and artifacts/) for a literal Include="X"/Include='X' match. Confirmed each of the 3 negative results manually, including checking for indirect GlobalPackageReference wiring and raw-string usages of the assembly name in C# (Newtonsoft.Json-qualified types also appear nowhere outside a documentation comment in test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj explaining a different package's transitive dependency).
🤖 Suggested Improvement Tasks
Task 1: Remove the 3 dead PackageVersion entries
Priority: Low
Estimated Effort: Small
In Directory.Packages.props, delete the Microsoft.TestPlatform.TranslationLayer (line 98), Microsoft.TestPlatform (line 124), and Newtonsoft.Json (line 132) PackageVersion entries, since no project in the repository consumes them via PackageReference. Re-run grep -rn 'PackageReference.*Include="Microsoft.TestPlatform.TranslationLayer"\|PackageReference.*Include="Microsoft.TestPlatform"\|PackageReference.*Include="Newtonsoft.Json"' --include=*.csproj . after the edit (expect zero results) and do a full restore (./build.sh or .\build.cmd) to confirm CPM doesn't fail — removing an unused entry is always safe for CPM resolution, but a confirming restore catches anything the static scan missed (e.g. a project file generated at build time).
Task 2: Add a CI lint step that fails on unreferenced PackageVersion entries
Priority: Medium
Estimated Effort: Medium
Add a script (e.g. .github/scripts/check_unused_package_versions.py, mirroring the style of the existing .github/scripts/check_action_pins.py) that performs the same cross-reference check in CI: parse Directory.Packages.props for every PackageVersion name, scan all .csproj/.props/.targets files for a matching PackageReference/GlobalPackageReference Include, and fail if any entry has zero matches. This prevents the registry from silently accumulating dead entries again after a dependency is removed from the last consuming project (which is presumably how these three went stale) and keeps the "CPM registry = actual dependency surface" invariant that dependency-health audits rely on. Wire it into the same workflow that runs check_action_pins.py, or a new lightweight job, and document the script's purpose in a header comment per repo convention.
Task 3: Document the removal in the next dependency-health review cycle
Priority: Low
Estimated Effort: Small
When the recurring dependency-health focus area next runs (see #9091 and its 2026-10-06 follow-up), note that the registry's true active entry count dropped from 69 to 66 after this cleanup, so future "N packages in central registry" metrics stay accurate and don't re-count the removed entries as if they were newly added back.
📊 Historical Context
This is a new finding, distinct from the two deferred items tracked in #9091 (System.CommandLine beta-pin staleness and Microsoft.WindowsAppSDK version drift in WinUI samples), which concern stale or drifting versions of packages that are actively used. This finding instead concerns entries with no consumers at all. No other focus-area run has examined CPM entries for zero-reference dead weight.
🎯 Recommendations
Immediate Actions (This Week)
- Remove the 3 confirmed-dead
PackageVersionentries — Priority: Low (safe, mechanical, immediately shrinks the registry)
Short-term Actions (This Month)
- Add the CI lint script so this class of drift is caught automatically going forward — Priority: Medium
Next analysis: a different focus area will be selected based on the diversity algorithm.
🤖 Automated content by GitHub Copilot. Generated by the Repository Quality Improver workflow. · copilot · auto · 268.6 AIC · ⌖ 8.59 AIC · ⊞ 17.4K · [◷]( · ◷)
Add this agentic workflow to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/repository-quality-improver.md@main
- expires on Oct 11, 2026, 10:37 PM UTC
- Dominant language
- C#
- Stars
- 1.1k
- Forks
- 312
- Avg merge
- 8h 33m
- Merged PRs (30d)
- 411
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/testfx
-
agentic-workflows area/performance type/automation
Difficulty 4/5 3-5 days Newbie friendliness 15/100
Maintainers usually reply within 1 day
-
[duplicate-code] Duplicate `HasDuplicateModuleIdentity` logic between AzureDevOps and GitHub Actions reportersPossibly taken @Evangelink claimed this today. Opentype/automation type/tech-debt
microsoft/testfx#12000 · 1 reaction · 2 assignees ·
Maintainers usually reply within 1 day
-
[test-improver] Add unit tests for DotnetTestConnection.StartServerControlChannelAsync guard conditionsPossibly taken @Evangelink claimed this today. Openarea/mtp needs/triage
microsoft/testfx#11998 · 1 reaction · 2 assignees ·
Maintainers usually reply within 1 day
-
area/mtp-github-actions-report external/dotnet-test needs/triage
Difficulty 4/5 3-5 days Newbie friendliness 56/100
Maintainers usually reply within 1 day
-
Allow a trailing CancellationToken parameter on MSTest test methodsPossibly taken @Evangelink claimed this 2 days ago. Openarea/mstest area/parameterized-tests needs/triage
Difficulty 4/5 3-5 days Newbie friendliness 22/100
Maintainers usually reply within 1 day
All issues in microsoft/testfx
Similar issues
-
status:waiting-for-triage type:bug
Difficulty 1/5 Under an hour Newbie friendliness 84/100
microsoftgraph/msgraph-sdk-dotnet#3194 ·
Maintainers usually reply within 1 day
-
Backend enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day
-
UI: money shows the minus sign next to the number, not before the currency (IL -3.0m, not -IL 3.0m)Openarea: sim area: unity enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
eyalgolan/statecraft-israel#1107 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
dimitar-radenkov/Pointframe#271 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
qew21/Genshin-Subtitles#45 ·