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
- 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.
- AOT-clean. Polecat's source-generator-first approach already favors AOT; this release closes the remaining gaps and stamps
IsAotCompatible=true where applicable.
- Cold-start friendly. Audit cold-start hot paths; consume
GenericFactoryCache / pre-generated code where Polecat still routes through dynamic instantiation.
- 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 audit — Polecat.AspNetCore + Polecat.EntityFrameworkCore now carry IsAotCompatible=true. All 3 packaged libs flagged. |
#115 |
First dedupe pillar row landed — SqlServerAppLock 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
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.
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
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
IsAotCompatible=truewhere applicable.GenericFactoryCache/ pre-generated code where Polecat still routes through dynamic instantiation.Out of scope for Polecat 4
✅ Major milestones already landed
Polecat is on the
4.0.0-alpha.10line. 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:#106Polecat.AotSmokeconsumer project + CI smoke-test gate#107#109partial; wired AotSmoke to the SG-only path via analyzer-only PackageReference; migrated off the removed inline-lambda API.#110#111#112#114Polecat.AspNetCore+Polecat.EntityFrameworkCorenow carryIsAotCompatible=true. All 3 packaged libs flagged.#115SqlServerAppLockfolded intoWeasel.SqlServer.AdvisoryLock(cross-product consolidation per pillar #214 Rule 2).#116#118IProjectionDistributor/IProjectionSet+ align SingleTenant lock-id with Marten (closes #117). Polecat now consumes the JasperFx.Events 2.0 daemon-coordination contract;PolecatDatabaseimplementsIProjectionDatabase; SingleTenant lock-id formula now bit-for-bit matches Marten's so co-deployed Marten+Polecat on the same SQL Server instance negotiate the samesp_getapplock. Addedprojection_lock_id_tests(3 pin facts).#120*ProjectionDistributor.csconcretes;ProjectionCoordinatornow constructs the liftedJasperFx.Events.Daemonversions (Solo / MultiTenanted / SingleTenant from JasperFx PRs #318/#319/#320) with closures over Polecat state + aWeasel.SqlServer.AdvisoryLockfactory.#121#1234.0.0-alpha.10after #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.
IProjectionDistributor/IProjectionSet/IProjectionDatabaseinterfaces lifted from Polecat intoJasperFx.Events.Daemonand consumed; Polecat-local interface declarations deleted; SingleTenant lock-id aligned with Marten's formula viaProjectionLockIds.Compute.)ProjectionCoordinatorconstructs the liftedJasperFx.Events.Daemonversions (JasperFx PRs #318/#319/#320 — issues #315/#316/#317) with closures + aWeasel.SqlServer.AdvisoryLockfactory.ProjectionBase,IInlineProjection, slicers) from JasperFx.Events 2.0.SliceGroup) from JasperFx.Events 2.0.JasperFx.MultiTenancy.IStorageOperation(and any other database-manipulation primitives) fromWeasel.Core9.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.)AOT (JasperFx/jasperfx#213)
IsAotCompatible=trueonPolecat.csprojonce it builds against JasperFx 2.0 + JasperFx.Events 2.0. (src/Polecat/Polecat.csproj— flag is set, class-level[UnconditionalSuppressMessage]justifications in place onDocumentSessionBase,PolecatCompositeProjection,PolecatProjectionOptions,PolecatLinqQueryProvider.)Polecat.CodeGeneration. Annotate or migrate. (Call-site tightening landed in PR Polecat#46: Tighten reflective surface annotations from class-level to call-site #107 / commit6f1b77c. Remaining class-level suppressions are framework-boundary cases —IServiceCollectionthreading, LinqExtensions markers consumed viaExpression.Call— and stay class-level by design.)Static-mode app passesdotnet publish /p:PublishAot=truewith no warnings. (PR Polecat#46: Add Polecat.AotSmoke consumer project #106 / commitfd6bebc—src/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)
GenericFactoryCache/ source generator equivalents. (Projection-apply path routes through the SG-only dispatch via PR JasperFx#276 Phase 3: Adopt FEC-free projection apply-method dispatch #109 / JasperFx#276; event-store LINQ + projection-batch dispatch hot paths cached via PR Polecat#46 cold-start: cache per-call generic instantiation in event-store LINQ + projection-batch hot paths #121 — sibling to Marten#4308.)JasperFx/CritterStackScalabilityfor side-by-side Polecat 3 vs. Polecat 4 measurement.Foundation bump
JasperFx 2.0+JasperFx.Events 2.0+Weasel.Core 9.0when alphas stabilize. (Directory.Packages.propsvia PR Polecat#119: foundation re-pin + adopt lifted *ProjectionDistributor concretes + cut 4.0.0-alpha.9 #120: JasperFx 2.0.0-alpha.20, JasperFx.Events 2.0.0-alpha.20, JasperFx.Events.SourceGenerator 2.0.0-alpha.9, JasperFx.RuntimeCompiler 5.0.0-alpha.8, Weasel.EntityFrameworkCore / Weasel.SqlServer 9.0.0-alpha.7. ⚠ One Events alpha behind main (alpha.21) — the alpha.21 delta is the DCB boundary-aggregate evolver (JasperFx #324); a convergence re-pin will follow.)net9.0;net10.0; drop any lingeringnet8.0. Addnet11.0when JasperFx does. (Default<TargetFrameworks>net9.0;net10.0</TargetFrameworks>inDirectory.Build.props;Polecat.CodeGenerationcorrectly overrides tonetstandard2.0as a source generator.)4.0.0-alpha.1on all packaged Polecat projects. (Currently on4.0.0-alpha.10— alpha.9 cut in PR Polecat#119: foundation re-pin + adopt lifted *ProjectionDistributor concretes + cut 4.0.0-alpha.9 #120, alpha.10 after Fix two DCB defects: cross-tag-type queries and boundary append to existing stream #123.)Pre-release validation (post-#276 sharp edges)
docs/projection-sg-audit-108.md+ regression harness atsrc/Polecat.Tests/Projections/projection_sg_dispatch_audit_tests.cs(32 rows, ~70ms, no DB).)Existing open issues to land in 4.0
FlatTableProjectioncase sensitivity. (Fixed in PR Fix #45 — FlatTableProjection case-sensitivity on SQL Server #49 — "Fix FlatTableProjection Case sensitivity #45 — FlatTableProjection case-sensitivity on SQL Server", merged 2026-05-11; closed COMPLETED.)Documentation
Cross-product dependencies
Open design questions
Polecat.CodeGenerationsource 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
Linked implementation work