Skip to content

Phase-1 tenant-partitioned aggregate matrix: exclusive/empty/MartenOps-tenant/DeliveryOptions/AlwaysEnforceConsistency + natural-key (#3021)#3033

Merged
jeremydmiller merged 2 commits into
mainfrom
feat-3021-phase1-battery
Jun 5, 2026
Merged

Phase-1 tenant-partitioned aggregate matrix: exclusive/empty/MartenOps-tenant/DeliveryOptions/AlwaysEnforceConsistency + natural-key (#3021)#3033
jeremydmiller merged 2 commits into
mainfrom
feat-3021-phase1-battery

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Advances #3021 Phase 1 — test-only, no version bump. Extends the single-store Conjoined + Quick + UseTenantPartitionedEvents fixture with the remaining aggregate-handler scenarios that don't need a new harness.

New coverage

tenant_partitioned_aggregate_matrix_phase1b (string identity):

  • Exclusive-write concurrency[AggregateHandler(ConcurrencyStyle.Exclusive)]FetchForExclusiveWriting; appends to the routed tenant, stays isolated.
  • Empty result → no write — handler yields nothing; stream + aggregate unchanged.
  • MartenOps tenant overloadsStore/Insert/Delete(doc, tenantId) land in the targeted tenant's document partition vs default, invoked with no ambient tenant.
  • DeliveryOptions{TenantId} routing → correct partition.
  • AlwaysEnforceConsistency — concurrent write on the same tenant stream → ConcurrencyException.

tenant_partitioned_natural_key_aggregate (Guid stream identity, string natural key — reuses NkOrderAggregate/NkOrderHandler):

  • Same natural-key value in two tenants resolves to the routed tenant's own stream (FetchForWriting<T, TNaturalKey> is tenant-scoped, not cross-tenant).
  • Multi-event return appends to the routed tenant.
  • [WriteAggregate] IEventStream<T> handler completes in the routed tenant and stays isolated.

Findings

Verification

  • Targeted: phase1b 6/6, natural-key 3/3.
  • Full MartenTests suite: 486/486 (one transient tracking flake on a first run did not reproduce on a clean re-run).

Still deferred on #3021 Phase 1

Message-member-bound tenant routing (no first-class core attribute found — needs a design call), the HTTP [Aggregate] matrix (needs an Alba host), IEventStream<T> loader shape (pending #3032), and remaining return shape IEventStream<T> non-aggregate. Phases 2–3 unchanged.

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits June 4, 2026 13:25
…no-write, MartenOps tenant overloads, DeliveryOptions routing, AlwaysEnforceConsistency (#3021)

Test-only. Extends the Conjoined + Quick + UseTenantPartitionedEvents single-store fixture (string
identity) with the remaining single-store aggregate-handler scenarios that persist without
AutoApplyTransactions:

- exclusive-write concurrency ([AggregateHandler(ConcurrencyStyle.Exclusive)] -> FetchForExclusiveWriting)
  appends to the routed tenant and stays isolated
- empty handler result makes no write (stream + aggregate unchanged)
- MartenOps.Store / Insert / Delete tenant overloads land in the targeted tenant's document partition
  vs default, invoked with no ambient tenant
- DeliveryOptions{TenantId} routes the message to that tenant's partition
- AlwaysEnforceConsistency detects a concurrent write on the same (tenant) stream -> ConcurrencyException

The IEventStream<T> handler-parameter return shape is intentionally omitted: a compound handler that
loads an IEventStream<T> via FetchForWriting and appends gets no SaveChanges without
AutoApplyTransactions (silently dropped), unlike [AggregateHandler]/IMartenOp returns. Filed as #3032.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Test-only. Reuses the NkOrderAggregate / NkHandlerOrderNumber / NkOrderHandler types from
natural_key_aggregate_handler_workflow.cs against the partitioned fixture (Guid stream identity,
string natural key). Pins that:

- the same natural-key value in two tenants resolves to the routed tenant's own stream
  (FetchForWriting<T, TNaturalKey> is scoped to the tenant partition, not cross-tenant)
- multi-event returns append to the routed tenant
- the [WriteAggregate] IEventStream<T> handler (CompleteNkOrder) appends to the routed tenant and
  stays isolated -- and persists without AutoApplyTransactions, confirming the aggregate-workflow
  IEventStream path is unaffected by the compound-loader gap (#3032)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 3112b34 into main Jun 5, 2026
24 checks passed
This was referenced Jun 8, 2026
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