Persist single IMartenOp side-effect returns; bump 6.4.4 (GH-3025)#3029
Merged
Conversation
….4.4 (GH-3025) A handler returning a single IMartenOp (e.g. MartenOps.StartStream / MartenOps.Store) is an ISideEffect — Wolverine generates the Execute() call onto the document session — but MartenOpPolicy only applied Marten transaction support (the SaveChangesAsync postprocessor) for IEnumerable<IMartenOp> returns. So a single op was executed onto the session and then silently dropped unless the app happened to enable AutoApplyTransactions. MartenOpPolicy now applies transaction support for single IMartenOp returns too. ApplyTransactionSupport is idempotent (guards CreateDocumentSessionFrame + DocumentSessionSaveChanges), so this composes with aggregate handlers and AutoApplyTransactions. The single op's Execute stays with the ISideEffect machinery (no foreach frame, so no double-execute). (Surfaced via per-tenant event partitioning, but not partitioning-specific: a test host without AutoApplyTransactions dropped a handler's MartenOps.StartStream entirely; direct session.Events.StartStream persisted. Regression test covers single StartStream + single Store with no AutoApplyTransactions — both fail without the fix.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 8, 2026
Merged
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.
Closes #3025.
Problem
A handler that returns a single
IMartenOp— e.g.MartenOps.StartStream<T>(...)orMartenOps.Store(doc)— silently dropped its work unless the app happened to enablePolicies.AutoApplyTransactions(). No events/documents persisted, no exception. A directsession.Events.StartStream(...)persisted fine.Surfaced via per-tenant event partitioning (
Events.UseTenantPartitionedEvents), but not partitioning-specific — it reproduces on any plain Marten host withoutAutoApplyTransactions.Root cause
A single
IMartenOpreturn is anISideEffect, so Wolverine generates theExecute()call onto the document session — butMartenOpPolicyonly applied Marten transaction support (theSaveChangesAsyncpostprocessor viaMartenPersistenceFrameProvider.ApplyTransactionSupport) forIEnumerable<IMartenOp>returns. So a single op was executed onto the session and then never committed.Fix
MartenOpPolicy.Applynow also detects singleIMartenOpreturns and applies transaction support for them.ApplyTransactionSupportis idempotent (guards onCreateDocumentSessionFrame+DocumentSessionSaveChanges), so this composes cleanly with aggregate handlers and withAutoApplyTransactions. The single op'sExecute()stays with theISideEffectmachinery — noForEachMartenOpFrameis added for singles, so there's no double-execute.Tests
New
single_marten_op_side_effect_persists(MartenTests) — a host withoutAutoApplyTransactionsinvokes a handler returning a singleMartenOps.StartStreamand a singleMartenOps.Store; both assert the data persisted. Both fail without the fix (stream count 0 / document null), pass with it.wolverine.slnxRelease build: 0 warnings, 0 errors.🤖 Generated with Claude Code