fix: fire analyzer-filter guards before _HandlePackageFileConflicts (2.0.2)#24
Merged
MarcelRoozekrans merged 4 commits intoMay 22, 2026
Merged
Conversation
…icts The 2.0.1 buildTransitive guards used BeforeTargets=\"CoreCompile\". By that point MSBuild's _HandlePackageFileConflicts target has already deduped @(Analyzer): if both the bundled-in-main analyzer and the standalone Generator analyzer reach the project (which is the entire point of the split-package recipe), the one with the higher AssemblyVersion wins and the other is discarded. The 2.0.1 publish pipeline emitted these two copies with different AssemblyVersions, so the bundled one (2.0.1.0) consistently won. Our DisableBundled guard then removed it on schedule, leaving no analyzer at all → no generator output → CS0234 'namespace ZeroAlloc.Authorization.Generated does not exist' in consumer code. Fixing BeforeTargets to _HandlePackageFileConflicts moves the guard ahead of conflict resolution. The bundled is removed first, no conflict ever triggers, and the standalone survives unconditionally. Both packages' guards updated for symmetry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 2.0.1 publish pipeline emitted the bundled-in-main analyzer with -p:Version=2.0.1 (so AssemblyVersion 2.0.1.0) and the standalone Generator package without that flag (so AssemblyVersion 1.0.0.0). The original smoke tests packed both packages in the same invocation without explicit Version overrides, so both DLLs ended up with the same default AssemblyVersion — masking the conflict-resolution path that bit production. This test packs the main with -p:Version=9.9.9 and the Generator with -p:Version=1.0.0, then runs the split-package scenario. Confirmed by temporarily reverting the BeforeTargets fix: this test fails with the exact CS0234 hit in the field, and passes again with the fix in place. PackProject gains an optional assemblyVersion parameter so existing tests stay terse. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 2.0.1 publish flow produced an AssemblyVersion mismatch between the bundled analyzer (built by release-please.yml with -p:Version=$VERSION) and the standalone Generator package (built here without -p:Version, defaulting to Directory.Build.props' 1.0.0). Pass -p:Version to keep the AssemblyVersions in lockstep across publish paths. The BeforeTargets fix in the previous commit makes the recipe robust regardless of AssemblyVersion ordering, so this is hygiene rather than strictly required. Removes a future class of bugs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t-order fix 2.0.1 shipped with a buildTransitive guard that fires too late: by the time it ran (BeforeTargets=\"CoreCompile\"), MSBuild had already discarded the standalone Generator analyzer via package-file conflict resolution. 2.0.2 moves the guard ahead of conflict resolution so the split-package recipe actually works in consumer builds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MarcelRoozekrans
added a commit
to ZeroAlloc-Net/ZeroAlloc.Templates
that referenced
this pull request
May 22, 2026
2.0.1's buildTransitive guards fired too late (BeforeTargets="CoreCompile"), so MSBuild's _HandlePackageFileConflicts had already discarded the standalone Generator analyzer before our DisableBundled guard ran. Net effect: no analyzer at all, no generator output, CS0234 'namespace ZeroAlloc.Authorization.Generated does not exist' in MyApp.Api. 2.0.2 (ZeroAlloc-Net/ZeroAlloc.Authorization#24) moves the guards to BeforeTargets="_HandlePackageFileConflicts" so the bundled is removed first, no conflict triggers, and the standalone survives. New Split_package_pattern_survives_assemblyversion_mismatch regression test upstream prevents this from re-regressing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MarcelRoozekrans
added a commit
to ZeroAlloc-Net/ZeroAlloc.Templates
that referenced
this pull request
May 22, 2026
2.0.1's buildTransitive guards fired too late (BeforeTargets="CoreCompile"), so MSBuild's _HandlePackageFileConflicts had already discarded the standalone Generator analyzer before our DisableBundled guard ran. Net effect: no analyzer at all, no generator output, CS0234 'namespace ZeroAlloc.Authorization.Generated does not exist' in MyApp.Api. 2.0.2 (ZeroAlloc-Net/ZeroAlloc.Authorization#24) moves the guards to BeforeTargets="_HandlePackageFileConflicts" so the bundled is removed first, no conflict triggers, and the standalone survives. New Split_package_pattern_survives_assemblyversion_mismatch regression test upstream prevents this from re-regressing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MarcelRoozekrans
added a commit
to ZeroAlloc-Net/ZeroAlloc.Templates
that referenced
this pull request
May 22, 2026
…analyzer-leak workaround (#105) * chore(deps): adopt ZA.Authorization 2.0.1 split-package recipe; drop workaround ZA.Authorization 2.0.1 splits its source generator into a standalone ZeroAlloc.Authorization.Generator package and ships a property-driven buildTransitive guard that filters analyzers per-project based on two consumer-set MSBuild properties. The za-clean template adopts the recipe: - Directory.Build.props sets ZeroAllocAuthorizationDisableBundledAnalyzer=true so the bundled-in-main analyzer is removed from every project in the template (Application, Api, Infrastructure alike). - MyApp.Application.csproj sets ZeroAllocAuthorizationOwnsPolicies=true (it declares [Policy] / [RequirePolicy]) and adds the new ZeroAlloc.Authorization.Generator PackageReference. The Generator package's own buildTransitive guard removes its analyzer from any project that does not set OwnsPolicies, so Api and Infrastructure no longer pick the generator up via cross-project @(Analyzer) propagation. Concrete result: the RemoveTransitiveZeroAllocAuthorizationAnalyzer MSBuild Target previously shipped in MyApp.Api.csproj and MyApp.Infrastructure.csproj is no longer necessary and has been removed. The PrivateAssets=\"analyzers\" defense-in-depth on MyApp.Application's ZA.Authorization PackageReference is also dropped (the buildTransitive guards in 2.0.1 are the authoritative filter). Both Directory.Packages.props files (repo root + content/za-clean) bumped to ZeroAlloc.Authorization 2.0.1 and add the new ZeroAlloc.Authorization.Generator 2.0.1 entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(deps): mirror Directory.Build.props at repo root (CI parity check) Repo CI requires Directory.Build.props, Directory.Packages.props, and global.json to be byte-identical between the repo root and content/za-clean/. Mirrors the ZeroAllocAuthorizationDisableBundledAnalyzer property added in the prior commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(deps): bump ZA.Authorization{,.Generator} 2.0.1 → 2.0.2 2.0.1's buildTransitive guards fired too late (BeforeTargets="CoreCompile"), so MSBuild's _HandlePackageFileConflicts had already discarded the standalone Generator analyzer before our DisableBundled guard ran. Net effect: no analyzer at all, no generator output, CS0234 'namespace ZeroAlloc.Authorization.Generated does not exist' in MyApp.Api. 2.0.2 (ZeroAlloc-Net/ZeroAlloc.Authorization#24) moves the guards to BeforeTargets="_HandlePackageFileConflicts" so the bundled is removed first, no conflict triggers, and the standalone survives. New Split_package_pattern_survives_assemblyversion_mismatch regression test upstream prevents this from re-regressing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
2.0.1's buildTransitive guards used `BeforeTargets="CoreCompile"`. By that point MSBuild's `_HandlePackageFileConflicts` target has already deduped `@(Analyzer)`, discarding one of the two copies of `ZeroAlloc.Authorization.Generator.dll` (bundled-in-main vs standalone). Whichever survived, our `DisableBundled` guard then removed it on schedule — leaving no analyzer at all, no generator output, and CS0234 `namespace ZeroAlloc.Authorization.Generated does not exist` in consumer code.
2.0.2 moves the guard to `BeforeTargets="_HandlePackageFileConflicts"` so the bundled analyzer is removed before conflict resolution runs. No conflict triggers, the standalone Generator analyzer survives, the recipe works.
Why it slipped past 2.0.1's PackSmoke
The 2.0.1 PackSmoke test packed both packages in a single `dotnet pack` invocation without explicit `-p:Version` overrides → both DLLs ended up with the same default AssemblyVersion (1.0.0.0). MSBuild conflict resolution with equal versions doesn't fire the "Choosing X" branch consistently; the test passed because the local case never hit the dedupe path the published 2.0.1 packages hit. The publish pipeline ran `release-please.yml` with `-p:Version=2.0.1` (bundled DLL → 2.0.1.0) and `publish-from-manifest.yml` without it (standalone Generator DLL → 1.0.0.0), so consumers saw the conflict that the test scenario didn't.
Changes
Followups
Test plan
🤖 Generated with Claude Code