Skip to content

Per-tenant-partitioned-events Phase 1: ReadAggregate, append return shapes, WriteAggregate (#3021)#3022

Merged
jeremydmiller merged 1 commit into
mainfrom
feat-3021-phase1-aggregate-matrix
Jun 4, 2026
Merged

Per-tenant-partitioned-events Phase 1: ReadAggregate, append return shapes, WriteAggregate (#3021)#3022
jeremydmiller merged 1 commit into
mainfrom
feat-3021-phase1-aggregate-matrix

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Phase 1 of #3021 — extends the foundational single-store partitioned-events slice (#3020) with the remaining single-store aggregate-handler scenarios. Test-only (no shippable code change; Marten 9.5.2 already on main).

Each is scoped by tenant against a Conjoined + Quick + UseTenantPartitionedEvents store (string identity), reusing TenantTally / PartitionedTenancyHost:

  • [ReadAggregate] reads the routed tenant's partition; Required=false returns null for a tenant with no such stream.
  • Append return shapes — single event, IEnumerable<object>, Events, IAsyncEnumerable<object> — each lands only in the routed tenant's partition (and is invisible to other tenants).
  • [WriteAggregate] (optimistic) appends to the routed tenant and stays isolated.

6 new tests; full AggregateHandlerWorkflow folder green (77, was 71 — clean +6, no discovery collisions).

Findings (folded into the #3021 checklist)

  • MartenOps.StartStream has no tenant overload (only Store/Insert/Update/Delete do) — StartStream uses the ambient session tenant. The issue's StartStream(id, tenantId, events) does not exist.
  • [WriteAggregate] Required=true → 404 is an HTTP-endpoint concept; a message handler does not throw for a missing required aggregate. The Required/404 wrong-tenant-isolation case therefore belongs in the deferred HTTP cluster.

Still deferred (tracked on #3021)

Exclusive concurrency, optimistic version / AlwaysEnforceConsistency, HTTP [Aggregate]/[WriteAggregate]/[ReadAggregate] + tenancy detection, natural-key, cascading-event tenant inheritance, event-as-message, ancillary stores; and all of Phase 2 (multi-node distribution) + Phase 3 (sharded DBs).

🤖 Generated with Claude Code

…hapes, WriteAggregate (#3021)

Extends the foundational single-store partitioned-events slice (#3020) with the remaining
single-store aggregate-handler scenarios, each scoped by tenant against a Conjoined + Quick +
UseTenantPartitionedEvents store (string identity), reusing TenantTally / PartitionedTenancyHost:

- [ReadAggregate] reads the routed tenant's partition; Required=false returns null for a tenant
  with no such stream.
- Every append return shape lands only in the routed tenant's partition: single event,
  IEnumerable<object>, Events, IAsyncEnumerable<object>.
- [WriteAggregate] (optimistic) appends to the routed tenant and stays isolated from other tenants.

Findings (folded into the #3021 checklist):
- MartenOps.StartStream has no tenant overload (only Store/Insert/Update/Delete do) — StartStream
  uses the ambient session tenant. The issue's StartStream(id, tenantId, events) does not exist.
- [WriteAggregate] Required=true -> 404 is an HTTP-endpoint concept; a message handler does not
  throw for a missing required aggregate. The Required/404 wrong-tenant-isolation case therefore
  belongs in the deferred HTTP cluster.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 9704091 into main Jun 4, 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