Skip to content

Adopt JasperFx 2.39.1 and compliance wave 4 - #5176

Merged
jeremydmiller merged 1 commit into
masterfrom
compliance/wave-4-portable
Aug 4, 2026
Merged

Adopt JasperFx 2.39.1 and compliance wave 4#5176
jeremydmiller merged 1 commit into
masterfrom
compliance/wave-4-portable

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Bumps JasperFx 2.38.0 → 2.39.1 and enrolls the four compliance suites that shipped in it (JasperFx/jasperfx#620).

Suite Tests Issue
fetch_for_writing_compliance 13 #5137
stream_read_compliance 11 #5139
event_metadata_compliance 9 #5143
live_aggregation_compliance 7 #5141

Marten's compliance coverage goes 65 → 105 tests, zero capability gates. The suites were authored against Marten and Polecat working copies simultaneously, so both stores were green before the upstream PR was opened.

Verified locally on net9.0, against the published packages

  • 105/105 compliance
  • 1667/0/7 EventSourcingTests
  • 280/280 DaemonTests

DaemonTests was run deliberately rather than as a formality: 2.39.x carries four daemon-side JasperFx changes (heartbeat removal, extended-progression writer scoping, per-tenant lag reads, EventProjection teardown targets).

The one thing in here that is not routine

The bump carries #618, which stops ShardName discarding the tenant slot for HighWaterMark names. A store-global high-water shard still collapses to the literal "HighWaterMark"; a tenant-scoped one now composes to "HighWaterMark:{tenant}".

That is the grammar Marten already persisted, through HighWaterShardIdentity.StoreGlobal / PerTenant. So the upstream change brought ShardName into line with Marten rather than the other way round, and the runtime needed no change — I checked every ShardState.HighWaterMark construction site in src/Marten to confirm the high-water row name is built from those constants and never from a ShardName ctor.

What did need updating is Bug_4785_delete_projection_progress_by_shard_name, whose assertion encoded the old "the tenant slot is always discarded" behaviour and failed deterministically on the bump. It now pins both halves of the new grammar, and cross-checks them against Marten's own constants so the two definitions cannot drift apart silently. The HighWaterShardIdentity doc comment describing the superseded behaviour is corrected in the same commit.

I want to flag that explicitly rather than bury it: a test assertion changed as part of a dependency bump. It is a stale-premise fix, not a softened assertion — the test is strictly stronger now (two identity shapes pinned instead of one, tied to the product constants) — but it is the kind of change that deserves a second pair of eyes.

Also included

EventSourcingTests.csproj gains the ComplianceSourceDir switch Polecat.Tests already had:

dotnet test src/EventSourcingTests/EventSourcingTests.csproj -f net9.0 \
    -p:ComplianceSourceDir=/path/to/jasperfx/src/JasperFx.Events.ComplianceTests

It swaps the published suites for a jasperfx working copy so a wave can be validated against Marten before the JasperFx release — which is what made same-day two-store verification possible for wave 4. Without the property, nothing changes.

MartenComplianceFixture resolves the new ComplianceStoreConfig.EnableHeaders flag onto Events.MetadataConfig.HeadersEnabled, exactly as it already resolves EnableCorrelationTracking.

Polecat's matching adoption is JasperFx/polecat#410.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde

Bumps JasperFx, JasperFx.Events, JasperFx.Events.ComplianceTests and both
source generators 2.38.0 -> 2.39.1, and enrolls the four new shared suites that
shipped in it (JasperFx/jasperfx#620):

- fetch_for_writing_compliance (13)
- stream_read_compliance (11)
- event_metadata_compliance (9)
- live_aggregation_compliance (7)

Marten's compliance coverage goes from 65 to 105 tests with zero capability
gates.

MartenComplianceFixture resolves the new ComplianceStoreConfig.EnableHeaders
flag onto Events.MetadataConfig.HeadersEnabled, the same way it already
resolves EnableCorrelationTracking.

EventSourcingTests.csproj gains the ComplianceSourceDir switch Polecat.Tests
already had: passing it swaps the published suites for a jasperfx working copy,
so a wave can be validated against Marten before the JasperFx release. Without
it nothing changes.

The bump also carries #618, which stops ShardName discarding the tenant
slot for HighWaterMark names -- a store-global high-water shard still collapses
to "HighWaterMark", but a tenant-scoped one now composes to
"HighWaterMark:{tenant}". That is the grammar Marten already persisted through
HighWaterShardIdentity, so the runtime needed no change; the upstream fix
brought ShardName into line with Marten rather than the other way round.
Bug_4785's assertion encoded the old "tenant slot is always discarded"
behaviour and is updated to pin both halves of the new grammar, and the
HighWaterShardIdentity doc comment that described the superseded behaviour is
corrected.

Verified on net9.0 against the published packages: 105/105 compliance,
1667/0/7 EventSourcingTests, 280/280 DaemonTests.

Closes #5137
Closes #5139
Closes #5141
Closes #5143
Refs #5118

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde
@jeremydmiller
jeremydmiller merged commit e50173c into master Aug 4, 2026
10 checks passed
@jeremydmiller
jeremydmiller deleted the compliance/wave-4-portable branch August 4, 2026 14:05
jeremydmiller added a commit that referenced this pull request Aug 4, 2026
…delete (#5178)

Follow-up to #5176, which updated this test for #618 (ShardName no
longer discards the tenant slot for HighWaterMark names) but left it in a state
worth tidying.

The name was the actual defect: the test was still called
high_water_mark_identity_is_the_literal_constant_and_is_deletable_by_it, while
the whole content of the change was that the identity is NOT always the literal
constant. Anyone grepping for the contract would have been misled.

It was also doing two unrelated jobs that fail for different reasons -- a
JasperFx/Marten contract check on the identity grammar, and the #4785 delete
behaviour. Now split:

- high_water_identity_grammar_agrees_between_shard_name_and_marten (no DB) pins
  that ShardName composition and HighWaterShardIdentity produce the same string.
  Both sides have to agree exactly, because the progression SQL is keyed by
  string equality on name, so drift desyncs writers from readers silently
  rather than failing.
- store_global_high_water_row_is_deletable_by_its_literal_identity keeps the
  original delete assertion.

Plus the coverage gap the bump exposed: per-tenant high-water rows became a
first-class shape and never went through the delete path. The new test uses
tenant ids acme_corp and acmeXcorp, which differ in exactly one character, and
that character is '_' -- a LIKE single-character wildcard in PostgreSQL. If this
delete ever stopped being `where name = ?` and became a pattern match, deleting
one tenant's row would silently take the other's. Verified against PostgreSQL
that the LIKE form does over-match and the equality form does not, so the test
discriminates rather than passing vacuously.

That is not a hypothetical failure mode for this table: #5171 is exactly this
bug in the per-tenant progression READ filter, which builds an unescaped
`name like '%:' || tenant`. The delete path is correct today; this pins it so
the two paths cannot converge on the wrong answer.

Test-only. 26/26 in the file (net9.0).

Refs #4785, #5171


Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit that referenced this pull request Aug 4, 2026
`EnableExtendedProgressionTracking` cost one pooled connection and one transaction per
shard database per node every 5 seconds, on an interval no application could reach — the
field was private on the daemon and no DaemonSettings knob touched it. At 512 tenant
databases that is ~37 connection acquisitions per second per node purely for telemetry,
against rows the progress writer is already updating.

#622 (JasperFx 2.39.0, adopted on master in #5176) turned the periodic beat off by
default and put it behind `DaemonSettings.ExtendedProgressionHeartbeatInterval`, which
Marten already surfaces on `opts.Projections` — so the fix is in the box and nothing here
changes behavior. What was missing on the Marten side is that the change is invisible from
the API surface and easy to regress silently.

Adds the documentation for the cost model and the knob, and three tests pinning both
halves: the default leaves ordinary progress publications unwritten, a configured interval
restores the periodic flush, and status transitions are written either way.


Claude-Session: https://claude.ai/code/session_017CTtw2kVRSZKp1p5RTxgAy

Co-authored-by: Claude Opus 5 (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