Skip to content

Polecat parity port from Wolverine.Marten + Polecat 2.1.0 bump#2598

Merged
jeremydmiller merged 3 commits intomainfrom
polecat-port-from-marten
Apr 27, 2026
Merged

Polecat parity port from Wolverine.Marten + Polecat 2.1.0 bump#2598
jeremydmiller merged 3 commits intomainfrom
polecat-port-from-marten

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Summary

Brings Wolverine.Polecat to parity with several improvements that landed in Wolverine.Marten over the past few weeks. All ports are additive — no existing public surface changes.

Why this port

The Marten side has been the canonical reference and has accumulated several quality-of-life additions that Polecat users would benefit from. Keeping them in lockstep keeps the mental model identical for users switching between or running both.

Implementation notes

  • StoreObjects on Polecat: Polecat 2.1.0's IDocumentOperations does not expose a StoreObjects(IEnumerable<object>) method like Marten does. The port dispatches each document to the generic Store<T>(document) by runtime type using a cached MethodInfo per type. This produces the same end-state semantics as Marten's StoreObjects.
  • TagAggregateOtelFrame: Direct port — uses Activity.Current?.SetTag(...) so it's a no-op when there's no OpenTelemetry consumer subscribed.
  • WriteAggregateAttribute.Modify: Pre-checks ValueSource != ValueSource.InputMember && ArgumentName.IsNotEmpty() and uses tryFindIdentityVariable() (from the base class) before falling back to the existing FindIdentity() logic. Identical to the Marten patch.

Test plan

  • dotnet build src/Persistence/Wolverine.Polecat/Wolverine.Polecat.csproj — clean (0 errors)
  • dotnet build src/Persistence/PolecatTests/PolecatTests.csproj — clean
  • New PolecatOps_store unit tests pass locally (4/4)
  • Integration tests requiring SQL Server 2025 native JSON column type — will run in CI; locally I have a 2022 image and the failures match the pre-existing automatically_adding_stream_id_to_the_audit_members failure (Cannot find data type json) — unrelated to this PR.

🤖 Generated with Claude Code

jeremydmiller and others added 3 commits April 26, 2026 21:05
…cat 1.6.1 → 2.1.0

Brings Wolverine.Polecat to parity with several improvements that landed in
Wolverine.Marten over the past few weeks. All ports preserve existing public
surface — additions only.

## Changes

**Polecat NuGet 1.6.1 → 2.1.0** (Directory.Packages.props)

**Wolverine.Polecat**

- WriteAggregateAttribute.Modify() now respects an explicitly set ValueSource
  (e.g. via FromMethod/FromRoute/FromHeader/FromClaim) when resolving the
  aggregate id, falling back to the existing FindIdentity() logic. Mirrors
  Wolverine.Marten#2451 fix.

- PolecatOps.StoreObjects(...) for storing mixed document types as a single
  side effect. Polecat's IDocumentOperations doesn't expose StoreObjects, so
  the operation dispatches each document by runtime type to the generic
  Store<T>(document) method via cached MethodInfo.

- New IDocumentsOp interface mirroring Marten's IDocumentsOp; DocumentsOp now
  implements it.

- Fluent .With(document) / .With(documents[]) on StoreManyDocs<T> and
  StoreObjects for incremental document accumulation.

- Tenant-scoped StoreObjects(string tenantId, params object[]) overload.

- New Codegen/TagAggregateOtelFrame injected by AggregateHandling.Apply() to
  emit wolverine.stream.id and wolverine.stream.type Activity tags for every
  Polecat aggregate handler workflow. Mirrors Wolverine.Marten#2470 with the
  value-type aggregate id codegen fix from 5.30.0.

**PolecatTests**

- New PolecatOps_store.cs covering StoreMany/.With/StoreObjects/.With +
  tenant-scoped overload + IDocumentsOp surface.

- aggregate_handler_workflow gains generates_wolverine_stream_id_otel_tag and
  generates_wolverine_stream_type_otel_tag codegen assertions.

**Docs**

- docs/guide/durability/polecat/operations.md gains "Storing Multiple
  Documents" and "Tenant-Scoped Operations" sections mirroring the Marten
  operations docs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Polecat 2.0 changed the default JSON storage to use SQL Server 2025's
native `json` column type (StoreOptions.UseNativeJsonType defaults to
true). The previous Azure SQL Edge image only emulates SQL Server 2022,
which fails Polecat schema migrations with:

    Microsoft.Data.SqlClient.SqlException : Column, parameter, or
    variable #6: Cannot find data type json.

This was causing every PolecatTests integration test to fail in CI.

Switch the shared docker-compose sqlserver service to the official
mcr.microsoft.com/mssql/server:2025-latest image (matches Polecat's own
docker-compose recommendation) and add MSSQL_SA_PASSWORD alongside the
legacy SA_PASSWORD env var for forward compatibility. Existing
Wolverine.SqlServer / RDBMS tests continue to work — SQL Server 2025
is backward-compatible at the schema level.

Documents the Apple Silicon caveat in a comment: ARM Mac users may want
to override locally via docker-compose.override.yml + UseNativeJsonType
= false on test fixtures, since SQL Server 2025 under Rosetta can be
flaky on memory-constrained machines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two `generates_wolverine_stream_*_otel_tag` tests on the Polecat port
were failing in CI with `NullReferenceException` from `Shouldly.StringHelpers.Clip`
because `chain.SourceCode` was null — the chain hadn't been compiled yet.
The Marten originals these tests were ported from call
`theHost.GetRuntime().Handlers.HandlerFor<RaiseABC>()` first to trigger
compilation, then `ChainFor<RaiseABC>()` to inspect the resulting chain.
That setup line was dropped during the port.

Restore it. Companion `automatically_adding_stream_id_to_the_audit_members`
test (which was passing) followed the same pattern incidentally because
it accesses `chain.AuditedMembers` which triggers compilation as a side
effect.

The SQL Server image is already on `mssql/server:2025-latest` (commit
1e904ff on this branch), so the native JSON type Polecat 2.x emits is
available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit a59c295 into main Apr 27, 2026
19 of 22 checks passed
jeremydmiller added a commit that referenced this pull request Apr 27, 2026
Release v5.33.0 includes:
- Fix #2602: leader split-brain via stale Postgres advisory lock (#2607)
- Port Polecat 2.x event store integration from Marten (#2598)
- Fix #2571: preserve context fields on scheduled-send wrap/unwrap (#2605)
- Add launchSettings.json to sample projects (#2600)
- gRPC: middleware weaving, validate convention, user exception mapping,
  bidirectional streaming, code-first codegen, new samples (#2565)
- Move non-sticky-handlers guard inside the compile lock (#2556)
- Allow RabbitMQ exchanges to be declared passive (#2574)

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