Skip to content

Cross-store event sourcing compliance library (#5111, #5112, #5113, #5116) - #5122

Merged
jeremydmiller merged 3 commits into
masterfrom
feat/5110-es-compliance-library
Aug 2, 2026
Merged

Cross-store event sourcing compliance library (#5111, #5112, #5113, #5116)#5122
jeremydmiller merged 3 commits into
masterfrom
feat/5110-es-compliance-library

Conversation

@jeremydmiller

@jeremydmiller jeremydmiller commented Aug 2, 2026

Copy link
Copy Markdown
Member

Phase 3 of the test-harness standardization program (#5119, epic #5110). Closes #5111, #5112, #5113, #5116.

Phases 1–2 (#5098#5107, merged 2026-08-01) standardized Marten's own harnesses. This lifts behavioral event sourcing tests out of Marten's test project entirely and into suites written once against a store-neutral seam, so Marten, Polecat and the planned Sqlite minimal store assert the same behavior instead of hand-mirroring each other's files.

The seam (#5111)

EventStoreComplianceFixture<TOperations, TQuerySession>, mirroring JasperFx's own IEventStore<,> closure — Marten closes it <IDocumentOperations, IQuerySession>, Polecat <IDocumentSession, IQuerySession>, and convergence stays a non-goal. Everything portable flows through the shared JasperFx surfaces; the fixture only absorbs what no shared interface declares: store construction, session acquisition, SaveChangesAsync, document load-back, batched DCB queries, daemon plumbing, teardown.

Marten's side is MartenComplianceFixture (~120 lines) plus a ComplianceQuerySession global alias, and enrolling a suite is a one-line empty subclass.

The suites (#5112, #5113)

Four suites, 42 tests: SelfAggregatingEvolveCompliance, DcbTagQueryAndConsistencyCompliance, AssignTagWhereCompliance, AsyncDaemonCompliance.

Strongest assertion wins where the Marten and Polecat copies had drifted:

  • Inline snapshot cases assert the persisted document through LoadDocumentAsync. The Polecat mirror read back via AggregateStreamAsync, so it would have passed with a broken inline projection.
  • assign_tag_where_by_stream_id keeps Marten's e.StreamId == stream1 assertion rather than Polecat's weakened Data-type check.
  • Adopts two tests Marten never had, both from the Polecat side and both green here on day one: can_query_events_across_distinct_tag_types_with_or (the OR-across-distinct-tag-types INNER JOIN regression guard) and fetch_for_writing_appends_to_existing_tag_derived_stream_without_collision.

That last assertion is not academic — it caught a real Polecat bug on the first run (polecat#392: QueryByTagsAsync never mapped stream_id onto the event envelope, so every DCB tag query returned StreamId == Guid.Empty).

Extraction (#5116)

The seam and suites live in the jasperfx repo and arrive here as the source-only NuGet JasperFx.Events.ComplianceTests (jasperfx#607). Source-only is forced, not preferred: JasperFx.Events.SourceGenerator emits aggregate dispatchers per consuming assembly and binds each product's own session type, so the shared aggregates must compile inside each consumer.

Both Marten.Testing and EventSourcingTests reference the package — the harness assembly compiles MartenComplianceFixture, and the test assembly needs the suites compiled into it for the source generator to bind Marten's session types.

Retirements

self_aggregating_evolve_method.cs and assign_tag_where_tests.cs are gone. dcb_tag_query_and_consistency_tests.cs is reduced to dcb_documentation_samples.cs, which keeps the eleven sample_marten_dcb_* snippet blocks docs/events/dcb.md pulls from plus the tag/event/aggregate types the HStore-specific fixtures share. Doc snippets stay repo-owned deliberately — after extraction the suite sources no longer live in this repo, so mdsnippets could not reach them.

The two upstream additives are not being done

Both were investigated against real usage and written up on their issues:

Verified

EventSourcingTests net9.0: 1613 passed, 0 failed, 7 skipped, identical before and after the switch to the package. Also builds clean on net10.0.

Note

Pinned to the published JasperFx.Events.ComplianceTests 2.37.1 (jasperfx#607, merged and shipped). The rest of the JasperFx packages move to 2.37.1 with it so the dependency graph stays on one line. Re-verified against the published packages, not a local feed.

🤖 Generated with Claude Code

#5113)

Phase 3 of the test harness standardization program (#5119, epic #5110).
Lifts behavioral event sourcing tests out of Marten's own test project and into
suites written once against a store-neutral seam, so Marten, Polecat and the
planned Sqlite minimal store assert the same behavior instead of hand-mirroring
each other's files.

P3.1a -- the seam (src/Marten.Testing/Compliance/, namespace
JasperFx.Events.ComplianceTests so extraction to the source-only package is a
file move):

- EventStoreComplianceFixture<TOperations, TQuerySession> mirroring JasperFx's
  own IEventStore<,> closure. Marten closes it <IDocumentOperations,
  IQuerySession>; Polecat will close it <IDocumentSession, IQuerySession>.
  Everything portable flows through the shared JasperFx surfaces; the fixture
  only absorbs what no shared interface declares -- store construction,
  session acquisition, SaveChangesAsync, document load-back, batched DCB
  queries, daemon plumbing and teardown.
- ComplianceStoreConfig + IComplianceStoreRegistrar: store-neutral config
  replayed through recorded generic closures, so nothing here needs reflection
  or InternalsVisibleTo.
- IComplianceBatch for the batched-DCB accessor divergence
  (batch.Events.EventsExist vs batch.EventsExist) until #5115 lands.
- EventStoreComplianceSuite<TFixture, TOperations, TQuerySession> owning the
  fixture lifecycle, so enrolling a suite is a one-line empty subclass.
- MartenComplianceFixture, Marten's ~120-line implementation.

P3.1b/P3.1c -- four suites (42 tests) and Marten's enrollment:
SelfAggregatingEvolveCompliance, DcbTagQueryAndConsistencyCompliance,
AssignTagWhereCompliance, AsyncDaemonCompliance.

Strongest assertion wins where the Marten and Polecat copies had drifted:

- Inline snapshot cases assert the *persisted* document through
  LoadDocumentAsync. The Polecat mirror read back via AggregateStreamAsync, so
  it would have passed with a broken inline projection.
- assign_tag_where_by_stream_id keeps Marten's e.StreamId == stream1 assertion
  rather than Polecat's weakened Data-type check.
- Adopts two tests Marten never had, both from the Polecat side and both green
  here on day one: can_query_events_across_distinct_tag_types_with_or (the
  OR-across-distinct-tag-types INNER JOIN regression guard) and
  fetch_for_writing_appends_to_existing_tag_derived_stream_without_collision.

Retirements: self_aggregating_evolve_method.cs and assign_tag_where_tests.cs
are gone; dcb_tag_query_and_consistency_tests.cs is reduced to
dcb_documentation_samples.cs, which keeps the eleven sample_marten_dcb_*
snippet blocks docs/events/dcb.md pulls from plus the tag/event/aggregate types
the HStore-specific fixtures share. Doc snippets stay repo-owned deliberately:
after extraction the suite sources no longer live in this repo.

EventSourcingTests net9.0: 1613 passed, 0 failed, 7 skipped.
…5116)

Second half of the extraction: the seam and the four suites now live in the
jasperfx repo and arrive here as a source-only NuGet package, so Marten's copy
under src/Marten.Testing/Compliance is deleted.

What stays Marten-side is exactly what should: MartenComplianceFixture (the
concrete seam implementation), the ComplianceQuerySession global alias binding
the shared aggregates' EvolveAsync parameter to Marten's IQuerySession, and the
empty enrollment subclasses in EventSourcingTests/Compliance.

Both Marten.Testing and EventSourcingTests reference the package, because the
harness assembly compiles MartenComplianceFixture and the test assembly needs
the suites compiled in it for the aggregate source generator to bind Marten's
session types.

Pinned to a locally packed 2.37.0-compliance.2 for now; this moves to the
published version when the package ships.

EventSourcingTests net9.0 compliance suites: 42 passed, 0 failed.
JasperFx.Events.ComplianceTests shipped in the 2.37.1 line (#607), so
the local prerelease pin used during development is replaced by the real
version, and the rest of the JasperFx packages move with it to keep the
dependency graph on one line.

EventSourcingTests net9.0 against the published packages: 1613 passed, 0 failed,
7 skipped.
@jeremydmiller
jeremydmiller merged commit 4cfe6c5 into master Aug 2, 2026
10 checks passed
@jeremydmiller
jeremydmiller deleted the feat/5110-es-compliance-library branch August 2, 2026 15:29
jeremydmiller added a commit that referenced this pull request Aug 2, 2026
…5118) (#5123)

Part of #5110 / program #5119. Moves four Marten test files onto the shared
JasperFx.Events.ComplianceTests suites (2.37.2) and deletes them here, the same
trade #5122 made for the first four.

Retired, and what replaced each:

- Aggregation/auto_discover_aggregate_types.cs -> AutoDiscoveredAggregateCompliance
- Projections/event_projection_should_register_document_types.cs ->
  EventProjectionRegistrationCompliance
- Projections/event_projection_enrichment_tests.cs ->
  EventProjectionEnrichmentCompliance
- rebuild_concurrency_cap_resolution.cs -> RebuildConcurrencyCapCompliance

Coverage went up, not down. Marten's registration test only asserted that
AuditRecord reached AllKnownDocumentTypes(); Polecat's only asserted
PublishedTypes(). The shared suite asserts both routes and adds an end-to-end
append proving the store really provisioned storage for a document type nobody
registered — the actual point of #4166.

MartenComplianceFixture picks up the seam members the new suites need:
StoreDocument, EventStore, AllAggregateTypes, an AddProjection registrar member,
and connection-string/DaemonSettings handling for the rebuild-cap knobs. The
harness alias file gains ComplianceOperations and ComplianceEventProjection
beside the existing ComplianceQuerySession, because the EventProjection suites
declare projection types at file scope and cannot reach the suite's generics.

EventSourcingTests net9.0: 1614/0/7 (was 1613/0/7 — twelve local tests out,
thirteen compliance tests in). Compliance namespace alone: 55/55, no capability
gates.

Blocked on the JasperFx 2.37.2 publish (jasperfx PR). Verified locally against a
packed prerelease of the same sources.


Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Compliance seam: EventStoreComplianceFixture<TOperations, TQuerySession> in Marten.Testing (P3.1a)

1 participant