#4509: document FetchForWriting inline-snapshot no-mutation contract + decider regression test#4512
Merged
jeremydmiller merged 1 commit intoMay 19, 2026
Conversation
…t + decider-pattern regression test #4509 reports that mutating stream.Aggregate from FetchForWriting under an inline snapshot + UseIdentityMapForAggregates=true (the V9 default) makes the persisted snapshot diverge from the AggregateStreamAsync rebuild. This is the same mechanism as #4439 and is by design: the optimization reuses the fetched aggregate as the inline projection's apply baseline, so in-place mutation is unsupported. Resolving as contract/documentation rather than a behavior change: - Cross-reference #4509 in the existing UseIdentityMapForAggregates warnings (command_handler_workflow.md + migration-guide.md), and state explicitly that the snapshot/rebuild divergence is by design — honor the decider pattern or set the flag to false. - Add decider_pattern_snapshot_matches_event_rebuild_4509 pinning the supported path: FetchForWriting -> append events without mutating stream.Aggregate -> persisted snapshot equals AggregateStreamAsync. The failing Wolverine [AggregateHandler] tests are a Wolverine-side fix (the handler should not mutate the aggregate) — filed separately. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This was referenced May 19, 2026
This was referenced May 19, 2026
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.
Addresses #4509.
Resolution: by-design contract + documentation (not a behavior change)
#4509 reports that with
FetchForWriting<T>+ an inline snapshot + the V9 defaultUseIdentityMapForAggregates = true, mutatingstream.Aggregatein place and then appending events makes the persisted snapshot =(mutated aggregate) + (events), which diverges from theAggregateStreamAsyncrebuild.Root cause (same mechanism as #4439):
FetchForWritingcallssession.UseIdentityMapFor<TDoc>()and stashes the fetched aggregate in the identity map. OnSaveChangesAsyncthe inline projection's baseline load (LoadManyAsync) reads that same mutated instance rather than a fresh DB snapshot, then applies the new events on top. The optimization deliberately reuses the fetched aggregate as the apply baseline, so it is only correct under the decider pattern (return events, never mutatestream.Aggregate).Per maintainer decision, resolving as contract/documentation rather than changing the optimization:
UseIdentityMapForAggregateswarnings (command_handler_workflow.md,migration-guide.md) and state explicitly that the snapshot↔rebuild divergence is by design; honor the decider pattern or set the flag tofalse.decider_pattern_snapshot_matches_event_rebuild_4509which pins the supported path:FetchForWriting→ append events without mutatingstream.Aggregate→ persisted snapshot equals theAggregateStreamAsyncrebuild (ACount == 2 == 2).Follow-up (separate repo)
The 4 failing Wolverine
[AggregateHandler]tests are a Wolverine-side fix — those handlers/tests should not mutate the aggregate. Filed as a Wolverine follow-up issue (linked in #4509).Test plan
decider_pattern_snapshot_matches_event_rebuild_4509passes (net10).silently_turns_on_identity_map_for_inline_aggregatesstill passes (net10).markdownlint+cspellclean on both docs.🤖 Generated with Claude Code