Skip to content

GH-3536: Conjoined EF Core contexts advertise a distinct DbContextUsage descriptor - #3545

Merged
jeremydmiller merged 1 commit into
mainfrom
fix/3536-conjoined-efcore-descriptor
Jul 20, 2026
Merged

GH-3536: Conjoined EF Core contexts advertise a distinct DbContextUsage descriptor#3545
jeremydmiller merged 1 commit into
mainfrom
fix/3536-conjoined-efcore-descriptor

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3536

Residual from the conjoined EF Core multi-tenancy epic (#3465 / #3464 Phase 3). As shipped in 6.21.0 / 6.22.0-alpha.1, a conjoined context looked identical to a plain single-DB context in its DbContextUsage descriptor, so CritterWatch's descriptor-driven UI (JasperFx/CritterWatch#720) had nothing to gate or badge on. Tenant management already lit up (via the IDynamicTenantSource<string> registration), but the UI gating side was blind to conjoined.

Root cause

TenantedDbContextUsageSource<T>'s tenancy-style discriminator switched on the IDbContextBuilder<T> implementation type name and only knew TenantedDbContextBuilderByDbDataSource / TenantedDbContextBuilderByConnectionString; ConjoinedDbContextBuilder<T> fell through to "Single", and its single FindAllAsync() context carried no tenant ids.

Fix

  • Detect ConjoinedDbContextBuilder<T> explicitly and advertise tenancy style "Conjoined".
  • Cardinality: conjoined is one physical database shared by a dynamic tenant list. With one shared-database descriptor and a non-"Single" style, the existing cardinality logic now reports DatabaseCardinality.DynamicMultiple — exactly the shape the Conjoined EF Core multi-tenancy, Phase 3: wolverine_tenants registry + IDynamicTenantSource for CritterWatch #3464 design promised ("DynamicMultiple plus tenant ids on its single DatabaseDescriptor"), without fabricating N per-tenant database entries.
  • Tenant ids: surface the active tenant ids from the wolverine_tenants registry — via the already-registered ConjoinedTenantSource<T> — onto that single shared DatabaseDescriptor.TenantIds. Isolated in its own try/catch so a registry read hiccup degrades to an empty tenant list rather than nulling the whole snapshot (matching the best-effort contract of the surrounding code).

Design note

Per the issue's acceptance criteria ("settle the exact shape with the CritterWatch#720 consumer, since conjoined is one physical database with a dynamic tenant list, which neither existing cardinality models cleanly"), this uses both signals: a "Conjoined" tenancy-style string (unambiguous discriminator) and DynamicMultiple cardinality with the tenant ids on the one shared descriptor. Happy to adjust the exact enum/string if the CritterWatch consumer prefers a different split.

Tests

EfCoreTests.MultiTenancy/ConjoinedTenancy/ConjoinedDescriptorCompliance.cs asserts, for both PostgreSQL and SqlServer:

  • tenancy style is "Conjoined" (not "Single"), cardinality is DynamicMultiple, and there is exactly one shared-database descriptor;
  • tenant ids added through the registry are surfaced on MainDatabase.TenantIds.

All 4 pass locally against the Postgres/SqlServer test containers.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FKAxzuZ36VP6UPcTQf3MUs

…ge descriptor

Residual from the conjoined EF Core multi-tenancy epic (#3465 / #3464 Phase 3):
a conjoined context looked identical to a plain single-DB context in its
DbContextUsage descriptor, so CritterWatch's descriptor-driven UI had nothing to
gate/badge on. The tenancy-style discriminator switched on the IDbContextBuilder
type name and only knew the by-data-source / by-connection-string builders;
ConjoinedDbContextBuilder<T> fell through to "Single".

- Detect ConjoinedDbContextBuilder<T> and advertise tenancy style "Conjoined"
- With one shared-database descriptor + a non-"Single" style, the existing
  cardinality logic now reports DatabaseCardinality.DynamicMultiple, as the
  #3464 design promised
- Surface the active tenant ids from the wolverine_tenants registry (via the
  already-registered ConjoinedTenantSource<T>) onto that single shared
  DatabaseDescriptor.TenantIds. Best-effort: a registry read failure degrades to
  an empty tenant list rather than nulling the whole snapshot

Compliance battery in EfCoreTests.MultiTenancy/ConjoinedTenancy asserts the
"Conjoined" style, DynamicMultiple cardinality, and registry tenant ids on the
descriptor for both PostgreSQL and SqlServer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKAxzuZ36VP6UPcTQf3MUs
@jeremydmiller
jeremydmiller merged commit 530e6f9 into main Jul 20, 2026
55 of 56 checks passed
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.

Conjoined EF Core contexts advertise TenancyStyle "Single" in DbContextUsage descriptors — CritterWatch gating gap

1 participant