Skip to content

GH-3365: stop double-registering the primary Polecat IEventStore#3412

Merged
jeremydmiller merged 1 commit into
mainfrom
gh-3365-polecat-eventstore-double-registration
Jul 13, 2026
Merged

GH-3365: stop double-registering the primary Polecat IEventStore#3412
jeremydmiller merged 1 commit into
mainfrom
gh-3365-polecat-eventstore-double-registration

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Root cause (not the one suspected in the issue)

The issue guessed that WolverineOptionsPolecatExtensions.IntegrateWithWolverine() was executing twice — once explicitly, once from an internal integration pass. That is wrong. IntegrateWithWolverine() runs exactly once.

The duplicate comes from Polecat itself. Dumping the IServiceCollection for the reported host shape produces three IEventStore descriptors with these implementation factories:

IEventStore -> Polecat.PolecatServiceCollectionExtensions+<>c.<AddPolecat>b__3_4                    <-- Polecat's own
IEventStore -> Wolverine.Polecat.WolverineOptionsPolecatExtensions+<>c.<IntegrateWithWolverine>b__0_3  <-- ours, redundant
IEventStore -> Wolverine.Polecat.AncillaryWolverineOptionsPolecatExtensions+<>c__0`1[ICritterWatchStore]...

AddPolecat() now registers the store-agnostic JasperFx.Events.IEventStore for the primary DocumentStore on its own — verified against all four AddPolecat overloads (Action<StoreOptions>, string, StoreOptions, Func<IServiceProvider, StoreOptions>) at Polecat 4.8.0, the floor of our package range. Both factories resolve the same IDocumentStore singleton, hence the reference-equal duplicate.

Wolverine's bridge dates to GH-3133 / GH-3219, when AddPolecat genuinely did not register IEventStore. Once Polecat started doing so, the two stacked.

Fix

Delete the redundant primary bridge in WolverineOptionsPolecatExtensions.IntegrateWithWolverine(). This restores parity with Wolverine.Marten, which registers nothing equivalent for its primary store precisely because AddMarten handles it.

TryAddEnumerable is not usable here: it throws when the descriptor's implementation type equals its service type, which is the case for an AddSingleton<IEventStore>(sp => ...) factory registration on both sides.

The ancillary bridge in AncillaryWolverineOptionsPolecatExtensions is untouched and still required — AddPolecatStore<T>() does not register IEventStore for the T store.

Test

New does_not_register_any_event_store_twice in bootstrapping_ancillary_polecat_stores_with_wolverine (primary + ancillary host shape from the issue) asserts reference-distinctness, not just a count: every resolved store is a distinct instance, the primary appears exactly once, each ancillary exactly once. It fails loudly if Polecat ever drops its own registration.

  • Full PolecatTests suite: 241 passed, 4 skipped, 0 failed
  • dotnet build wolverine.slnx -c Release: clean, 0 warnings

Fixes #3365

🤖 Generated with Claude Code

Polecat's own AddPolecat() already registers JasperFx.Events.IEventStore for
the primary DocumentStore -- on every overload, as of the 4.8.0 floor of our
package range. Wolverine's IntegrateWithWolverine() bridged it a second time,
so GetServices<IEventStore>() handed back the same DocumentStore instance
twice and every consumer enumerating the registered stores double-counted the
primary.

Drop the redundant bridge (Wolverine.Marten registers nothing equivalent for
its primary store, for exactly this reason). The ancillary bridge stays --
AddPolecatStore<T>() does NOT register IEventStore for the T store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit 22d05d4 into main Jul 13, 2026
26 checks passed
This was referenced Jul 14, 2026
This was referenced Jul 18, 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.

Polecat primary IEventStore bridge registers twice — GetServices<IEventStore>() yields the same DocumentStore instance two times

1 participant