Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ updates:
- "major"
patterns:
- "*"
ignore:
# Directory.Packages.props' central Microsoft.CodeAnalysis.CSharp pin is deliberately
# floored to the .NET 8 SDK's own bundled Roslyn compiler version (4.11.0), not the latest
# available - Compono.Generators.dll (the packaged, shipped analyzer) is built once against
# this version and loaded as-is by every consumer's host compiler regardless of their own
# TargetFramework. A newer Roslyn compiler always loads an older-referenced analyzer fine
# (forward-compatible), but the reverse silently fails: Roslyn's own analyzer-version gate
# (CS9057) refuses to load an analyzer built against a NEWER compiler than the host's own,
# with only a build warning, not an error - the generator then just never runs, and a
# consumer's Composer.Create<T>() fails at runtime with a misleading "no generated plan"
# CompositionException instead of a build-time signal pointing at the real cause. Confirmed
# empirically: bumping this above 4.11.0 breaks the .NET 8/9/10 STABLE SDKs (this repo's own
# CI pins an 11.0-preview SDK, so CI alone would not catch a regression here). Raising this
# floor is a deliberate, manually-verified decision (re-run the cross-SDK empirical check
# this ignore rule's own commit performed), not something to accept via an automated bump.
- dependency-name: "Microsoft.CodeAnalysis.CSharp"

- package-ecosystem: "github-actions"
directory: "/"
Expand Down
24 changes: 23 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,29 @@
PrivateAssets="all" so they never leak to consumers - see
docs/adr/0003-generator-package-distribution.md. -->
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="5.9.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.9.0" />
<!-- Pinned to 4.11.0, not the latest available - this is a hard technical floor, not a chosen
one: Compono.Generators/Discovery/TestDoubleAnalyzer.cs uses
ITypeParameterSymbol.AllowsRefLikeType, a Roslyn API that only exists starting at compiler
package version 4.11.0 (bisected empirically: 4.9.2/4.10.0 fail CS1061, 4.11.0 compiles) -
a genuinely lower pin (e.g. 4.8.0, matching .NET 8 SDK 8.0.100's GA-bundled compiler)
doesn't compile at all, not just "doesn't load." 4.11.0 first shipped with .NET SDK
8.0.4xx (VS 17.11-era, per Microsoft's Roslyn-to-SDK-feature-band mapping) - so Compono's
real minimum-supported .NET 8 SDK is 8.0.400, not 8.0.100, which
docs/getting-started/installation.md now states explicitly (docs/adr/0003's Amendment 1) -
a Codex review finding on PR #136 caught that this repo's docs previously stated no minimum
SDK *feature band* at all, only the net8.0/net9.0/net10.0/net11.0 TFM floor, which would
have left every pre-8.0.400 .NET 8 install undocumented as broken. Separately, empirically
confirmed 5.9.0 made Compono.Generators.dll fail Roslyn's own analyzer version gate
(CS9057: "references version 'X' of the compiler, which is newer than the currently
running version") under the .NET 8/9/10 STABLE SDKs - the generator silently never ran, and
a consuming Composer.Create<T>() failed at runtime with a misleading "no generated plan"
exception instead of a build error pointing at the real cause. A Roslyn analyzer assembly is
forward-compatible with a newer host compiler (the host's own version check is
one-directional - too-new fails, older-or-equal always loads), so pinning to the oldest
supported SDK's actual GA compiler version is correct and sufficient; it isn't a floor that
needs bumping merely because a newer package version exists - see
docs/adr/0003-generator-package-distribution.md's Amendment 1. -->
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
Comment thread
ncipollina marked this conversation as resolved.
<!-- Templating, per docs/adr/0005-generator-implementation-conventions.md - shipped as source
(PackageScribanIncludeSource, set on Compono.Generators.csproj) rather than a compiled lib,
matching dynamo-mapper's pattern exactly: Scriban's code compiles directly into
Expand Down
20 changes: 12 additions & 8 deletions benchmarks/Compono.Benchmarks/Compono.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
<!-- Ecosystem-comparison reference point only - see the AutoFixture comment in
Directory.Packages.props. -->
<PackageReference Include="AutoFixture" />
<!-- BenchmarkDotNet pulls in Microsoft.CodeAnalysis.CSharp 4.14.0 transitively, older
than the 5.6.0 Compono.Generators/Compono.Generators.Tests use (Directory.Packages.props).
CI publishes every project's output into one shared per-TFM folder, so without this
explicit bump the lower transitive version wins the copy and
Compono.Generators.Tests fails at runtime with FileNotFoundException looking for
Microsoft.CodeAnalysis 5.6.0.0. Pinning to the same central version here keeps every
published Microsoft.CodeAnalysis.dll consistent. -->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<!-- Directory.Packages.props' central Microsoft.CodeAnalysis.CSharp pin is deliberately
floored to the .NET 8 SDK's own bundled Roslyn compiler version (4.11.0) so the packaged
Compono.Generators.dll analyzer loads under every officially-supported SDK - see that
file's comment. This project is never packed/shipped, so that host-compiler-compatibility
constraint doesn't apply to it, and it needs a newer version anyway:
GeneratorDriverBenchmarks.cs (ADR-0034) drives ComponoIncrementalGenerator in-process via
CSharpGeneratorDriver against LanguageVersion.CSharp14 (net10.0/net11.0 targets), which
4.11.0's LanguageVersion enum doesn't define yet. Also avoids the NU1605 downgrade error
BenchmarkDotNet's own >= 4.14.0 transitive floor would otherwise trigger, and keeps every
published Microsoft.CodeAnalysis.dll in CI's shared per-TFM output folder consistent -
same reasoning and version test/Compono.Generators.Tests uses for the identical need. -->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" VersionOverride="5.9.0" />
</ItemGroup>

<!-- ADR-0034's SourceGeneration category drives ComponoIncrementalGenerator directly via
Expand Down
65 changes: 65 additions & 0 deletions docs/adr/0003-generator-package-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,68 @@ exactly.
scope ("Create generator project").
- Precedent: `AlexaVoxCraft.MediatR.csproj` /
`AlexaVoxCraft.MediatR.Generators.csproj` in the `alexa-vox-craft` repo.

## Amendment 1 (2026-09-08): minimum-supported Roslyn/SDK version

**Context.** This ADR's own Milestone 1 review round (`docs/plans/0001-milestone-1-source-generation-foundation.md`)
already flagged pinning `Compono.Generators`' compile-time
`Microsoft.CodeAnalysis.CSharp` reference to the oldest supported
Roslyn/SDK version as "a real supply-chain concern," but the decision on
an actual minimum version was explicitly deferred at the time. That gap
became a real, live bug: `Directory.Packages.props` pinned
`Microsoft.CodeAnalysis.CSharp` at `5.6.0`–`5.9.0` from the very first
generator commit onward — every published `Compono` release, `v0.1.0`
through `v1.2.0`. Roslyn refuses to load an analyzer built against a
compiler *newer* than the host's own (silently — `CS9057`, a build
warning, never an error), so on any officially-supported `net8.0`/
`net9.0`/`net10.0` **stable** SDK, `Compono.Generators.dll` simply never
ran; a consumer's `Composer.Create<T>()` then failed at runtime with a
misleading "no generated plan" `CompositionException` instead of a
build-time signal pointing at the real cause. This repo's own CI, and
every dogfood consumer used to validate releases, all pin an
`11.0.100-preview` SDK (`global.json`), whose bundled Roslyn was new
enough — so nothing caught it until a Codex review on the fixing PR
(#136) pointed out the first attempted fix itself only verified against
one specific .NET 8 SDK patch build, not the actual documented minimum.

**Decision.** `Microsoft.CodeAnalysis.CSharp` is pinned to `4.11.0` —
confirmed to be a **hard technical floor**, not a chosen one:
`Compono.Generators/Discovery/TestDoubleAnalyzer.cs` uses
`ITypeParameterSymbol.AllowsRefLikeType`, a Roslyn API that only exists
starting at compiler package version `4.11.0` (bisected empirically:
`4.9.2`/`4.10.0` fail `CS1061`, `4.11.0` compiles). `4.11.0` first shipped
with .NET SDK **`8.0.4xx`** (the VS 17.11-era feature band) — so
Compono's real minimum-supported .NET 8 SDK is **`8.0.400`**, not
`8.0.100` (GA), which is a materially narrower floor than
`docs/getting-started/installation.md` previously implied (it stated only
the `net8.0`/`net9.0`/`net10.0`/`net11.0` TFM floor, with no SDK feature-
band minimum at all). `net9.0`/`net10.0`/`net11.0` have no equivalent
constraint — every released SDK for those TFMs already bundles a Roslyn
compiler `>= 4.11.0`.

Verified empirically across all four officially-supported SDKs (a
throwaway packed-consumer build/run against `8.0.408`, `9.0.304`,
`10.0.103`, and `11.0.100-preview.7`) both before (`CS9057` +
`CompositionException` on the three stable SDKs) and after (identical,
correct generated output on all four) this fix.

**Consequences.**

- `docs/getting-started/installation.md` now states the `8.0.400` minimum
explicitly, closing the documentation gap the Codex review caught.
- `.github/dependabot.yml` ignores all automated updates to
`Microsoft.CodeAnalysis.CSharp` — this floor is a deliberately
cross-SDK/API-verified decision (both "does it load" and "does it even
compile" constraints), not something that should move via an unattended
bump; this repo's own CI wouldn't catch a regression here, since it
pins the `11.0-preview` SDK.
- Raising this floor in the future (e.g. to use a newer Roslyn API) is a
deliberate decision that should re-run this same empirical verification
before merging, not something to infer is safe from a successful local
build alone (a local build only proves the *compile-time* floor, not
the *runtime-load* floor on every supported SDK — this amendment's own
history is a direct example of that distinction actually mattering).
- This does not change ADR-0003's core decision (single sibling project,
never independently published) — it only completes a previously
explicitly-deferred piece of the same "how does a consumer's host
actually consume this analyzer" question ADR-0003 already opened.
16 changes: 16 additions & 0 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ for all of them with no extra flag. See
[Package Guides](../packages/index.md) for what each package is for and
when to add it.

### Minimum .NET SDK version

Building a `net8.0` project against `Compono` needs **.NET SDK `8.0.400`
or later** — not just any SDK that can target `net8.0`. `Compono`'s
embedded source generator (below) is a Roslyn analyzer, and Roslyn refuses
to load an analyzer built against a newer compiler than the host SDK's own
(silently — a build warning, `CS9057`, not an error — so the generator
just stops running instead of failing loudly). An SDK older than `8.0.400`
(i.e. any `8.0.1xx`/`8.0.2xx`/`8.0.3xx` feature band) bundles a compiler
older than what `Compono` requires and hits exactly that. `net9.0`,
`net10.0`, and `net11.0` have no equivalent minimum beyond "the SDK that
ships that TFM" — every released SDK for those already bundles a new
enough compiler. See
[ADR-0003 Amendment 1](../adr/0003-generator-package-distribution.md) for
the full account.

## No other setup required

`Compono` embeds its source generator as a Roslyn analyzer inside its own
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<!-- Directory.Packages.props' central Microsoft.CodeAnalysis.CSharp pin is deliberately floored
to the .NET 8 SDK's own bundled Roslyn compiler version (4.11.0) so the packaged
Compono.Generators.dll analyzer loads under every officially-supported SDK - see that
file's comment. This project is never packed/shipped, and drives CSharpGeneratorDriver
in-process against LanguageVersion.CSharp14 (net10.0/net11.0 targets, see the
TargetFrameworks comment above), which 4.11.0's LanguageVersion enum doesn't define yet -
overridden back up to the newer version this project actually needs. -->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" VersionOverride="5.9.0" />
<PackageReference Include="Verify.SourceGenerators" />
<PackageReference Include="Verify.XunitV3" />
<!-- Compono.Logging's own generator tests (PLAN-0055 task 14) need
Expand Down
Loading