Skip to content

saas-EPIC-ENT — Entitlements gap backlog

Epic ID: saas-EPIC-ENT
Repository: ConnectSoft.Saas.EntitlementsTemplate
Aggregate root: Entitlement
Status: Not Started
Evidence: saas-gap-deep-analysis.md §4.3
Last verified: 2026-05-27
Master backlog: saas-gap-implementation-backlog.md (when authored)

Epic summary

Closes wave-1 gaps in the Entitlements bounded context: EffectiveEntitlementDescriptor materialization (or ADR deferral), suspend/decommission lifecycle commands, catalog retirement policy completion, catalog integrity on assign, saga and processor test coverage, architecture test placeholders, Orleans write-path wiring, and ProductsCatalog.MessagingModel NuGet pin policy.

Order Feature ID Title
[030] saas-ENT-F01 EffectiveEntitlementDescriptor VO + materialization on assign / override / activate (OR demote-to-summary ADR)
[031] saas-ENT-F02 Suspend + Decommission lifecycle commands end-to-end
[032] saas-ENT-F03 Catalog retirement policy completion: per-row assignment-changed events, optional entitlement suspend
[033] saas-ENT-F04 Catalog integrity validation on assign (existence check via ServiceModel or saga)
[034] saas-ENT-F05 Saga behavioral test suite + DefaultEntitlementsProcessor unit tests
[035] saas-ENT-F06 Replace placeholder architecture tests
[036] saas-ENT-F07 Wire writes through EntitlementEditorGrain
[037] saas-ENT-F08 ProductsCatalog.MessagingModel pin bump to documented version

[030] saas-ENT-F01 — EffectiveEntitlementDescriptor VO + materialization (OR demote-to-summary ADR)

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 030
Status: Not Started
Evidence: Gap analysis entity model — EffectiveEntitlementDescriptor Missing; finding E-001
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, domain, P1, adr
Priority: P1
Effort: L
Dependencies:
Blocks: saas-ENT-F04 (partial — integrity may use descriptor shape)
Source gap analysis: §4.3 Entitlements — Entity model, §5 ADR-ENT-001, finding E-001

Description (full):

The canonical DDD blueprint (saas-platform-ddd-entities.md) defines EffectiveEntitlementDescriptor as a value object capturing the resolved feature matrix, edition reference, and effective window after assign, override, and activate operations. Wave-1 Entitlements implements IEntitlement, assignments, overrides, and status transitions in DefaultEntitlementsProcessor, but does not materialize or persist an EffectiveEntitlementDescriptor — consumers infer effective state from assignment rows only.

Strategic decision ADR-ENT-001 requires either (A) materialize the VO on assign/override/activate (persisted column or JSON blob, exposed on query API), or (B) accept summary-only representation with a formal ADR demoting the VO to documentation-only for this wave. Finding E-001 tracks this gap.

Acceptance criteria (testable):

  • AC-1: ADR-ENT-001 authored with Accepted status documenting option (A) or (B).
  • AC-2: If option (A): EffectiveEntitlementDescriptor type exists in DomainModel/EntityModel; populated in processor on assign/override/activate; included in EntitlementResponse query DTO; migration adds storage if persisted.
  • AC-3: If option (B): ADR explains summary-only approach; Feature marked Deferred for VO materialization; query API documents how consumers compute effective state.
  • AC-4: Unit tests verify descriptor content matches assignment + override rules for at least one golden scenario.

Implementation notes (full):

  • Files: DefaultEntitlementsProcessor.cs, IEntitlement.cs / entity mappings, EntitlementResponse.cs, NHibernate mappings, docs/domain/entitlement-aggregate.md.
  • ADR path: docs/adr/0005-effective-entitlement-descriptor.md (number TBD).
  • Cross-check JSON descriptor ConnectSoft.Saas.Entitlements.json.

Out of scope:

  • Billing rating logic.
  • Real-time catalog sync (F03/F04).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[030] saas-ENT-S01.1 — Decide and implement EffectiveEntitlementDescriptor strategy

Type: User Story
Parent: saas-ENT-F01
Implementation order: 030
Status: Not Started
Evidence: Finding E-001; no EffectiveEntitlementDescriptor symbol in Entitlements codebase
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, domain, adr
Priority: P1
Effort: M
Dependencies:
Blocks: saas-ENT-T01.1.1, saas-ENT-T01.1.2
Source gap analysis: ADR-ENT-001, finding E-001

Description (full):

As an Entitlements domain owner, I need a clear, tested representation of effective entitlement state after mutations so downstream Billing and Metering can trust query responses and integration events without re-implementing override resolution rules.

Run ADR-ENT-001 decision process. If materializing, implement VO builder in processor private method invoked from AssignEditionAsync, OverrideFeatureAsync, and ActivateAsync.

Acceptance criteria (testable):

  • AC-1: ADR merged before implementation tasks complete.
  • AC-2: Golden test: assign edition + override feature → descriptor (or documented summary) reflects override precedence.
  • AC-3: docs/domain/entitlement-aggregate.md updated with effective-state narrative.

Implementation notes (full):

  • Align with catalog feature keys from Products Catalog MessagingModel / ServiceModel refs.

Out of scope:

  • Event payload changes unless ADR mandates descriptor on EntitlementsChangedEvent.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[030] saas-ENT-T01.1.1 — Author ADR-ENT-001 (materialize vs summary-only)

Type: Task
Parent: saas-ENT-S01.1
Implementation order: 030
Status: Not Started
Evidence: Pending decision in gap analysis decision log
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, adr
Priority: P1
Effort: S
Dependencies:
Blocks: saas-ENT-T01.1.2
Source gap analysis: §5 Decision log

Description (full):

Draft ADR-ENT-001 comparing materialized VO (storage cost, query simplicity) vs summary-only (assignment rows as source of truth). Cite saas-platform-ddd-entities.md and wave-1 E2E demo needs.

Acceptance criteria (testable):

  • AC-1: ADR file in docs/adr/ with Accepted status after review.
  • AC-2: Consequences section lists impact on ServiceModel DTOs and migrations.
  • AC-3: Linked from gap analysis traceability matrix comment in PR.

Implementation notes (full):

  • Follow existing ADR front-matter in Entitlements repo.

Out of scope:

  • Code changes.

Definition of done:

  • All AC pass
  • Docs updated
  • Status updated in master + mirrors

[030] saas-ENT-T01.1.2 — Implement EffectiveEntitlementDescriptor materialization (if ADR option A)

Type: Task
Parent: saas-ENT-S01.1
Implementation order: 030
Status: Not Started
Evidence: N/A until ADR decision
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, domain
Priority: P1
Effort: L
Dependencies: saas-ENT-T01.1.1 (option A only)
Blocks:
Source gap analysis: Finding E-001

Description (full):

If ADR option (A), add VO type, NHibernate mapping (owned component or JSON column), builder logic in processor, query projection on GetEntitlementById, and unit tests.

Acceptance criteria (testable):

  • AC-1: After assign + override, persisted entitlement row includes descriptor snapshot matching test expectations.
  • AC-2: Query API returns descriptor fields on EntitlementResponse.
  • AC-3: Migration applies cleanly on SQL Server and SQLite test dialects.

Implementation notes (full):

  • DefaultEntitlementsProcessor.cs, EntityModel, DatabaseModel.Migrations.

Out of scope:

  • Executing if ADR option (B) — mark Cancelled/Deferred.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[031] saas-ENT-F02 — Suspend + Decommission lifecycle commands end-to-end

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 031
Status: Not Started
Evidence: EntitlementStatusEnumeration includes Suspended/Decommissioned; no SuspendAsync/DecommissionAsync in ServiceModel; finding E-002
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, lifecycle, P1
Priority: P1
Effort: M
Dependencies:
Blocks: saas-ENT-F03 (optional suspend on catalog retirement)
Source gap analysis: §4.3 Entity model — Suspend/Decommission Partial, finding E-002

Description (full):

Processor transition table in DefaultEntitlementsProcessor defines valid paths to Suspended and Decommissioned, but public ServiceModel operations (IEntitlementManagementService), REST/gRPC adapters, and actor interface do not expose SuspendEntitlement or DecommissionEntitlement commands. E2E tenant/offboarding flows and Billing quota reactions expect entitlement suspension semantics.

This Feature adds domain inputs, processor methods, ServiceModel contracts, REST/gRPC endpoints, integration events (if not already defined), metrics, and tests for suspend and decommission — mirroring patterns from ActivateAsync and CreateDraftAsync.

Acceptance criteria (testable):

  • AC-1: SuspendEntitlementAsync and DecommissionEntitlementAsync exposed on REST and gRPC; OpenAPI documented.
  • AC-2: Invalid transitions return validation fault (e.g., decommission → active rejected).
  • AC-3: Outbound integration events published on canonical topics with aggregate version increment.
  • AC-4: Acceptance or unit tests cover happy path and invalid transition for both commands.
  • AC-5: JSON descriptor ConnectSoft.Saas.Entitlements.json lists new operations and events.

Implementation notes (full):

  • Files: IEntitlementManagementService.cs, EntitlementsController.cs, GrpcEntitlementManagementService.cs, DefaultEntitlementsProcessor.cs, IEntitlementEditorActor / grain if F07 complete.
  • Symbols: EntitlementStatusEnumeration.Suspended, Decommissioned.
  • Events: check EntitlementsConstants.EventTopics for suspend/decommission topics or add per published language.

Out of scope:

  • Automatic suspend on quota (Billing saas-BIL-F06).
  • Catalog-driven suspend policy (F03).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated (rest-api.md, grpc-api.md, reference/events.md)
  • Status updated in master + mirrors

[031] saas-ENT-S02.1 — Expose suspend and decommission commands on ServiceModel

Type: User Story
Parent: saas-ENT-F02
Implementation order: 031
Status: Not Started
Evidence: Grep — no SuspendAsync/DecommissionAsync in ServiceModel layer
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, lifecycle
Priority: P1
Effort: M
Dependencies:
Blocks: saas-ENT-T02.1.1, saas-ENT-T02.1.2
Source gap analysis: Finding E-002

Description (full):

As an API consumer, I need explicit suspend and decommission operations so I can orchestrate entitlement lifecycle without direct database access or undocumented processor hooks.

Acceptance criteria (testable):

  • AC-1: REST POST/PATCH endpoints invoke processor suspend/decommission with tenant scoping.
  • AC-2: gRPC client can suspend then decommission same entitlement in sequence.
  • AC-3: Metrics counters increment on success/failure (EntitlementsMetrics pattern).

Implementation notes (full):

  • Request DTOs: SuspendEntitlementRequest, DecommissionEntitlementRequest with entitlement id + tenant id.

Out of scope:

  • Bulk suspend by tenant.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[031] saas-ENT-T02.1.1 — Implement processor suspend/decommission with events

Type: Task
Parent: saas-ENT-S02.1
Implementation order: 031
Status: Not Started
Evidence: DefaultEntitlementsProcessor.cs transition dictionary includes Suspended/Decommissioned
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, domain
Priority: P1
Effort: M
Dependencies:
Blocks:
Source gap analysis: Finding E-002

Description (full):

Add SuspendAsync and DecommissionAsync to IEntitlementsProcessor and DefaultEntitlementsProcessor with transition guards, NHibernate persistence, and IEventBus publish.

Acceptance criteria (testable):

  • AC-1: Unit tests for valid and invalid transitions.
  • AC-2: Events include TenantId, entitlement id, AggregateVersion, OccurredOn.
  • AC-3: Decommission is terminal (no further transitions).

Implementation notes (full):

  • Domain inputs: SuspendEntitlementInput, DecommissionEntitlementInput.
  • MessagingModel event types if missing.

Out of scope:

  • REST/gRPC wiring (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[031] saas-ENT-T02.1.2 — Wire REST/gRPC adapters and update API documentation

Type: Task
Parent: saas-ENT-S02.1
Implementation order: 031
Status: Not Started
Evidence: IEntitlementManagementService.cs — no suspend/decommission operations
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, rest, grpc
Priority: P1
Effort: S
Dependencies: saas-ENT-T02.1.1
Blocks:
Source gap analysis: Finding E-002

Description (full):

Extend ServiceModel interface, REST controller, gRPC service, AutoMapper profiles, Swagger metadata, and API docs for suspend/decommission.

Acceptance criteria (testable):

  • AC-1: OpenAPI spec includes new operations; Swashbuckle build clean.
  • AC-2: Sample entitlements acceptance scenario exercises suspend path.
  • AC-3: ServiceModel NuGet pack succeeds with SemVer minor bump.

Implementation notes (full):

  • Mirror ActivateAsync adapter structure.

Out of scope:

  • Grain routing (F07).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[032] saas-ENT-F03 — Catalog retirement policy completion (per-row assignment-changed, optional suspend)

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 032
Status: Not Started
Evidence: ProductCatalogReactionStateMachine.cs handles ProductRetired; per-row assignment-changed Partial in gap analysis
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, messaging, catalog, P1
Priority: P1
Effort: L
Dependencies: saas-ENT-F02 (optional suspend), saas-ENT-F08 (catalog event types)
Blocks:
Source gap analysis: §4.3 Messaging

Description (full):

Entitlements reacts to Products Catalog retirement via ProductCatalogReactionStateMachine consuming ProductRetiredEvent from ConnectSoft.Saas.ProductsCatalog.MessagingModel. Wave-1 implements aggregate-level reaction but gap analysis marks Partial for per-row assignment-changed events when catalog editions/products retire, and optional automatic entitlement suspend when catalog policy requires it.

This Feature completes retirement policy: enumerate affected assignments, emit per-assignment integration events (canonical topic per published language), optionally invoke suspend/decommission per ADR-0003 saga policy, and ensure idempotent saga handling with (sourceContext, eventId) dedupe alignment (saas-INTEG-F04).

Acceptance criteria (testable):

  • AC-1: Given ProductRetiredEvent with edition ids, when saga processes, then one assignment-changed (or equivalent) event per affected assignment row is published.
  • AC-2: Saga replay with same eventId does not duplicate side effects (idempotent).
  • AC-3: If policy ADR specifies auto-suspend, affected active entitlements transition to Suspended with audit trail.
  • AC-4: Behavioral saga test in FlowModel.MassTransit test harness passes.
  • AC-5: docs/messaging.md and ADR-0003 updated with retirement semantics.

Implementation notes (full):

  • Files: ProductCatalogReactionStateMachine.cs, DefaultEntitlementsProcessor.cs reaction method, MessagingModel outbound events.
  • Coordinate with Catalog RetireProduct event payload fields.
  • Depends on F02 if auto-suspend implemented.

Out of scope:

  • Catalog-side retirement (ProductsCatalog repo).
  • ProductCreated/Updated consumers (topology without consumers — separate backlog if needed).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[032] saas-ENT-S03.1 — Complete ProductRetired saga with per-assignment event fan-out

Type: User Story
Parent: saas-ENT-F03
Implementation order: 032
Status: Not Started
Evidence: ProductCatalogReactionStateMachine.cs — single reaction path
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, saga
Priority: P1
Effort: M
Dependencies: saas-ENT-F02, saas-ENT-F08
Blocks: saas-ENT-T03.1.1, saas-ENT-T03.1.2
Source gap analysis: §4.3 Messaging

Description (full):

As a downstream Billing operator, I need granular assignment-changed signals when catalog products retire so subscriptions and meters reconcile per assignment row, not only at aggregate summary level.

Acceptance criteria (testable):

  • AC-1: Test fixture with two assignments on retired product emits two outbound events.
  • AC-2: Assignments marked inactive/retired in database per policy.
  • AC-3: Saga completes and reaches final state in MassTransit test harness.

Implementation notes (full):

  • Extend processor method invoked from saga ReactToCatalogProductRetiredAsync.

Out of scope:

  • Billing consumer changes.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[032] saas-ENT-T03.1.1 — Implement per-row assignment-changed publish in retirement reaction

Type: Task
Parent: saas-ENT-S03.1
Implementation order: 032
Status: Not Started
Evidence: Partial per-row assignment-changed in gap analysis
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, messaging
Priority: P1
Effort: M
Dependencies: saas-ENT-F08
Blocks:
Source gap analysis: §4.3 Messaging

Description (full):

Update processor/saga collaboration to loop assignments affected by retired product/edition, update row state, publish assignment-changed integration event per row with correct aggregate version.

Acceptance criteria (testable):

  • AC-1: Unit test on processor with mocked bus verifies N publishes for N rows.
  • AC-2: Event topic matches EntitlementsConstants.EventTopics.
  • AC-3: No publish when zero assignments affected (no-op completion).

Implementation notes (full):

  • Query assignments by catalog product/edition ref (external ids per ADR-0002).

Out of scope:

  • Optional suspend (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[032] saas-ENT-T03.1.2 — Add optional auto-suspend policy and saga idempotency tests

Type: Task
Parent: saas-ENT-S03.1
Implementation order: 032
Status: Not Started
Evidence: ProductCatalogReactionStateMachine.cs — idempotency not fully tested
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, saga, tests
Priority: P1
Effort: M
Dependencies: saas-ENT-T03.1.1, saas-ENT-F02
Blocks:
Source gap analysis: §4.3 Messaging

Description (full):

If product policy requires, call suspend on parent entitlement when all assignments retired. Add saga test proving duplicate ProductRetiredEvent delivery does not double-publish or double-suspend. Document policy flag in appsettings or ADR-0003 amendment.

Acceptance criteria (testable):

  • AC-1: Saga behavioral test passes for duplicate delivery scenario.
  • AC-2: Auto-suspend configurable default off; when on, integration test demonstrates Suspended status.
  • AC-3: Aligns with saas-INTEG-F04 dedupe key pattern (sourceContext, eventId).

Implementation notes (full):

  • MassTransit test harness in FlowModel.MassTransit test project or ArchitectureTests.

Out of scope:

  • Redis dedupe infrastructure (INTEG epic).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[033] saas-ENT-F04 — Catalog integrity validation on assign

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 033
Status: Not Started
Evidence: Gap analysis ServiceModel — catalog integrity on assign Missing; AssignEditionAsync has no existence check
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, catalog, P1
Priority: P1
Effort: M
Dependencies: saas-CAT-F06 (query ops helpful), saas-ENT-F08
Blocks:
Source gap analysis: §4.3 ServiceModel

Description (full):

AssignEditionAsync accepts catalog product/edition identifiers without verifying they exist in Products Catalog. This allows orphan assignments that break E2E demos and violate anti-corruption expectations. ADR-0002 documents external catalog identifiers; integrity validation should use ServiceModel gRPC/REST client to Products Catalog (IProductQueryService) or a defensive saga pattern — prefer synchronous ACL check in processor for fail-fast API behavior.

Acceptance criteria (testable):

  • AC-1: Assign to non-existent edition returns ResourceNotFoundFault (or validation fault) without persisting assignment.
  • AC-2: Assign to retired/decommissioned catalog product/edition rejected with explicit fault message.
  • AC-3: Successful assign still works against seeded sample catalog in acceptance tests.
  • AC-4: Catalog client registered in DI with configurable base URL; health/degraded behavior documented when catalog unavailable.
  • AC-5: Unit test mocks catalog client to simulate 404 and timeout.

Implementation notes (full):

  • Files: DefaultEntitlementsProcessor.AssignEditionAsync, new IProductsCatalogAcl or direct ServiceModel client package reference.
  • Packages: ConnectSoft.Saas.ProductsCatalog.ServiceModel (consumer NuGet).
  • Config: catalog service URL in appsettings.

Out of scope:

  • Caching catalog snapshots long-term (optional enhancement).
  • Catalog write operations.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated (docs/domain/products-catalog-references.md)
  • Status updated in master + mirrors

[033] saas-ENT-S04.1 — Validate catalog edition exists before assignment persistence

Type: User Story
Parent: saas-ENT-F04
Implementation order: 033
Status: Not Started
Evidence: DefaultEntitlementsProcessor.AssignEditionAsync — no catalog call
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, catalog
Priority: P1
Effort: M
Dependencies: saas-ENT-F08, saas-CAT-F06
Blocks: saas-ENT-T04.1.1, saas-ENT-T04.1.2
Source gap analysis: §4.3 ServiceModel

Description (full):

As an Entitlements API caller, I need assign-edition to fail fast when catalog references are invalid so I do not create orphan assignments that silently break Billing and Metering.

Acceptance criteria (testable):

  • AC-1: Integration test with test catalog stub returns 404 fault for unknown edition id.
  • AC-2: Valid assign from sample catalog seed unchanged.
  • AC-3: OpenTelemetry span includes catalog ACL call for observability.

Implementation notes (full):

  • Use GetEditionByIdAsync or ListEditions from Catalog query service.

Out of scope:

  • ProductCreated/Updated proactive sync sagas.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[033] saas-ENT-T04.1.1 — Add Products Catalog ACL client and DI registration

Type: Task
Parent: saas-ENT-S04.1
Implementation order: 033
Status: Not Started
Evidence: No catalog client in Entitlements ApplicationModel
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, catalog, acl
Priority: P1
Effort: M
Dependencies: saas-ENT-F08
Blocks:
Source gap analysis: §4.3 ServiceModel

Description (full):

Introduce IProductsCatalogAcl wrapping gRPC IProductQueryService client with tenant header propagation, timeout, and Polly retry policy per BaseTemplate conventions.

Acceptance criteria (testable):

  • AC-1: Client resolves in DI; configuration section documented in configuration.md.
  • AC-2: Unit test with fake handler returns edition metadata.
  • AC-3: Package references align with INTEG-F07 pin policy when available.

Implementation notes (full):

  • ApplicationModel registration extensions.
  • Reference ADR-0002 external catalog identifiers.

Out of scope:

  • Processor integration (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[033] saas-ENT-T04.1.2 — Enforce catalog existence check in AssignEditionAsync

Type: Task
Parent: saas-ENT-S04.1
Implementation order: 033
Status: Not Started
Evidence: AssignEditionAsync processor method
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, domain
Priority: P1
Effort: S
Dependencies: saas-ENT-T04.1.1
Blocks:
Source gap analysis: §4.3 ServiceModel

Description (full):

Call ACL before NHibernate transaction; map catalog not-found to ServiceModel fault; validate product/edition not retired if catalog response includes status.

Acceptance criteria (testable):

  • AC-1: Processor unit test mocks ACL 404 → no DB write occurred.
  • AC-2: Acceptance assign scenario still passes against docker-compose catalog service.
  • AC-3: Fault message includes catalog edition id for operator debugging.

Implementation notes (full):

  • DefaultEntitlementsProcessor.cs, validator classes if present.

Out of scope:

  • Override feature catalog checks (future if overrides reference catalog features).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[034] saas-ENT-F05 — Saga behavioral test suite + DefaultEntitlementsProcessor unit tests

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 034
Status: Not Started
Evidence: Gap analysis Tests — processor/saga coverage Missing for Entitlements
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, tests, P1
Priority: P1
Effort: L
Dependencies: saas-ENT-F03 (saga tests overlap)
Blocks:
Source gap analysis: §4.3 Entitlements

Description (full):

Entitlements has architecture tests for layering/gRPC/repository but lacks behavioral tests for ProductCatalogReactionStateMachine and comprehensive unit tests for DefaultEntitlementsProcessor command methods (draft, activate, assign, override, and F02 suspend/decommission when added). Gap program requires production-grade template CI gates.

Acceptance criteria (testable):

  • AC-1: Unit test class covers each public processor command with happy path + at least one validation failure.
  • AC-2: Saga test project includes ProductRetired flow test (may overlap F03 task).
  • AC-3: Code coverage on DefaultEntitlementsProcessor ≥ 70% line coverage.
  • AC-4: All tests run in CI without [Ignore] placeholders.

Implementation notes (full):

  • Files: new DefaultEntitlementsProcessorTests.cs, saga tests under FlowModel.MassTransit tests or UnitTests.
  • Use in-memory DB or NHibernate test fixture per repo patterns.

Out of scope:

  • AcceptanceTests BDD expansion (optional follow-up).
  • Architecture tests (F06).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated (docs/Testing.md)
  • Status updated in master + mirrors

[034] saas-ENT-S05.1 — Build processor unit test suite for all entitlement commands

Type: User Story
Parent: saas-ENT-F05
Implementation order: 034
Status: Not Started
Evidence: No dedicated processor unit test class in UnitTests project
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, tests
Priority: P1
Effort: M
Dependencies: saas-ENT-F02
Blocks: saas-ENT-T05.1.1, saas-ENT-T05.1.2
Source gap analysis: §4.3 Tests

Description (full):

As a CI maintainer, I need processor unit tests so domain regressions are caught before integration tests run.

Acceptance criteria (testable):

  • AC-1: Tests exist for CreateDraft, Activate, AssignEdition, OverrideFeature, Suspend, Decommission.
  • AC-2: Mocked IEventBus verifies publish on state-changing commands.
  • AC-3: Tests execute in under 60 seconds total.

Implementation notes (full):

  • Follow Products Catalog processor test patterns if present.

Out of scope:

  • Full NHibernate integration (use doubles).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[034] saas-ENT-T05.1.1 — Add DefaultEntitlementsProcessorTests for core commands

Type: Task
Parent: saas-ENT-S05.1
Implementation order: 034
Status: Not Started
Evidence: Missing processor test class
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, tests
Priority: P1
Effort: M
Dependencies:
Blocks:
Source gap analysis: §4.3 Tests

Description (full):

Create test class with repository stub and event bus fake covering draft/activate/assign/override flows including invalid transitions.

Acceptance criteria (testable):

  • AC-1: Minimum 8 test methods passing.
  • AC-2: No external service dependencies (catalog ACL mocked when F04 lands).
  • AC-3: Included in dotnet test UnitTests project.

Implementation notes (full):

  • tests/ConnectSoft.Saas.Entitlements.UnitTests/DomainModel/.

Out of scope:

  • Saga tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[034] saas-ENT-T05.1.2 — Add ProductCatalogReactionStateMachine behavioral tests

Type: Task
Parent: saas-ENT-S05.1
Implementation order: 034
Status: Not Started
Evidence: No saga unit tests listed in gap analysis
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, tests, saga
Priority: P1
Effort: M
Dependencies: saas-ENT-F03
Blocks:
Source gap analysis: §4.3 Messaging

Description (full):

Add MassTransit test harness tests for ProductCatalogReactionStateMachine covering ProductRetired happy path, idempotent redelivery, and processor exception fault handling.

Acceptance criteria (testable):

  • AC-1: At least 3 saga test scenarios green.
  • AC-2: Uses in-memory saga repository or test harness equivalent.
  • AC-3: Documented in docs/Testing.md under MassTransit section.

Implementation notes (full):

  • Reference Billing saga tests in BillingTemplate for pattern.

Out of scope:

  • ProductCreated/Updated consumer tests (no consumers yet).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[035] saas-ENT-F06 — Replace placeholder architecture tests

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 035
Status: Not Started
Evidence: OneAggregateRootPerRepoTests.csAssert.IsTrue(true) placeholder; CrossRepoPublishedLanguageTests.cs placeholder comment
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, architecture, tests, P1
Priority: P1
Effort: S
Dependencies:
Blocks:
Source gap analysis: §4.3 Architecture tests

Description (full):

Products Catalog already implements real NetArch tests for OneAggregateRootPerRepo and CrossRepoPublishedLanguage. Entitlements copies placeholder tests that always pass, providing false CI confidence. This Feature ports the Catalog test patterns to Entitlements: scan DomainModel for aggregate root markers, validate MessagingModel topic constants against published language assembly rules, and ensure gRPC/ServiceModel layering tests remain green.

Acceptance criteria (testable):

  • AC-1: OneAggregateRootPerRepoTests fails if a second aggregate root is introduced in DomainModel (real NetArch rule).
  • AC-2: CrossRepoPublishedLanguageTests validates event topic constants and naming conventions (copy/adapt from Products Catalog ArchitectureTests).
  • AC-3: No Assert.IsTrue(true) placeholders remain in ArchitectureTests project.
  • AC-4: CI ArchitectureTests job passes on main branch codebase.

Implementation notes (full):

  • Files: OneAggregateRootPerRepoTests.cs, CrossRepoPublishedLanguageTests.cs.
  • Reference: ConnectSoft.Saas.ProductsCatalog.ArchitectureTests implementations.
  • ADR: docs/adr/0001-one-aggregate-root-per-repo.md.

Out of scope:

  • Orleans grain partition tests (Metering epic MET-F07 pattern — not required unless grains gain partition rules).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[035] saas-ENT-S06.1 — Implement real NetArch rules in Entitlements ArchitectureTests

Type: User Story
Parent: saas-ENT-F06
Implementation order: 035
Status: Not Started
Evidence: Placeholder tests in ArchitectureTests project
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, architecture, tests
Priority: P1
Effort: S
Dependencies:
Blocks: saas-ENT-T06.1.1, saas-ENT-T06.1.2
Source gap analysis: §4.3 Architecture tests

Description (full):

As a platform architect, I need Entitlements architecture tests to enforce the same structural rules as other SaaS templates so aggregate and messaging drift is caught in CI.

Acceptance criteria (testable):

  • AC-1: Deliberate test branch with fake second aggregate root fails CI (verified in PR demonstration or code review note).
  • AC-2: Tests documented in docs/Testing.md.
  • AC-3: NetArchTest package version aligned with Catalog repo.

Implementation notes (full):

  • Copy rule definitions from Catalog; adjust namespaces to Entitlements assemblies.

Out of scope:

  • New layering rules beyond existing ServiceModelLayering tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[035] saas-ENT-T06.1.1 — Replace OneAggregateRootPerRepoTests placeholder

Type: Task
Parent: saas-ENT-S06.1
Implementation order: 035
Status: Not Started
Evidence: OneAggregateRootPerRepoTests.cs line 15-16 placeholder
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, architecture, tests
Priority: P1
Effort: S
Dependencies:
Blocks:
Source gap analysis: §4.3 Architecture tests

Description (full):

Implement NetArchTest rule counting types implementing aggregate root marker in ConnectSoft.Saas.Entitlements.DomainModel — expect exactly one (Entitlement).

Acceptance criteria (testable):

  • AC-1: Test uses NetArchTest Types.InAssembly(...) pattern matching Catalog.
  • AC-2: Passes on current codebase.
  • AC-3: Remove TODO comment and placeholder assert.

Implementation notes (full):

  • Reference Catalog OneAggregateRootPerRepoTests.cs.

Out of scope:

  • CrossRepo test (separate task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[035] saas-ENT-T06.1.2 — Replace CrossRepoPublishedLanguageTests placeholder

Type: Task
Parent: saas-ENT-S06.1
Implementation order: 035
Status: Not Started
Evidence: CrossRepoPublishedLanguageTests.cs placeholder comment
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, architecture, tests
Priority: P1
Effort: S
Dependencies:
Blocks:
Source gap analysis: §4.3 Architecture tests, finding X-008 partial

Description (full):

Implement assembly scan validating EntitlementsConstants.EventTopics values match regex/naming rules from cross-repo published language doc; optionally validate inbound catalog event type names from ProductsCatalog.MessagingModel package.

Acceptance criteria (testable):

  • AC-1: Test fails if topic constant renamed to non-canonical string (demonstrated via review).
  • AC-2: Passes on current constants.
  • AC-3: Links to published language doc in test class summary comment.

Implementation notes (full):

  • Port from Products Catalog ArchitectureTests.

Out of scope:

  • CI NuGet pin enforcement (F08 / INTEG-F07).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[036] saas-ENT-F07 — Wire writes through EntitlementEditorGrain

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 036
Status: Not Started
Evidence: EntitlementsController.cs, GrpcEntitlementManagementService.csIEntitlementsProcessor directly; grain exists at EntitlementEditorGrain.cs
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, orleans, P1
Priority: P1
Effort: L
Dependencies: saas-INTEG-F06
Blocks:
Source gap analysis: §3.6 Orleans write-path, §4.3 Entitlements

Description (full):

Entitlements registers Orleans and implements EntitlementEditorGrain delegating to IEntitlementsProcessor for CreateDraftAsync, ActivateAsync, AssignEditionAsync, and OverrideFeatureAsync. Silo tests cover CreateDraftAsync only. REST/gRPC adapters inject processor directly — no GetGrain<IEntitlementEditorGrain> on write path (cross-cutting X-007). Grain key is tenant id string per IGrainWithStringKey.

Per saas-INTEG-F06 / ADR-INTEG-001 outcome, route all management writes through the grain for per-tenant write serialization, matching Products Catalog F01 pattern.

Acceptance criteria (testable):

  • AC-1: Management commands on REST/gRPC invoke IEntitlementEditorGrain not processor directly.
  • AC-2: Tenant id in request matches grain primary key; mismatch throws (existing silo test pattern).
  • AC-3: If ADR-INTEG-001 option (B) processor-only bypass accepted, Feature Deferred with citation.
  • AC-4: Query operations bypass grain (read path unchanged).
  • AC-5: Grain silo tests extended for activate/assign/override (coordinate with F05/F07 grain tests if split).

Implementation notes (full):

  • Files: EntitlementsController.cs, GrpcEntitlementManagementService.cs, DI registration, optional EntitlementEditorGrainCoordinator.
  • Include F02 suspend/decommission on actor interface when F02 completes.

Out of scope:

  • Grain persistent state (stateless coordinator).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[036] saas-ENT-S07.1 — Route entitlement management writes through EntitlementEditorGrain

Type: User Story
Parent: saas-ENT-F07
Implementation order: 036
Status: Not Started
Evidence: Direct processor injection in ServiceModel adapters
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, orleans
Priority: P1
Effort: M
Dependencies: saas-INTEG-F06
Blocks: saas-ENT-T07.1.1, saas-ENT-T07.1.2
Source gap analysis: §3.6

Description (full):

As a platform engineer, I need API writes serialized per tenant via Orleans so concurrent entitlement mutations do not corrupt NHibernate session usage on the same tenant partition.

Acceptance criteria (testable):

  • AC-1: All management endpoints use grain factory with tenant id key.
  • AC-2: Existing EntitlementEditorGrainSiloTests still pass; extended for additional ops if in scope.
  • AC-3: No regression in acceptance tests.

Implementation notes (full):

  • Grain key: tenant id string from tenant context middleware.

Out of scope:

  • Cross-tenant batch operations.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[036] saas-ENT-T07.1.1 — Add grain write coordinator and wire REST controller

Type: Task
Parent: saas-ENT-S07.1
Implementation order: 036
Status: Not Started
Evidence: EntitlementsController.csIEntitlementsProcessor field
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, orleans, rest
Priority: P1
Effort: M
Dependencies: saas-INTEG-F06
Blocks:
Source gap analysis: §3.6

Description (full):

Implement coordinator using IGrainFactory.GetGrain<IEntitlementEditorGrain>(tenantId); replace processor calls in EntitlementsController for write operations.

Acceptance criteria (testable):

  • AC-1: Controller no longer calls processor directly for writes.
  • AC-2: Integration test or unit test verifies grain dispatch.
  • AC-3: OpenTelemetry scopes preserved.

Implementation notes (full):

  • Register coordinator in ApplicationModel DI.

Out of scope:

  • gRPC (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[036] saas-ENT-T07.1.2 — Wire gRPC management service through grain coordinator

Type: Task
Parent: saas-ENT-S07.1
Implementation order: 036
Status: Not Started
Evidence: GrpcEntitlementManagementService.cs — direct processor calls
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, orleans, grpc
Priority: P1
Effort: S
Dependencies: saas-ENT-T07.1.1
Blocks:
Source gap analysis: §4.3 Entitlements

Description (full):

Refactor GrpcEntitlementManagementService to shared grain coordinator; extend IEntitlementEditorActor / grain with suspend/decommission when F02 ships.

Acceptance criteria (testable):

  • AC-1: gRPC write ops use coordinator exclusively.
  • AC-2: gRPC acceptance tests pass.
  • AC-3: Code search confirms ServiceModel write path free of direct processor calls.

Implementation notes (full):

  • Shared coordinator from T07.1.1.

Out of scope:

  • Query gRPC service.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[037] saas-ENT-F08 — ProductsCatalog.MessagingModel pin bump to documented version

Type: Feature
Parent: saas-EPIC-ENT
Implementation order: 037
Status: Not Started
Evidence: ConnectSoft.Saas.Entitlements.FlowModel.MassTransit.csproj PackageReference without documented pin; gap analysis X-008
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, nuget, P1
Priority: P1
Effort: S
Dependencies: saas-INTEG-F07
Blocks: saas-ENT-F03, saas-ENT-F04
Source gap analysis: §3.7 MessagingModel NuGet pin, finding X-008

Description (full):

Entitlements references ConnectSoft.Saas.ProductsCatalog.MessagingModel for inbound catalog events (ProductRetiredEvent, etc.) in FlowModel.MassTransit and ApplicationModel projects. Cross-repo published language requires a documented, CI-enforced NuGet version pin strategy so catalog event contract changes do not break Entitlements at runtime without explicit upgrade. saas-INTEG-F07 defines the program-wide policy; this Feature applies the pin to Entitlements repos (Directory.Packages.props or central package management entry), documents the pinned version, and adds a CI check or architecture test verifying package version matches policy file.

Acceptance criteria (testable):

  • AC-1: ConnectSoft.Saas.ProductsCatalog.MessagingModel version explicitly pinned in repo central package management matching INTEG-F07 policy doc.
  • AC-2: README or docs/messaging.md states pinned version and upgrade procedure when catalog ships breaking MessagingModel change.
  • AC-3: CI step fails if package version drifts from allowed range without PR updating policy doc.
  • AC-4: dotnet restore and full test suite pass with pinned version.
  • AC-5: CrossRepoPublishedLanguageTests (F06) validates event type assembly from pinned package loads.

Implementation notes (full):

  • Files: Directory.Packages.props, FlowModel.MassTransit csproj, ApplicationModel csproj, docs/domain/products-catalog-references.md.
  • Coordinate version with latest published Catalog MessagingModel NuGet on feed.
  • ADR-0002 external catalog identifiers may reference package version.

Out of scope:

  • Pinning other cross-repo packages (Billing, Metering) — covered under their epics / INTEG-F07.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[037] saas-ENT-S08.1 — Pin and document ProductsCatalog.MessagingModel version in Entitlements repo

Type: User Story
Parent: saas-ENT-F08
Implementation order: 037
Status: Not Started
Evidence: Undocumented PackageReference in csproj files
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, nuget
Priority: P1
Effort: S
Dependencies: saas-INTEG-F07
Blocks: saas-ENT-T08.1.1, saas-ENT-T08.1.2
Source gap analysis: Finding X-008

Description (full):

As an Entitlements maintainer, I need an explicit catalog MessagingModel pin so catalog event schema upgrades are deliberate and traceable across repos.

Acceptance criteria (testable):

  • AC-1: Pin version recorded in repo and matches master INTEG policy table.
  • AC-2: Upgrade runbook section added to docs.
  • AC-3: No floating version references remain.

Implementation notes (full):

  • Use same CPM pattern as other SaaS templates when INTEG-F07 lands.

Out of scope:

  • Publishing new Catalog MessagingModel version (Catalog repo).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[037] saas-ENT-T08.1.1 — Set central package pin for ProductsCatalog.MessagingModel

Type: Task
Parent: saas-ENT-S08.1
Implementation order: 037
Status: Not Started
Evidence: PackageReference without Version in csproj (CPM)
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, nuget
Priority: P1
Effort: S
Dependencies: saas-INTEG-F07
Blocks:
Source gap analysis: §3.7

Description (full):

Add or update Directory.Packages.props entry for ConnectSoft.Saas.ProductsCatalog.MessagingModel at version aligned with catalog template release; run restore and tests.

Acceptance criteria (testable):

  • AC-1: dotnet list package shows explicit version for MessagingModel in FlowModel and ApplicationModel projects.
  • AC-2: All tests green after pin bump if version changed.
  • AC-3: PR description links to catalog release notes for chosen version.

Implementation notes (full):

  • Check internal NuGet feed for latest stable package.

Out of scope:

  • CI guard script (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[037] saas-ENT-T08.1.2 — Document pin policy and add CI drift check

Type: Task
Parent: saas-ENT-S08.1
Implementation order: 037
Status: Not Started
Evidence: No pin documentation in Entitlements docs
Last verified: 2026-05-27
Area path: ConnectSoft\SaaS\Entitlements
Iteration: TBD
Tags: saas-platform, gap, entitlements, nuget, ci
Priority: P1
Effort: S
Dependencies: saas-ENT-T08.1.1
Blocks:
Source gap analysis: Finding X-008

Description (full):

Update docs/messaging.md and docs/domain/products-catalog-references.md with pinned version table and upgrade steps. Add CI script or architecture test comparing csproj/CPM version to docs/cross-repo-packages.md (or INTEG policy file path when published).

Acceptance criteria (testable):

  • AC-1: Docs list pinned version and owning Feature ID saas-ENT-F08.
  • AC-2: CI pipeline includes pin verification step (script or test).
  • AC-3: Drift intentionally introduced in test branch fails CI (review evidence).

Implementation notes (full):

  • Align with INTEG-F07 master policy document path.

Out of scope:

  • GitHub Dependabot config (optional).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

Implementation ordering (this epic)

Preferred sequence within saas-EPIC-ENT (global order in brackets):

  1. [037] saas-ENT-F08 — MessagingModel pin (unblocks catalog event consumers; align with saas-INTEG-F07).
  2. [030] saas-ENT-F01 — EffectiveEntitlementDescriptor ADR + implementation.
  3. [031] saas-ENT-F02 — Suspend/decommission commands.
  4. [033] saas-ENT-F04 — Catalog integrity on assign (after F08; benefits from saas-CAT-F06).
  5. [032] saas-ENT-F03 — Catalog retirement saga completion (after F02, F08).
  6. [035] saas-ENT-F06 — Architecture tests (parallel-friendly).
  7. [034] saas-ENT-F05 — Processor + saga tests (after F02/F03).
  8. [036] saas-ENT-F07 — Orleans write-path (after saas-INTEG-F06).

Cross-epic dependencies: saas-INTEG-F06, saas-INTEG-F07, saas-INTEG-F04, saas-CAT-F04, saas-CAT-F06.