Skip to content

Fix #432 regression — self-aggregating projection dispatcher dropped (2.9.5)#439

Merged
jeremydmiller merged 1 commit into
mainfrom
fix/432-self-aggregating-dispatcher-regression
Jun 10, 2026
Merged

Fix #432 regression — self-aggregating projection dispatcher dropped (2.9.5)#439
jeremydmiller merged 1 commit into
mainfrom
fix/432-self-aggregating-dispatcher-regression

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Problem

Published 2.9.3 and 2.9.4 break self-aggregating single-stream projections: at runtime they throw

No source-generated dispatcher found for SingleStreamProjection<T, TId>

This regresses a core Marten pattern (e.g. SingleStreamProjection<SimpleAggregate, Guid>) — surfaced when bumping Marten to 2.9.4 (JasperFx/marten#4714); Marten's EventSourcingTests pass on 2.9.2 and fail on 2.9.4.

Root cause

#432 (2.9.3) added a Pipeline-1 dedupe in AggregateEvolverGenerator.ExecuteCombined to avoid emitting the same evolver hintName twice when a type's Apply/Create methods are split across multiple partial declarations (CS8785). The guard reused the cross-pipeline seen set:

if (!seen.Add(SymbolKey(info.ClassSymbol))) continue;
MarkSeen(seen, info);

But MarkSeen seeds seen with the class symbol and (for partial projections) the aggregate type. So a self-aggregating type whose key was already added to seen by an earlier candidate's MarkSeen (e.g. a projection subclass aggregating that same type) had its Pipeline-1 emission falsely skipped — no evolver generated.

Fix

Dedupe Pipeline-1 emissions in a set distinct from seen, keyed by (type, identity) to match the emitted hintName granularity, while still calling MarkSeen for cross-pipeline coordination. Preserves #432's partial-split dedupe; restores emission for self-aggregating types.

Verification

Bumps to 2.9.5. (Recommend yanking/superseding 2.9.3 & 2.9.4 given the regression.)

🤖 Generated with Claude Code

…bump 2.9.5

#432 (2.9.3) added a Pipeline-1 dedupe in AggregateEvolverGenerator.ExecuteCombined
to stop the same evolver hintName being emitted twice when a type's Apply/Create
methods are split across multiple partial declarations (CS8785). The guard —
`if (!seen.Add(SymbolKey(info.ClassSymbol))) continue;` — reused the cross-pipeline
`seen` set, which MarkSeen also seeds with the class symbol AND (for partial
projections) the aggregate type. So a self-aggregating type whose key had already
been added to `seen` by an earlier candidate's MarkSeen (e.g. a projection subclass
aggregating that same type) had its Pipeline-1 emission falsely skipped — no evolver
was generated, surfacing at runtime as
"No source-generated dispatcher found for SingleStreamProjection<T, TId>"
(broke Marten's self-aggregating single-stream projections on 2.9.3/2.9.4).

Dedupe Pipeline-1 emissions in a SET DISTINCT from `seen`, keyed by (type, identity)
to match the emitted hintName granularity, and still call MarkSeen for cross-pipeline
coordination. Preserves #432's partial-split dedupe (its regression test still passes)
while restoring emission for self-aggregating types.

Verified: JasperFx.Events.SourceGenerator.Tests 21/21; Marten EventSourcingTests
Aggregation 228/230 (2 pre-existing skips) and TenantPartitionedEventsTests 186/186
against a local 2.9.5 build (both RED on 2.9.4).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 56d54fe into main Jun 10, 2026
2 checks passed
jeremydmiller added a commit that referenced this pull request Jun 10, 2026
Clean mainline release. Content matches 2.9.5 (the self-aggregating dispatcher
regression fix, #439, was published from its branch); 2.9.6 cuts the same
fix from main so the mainline release stream is current.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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