Fix stale app.config binding redirects across the solution#359
Merged
Conversation
…ject references - Update bindingRedirect newVersion attributes across 9 projects to match actual assembly versions referenced in .csproj files - Fixes FileLoadException at runtime caused by CLR redirecting to non-existent versions - Add fix-validation script and feature documentation with test-regression evidence Refs: #354
…o binding-redirect fixer - Extract nested closures into typed, documented module-level functions: parse_version, discover_projects, load_project_config_texts, find_referenced_versions, correct_binding_redirects, apply_fixes - Add module-level docstring with purpose, responsibilities, usage, flow, and invariants - Add Google-style docstrings and intent comments to each function - Create test_fix_binding_redirects.py with 284-line pytest suite covering stale-redirect correction, idempotency, missing-file skip, project filtering, version extraction, and end-to-end composition - Achieve 94% line coverage on fix_binding_redirects.py - Move script orchestration behind if __name__ == "__main__" guard for import-safe, testable structure - Use monkeypatch for all file I/O in tests; no real temporary files Refs: #354
Independent re-verification of the remediation cycle's fix (Python coverage + code-quality gaps resolved): 94% test coverage confirmed, black/ruff/pyright clean, zero blocking findings remain. Refs: #354
…binding-redirects-354 # Conflicts: # .claude/agent-memory/atomic-planner/MEMORY.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix stale app.config binding redirects across the solution
Summary
<bindingRedirect>newVersion/oldVersionentries inapp.configacross 9 first-party projects so each redirect matches the assembly version actually referenced by the project's own.csproj.System.IO.FileLoadException: ... manifest definition does not match the assembly referencerisk at runtime — not test-only, since these redirects govern assembly loading for the VSTO add-in itself..csfiles changed; the fix is a config-only correction plus a durable, test-covered audit/fix script.Why
While remediating Dependabot NuGet PRs #343–#348, a prior remediation script (
fix_reference_versions.ps1) corrected each project's<Reference Include="...">Version=attribute to match the real assembly version read from the restored DLL, but never updated the siblingapp.config<bindingRedirect>entry for the same assembly. An audit ofmainfound 57 stale redirects across QuickFiler, QuickFiler.Test, Tags.Test, TaskMaster, TaskMaster.Test, TaskTree.Test, TaskVisualization.Test, ToDoModel.Test, UtilitiesCS, UtilitiesCS.Test, and VBFunctions.Test, spanningMicrosoft.Bcl.TimeProvider, theMicrosoft.Extensions.*family,Microsoft.Identity.Client(.Extensions.Msal), theMicrosoft.IdentityModel.*family,System.ClientModel,System.IdentityModel.Tokens.Jwt,System.Collections.Immutable,System.Diagnostics.DiagnosticSource,System.Formats.Asn1,System.Memory.Data,System.Net.Http.WinHttpHandler,System.Reflection.Metadata,System.Security.Cryptography.ProtectedData,System.Text.Encoding.CodePages,System.Text.Encodings.Web,System.Text.Json,Microsoft.ApplicationInsights, andMicrosoft.Web.WebView2.Core.A mismatched redirect causes the CLR to redirect a dependent-assembly reference to a version number that doesn't correspond to the DLL physically present at the
HintPath, throwingFileLoadExceptionat load time. This was reproduced and confirmed withMicrosoft.Bcl.TimeProviderinQuickFiler.Test: correcting the redirect fromnewVersion="10.0.0.7"tonewVersion="10.0.0.10"tookQfcHomeControllerMetricsTests+QfcStreamingDequeueConfidenceGateTestsfrom 8 failing (of 21) to 0 failing.What Changed
Core fix
QuickFiler.Test/app.config,Tags.Test/app.config,TaskMaster.Test/app.config,TaskTree.Test/app.config,TaskVisualization.Test/app.config,ToDoModel.Test/app.config,UtilitiesCS/app.config,UtilitiesCS.Test/app.config,VBFunctions.Test/app.config— every<bindingRedirect>corrected to match the corresponding.csproj<Reference Version=...>.Tooling
docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/scripts/fix_binding_redirects.py— durable audit/fix script: parses each project's.csproj<Reference Include="{pid}, Version={ver}, ...">entries as ground truth, finds the matchingapp.config<dependentAssembly>block by assembly name + publicKeyToken, and correctsoldVersion's upper bound andnewVersionon mismatch. Idempotent (a second run reports zero changes).docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/tests/scripts/test_fix_binding_redirects.py— new pytest suite (94% line coverage) covering stale-redirect correction, idempotency on an already-correct redirect, and skip-without-error when a project'sapp.config/.csprojdoesn't reference the target assembly.Docs/process
docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/— issue, plan, remediation plan, policy-audit/code-review/feature-audit artifacts (both review passes), and evidence for every toolchain stage run during this fix.Architecture / How It Fits Together
No architectural change.
app.config<bindingRedirect>entries are read by the .NET Framework CLR at assembly-load time; this fix only corrects data values in those XML files so they agree with the assemblies each project's.csprojalready declares it uses. The audit/fix script is a one-time-per-drift developer tool, not part of the shipped add-in.Verification
Completed (from evidence in
docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/evidence/):vstest.console.exeacross all 8 first-party test assemblies: 5468/5468 passing, 0 failures, both pre-fix and post-fix (line coverage 71.05% → 71.08%).TOTAL: 0(idempotency confirmed).git diff --name-onlyscope-lock check confirms zero.cs/.csprojfiles touched, onlyapp.config.black,ruff,pyrightclean on the new Python script and its test file;pytest --covreports 8/8 tests passing, 94% line coverage.Recommended (for reviewer, not run in this PR):
gh pr checksagainst this PR's head SHA once CI completes.Backward Compatibility / Migration Notes
None. This is a corrective change to redirect metadata only; no public API, schema, or behavior contract changes.
Risks and Mitigations
.csprojreference version were itself wrong.Mitigation: The
.csprojreference versions were independently established and verified during the Dependabot PR Bump the analyzers-dev-deps group with 3 updates #343–Bump Microsoft.Web.WebView2 from 1.0.3912.50 to 1.0.4078.44 #348 remediation (each cross-checked against the real restored DLL version via reflection), so this fix aligns redirects to already-verified ground truth rather than introducing a new assumption.Mitigation:
SVGControl/SVGControl.Testare intentionally excluded (pre-existing, conventionally vendored/exempt in this repo); one residual stale redirect there is documented as a non-blocking follow-up, not fixed in this PR.Review Guide
Suggested order:
docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/issue.md— root cause and acceptance criteria (AC1–AC5).app.configdiffs — each is a small, mechanicalbindingRedirectvalue change; spot-check one or two against the corresponding.csproj.docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/scripts/fix_binding_redirects.py+ its test file — the durable tooling and its coverage.docs/features/active/2026-07-18-stale-app-config-binding-redirects-354/policy-audit.2026-07-18T16-00.md,code-review.2026-07-18T16-00.md,feature-audit.2026-07-18T16-00.md— the final, clean review pass.The bulk of the diff (44 files) is process/evidence documentation under the feature folder and is not code review-relevant in the traditional sense — it exists to satisfy this repo's evidence-and-timestamp conventions.
Follow-ups
SVGControl/app.config's residual staleSystem.Runtime.CompilerServices.Unsaferedirect (6.0.2.0vs. csproj's6.0.3.0), or formally document whySVGControl/SVGControl.Testare exempt from binding-redirect audits the same way they're exempt from other build gates.issue.mdnoting that the originally-reported 8-failing-test repro was not reproducible in this branch's actual baseline capture (that specific package's redirect already matched by the time this branch was cut) — the broader 57-redirect defect was real and is what this PR fixes.GitHub Auto-close