Adapter goals
The adapter recovers bounded Marten and Wolverine semantics from authorized source and reports explicit diagnostics whenever source behavior cannot be represented faithfully. This page lists the current goals in full; the overview summarizes the adapter and its boundaries.
- Marten-only event stores, documents, aggregates, projections, and queries.
- Generic and instance-based Marten projection registrations, including
Snapshot<T,TId>andLiveStreamAggregation<T,TId>with lifecycle/configuration arguments. The first type argument is the model; the identity type is not a second model. Authored projection name/version evidence is retained, with explicit diagnostics for unsupported async/live lifecycle semantics. - Async daemon mode and first-class subscription registration/configuration evidence without inventing state views, automations, translations, events, messages, or document consequences from arbitrary processing code.
- Marten document identities from exact configuration, identity attributes, and conventions, without guessing unresolved expressions.
- Authored Marten event/document tenancy declarations, attributes, and global policies retained as located
MARTEN0013diagnostic evidence without inferring effective state, runtime tenant resolution, or database topology. - Authored Marten event aliases, schema-version helpers, naming style, and current upcast registrations retained as
MARTEN0011/MARTEN0012diagnostic evidence without renaming or originating events or inferring upcast behavior. - Marten compiled-query execution linked to proven Wolverine HTTP query entry points, including public plan parameters; unresolved nested executable flow reports
MARTEN0006instead of guessing. - Marten + Wolverine HTTP and message handlers, including signature-stable overloaded handler identities and batched
T[]message delivery. - Returned
IStorageAction<T>/UnitOfWork<T>persistence, exact per-slot storage-factory refinement, and[Entity]/[FirstOrDefault]/[Queryable]bound reads. - Presence diagnostics for Wolverine/Marten convention-alteration hooks, per-chain
Configure(HandlerChain), and Marten session listeners without interpreting policy or listener bodies. - Compound
Load*,Before*,After*,PostProcess*,Finally*, and after-commit stages, with exact outgoing-message consequences retained on the owning entry point and explicitWOLVERINE0020loss. - Literal projection
PublishMessage(new TMessage(...))side effects retained as Message/Publishesevidence.MARTEN0015reports unresolved payload flow (Unknown) or exactWolverine.ISendMyselfpayloads (Unsupported): customApplyAsyncsending is not interpreted, and delivery wrappers are not invented as published domain messages. Built-inTimeoutMessagedescendants retain their existing message evidence. - Event wire configuration (
UseBinarySerializer<T>, append mode, stream identity) andRegisterValueTypeconcept nomination retained without fabricating event or concept representations. - Vogen concepts, primitive representations, authored validation hooks, nullable usages, and explicit loss diagnostics through the separately composed
Cratis.Screenplay.Generation.DotNet.Vogenadapter. - Authored enums used by recovered artifacts emitted as enumeration concepts. Flags enums report
CRITTERSTACK0001rather than pretending a combinable bit field is a closed set of choices. Enums with no values, or with values that collide after Screenplay naming, reportCRITTERSTACK0002; an enum whose concept name is also required by another type (another enum, a Vogen concept or a Marten value type), or is printed for a different type without a concept (a generated, flags or package enum, a record, or a value object without its adapter), reportsCRITTERSTACK0003and only the enum gives way. A field whose type has no emitted concept keeps its plain type name instead of dropping the artifact that uses it. - Current store-agnostic Wolverine event-sourcing APIs and legacy Marten-specific APIs.
- Command-to-event
produceslinks for unconditionalsession.Events.StartStream(id, new TEvent(...))/session.Events.Append(id, new TEvent(...))writes and for events an[AggregateHandler]returns or yields, with the command member that identifies the stream recorded on the link and marked as the command identifier. A conditional write, a stream identity that is not a command property, or an indirect payload keeps the handler reference and reportsWOLVERINE0025naming the command, the event, and the reason. Produced events are placed with their command, and an HTTP endpoint that only forwards its command to a Wolverine handler defers to that handler’s source file. - Source placement that never aborts on a flat feature namespace: when one namespace or folder would hold artifacts of more than one slice kind, each command, aggregate, or read model gets its own slice and
CRITTERSTACK0004explains how to choose the slices through folders, namespaces, or the skip-segments, feature-root, and module options. - Target-aware exact current and legacy
IEventStream<T>appends across multiple handler parameters, including commandless HTTP and metadata-only loaded streams, with per-binding identities and explicit diagnostics instead of first-stream guesses. - Bounded current and legacy Wolverine DCB evidence from authored
[DcbModel]/[BoundaryModel]parameters, directEventTagQueryfluent chains, exact boundary appends, and safe declarative returns, withWOLVERINE0014/WOLVERINE0015instead of invented stream topology. - Bounded authored Wolverine saga discovery for public concrete closed
Wolverine.Sagastate, grouped by message with Wolverine-compatibleSagaChainadmission. It preserves admitted role spellings andAsynctwins, constructor/returned-state creation constraints, collision-safe handler identities, exact correlation precedence (including inherited public members), cascades, timeouts, direct bus calls, and exactMarkCompleted()evidence. Saga state is excluded at every final HTTP query, message, and event admission boundary.WOLVERINE0016is a report-only realization/provenance diagnostic: Wolverine-managed lifecycle is intentionally not lowered because authored source does not safely establish a portable domain workflow. Screenplay uses ordinary Event Modeling building blocks; this is not a language-gap request, and generated.playbytes remain unchanged.WOLVERINE0017reports runtime-resolved correlation, whileWOLVERINE0018reports rejected lifecycle shapes without inventing persistence or transport topology. - Markerless event/message discovery from actual framework usage.
- Deterministic output without starting the application or connecting to PostgreSQL.
- Explicit diagnostics whenever source behavior cannot be represented faithfully.
Declared Wolverine slice patterns
Section titled “Declared Wolverine slice patterns”The exact Wolverine.Persistence.EventSourcing.SlicePatternAttribute constructor accepts JasperFx.Events.EventModeling.SlicePattern. Its mappings are explicit:
| Declaration | Screenplay slice kind |
|---|---|
Command | StateChange |
View | StateView |
Automation | Automation |
Translation | Translate |
Proven HTTP and TimeoutMessage scheduler triggers take precedence (HTTP GET and QUERY are read triggers, and other verbs are state-change triggers except HEAD and OPTIONS, which keep their full effect analysis but prove no slice kind), followed by the method declaration (including overridden-method metadata), the nearest handler-type declaration, and existing inference. Message types and unrelated enclosing types do not supply this metadata. Generated attributes and ignored or undiscovered handlers remain excluded. This does not add gRPC, recurring-schedule, or external-listener discovery.
Classification changes placement only. An automation-classified writer remains a Command with its Reads, Produces, and Appends relationships; a command-classified cascade does not become a persisted event. Produced events receive the same slice kind. Placement explanations preserve exact classification evidence separately from heuristic folder placement. Reaction classification does not add reaction lowering.
| Diagnostic | Boundary |
|---|---|
WOLVERINE0022 | Unresolved constants (Unknown) or undefined enum values (Unsupported); independent inference survives. |
WOLVERINE0023 | Declaration conflicts with a proven trigger (Conflict); the trigger wins. Method-over-type precedence is not a conflict. |
WOLVERINE0024 | An admitted declaration cannot obtain a supported artifact placement (Unsupported); no handler behavior is invented. |
Conflicting classifications from different handlers on shared artifacts still fail closed through the existing DOTNETSP0013, GEN0008, and GEN0007 placement/lowering diagnostics.
Batch-fetched event streams
Section titled “Batch-fetched event streams”The adapter recognizes the Guid and string overloads of JasperFx.Events.IEventStoreOperations.FetchManyForWriting<T>, including calls through the inheriting Marten.Events.IEventStoreOperations. It requires the exact Task<IReadOnlyList<IEventStream<T>>> return shape and a local initialized by awaiting the call, optionally through Task<T>.ConfigureAwait(bool). Optional and named cancellation arguments are supported.
- Inline arrays and collection expressions produce one Reads binding per fixed slot. Constant result indexing, a local initialized directly from an indexed result, and direct appends inside
foreachretain per-slot identities and distinct Appends discriminators. - Runtime ID collections iterated with
foreachproduce quantified Reads/Appends families (IsCollection=true), not an invented stream count. A direct request-member identity is retained asSourceMember. - Produces is emitted once per command/event type even when several slots append that type. Fetches without appends retain reads. Batch IDs are never marked as global command identifiers.
- Statically empty arrays, collection expressions, and
Array.Empty<T>()establish no stream instances. Repeated authored identity expressions remain distinct read evidence but are not proven distinct; append targets are not inferred. The diagnostic states the framework’s duplicate-ID rejection rule without claiming to execute it. Missing streams are not simulated or validated by source analysis. - Reassigned or ref-aliased locals, locals escaping into arbitrary aliases, helper arguments, extension-method receivers, or captured callbacks, fields, helper-returned streams, LINQ pipelines, dynamic indices, runtime-family indexing, and non-append member access are outside the supported target shapes. Unresolved targets or opaque payloads keep independently proven reads but omit unproven append/event consequences.
WOLVERINE0012 locates per-binding loading/version loss at the fetch site and explains unknown runtime cardinality and quantified identity correspondence where applicable. Batch optimistic checks are not one global concurrency rule. WOLVERINE0013 locates each unsupported exact append. WOLVERINE0003 remains reserved for observed version/consistency metadata; this API has no expected-version argument.
Fetched bindings do not alter aggregate-return event classification or an independently established aggregate identifier. A single stream parameter keeps its own identifier, return conventions, and primary state-feature placement even alongside fetched streams: only the fetches receive batch-loading WOLVERINE0012 diagnostics, not a spurious multiple-parameter warning. Multiple stream parameters still receive the parameter-specific loading diagnostic. Direct FetchForWriting invocation analysis and speculative collection-parameter handler injection are not supported.