Skip to content

Lift IEventStream, session API + daemon contracts to JasperFx.Events …#268

Merged
jeremydmiller merged 1 commit into
mainfrom
claude/sleepy-wilson-b2e793
May 13, 2026
Merged

Lift IEventStream, session API + daemon contracts to JasperFx.Events …#268
jeremydmiller merged 1 commit into
mainfrom
claude/sleepy-wilson-b2e793

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

…for dedupe pillar

Foundation drop for the Marten ↔ Polecat dedupe pillar (#214). Adds the database-agnostic contracts both products will inherit so common event-sourcing logic stops living in two parallel implementations. Purely additive — nothing in Marten or Polecat changes yet.

JasperFx.Events:

  • IEventStream — writable stream handle (where T : notnull)
  • IQueryEventStore — read-side session API (LINQ-returning methods stay product-specific since they return IMartenQueryable / IPolecatQueryable)
  • IEventOperations — write-side basics (Append × 7, StartStream × 16)
  • IEventStoreOperations — combined aggregate-handler workflow (FetchForWriting, WriteToAggregate, AppendOptimistic/Exclusive, FetchLatest, ProjectLatest, OverwriteEvent, AssignTagWhere, tag queries, natural-key fetches)
  • ConcurrencyStyle — was duplicated in both Wolverine integrations

JasperFx.Events.Daemon:

  • IEventFilter — storage-agnostic event-type allowlist
  • IProjectionDatabase — minimal { Identifier; DatabaseUri } seam
  • IDaemonChangeListener — post-batch hook (was Polecat's IChangeListener; renamed to avoid clash with Marten's session-level IChangeListener)
  • IProjectionCoordinator + IProjectionCoordinator — daemon control plane
  • IProjectionDistributor + IProjectionSet + ProjectionLockIds — shard distribution contracts

Updates:

  • StreamState gains the Marten/Polecat-compatible constructors so the existing class is drop-in for both products
  • IEventStream takes where T : notnull (matches Marten's broader shape; Polecat will adapt)

Excluded from this round (follow-ups):

  • StreamCompactingRequest + CompactStreamAsync — execution is product-specific; lift the data class in a separate PR
  • FetchForWritingByTags returning IEventBoundary — blocked on Polecat DCB parity
  • StreamLatestJson — Marten-specific JSON-passthrough optimization
  • ProjectionDistributor abstract base + Solo/SingleTenant/MultiTenanted concretes — designed against real consumption call sites in the Marten 9 PR rather than guessed at the seams here

Companion: docs/dedupe-namespace-table-2026.md is the canonical reference that Marten 9 / Polecat 4 / Wolverine 6 migration guides will link to.

Refs #214 (dedupe pillar), part of #217 (Critter Stack 2026).

…for dedupe pillar

Foundation drop for the Marten ↔ Polecat dedupe pillar (#214). Adds
the database-agnostic contracts both products will inherit so common
event-sourcing logic stops living in two parallel implementations. Purely
additive — nothing in Marten or Polecat changes yet.

JasperFx.Events:
- IEventStream<T> — writable stream handle (where T : notnull)
- IQueryEventStore — read-side session API (LINQ-returning methods stay
  product-specific since they return IMartenQueryable / IPolecatQueryable)
- IEventOperations — write-side basics (Append × 7, StartStream × 16)
- IEventStoreOperations — combined aggregate-handler workflow
  (FetchForWriting, WriteToAggregate, AppendOptimistic/Exclusive, FetchLatest,
  ProjectLatest, OverwriteEvent, AssignTagWhere, tag queries, natural-key
  fetches)
- ConcurrencyStyle — was duplicated in both Wolverine integrations

JasperFx.Events.Daemon:
- IEventFilter — storage-agnostic event-type allowlist
- IProjectionDatabase — minimal { Identifier; DatabaseUri } seam
- IDaemonChangeListener — post-batch hook (was Polecat's IChangeListener;
  renamed to avoid clash with Marten's session-level IChangeListener)
- IProjectionCoordinator + IProjectionCoordinator<T> — daemon control plane
- IProjectionDistributor + IProjectionSet + ProjectionLockIds — shard
  distribution contracts

Updates:
- StreamState gains the Marten/Polecat-compatible constructors so the
  existing class is drop-in for both products
- IEventStream<T> takes where T : notnull (matches Marten's broader shape;
  Polecat will adapt)

Excluded from this round (follow-ups):
- StreamCompactingRequest<T> + CompactStreamAsync<T> — execution is
  product-specific; lift the data class in a separate PR
- FetchForWritingByTags<T> returning IEventBoundary<T> — blocked on Polecat
  DCB parity
- StreamLatestJson<T> — Marten-specific JSON-passthrough optimization
- ProjectionDistributor abstract base + Solo/SingleTenant/MultiTenanted
  concretes — designed against real consumption call sites in the Marten 9
  PR rather than guessed at the seams here

Companion: docs/dedupe-namespace-table-2026.md is the canonical reference
that Marten 9 / Polecat 4 / Wolverine 6 migration guides will link to.

Refs #214 (dedupe pillar), part of #217 (Critter Stack 2026).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 820d8e0 into main May 13, 2026
1 check passed
jeremydmiller added a commit to JasperFx/marten that referenced this pull request May 13, 2026
…ha.6

The contracts lifted in JasperFx/jasperfx#268 are now published as
JasperFx.Events 2.0.0-alpha.6 on NuGet. Restores the standard
PackageReference path; removes the temporary ProjectReference workaround.

- src/Marten/Marten.csproj: ProjectReference → PackageReference.
- Directory.Packages.props: JasperFx.Events 2.0.0-alpha.5 → 2.0.0-alpha.6.

Build: 0 errors, 1180 warnings (all pre-existing AOT analyzer warnings).
Targeted EventSourcingTests on lifted-type files: 4 passed / 4 total
on net9.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit to JasperFx/polecat that referenced this pull request May 13, 2026
…ha.6

The contracts lifted in JasperFx/jasperfx#268 are now published as
JasperFx.Events 2.0.0-alpha.6 on NuGet. Restores the standard
PackageReference path; removes the temporary ProjectReference workaround.

- src/Polecat/Polecat.csproj: ProjectReference → PackageReference.
- Directory.Packages.props: JasperFx.Events 2.0.0-alpha.5 → 2.0.0-alpha.6.

Build still fails (46 errors) — blocked on the gap-fill issues
#88 (Append/StartStream overloads), #89 (LoadAsync), #90 (CompletelyReplaceEvent).
Those need to land first, then this PR rebases and the consumption-internal
issues #91 / #92 get resolved as part of this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit to JasperFx/polecat that referenced this pull request May 13, 2026
Part of Polecat 4 (#46) under the Critter Stack 2026 dedupe pillar
(JasperFx/jasperfx#214). Begins consuming the database-agnostic event-store
contracts that landed in JasperFx/jasperfx#268, so Marten and Polecat stop
maintaining parallel copies of the same surface.

**Status: DRAFT — does not build (46 errors).** Three categories of
Polecat-side gap-fills are required before this PR can go green. Filed
as separate Polecat issues; see the PR body for the dependency map.

Type deletions (force resolution to JasperFx.Events):

- Polecat.Events.IEventStream<T> — public interface removed. Internal
  EventStream<T> now implements JasperFx.Events.IEventStream<T> directly
  and exposes the Cancellation property the canonical contract requires.
- Polecat.Events.StreamState — class removed; file kept as a migration
  breadcrumb pointing at JasperFx.Events.StreamState.

Interface restructuring (Polecat keeps namespace + Polecat-only extras):

- Polecat.Events.IQueryEventStore — now inherits JasperFx.Events.IQueryEventStore;
  keeps QueryRawEventDataOnly<T> + QueryAllRawEvents (return IPolecatQueryable).
- Polecat.Events.IEventOperations — now inherits JasperFx.Events.IEventStoreOperations
  + IQueryEventStore. Keeps Polecat extras: UnArchiveStream, TombstoneStream,
  FetchForWritingByTags<T> (DCB), CompactStreamAsync<T>. Marten's 3-tier
  split (IQueryEventStore + IEventOperations + IEventStoreOperations) is the
  canonical shape per the dedupe pillar — Polecat retains its 2-tier shape
  for now; structural split is a follow-up.

Constraint relaxation:

- `where T : class, new()` → `where T : class` in 3 files (EventOperations,
  QueryEventStore, NaturalKeyFetchPlanner). The new() constraint was
  defensive — no `new T()` call sites exist in Polecat's event-store impls.

Csproj changes (temporary, MUST be reverted before merge):

- src/Polecat/Polecat.csproj: JasperFx.Events PackageReference replaced
  with a ProjectReference to the local JFx.Events worktree. Flip back to
  PackageReference once 2.0.0-alpha.6+ is published.
- Directory.Packages.props: JasperFx 2.0.0-alpha.11 → 2.0.0-alpha.12,
  JasperFx.Events 2.0.0-alpha.4 → 2.0.0-alpha.5.

Refs #46, JasperFx/jasperfx#214, JasperFx/jasperfx#268.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit to JasperFx/polecat that referenced this pull request May 13, 2026
…ha.6

The contracts lifted in JasperFx/jasperfx#268 are now published as
JasperFx.Events 2.0.0-alpha.6 on NuGet. Restores the standard
PackageReference path; removes the temporary ProjectReference workaround.

- src/Polecat/Polecat.csproj: ProjectReference → PackageReference.
- Directory.Packages.props: JasperFx.Events 2.0.0-alpha.5 → 2.0.0-alpha.6.

Build still fails (46 errors) — blocked on the gap-fill issues
#88 (Append/StartStream overloads), #89 (LoadAsync), #90 (CompletelyReplaceEvent).
Those need to land first, then this PR rebases and the consumption-internal
issues #91 / #92 get resolved as part of this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit to JasperFx/polecat that referenced this pull request May 13, 2026
)

* WIP: Consume JFx.Events 2.0 lifted contracts for dedupe pillar

Part of Polecat 4 (#46) under the Critter Stack 2026 dedupe pillar
(JasperFx/jasperfx#214). Begins consuming the database-agnostic event-store
contracts that landed in JasperFx/jasperfx#268, so Marten and Polecat stop
maintaining parallel copies of the same surface.

**Status: DRAFT — does not build (46 errors).** Three categories of
Polecat-side gap-fills are required before this PR can go green. Filed
as separate Polecat issues; see the PR body for the dependency map.

Type deletions (force resolution to JasperFx.Events):

- Polecat.Events.IEventStream<T> — public interface removed. Internal
  EventStream<T> now implements JasperFx.Events.IEventStream<T> directly
  and exposes the Cancellation property the canonical contract requires.
- Polecat.Events.StreamState — class removed; file kept as a migration
  breadcrumb pointing at JasperFx.Events.StreamState.

Interface restructuring (Polecat keeps namespace + Polecat-only extras):

- Polecat.Events.IQueryEventStore — now inherits JasperFx.Events.IQueryEventStore;
  keeps QueryRawEventDataOnly<T> + QueryAllRawEvents (return IPolecatQueryable).
- Polecat.Events.IEventOperations — now inherits JasperFx.Events.IEventStoreOperations
  + IQueryEventStore. Keeps Polecat extras: UnArchiveStream, TombstoneStream,
  FetchForWritingByTags<T> (DCB), CompactStreamAsync<T>. Marten's 3-tier
  split (IQueryEventStore + IEventOperations + IEventStoreOperations) is the
  canonical shape per the dedupe pillar — Polecat retains its 2-tier shape
  for now; structural split is a follow-up.

Constraint relaxation:

- `where T : class, new()` → `where T : class` in 3 files (EventOperations,
  QueryEventStore, NaturalKeyFetchPlanner). The new() constraint was
  defensive — no `new T()` call sites exist in Polecat's event-store impls.

Csproj changes (temporary, MUST be reverted before merge):

- src/Polecat/Polecat.csproj: JasperFx.Events PackageReference replaced
  with a ProjectReference to the local JFx.Events worktree. Flip back to
  PackageReference once 2.0.0-alpha.6+ is published.
- Directory.Packages.props: JasperFx 2.0.0-alpha.11 → 2.0.0-alpha.12,
  JasperFx.Events 2.0.0-alpha.4 → 2.0.0-alpha.5.

Refs #46, JasperFx/jasperfx#214, JasperFx/jasperfx#268.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Switch JFx.Events from ProjectReference to PackageReference 2.0.0-alpha.6

The contracts lifted in JasperFx/jasperfx#268 are now published as
JasperFx.Events 2.0.0-alpha.6 on NuGet. Restores the standard
PackageReference path; removes the temporary ProjectReference workaround.

- src/Polecat/Polecat.csproj: ProjectReference → PackageReference.
- Directory.Packages.props: JasperFx.Events 2.0.0-alpha.5 → 2.0.0-alpha.6.

Build still fails (46 errors) — blocked on the gap-fill issues
#88 (Append/StartStream overloads), #89 (LoadAsync), #90 (CompletelyReplaceEvent).
Those need to land first, then this PR rebases and the consumption-internal
issues #91 / #92 get resolved as part of this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Resolve consumption-PR rebase fallout after #93

Post-rebase fixes that landed cleanly once polecat#93 was merged.

- IDocumentSession.Events / DocumentSessionBase.Events return types
  fully-qualified to Polecat.Events.IEventOperations and IQueryEventStore
  to disambiguate from the JasperFx.Events versions in scope
  (issues #91 / #92 — consumption-PR-internal).

- IQueryEventStore.FetchLatest<T>(Guid|string) kept on Polecat's
  IQueryEventStore so existing query-session call sites
  (theStore.QuerySession().Events.FetchLatest<T>(...)) keep working.
  Marten's canonical position is on IEventStoreOperations (write side)
  only; Polecat retains the read-side convenience.

- Polecat.Events.IEventOperations re-declares FetchLatest<T> with `new`
  to collapse the diamond between Polecat.IQueryEventStore.FetchLatest
  and JasperFx.Events.IEventStoreOperations.FetchLatest. Both inherited
  slots have identical signatures and resolve to the same impl on
  EventOperations; the `new` declaration just keeps the caller-facing
  surface unambiguous.

Build clean: 0 errors. 39/39 event-store-API tests pass
(event_store_api_completeness, fetch_latest, project_latest, start_stream,
append_stream).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pull Bot pushed a commit to TheTechOddBug/marten that referenced this pull request May 14, 2026
Part of Marten 9 (JasperFx#4349) under the Critter Stack 2026 dedupe
pillar (JasperFx/jasperfx#214). Consumes the database-agnostic event-store
contracts that landed in JasperFx/jasperfx#268, so Marten and Polecat stop
maintaining parallel copies of the same surface.

Type deletions (force resolution to JasperFx.Events via existing using
JasperFx.Events; imports):

- Marten.Events.IEventStream<T> — public interface removed; the internal
  marker IEventStream is preserved. Marten's EventStream<T> now implements
  JasperFx.Events.IEventStream<T> directly. Key annotation corrected from
  string to string? to match the underlying StreamAction.Key.
- Marten.Events.StreamState — class removed; the file is kept as a
  migration breadcrumb pointing at JasperFx.Events.StreamState.

Empty-inheriting interfaces (Marten keeps the namespace + Marten-only extras
only; everything else is inherited from the JFx canonical):

- Marten.Events.IQueryEventStore — keeps QueryRawEventDataOnly<T> +
  QueryAllRawEvents (return IMartenQueryable). 131 → 28 lines.
- Marten.Events.IEventOperations — keeps the two CompactStreamAsync<T>
  overloads (depend on Marten's StreamCompactingRequest<T>). 234 → 35 lines.
- Marten.Events.IEventStoreOperations — keeps FetchForWritingByTags<T> (DCB,
  returns Marten.Events.Dcb.IEventBoundary<T>) and the two StreamLatestJson<T>
  overloads (Postgres JSON-passthrough optimization). 485 → 59 lines.
- Marten.Events.Daemon.Coordination.IProjectionCoordinator (+ generic
  variant) — empty inheriting; generic constraint tightened to
  `where T : class, IDocumentStore` so the inherited
  JFx.Events.Daemon.IProjectionCoordinator<T>'s `class` constraint is
  satisfied. 39 → 23 lines.

Disambiguation surgery (where both Marten.Events and JasperFx.Events are
imported and a name collides):

- 3 files: `using StreamState = Marten.Events.StreamState;` →
  `using StreamState = JasperFx.Events.StreamState;`
  (BatchedQuery.Events, IBatchedQuery, StorageFeatures).
- 4 files: added `using JasperFx.Events;` so `IEventStream<T>` resolves
  unambiguously (EventStore.WriteToAggregate, the two FetchInlinedPlan
  partials, StreamStateSelector).
- 2 files: fully-qualified `Marten.Events.IEventStoreOperations` where the
  source intent was the Marten variant — IDocumentOperations.Events return
  type, DocumentStore.EventStore.cs's CompactStreamAsync reflection target.
- 2 files: fully-qualified `Marten.Events.IQueryEventStore` —
  DocumentSessionBase.CreateEventStore override, DocumentStore.EventStoreExplorer.cs
  reflection target.
- 2 files: replaced `using JasperFx.Events.Daemon;` with a selective
  `using DaemonMode = JasperFx.Events.Daemon.DaemonMode;` to keep DaemonMode
  in scope without re-introducing the IProjectionCoordinator ambiguity
  (HostExtensions, AsyncProjectionTestingExtensions).
- 2 files: fully-qualified `Marten.Events.Daemon.Coordination.IProjectionCoordinator`
  in MartenServiceCollectionExtensions for DI registration.
- Generic constraint tightening (13 sites): `where T : IDocumentStore` →
  `where T : class, IDocumentStore` on extension methods and the concrete
  Solo/SingleTenant/MultiTenanted coordinators. The JFx-side
  IProjectionCoordinator<T> has `class` and IDocumentStore being an
  interface doesn't imply class.

Test files (3) updated: same `using JasperFx.Events;` / StreamState alias
patterns.

Csproj changes (temporary, MUST be reverted before merge):

- src/Marten/Marten.csproj: JasperFx.Events PackageReference replaced with
  a ProjectReference to the local JFx.Events worktree. Flip back to
  PackageReference once 2.0.0-alpha.6+ is published.
- Directory.Packages.props: JasperFx 2.0.0-alpha.9 → 2.0.0-alpha.12,
  JasperFx.Events 2.0.0-alpha.3 → 2.0.0-alpha.5 (matches the dependency
  chain pulled in by the JasperFx PR JasperFx#268 contracts).

Verification:

- `dotnet build src/Marten/Marten.csproj` — 0 errors, 1148 warnings (all
  pre-existing AOT analyzer warnings, none introduced by this diff).
- `dotnet build src/EventSourcingTests/EventSourcingTests.csproj` — 0 errors.
- Targeted EventSourcingTests on the lifted-type test files
  (event_storage_stream_state_selector + Bug_2281_stream_action_without_events_save_changes_throws) —
  4 passed / 4 total on net9.0.

What this PR does NOT do (deliberate scope cut):

- No fetch planner / NaturalKey / IProjectionDistributor consumption.
  Those rows in `dedupe-namespace-table-2026.md` are still `🔄 in flight`
  and live in their own follow-up PRs once the call-site design is settled.
- No abstract base class for the projection distributor. JasperFx/jasperfx#268
  shipped only the interfaces (IProjectionDistributor, IProjectionSet,
  ProjectionLockIds); the abstract Solo / SingleTenant / MultiTenanted
  scaffolding is designed against this consumption PR and the parallel
  Polecat distributor work (JasperFx/polecat#83), in a separate PR.
- No `StreamCompactingRequest<T>` lift. The data class stays Marten-side
  for now because its execution body is Marten-specific.

Refs JasperFx#4349 (Marten 9 master plan), JasperFx/jasperfx#214
(dedupe pillar), JasperFx/jasperfx#268 (JFx.Events 2.0 foundation).

Co-Authored-By: Claude Opus 4.7 (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.

1 participant