Skip to content

fix(deps): declare borrowed test packages and sync transitive binding redirects (#985) - #987

Merged
drmoisan merged 5 commits into
mainfrom
bug/dependabot-repair-borrowed-packages-and-transitive-redirects-985
Oct 9, 2026
Merged

drmoisan merged 5 commits into
mainfrom
bug/dependabot-repair-borrowed-packages-and-transitive-redirects-985

Conversation

@drmoisan

@drmoisan drmoisan commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Suggested title

fix(deps): declare borrowed test packages and sync transitive binding redirects so Dependabot PRs pass CI unattended (#985)

Summary

  • Adds scripts/dependencies/BindingRedirectSync.psm1, a redirect-sync pass that Repair-PackageManifestConsistency.ps1 now runs unconditionally. It rewrites any app.config bindingRedirect whose newVersion matches no assembly version referenced in the solution, including redirects for assemblies a project receives only transitively.
  • Declares packages that three test projects used without declaring: Microsoft.Web.WebView2 in QuickFiler.Test and UtilitiesCS.Test, and ObjectListView.Official in QuickFiler.Test and TaskTree.Test. Removes a duplicate Microsoft.Web.WebView2.Core reference from QuickFiler.Test.csproj.
  • Adds a Pester gate in RepositoryTreeConsistency.Tests.ps1 asserting Find-OrphanedHintPath reports zero findings across every project, so a project cannot silently borrow another project's package again.
  • No change under .github/workflows/**: the dependabot-repair workflow runs the Dependabot branch's own copy of the repair script, so the new pass reaches every future Dependabot PR without a workflow edit.
  • Review remediation in the same branch: sync repairs record an Upgrade/Downgrade direction, WrittenPath is de-duplicated, assembly-name comparison is case-insensitive, and an account-name fragment was removed from the committed plan.

Why

Grouped NuGet Dependabot PR #984 still failed CI after the dependabot-repair workflow (issue #911) ran successfully. Two classes of manifest inconsistency are invisible to both Dependabot and the existing repair script, because both act only on packages a project declares in its own packages.config:

  1. Test projects that hint-path a package declared only by a sibling production project. When Dependabot bumped WebView2 in the production projects, nothing restored the old version the test projects pointed at, producing CS0012/CS0234/CS0246 in the build, nullable and MSTest checks.
  2. Binding redirects for transitively received assemblies. Five test projects kept the log4net redirect at the old version, failing BindingRedirectVerification.Tests.ps1. The existing redirect pass does not run from the workflow_run trigger because no -CandidateUpgrade is supplied.

The objective is that future Dependabot PRs pass all required checks with no manual step.

What Changed

Core fix

  • scripts/dependencies/BindingRedirectSync.psm1 (new): stale-only rewrite; target version is the project's own reference version when present, otherwise the highest version referenced anywhere in the solution; assemblies with no referenced version or an unparsable version are left unchanged and reported; idempotent (a second run writes nothing). Results are reported in a separate RedirectSync field, so the workflow's beyond-known-weak count is unaffected.
  • scripts/dependencies/Repair-PackageManifestConsistency.ps1: invokes the sync pass unconditionally before manifest normalisation; de-duplicates WrittenPath.

Project manifests

  • QuickFiler.Test/packages.config, UtilitiesCS.Test/packages.config, TaskTree.Test/packages.config: declare the borrowed packages at the production versions.
  • QuickFiler.Test/QuickFiler.Test.csproj: removes the duplicate WebView2.Core item group.

Tests

  • tests/scripts/dependencies/BindingRedirectSync.Tests.ps1 (new) and tests/scripts/dependencies/Repair-PackageManifestConsistency.RedirectSync.Tests.ps1 (new): in-memory fixtures only.
  • tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1: new orphaned-hint-path gate.

Docs and evidence

  • Feature folder docs/features/active/2026-10-09-dependabot-repair-borrowed-packages-and-transitive-redirects-985/: issue, spec, research, plans, review artifacts and evidence.

Architecture / How It Fits Together

dependabot-repair.yml (workflow_run after CI on dependabot/* branches) checks out the Dependabot branch and calls Repair-PackageManifestConsistency.ps1. The entry point now runs, in order: analyzer-item repair, the new redirect sync over every app.config, then manifest normalisation. Every written path flows into WrittenPath, which the workflow's push gate (written-count) already reads, so a sync-only repair is pushed back to the Dependabot branch and CI re-runs. Separately, declaring the borrowed packages makes Dependabot itself update those test projects in the same grouped PR.

Verification

Completed (from feature evidence)

  • PowerShell toolchain (PoshQC format, analyze, test): pass; 187 tests, 0 failures. Direct Pester run: 447 passed, 0 failed.
  • PowerShell line coverage: aggregate 94.99%; BindingRedirectSync.psm1 100% (120/120); Repair-PackageManifestConsistency.ps1 94.17% (baseline 94.14%).
  • C# toolchain on the manifest change: csharpier check exit 0; msbuild /t:Rebuild with analyzers 0 errors; msbuild /t:Rebuild /p:TreatWarningsAsErrors=true 0 errors; MSTest 7427/7427 passed (four shell-icon test classes excluded locally because they hang on the development machine; CI runs the full set). C# coverage 85.41% line / 79.83% branch, unchanged.
  • Regression-first: the orphaned-hint-path gate failed with the predicted findings before the manifest edits and passed after; the redirect-sync tests failed before the module and passed after.
  • Integration rehearsal on PR Bump the all-nuget-updates group with 16 updates #984's branch with this fix merged and a simulated Dependabot bump of the newly declared packages: the repair script, invoked as the workflow invokes it, rewrote the five stale log4net redirects and the WebView2.Core redirects; a second run wrote nothing; both Rebuilds passed; BindingRedirectVerification.Tests.ps1 16/16 and RepositoryTreeConsistency.Tests.ps1 5/5 passed.
  • Feature review: re-audit PASS with zero blocking findings.

Recommended

Backward Compatibility / Migration Notes

  • No public API is removed. The repair result gains a RedirectSync field, and sync repair records carry a Direction property; existing consumers in .github/ and scripts/ do not read the changed report line.
  • The repair script now writes app.config files on any Dependabot branch whose redirects are stale; previously those were left for a human.

Risks and Mitigations

  • Risk: the sync could choose an unintended target when several versions of an assembly are referenced. Mitigation: the project's own reference version wins; otherwise the highest referenced version is used, and every rewrite is reported with its rule and direction in the PR disclosure body.
  • Risk: a future Dependabot bump introduces failures outside these two classes (for example new analyzer diagnostics). Mitigation: those surface as ordinary CI failures on the Dependabot PR; this change does not suppress any diagnostic.
  • Rollback: revert this PR; the repair workflow returns to its previous behavior.

Review Guide

  1. scripts/dependencies/BindingRedirectSync.psm1 and its tests.
  2. scripts/dependencies/Repair-PackageManifestConsistency.ps1 (small wiring diff).
  3. The three packages.config files and QuickFiler.Test.csproj.
  4. tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1.
  5. The feature folder is evidence and review artifacts; it can be skimmed.

Follow-ups

  • Filed as a separate follow-up issue: update the explanatory comments in .github/workflows/dependabot-repair.yml lines 87-105, which predate the redirect sync pass (comment-only).
  • AC7: verify PR Bump the all-nuget-updates group with 16 updates #984 goes green after @dependabot recreate.

GitHub Auto-close

  • None

… redirects (#985)

Declare Microsoft.Web.WebView2 and ObjectListView.Official in the test manifests that borrowed them, remove the duplicate WebView2.Core reference group from QuickFiler.Test, add an unconditional solution-wide binding-redirect sync pass (BindingRedirectSync.psm1) wired into Repair-PackageManifestConsistency.ps1, and add a Pester gate that fails when a project hint-paths a package its own manifest does not declare. Evidence under the feature folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Gw2R64FrQkj5f88mFAe3KA
Record the fix commit, the Phase 7 integration rehearsal against the PR #984 Dependabot branch (verdict PASS) and the acceptance-criteria status (AC1 to AC6 delivered, AC7 pending CI). The rehearsal worktree cleanup was refused by the worktree-removal hook and is reported as open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Gw2R64FrQkj5f88mFAe3KA
B-1: replace the encoded session-scratchpad segment carrying the operator account name in plan.2026-10-09T13-06.md line 26 with a placeholder; branch identity sweep is clean. CR-1: every binding-redirect sync repair record carries a Direction (Upgrade, Downgrade or Unknown) and the report line states it. CR-2: WrittenPath lists each path once, case-insensitively, in first-occurrence order. CR-3: the already-handled assembly-name check compares names case-insensitively. Adds regression tests N1 to N9 with fail-before and pass-after evidence, the R1 QA-gate evidence, the review artifacts, the issue 986 promoted record and the agent-memory notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Gw2R64FrQkj5f88mFAe3KA
@drmoisan
drmoisan merged commit 564a43b into main Oct 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant