Skip to content

Marten IDocumentSession scope priming (GH-3001, Marten slice)#3003

Merged
jeremydmiller merged 1 commit into
mainfrom
feat-3001-marten-scope-priming
Jun 1, 2026
Merged

Marten IDocumentSession scope priming (GH-3001, Marten slice)#3003
jeremydmiller merged 1 commit into
mainfrom
feat-3001-marten-scope-priming

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

The next slice of #3001, building on the merged core MessageContext slice (#3002). 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 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 enrolled IDocumentSession right after the scope is created; self-guards (no-op 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 Marten's session options/tenancy).

Core seam change (please review)

The #3001 core slice collected scoping frames from IRequireScopingFrame implementers at DetermineFrames time. That works for sessions added as middleware (AutoApplyTransactions / [Transactional]), but not when a handler takes IDocumentSession directly — SessionVariableSource creates 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 IRequireScopingFrame with a WolverineOptions.ScopingFrameSources registry: 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. IRequireScopingFrame (introduced days ago in #3002, unreleased) is removed.

Verification

  • New MartenTests.service_location_document_session proves one IDocumentSession flows through a service-located object graph (ReferenceEquals).
  • Core 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 Release clean.

Follow-ups (same ScopingFrameSources seam)

Polecat IDocumentSession/IQuerySession; HTTP + gRPC chains; the ancillary-store matrix.

🤖 Generated with Claude Code

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>
@jeremydmiller jeremydmiller merged commit fec065d into main Jun 1, 2026
23 of 24 checks passed
This was referenced Jun 2, 2026
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