Repository navigation
JasperFx 2.59.0
Closes the tenancy-slicing gap opened by 2.58.0, and adds two opt-in compliance suites.
Nothing here changes behavior for a store that does nothing. The fix ships inert — it activates only when a store adopts a new one-line seam — and both new suites are opt-in, so neither runs until a store enrolls it.
Changes
- #726 —
JasperFxSingleStreamProjectionBasenow resolvesForceSingleTenancyitself (#723), plusSingleTenantedEventSlicingCompliance(#724) andCompositeProjectionCompliance(#725).
#723 — the tenancy seam
2.58.0 made ForceSingleTenancy take effect on the async daemon for the first time. Only Marten ever set it, by overriding BuildSlicer; Polecat's and Fisher's SingleStreamProjection<TDoc,TId> are empty class bodies. So 2.58.0 fixed wolverine#2053 / marten#4085 on one store out of three and left the other two carrying a live async-projection correctness bug.
The base now resolves it from a new IEventTenancySource on the session — the only thing BuildSlicer is handed. A session that does not implement it yields false, exactly the previous behavior, so upgrading changes nothing until a store opts in:
public TenancyStyle EventTenancyStyle => Options.Events.TenancyStyle;The member is EventTenancyStyle rather than TenancyStyle on purpose: all three stores already declare a TenancyStyle somewhere in their options graph (Marten on EventGraph, Polecat and Fisher on EventStoreOptions), so the shorter name would bind implicitly on some and not others — silently correct in one store and silently absent in the next, which is the failure mode being ended.
Adopting this is what closes polecat#526 and fisher#139. Once adopted, Marten's own BuildSlicer override is redundant.
New compliance suites, both opt-in
SingleTenantedEventSlicingCompliance (#724) — on a single-tenanted store, events whose tenant_id values disagree must still fold into one aggregate. Drives the async daemon, since that is the only path the bug ever reached. It guards its own precondition: if a store normalizes the stamped tenant ids away on write, the fact skips with a message rather than passing vacuously.
CompositeProjectionCompliance (#725) — composite staging, one-shard identity, and member teardown on rebuild. Needs the new IComplianceStoreRegistrar.AddCompositeProjection seam, because a composite cannot be constructed by a suite: every product keeps its subclass's constructor internal. Implementations are a forward plus a small adapter, roughly three lines. Its rebuild fact is the load-bearing one, and members are additive so a store that replayed over surviving rows instead of tearing them down reads back exactly doubled.
Both are documented in the package README, along with the new seam.