Skip to content

[Master] Polecat 4.0 #46

Description

@jeremydmiller

Status: in-flight (foundation + AOT readiness + FEC-free dispatch + dedupe distributor lift (interfaces and concretes, #117/#119) + cold-start hot-path caching (#121) + DCB defect fixes (#123) all complete; remaining: converge to JFx.Events alpha.21 DCB evolver, remaining cross-product dedupe rows, cold-start benchmarks)
Target version: Polecat 4.0
Milestone: 4.0
Part of [Master] Critter Stack 2026 (JasperFx/jasperfx#217).
Pillars: cold-start (JasperFx/jasperfx#212), AOT compliance (JasperFx/jasperfx#213), dedupe Marten ↔ Polecat (JasperFx/jasperfx#214).

Polecat 4 is the EF Core-rooted sibling release in the Critter Stack 2026 wave. Polecat's source-generator-first architecture is unchanged; the work is consolidation with Marten under the dedupe pillar, plus AOT readiness and cold-start improvements.

Polecat 4 ships simultaneously with Marten 9.0 (JasperFx/marten#4349). The dedupe migration is iterative and bidirectional between the two products.

Goals for 4.0

  1. Consume the consolidated infrastructure. Polecat 4 builds against the JasperFx.Events 2.0 / Weasel.Core 9.0 / JasperFx 2.0 trio with no Polecat-side forks of abstractions that satisfy pillar #214's rules.
  2. AOT-clean. Polecat's source-generator-first approach already favors AOT; this release closes the remaining gaps and stamps IsAotCompatible=true where applicable.
  3. Cold-start friendly. Audit cold-start hot paths; consume GenericFactoryCache / pre-generated code where Polecat still routes through dynamic instantiation.
  4. Ship in lockstep with Marten 9.0.

Out of scope for Polecat 4

  • Greenfield Polecat features unrelated to the pillars. Save for 4.x.
  • Merging with Marten (per pillar #214 — separate products, shared infrastructure).

✅ Major milestones already landed

Polecat is on the 4.0.0-alpha.10 line. Foundation bump + AOT readiness + FEC-free projection apply dispatch + extension-package AOT audit + migration guide + dedupe distributor lift (interfaces and concretes) + cold-start hot-path caching all complete:

PR What landed
#106 Polecat.AotSmoke consumer project + CI smoke-test gate
#107 Reflective surface call-site tightening (class-level → call-site annotations)
#109 JasperFx#276 Phase 3 — adopted FEC-free projection apply-method dispatch. Marked ~12 projection classes partial; wired AotSmoke to the SG-only path via analyzer-only PackageReference; migrated off the removed inline-lambda API.
#110 Test-library projection audit (Polecat#108) — 50 types audited (41 generated / 9 deliberate bypass / 0 SG-discovery gaps filed).
#111 Re-pin to JasperFx alpha.16/.15/.8 + Weasel alpha.5 + cut 4.0.0-alpha.6.
#112 Migration guide Polecat 3 → Polecat 4 — foundation pins, SG-only dispatch contract, inline-lambda removal, AOT publishing pointer.
#114 Extension-package AOT auditPolecat.AspNetCore + Polecat.EntityFrameworkCore now carry IsAotCompatible=true. All 3 packaged libs flagged.
#115 First dedupe pillar row landedSqlServerAppLock folded into Weasel.SqlServer.AdvisoryLock (cross-product consolidation per pillar #214 Rule 2).
#116 Foundation re-pin to JasperFx alpha.17/.16/.9 + Marten 9.0-alpha.4 + Weasel 9.0-alpha.6 + cut 4.0.0-alpha.8.
#118 Adopt lifted IProjectionDistributor / IProjectionSet + align SingleTenant lock-id with Marten (closes #117). Polecat now consumes the JasperFx.Events 2.0 daemon-coordination contract; PolecatDatabase implements IProjectionDatabase; SingleTenant lock-id formula now bit-for-bit matches Marten's so co-deployed Marten+Polecat on the same SQL Server instance negotiate the same sp_getapplock. Added projection_lock_id_tests (3 pin facts).
#120 Foundation re-pin + adopt lifted distributor concretes (closes #119). Re-pinned to JasperFx alpha.20 / Events alpha.20 / SG alpha.9 / RC 5.0-alpha.8 + cut 4.0.0-alpha.9. Deleted the three Polecat-local *ProjectionDistributor.cs concretes; ProjectionCoordinator now constructs the lifted JasperFx.Events.Daemon versions (Solo / MultiTenanted / SingleTenant from JasperFx PRs #318/#319/#320) with closures over Polecat state + a Weasel.SqlServer.AdvisoryLock factory.
#121 Cold-start hot-path caching (Polecat#46 cold-start row). Cached per-call generic instantiation in the event-store LINQ provider + projection-batch dispatch hot paths — sibling to Marten#4308. Closes the non-projection-apply side of the cold-start audit.
#123 DCB defect fixes — cross-tag-type queries + boundary append to an existing stream. Polecat side of the cross-store DCB parity story (sibling to Wolverine #2861 DCB parity suite + JasperFx #324 boundary-aggregate evolver).
(cut) Bumped to 4.0.0-alpha.10 after #123.

What remains: converge to JFx.Events alpha.21 (the DCB boundary-aggregate evolver — currently pinned at alpha.20), remaining cross-product dedupe rows (projection lifecycle/sharding, SliceGroup, multi-tenancy strategies, IStorageOperation validation, database enums), cold-start benchmarks in CSS.


What's left

Dedupe Marten ↔ Polecat (JasperFx/jasperfx#214)

Polecat is the validation side of the iterative dedupe migration. The audit deliverable (filed against the pillar) drives row-by-row work; Polecat 4 confirms each consolidated abstraction works for its codebase.

  • Participate in the audit deliverable — identify Polecat-side abstractions that duplicate Marten's. Per Rule 3 (favor Marten), most rows will pull Marten's implementation up; some may be Polecat-side wins worth preserving.
  • Adopt consolidated async daemon abstractions from JasperFx.Events 2.0; remove Polecat-side fork. (PR Polecat: adopt lifted IProjectionDistributor / IProjectionSet + align SingleTenant lock-id with Marten (#117) #118IProjectionDistributor / IProjectionSet / IProjectionDatabase interfaces lifted from Polecat into JasperFx.Events.Daemon and consumed; Polecat-local interface declarations deleted; SingleTenant lock-id aligned with Marten's formula via ProjectionLockIds.Compute.)
  • Adopt lifted distributor concretes — Polecat#119, closed via PR Polecat#119: foundation re-pin + adopt lifted *ProjectionDistributor concretes + cut 4.0.0-alpha.9 #120. Deleted the three Polecat-local concretes; ProjectionCoordinator constructs the lifted JasperFx.Events.Daemon versions (JasperFx PRs #318/#319/#320 — issues #315/#316/#317) with closures + a Weasel.SqlServer.AdvisoryLock factory.
  • Adopt consolidated projection lifecycle / sharding (ProjectionBase, IInlineProjection, slicers) from JasperFx.Events 2.0.
  • Adopt consolidated event grouping / multi-stream slicing (SliceGroup) from JasperFx.Events 2.0.
  • Adopt consolidated multi-tenancy strategies from JasperFx.MultiTenancy.
  • Adopt IStorageOperation (and any other database-manipulation primitives) from Weasel.Core 9.0 once migrated. Validate the Weasel-Core surface works for Polecat's EF Core path. (Marten side landed via Marten PR #4503 — Polecat can validate now.)
  • Database-related enums — pick up the consolidated versions from Weasel.Core (Rule 4 + Rule 2).

AOT (JasperFx/jasperfx#213)

  • IsAotCompatible=true on Polecat.csproj once it builds against JasperFx 2.0 + JasperFx.Events 2.0. (src/Polecat/Polecat.csproj — flag is set, class-level [UnconditionalSuppressMessage] justifications in place on DocumentSessionBase, PolecatCompositeProjection, PolecatProjectionOptions, PolecatLinqQueryProvider.)
  • Audit reflective surfaces that aren't covered by Polecat.CodeGeneration. Annotate or migrate. (Call-site tightening landed in PR Polecat#46: Tighten reflective surface annotations from class-level to call-site #107 / commit 6f1b77c. Remaining class-level suppressions are framework-boundary cases — IServiceCollection threading, LinqExtensions markers consumed via Expression.Call — and stay class-level by design.)
  • AOT smoke test: Polecat in a Static-mode app passes dotnet publish /p:PublishAot=true with no warnings. (PR Polecat#46: Add Polecat.AotSmoke consumer project #106 / commit fd6bebcsrc/Polecat.AotSmoke/. Phase 3 wired the SG-only path through the smoke binary via analyzer-only PackageReference — see PR JasperFx#276 Phase 3: Adopt FEC-free projection apply-method dispatch #109.)

Cold-start (JasperFx/jasperfx#212)

Foundation bump

Pre-release validation (post-#276 sharp edges)

Existing open issues to land in 4.0

Documentation


Cross-product dependencies

Open design questions

  • Source-generator scope: does Polecat 4 widen what its Polecat.CodeGeneration source generator covers (closer to "all the reflection Polecat needs at runtime"), or does it stay at current scope and rely on JasperFx's source generators for the rest?

Explicitly out of scope for Polecat 4

  • Merging Marten and Polecat into one product (per pillar #214 — separate products).
  • Polecat-specific features that aren't pillar-driven. Save for 4.x.

Linked implementation work

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions