Marten IDocumentSession scope priming (GH-3001, Marten slice)#3003
Merged
Conversation
Extends the GH-3001 scope-priming to Marten: when a handler falls back to service location, a service-located IDocumentSession / IQuerySession now resolves to the SAME outbox-enrolled session the handler is using, not a separate un-enrolled one (which defeated the transaction boundary). - ScopedDocumentSessionHolder + PrimeScopedDocumentSessionFrame (primes the child scope's holder with the enrolled session, self-guarding when the chain has no Marten session). - IntegrateWithWolverine decorates Marten's own IDocumentSession / IQuerySession scoped registrations to prefer the primed session, capturing and delegating to Marten's original factory for non-handler scopes (preserving session options/tenancy). Core seam change: replaced the IRequireScopingFrame collection (added in the #3001 core slice) with a WolverineOptions.ScopingFrameSources registry. The collection ran at DetermineFrames time and so could not see the Marten session frame, which SessionVariableSource creates lazily during ARRANGEMENT when a handler takes IDocumentSession directly. The registry has integrations contribute a scoping-frame factory; the activator always emits them (each self-guards) regardless of when the target variable is created. The always-on MessageContext priming is unchanged. New MartenTests.service_location_document_session proves one IDocumentSession flows through a service-located object graph (ReferenceEquals). Core service-location tests, F# Core/Marten/Behavioural gates, 90 Marten outbox/saga/transactional tests, and wolverine.slnx all pass. Polecat + HTTP/gRPC remain follow-ups (same ScopingFrameSources seam). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 2, 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.
The next slice of #3001, building on the merged core
MessageContextslice (#3002). When a handler falls back to service location, a service-locatedIDocumentSession/IQuerySessionnow resolves to the same outbox-enrolled session the handler is using — not a separate, un-enrolled session (which silently defeated the transaction boundary, Problem 2 in the issue).How it works
ScopedDocumentSessionHolder(scope-local) +PrimeScopedDocumentSessionFrame— primes the child scope's holder with the handler's enrolledIDocumentSessionright after the scope is created; self-guards (no-op when the chain has no Marten session).IntegrateWithWolverinedecorates Marten's ownIDocumentSession/IQuerySessionscoped registrations to prefer the primed session, capturing and delegating to Marten's original factory for non-handler scopes (preserving Marten's session options/tenancy).Core seam change (please review)
The #3001 core slice collected scoping frames from
IRequireScopingFrameimplementers atDetermineFramestime. That works for sessions added as middleware (AutoApplyTransactions/[Transactional]), but not when a handler takesIDocumentSessiondirectly —SessionVariableSourcecreates that session frame lazily during arrangement, after the collection has run, so the priming frame was never attached (verified by dumping the generated handler: the MessageContext priming line emitted, the session one didn't).So this replaces
IRequireScopingFramewith aWolverineOptions.ScopingFrameSourcesregistry: integrations contribute a scoping-frame factory; the activator always emits them (each self-guards) regardless of when the target variable is created. The always-onMessageContextpriming is unchanged.IRequireScopingFrame(introduced days ago in #3002, unreleased) is removed.Verification
MartenTests.service_location_document_sessionproves oneIDocumentSessionflows through a service-located object graph (ReferenceEquals).service_location_message_context(4) still green; F# Core/Marten/Behavioural gates green; 90 Marten outbox/saga/transactional tests green;dotnet build wolverine.slnx -c Releaseclean.Follow-ups (same
ScopingFrameSourcesseam)Polecat
IDocumentSession/IQuerySession; HTTP + gRPC chains; the ancillary-store matrix.🤖 Generated with Claude Code