Skip to content

Fix #4557: deliver the events source generator to consumers + consume JasperFx.Events 2.1.1#4558

Merged
jeremydmiller merged 3 commits into
masterfrom
investigate/4557-sg-dispatcher
May 25, 2026
Merged

Fix #4557: deliver the events source generator to consumers + consume JasperFx.Events 2.1.1#4558
jeremydmiller merged 3 commits into
masterfrom
investigate/4557-sg-dispatcher

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Fixes #4557.

Problem

A user upgrading 8 → 9 with a self-aggregating immutable record snapshot (static Create/Apply, registered via Projections.Snapshot<MyType>(Inline)) hit this at DocumentStore.For(...):

InvalidProjectionException: No source-generated dispatcher found for
SingleStreamProjection<MyType, System.Guid>...

It worked in v8 (runtime codegen). Marten 9 dispatches conventional Apply/Create/ShouldDelete through the compile-time JasperFx.Events.SourceGenerator and has no runtime fallback — but the generator ships as a DevelopmentDependency referenced with PrivateAssets=all, so it never flowed to a consumer that only references the Marten package. The generator simply never ran, so no [GeneratedEvolver] was emitted and the runtime fail-fasted.

Confirmed by adding only the analyzer package to the user's sample (zero code change) → it round-trips.

Fix

  1. Bundle the analyzer in Marten's package (Marten.csproj): a per-TFM TargetsForTfmSpecificContentInPackage hook ships JasperFx.Events.SourceGenerator.dll in analyzers/dotnet/cs, so a plain <PackageReference Include="Marten" /> applies the generator automatically. Validated by packing Marten locally and running the issue's sample unmodified (non-partial record, no analyzer reference) → Snapshot found: True.
  2. Consume JasperFx.Events 2.1.1 (Directory.Packages.props): jasperfx#367 makes the generator emit a self-aggregating evolver for record aggregates from their own declaration (parity with classes — no Snapshot<T> call site, no partial), which also closes the cross-assembly case (aggregate defined in one assembly, registered in another). The bundled analyzer now carries this fix.
  3. Docs (migration-guide.md): removed the incorrect "Marten falls back to runtime evolver lookup" claim; documented that there is no runtime fallback, that the generator ships inside the Marten package, and that self-aggregating Snapshot<T> types do not need to be partial (only projection subclasses do).
  4. Version bumped to 9.0.2.

Tests

  • Bug_4557_self_aggregating_snapshot_without_source_generator documents the runtime fail-fast when the analyzer is absent from the aggregate's assembly (repro types in Marten.Testing.OtherAssembly, a ProjectReference consumer that — by design — can't observe the NuGet bundling; the package fix is validated via packaging).
  • dotnet restore + Release build clean on the 2.1.1 pins; the bundled-analyzer path resolves to jasperfx.events.sourcegenerator/2.1.1.

🤖 Generated with Claude Code

jeremydmiller and others added 3 commits May 24, 2026 18:39
…rator

A self-aggregating immutable record snapshot with static Create/Apply,
registered via Projections.Snapshot<MyType>(Inline), worked in Marten 8
(runtime codegen) but throws at DocumentStore.For(...) in Marten 9:

  InvalidProjectionException: No source-generated dispatcher found for
  SingleStreamProjection<MyType, Guid>...

Root cause: the JasperFx.Events.SourceGenerator analyzer is referenced by
Marten with PrivateAssets=all, so it never flows to a consumer that only
references the Marten package. With no analyzer in the consumer assembly,
Pipeline 3 (Snapshot<T> call-site detection) never emits a [GeneratedEvolver],
and JasperFxAggregationProjectionBase.AssembleAndAssertValidity fail-fasts —
there is no runtime evolver fallback for conventional methods, despite the
migration guide promising one.

Repro types + Snapshot<T> registration live in Marten.Testing.OtherAssembly
(references Marten, no analyzer) to mirror a real consumer. Confirmed: adding
ONLY the analyzer package to the user's sample (no code change) makes it work.

- throws_at_registration: green, pins the current failure
- should_round_trip: skipped, the desired post-fix behavior

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
B — Marten now bundles the JasperFx.Events.SourceGenerator analyzer in its own
NuGet package (analyzers/dotnet/cs) via a per-TFM pack hook. Marten 9 requires a
source-generated evolver for conventional Apply/Create/ShouldDelete projections
(there is no runtime fallback — that was the deliberate goal of the 9.0 projections
rework), but the generator ships as a DevelopmentDependency that does not flow
transitively, so a consumer referencing only the Marten package never ran it and hit
"No source-generated dispatcher found ..." at DocumentStore.For(). Carrying the
analyzer in Marten's package makes a plain `<PackageReference Include="Marten" />`
sufficient. Validated by packing Marten locally and running the issue's reproduction
sample unmodified (non-partial record, no analyzer reference): it now round-trips.

C — Corrected the migration guide, which wrongly promised "Marten falls back to
runtime evolver lookup" for non-partial convention projections. There is no such
fallback; documented that the generator now ships inside the Marten package, that
self-aggregating Snapshot<T> types do NOT need to be `partial` (only projection
subclasses do), and that it must run in the assembly defining the aggregate type.

Test refinement: the reproduction documents the runtime fail-fast when the analyzer
is absent from the aggregate's assembly (ProjectReference consumers can't observe the
NuGet bundling, so the package fix is validated via packaging instead).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- JasperFx.Events + JasperFx.Events.SourceGenerator 2.1.0 -> 2.1.1, which carries
  #367: the source generator now emits a self-aggregating evolver for
  `record` aggregates from their own declaration (parity with classes — no
  Snapshot<T> call site and no `partial` required), fixing the cross-assembly gap.
  Marten bundles this analyzer, so the bundled copy now carries the fix.
- Marten <Version> 9.0.1 -> 9.0.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 7d630d5 into master May 25, 2026
6 checks passed
@jeremydmiller jeremydmiller deleted the investigate/4557-sg-dispatcher branch May 25, 2026 02:15
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.

No source-generated dispatcher found for Marten.Events.Aggregation.SingleStreamProjection<MyType, System.Guid>

1 participant