diff --git a/docs/migration/behavior-invariants.md b/docs/migration/behavior-invariants.md index 0233310..ba3889c 100644 --- a/docs/migration/behavior-invariants.md +++ b/docs/migration/behavior-invariants.md @@ -4,6 +4,8 @@ - Availability decision outcome remains unchanged for equivalent inputs. - Correlation propagation behavior remains unchanged. - Transport contracts stay stable at service boundary. +- Missing display names map to `Unknown Furniture`. +- Negative inventory quantities are clamped to `0`. ## Validation Approach - Compare pre/post extraction contract examples. diff --git a/src/Furniture.Domain/Decisions/FurnitureAvailabilityDecisionService.cs b/src/Furniture.Domain/Decisions/FurnitureAvailabilityDecisionService.cs index c2337ef..c9a9a24 100644 --- a/src/Furniture.Domain/Decisions/FurnitureAvailabilityDecisionService.cs +++ b/src/Furniture.Domain/Decisions/FurnitureAvailabilityDecisionService.cs @@ -38,10 +38,17 @@ public sealed class FurnitureAvailabilityDecisionService : IFurnitureAvailabilit ProductContractResponse catalogResponse, InventoryItemLookupResponse inventoryResponse) { + var displayName = string.IsNullOrWhiteSpace(catalogResponse.DisplayName) + ? "Unknown Furniture" + : catalogResponse.DisplayName; + var quantityAvailable = inventoryResponse.QuantityAvailable < 0 + ? 0 + : inventoryResponse.QuantityAvailable; + return new FurnitureAvailabilityDecisionResponse( request.FurnitureId, - catalogResponse.DisplayName, - inventoryResponse.QuantityAvailable); + displayName, + quantityAvailable); } private static string ResolveCorrelationId(string correlationId) diff --git a/tests/Furniture.Domain.UnitTests/FurnitureAvailabilityDecisionServiceTests.cs b/tests/Furniture.Domain.UnitTests/FurnitureAvailabilityDecisionServiceTests.cs index 67c3b20..3dbc098 100644 --- a/tests/Furniture.Domain.UnitTests/FurnitureAvailabilityDecisionServiceTests.cs +++ b/tests/Furniture.Domain.UnitTests/FurnitureAvailabilityDecisionServiceTests.cs @@ -51,4 +51,42 @@ public class FurnitureAvailabilityDecisionServiceTests Assert.Equal("Chair", response.DisplayName); Assert.Equal(12, response.QuantityAvailable); } + + [Fact] + public void ComposeResponse_WhenCatalogDisplayNameMissing_UsesFallbackName() + { + var service = new FurnitureAvailabilityDecisionService(); + var request = new FurnitureAvailabilityDecisionRequest("FUR-004", "corr-004"); + var catalog = new ProductContractResponse( + new CatalogContractEnvelope("1.0.0", "corr-004"), + "FUR-004", + string.Empty); + var inventory = new InventoryItemLookupResponse( + new InventoryContractEnvelope("1.0.0", "corr-004"), + "FUR-004", + 5); + + var response = service.ComposeResponse(request, catalog, inventory); + + Assert.Equal("Unknown Furniture", response.DisplayName); + } + + [Fact] + public void ComposeResponse_WhenInventoryNegative_ClampsQuantityToZero() + { + var service = new FurnitureAvailabilityDecisionService(); + var request = new FurnitureAvailabilityDecisionRequest("FUR-005", "corr-005"); + var catalog = new ProductContractResponse( + new CatalogContractEnvelope("1.0.0", "corr-005"), + "FUR-005", + "Shelf"); + var inventory = new InventoryItemLookupResponse( + new InventoryContractEnvelope("1.0.0", "corr-005"), + "FUR-005", + -3); + + var response = service.ComposeResponse(request, catalog, inventory); + + Assert.Equal(0, response.QuantityAvailable); + } }