diff --git a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs
new file mode 100644
index 0000000..d53bce9
--- /dev/null
+++ b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs
@@ -0,0 +1,56 @@
+using BuildingBlock.Catalog.Contracts.Conventions;
+using BuildingBlock.Catalog.Contracts.Products;
+using BuildingBlock.Catalog.Contracts.Responses;
+using BuildingBlock.Inventory.Contracts.Conventions;
+using BuildingBlock.Inventory.Contracts.Requests;
+using BuildingBlock.Inventory.Contracts.Responses;
+using Furniture.Service.Contracts.UseCases;
+
+namespace Furniture.Service.Application.Adapters;
+
+///
+/// Default adapter implementation for furniture service contract composition.
+///
+public sealed class FurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter
+{
+ private const string ContractVersion = "1.0.0";
+
+ ///
+ public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request)
+ {
+ return new InventoryItemLookupRequest(
+ new InventoryContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
+ request.FurnitureId);
+ }
+
+ ///
+ public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request)
+ {
+ return new ProductContract(
+ new CatalogContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
+ request.FurnitureId,
+ string.Empty);
+ }
+
+ ///
+ public GetFurnitureAvailabilityResponse ToServiceResponse(
+ GetFurnitureAvailabilityRequest request,
+ ProductContractResponse catalogResponse,
+ InventoryItemLookupResponse inventoryResponse)
+ {
+ return new GetFurnitureAvailabilityResponse(
+ request.FurnitureId,
+ catalogResponse.DisplayName,
+ inventoryResponse.QuantityAvailable);
+ }
+
+ private static string ResolveCorrelationId(string correlationId)
+ {
+ if (!string.IsNullOrWhiteSpace(correlationId))
+ {
+ return correlationId;
+ }
+
+ return $"corr-{Guid.NewGuid():N}";
+ }
+}
diff --git a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs
new file mode 100644
index 0000000..bbaeb4a
--- /dev/null
+++ b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs
@@ -0,0 +1,36 @@
+using Furniture.Service.Application.Grpc;
+using Furniture.Service.Contracts.UseCases;
+
+namespace Furniture.Service.Application.Adapters;
+
+///
+/// Default adapter implementation for furniture service gRPC contract translation.
+///
+public sealed class FurnitureAvailabilityGrpcContractAdapter : IFurnitureAvailabilityGrpcContractAdapter
+{
+ ///
+ public GetFurnitureAvailabilityGrpcContract ToGrpc(GetFurnitureAvailabilityRequest request)
+ {
+ return new GetFurnitureAvailabilityGrpcContract(
+ request.FurnitureId,
+ ResolveCorrelationId(request.CorrelationId));
+ }
+
+ ///
+ public GetFurnitureAvailabilityRequest FromGrpc(GetFurnitureAvailabilityGrpcContract contract)
+ {
+ return new GetFurnitureAvailabilityRequest(
+ contract.FurnitureId,
+ ResolveCorrelationId(contract.CorrelationId));
+ }
+
+ private static string ResolveCorrelationId(string correlationId)
+ {
+ if (!string.IsNullOrWhiteSpace(correlationId))
+ {
+ return correlationId;
+ }
+
+ return $"corr-{Guid.NewGuid():N}";
+ }
+}
diff --git a/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs
new file mode 100644
index 0000000..3dd7863
--- /dev/null
+++ b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs
@@ -0,0 +1,34 @@
+using Core.Blueprint.Common.DependencyInjection;
+using Furniture.DAL.DependencyInjection;
+using Furniture.Service.Application.Adapters;
+using Furniture.Service.Application.Ports;
+using Furniture.Service.Application.UseCases;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Furniture.Service.Application.DependencyInjection;
+
+///
+/// Registers furniture-service runtime orchestration and DAL adapters.
+///
+public static class FurnitureServiceRuntimeServiceCollectionExtensions
+{
+ ///
+ /// Adds furniture-service runtime wiring aligned with blueprint runtime and furniture-dal runtime.
+ ///
+ /// Service collection.
+ /// Service collection for fluent chaining.
+ public static IServiceCollection AddFurnitureServiceRuntime(this IServiceCollection services)
+ {
+ services.AddBlueprintRuntimeCore();
+ services.AddFurnitureDalRuntime();
+
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+
+ return services;
+ }
+}
diff --git a/src/Furniture.Service.Application/Furniture.Service.Application.csproj b/src/Furniture.Service.Application/Furniture.Service.Application.csproj
index 007938b..236c500 100644
--- a/src/Furniture.Service.Application/Furniture.Service.Application.csproj
+++ b/src/Furniture.Service.Application/Furniture.Service.Application.csproj
@@ -5,8 +5,10 @@
enable
+
+
diff --git a/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs b/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs
new file mode 100644
index 0000000..35e9bfc
--- /dev/null
+++ b/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs
@@ -0,0 +1,38 @@
+using BuildingBlock.Catalog.Contracts.Conventions;
+using BuildingBlock.Catalog.Contracts.Products;
+using BuildingBlock.Catalog.Contracts.Responses;
+using Furniture.DAL.Contracts;
+using Furniture.DAL.Repositories;
+
+namespace Furniture.Service.Application.Ports;
+
+///
+/// Default DAL adapter for catalog product read port.
+///
+public sealed class CatalogProductReadPortDalAdapter(ICatalogRepository catalogRepository) : ICatalogProductReadPort
+{
+ ///
+ public async Task ReadProductAsync(ProductContract request)
+ {
+ var lookupRequest = new CatalogProductLookupRequest(
+ new FurnitureDalContractEnvelope(
+ request.Envelope.ContractVersion,
+ request.Envelope.CorrelationId),
+ request.ProductId);
+
+ var projectionRecord = await catalogRepository.ReadProductAsync(lookupRequest);
+ if (projectionRecord is null)
+ {
+ return new ProductContractResponse(request.Envelope, request.ProductId, string.Empty);
+ }
+
+ var responseEnvelope = new CatalogContractEnvelope(
+ projectionRecord.Envelope.ContractVersion,
+ projectionRecord.Envelope.CorrelationId);
+
+ return new ProductContractResponse(
+ responseEnvelope,
+ projectionRecord.ProductId,
+ projectionRecord.DisplayName);
+ }
+}
diff --git a/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs b/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs
new file mode 100644
index 0000000..f30d0b6
--- /dev/null
+++ b/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs
@@ -0,0 +1,39 @@
+using BuildingBlock.Inventory.Contracts.Conventions;
+using BuildingBlock.Inventory.Contracts.Requests;
+using BuildingBlock.Inventory.Contracts.Responses;
+using Furniture.DAL.Contracts;
+using Furniture.DAL.Repositories;
+
+namespace Furniture.Service.Application.Ports;
+
+///
+/// Default DAL adapter for furniture availability read port.
+///
+public sealed class FurnitureAvailabilityReadPortDalAdapter(
+ IFurnitureRepository furnitureRepository) : IFurnitureAvailabilityReadPort
+{
+ ///
+ public async Task ReadAvailabilityAsync(InventoryItemLookupRequest request)
+ {
+ var lookupRequest = new FurnitureAvailabilityLookupRequest(
+ new FurnitureDalContractEnvelope(
+ request.Envelope.ContractVersion,
+ request.Envelope.CorrelationId),
+ request.ItemCode);
+
+ var availabilityRecord = await furnitureRepository.ReadAvailabilityAsync(lookupRequest);
+ if (availabilityRecord is null)
+ {
+ return new InventoryItemLookupResponse(request.Envelope, request.ItemCode, 0);
+ }
+
+ var responseEnvelope = new InventoryContractEnvelope(
+ availabilityRecord.Envelope.ContractVersion,
+ availabilityRecord.Envelope.CorrelationId);
+
+ return new InventoryItemLookupResponse(
+ responseEnvelope,
+ availabilityRecord.FurnitureId,
+ availabilityRecord.QuantityAvailable);
+ }
+}
diff --git a/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj b/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj
index d236f97..c391cd2 100644
--- a/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj
+++ b/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj
@@ -4,6 +4,16 @@
enable
enable
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
diff --git a/src/Furniture.Service.Grpc/Program.cs b/src/Furniture.Service.Grpc/Program.cs
index ef5cbdd..4f71e79 100644
--- a/src/Furniture.Service.Grpc/Program.cs
+++ b/src/Furniture.Service.Grpc/Program.cs
@@ -1,6 +1,15 @@
+using Furniture.Service.Application.DependencyInjection;
+using Furniture.Service.Grpc.Services;
+
var builder = WebApplication.CreateBuilder(args);
-// Stage 3 skeleton: keep a single active internal protocol policy (gRPC-first).
+builder.Services.AddGrpc();
+builder.Services.AddHealthChecks();
+builder.Services.AddFurnitureServiceRuntime();
+
var app = builder.Build();
+app.MapGrpcService();
+app.MapHealthChecks("/healthz");
+
app.Run();
diff --git a/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto b/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto
new file mode 100644
index 0000000..785ba0f
--- /dev/null
+++ b/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto
@@ -0,0 +1,20 @@
+syntax = "proto3";
+
+option csharp_namespace = "Furniture.Service.Grpc";
+
+package furniture.service.grpc;
+
+service FurnitureRuntime {
+ rpc GetFurnitureAvailability (GetFurnitureAvailabilityGrpcRequest) returns (GetFurnitureAvailabilityGrpcResponse);
+}
+
+message GetFurnitureAvailabilityGrpcRequest {
+ string furniture_id = 1;
+ string correlation_id = 2;
+}
+
+message GetFurnitureAvailabilityGrpcResponse {
+ string furniture_id = 1;
+ string display_name = 2;
+ int32 quantity_available = 3;
+}
diff --git a/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs b/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs
new file mode 100644
index 0000000..4d2bb1e
--- /dev/null
+++ b/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs
@@ -0,0 +1,39 @@
+using Grpc.Core;
+using Furniture.Service.Application.Adapters;
+using Furniture.Service.Application.Grpc;
+using Furniture.Service.Application.UseCases;
+
+namespace Furniture.Service.Grpc.Services;
+
+///
+/// Internal gRPC endpoint implementation for furniture runtime operations.
+///
+public sealed class FurnitureRuntimeGrpcService(
+ IGetFurnitureAvailabilityUseCase getFurnitureAvailabilityUseCase,
+ IFurnitureAvailabilityGrpcContractAdapter grpcContractAdapter) : FurnitureRuntime.FurnitureRuntimeBase
+{
+ ///
+ /// Executes furniture availability lookup through service use-case orchestration.
+ ///
+ /// gRPC availability request.
+ /// gRPC server call context.
+ /// gRPC availability response.
+ public override async Task GetFurnitureAvailability(
+ GetFurnitureAvailabilityGrpcRequest request,
+ ServerCallContext context)
+ {
+ var grpcContract = new GetFurnitureAvailabilityGrpcContract(
+ request.FurnitureId,
+ request.CorrelationId);
+
+ var useCaseRequest = grpcContractAdapter.FromGrpc(grpcContract);
+ var useCaseResponse = await getFurnitureAvailabilityUseCase.HandleAsync(useCaseRequest);
+
+ return new GetFurnitureAvailabilityGrpcResponse
+ {
+ FurnitureId = useCaseResponse.FurnitureId,
+ DisplayName = useCaseResponse.DisplayName,
+ QuantityAvailable = useCaseResponse.QuantityAvailable
+ };
+ }
+}
diff --git a/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj b/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj
index f2fe7f7..a5758c1 100644
--- a/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj
+++ b/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj
@@ -7,6 +7,7 @@
+
diff --git a/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs b/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs
new file mode 100644
index 0000000..18e861e
--- /dev/null
+++ b/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs
@@ -0,0 +1,51 @@
+using Furniture.Service.Application.Adapters;
+using Furniture.Service.Application.DependencyInjection;
+using Furniture.Service.Application.Grpc;
+using Furniture.Service.Application.UseCases;
+using Furniture.Service.Contracts.UseCases;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Furniture.Service.Application.UnitTests;
+
+public class RuntimeWiringTests
+{
+ [Fact]
+ public async Task AddFurnitureServiceRuntime_WhenInvoked_ResolvesUseCase()
+ {
+ var services = new ServiceCollection();
+ services.AddFurnitureServiceRuntime();
+
+ using var provider = services.BuildServiceProvider();
+ var useCase = provider.GetRequiredService();
+
+ var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123"));
+
+ Assert.Equal("FUR-001", response.FurnitureId);
+ Assert.Equal(8, response.QuantityAvailable);
+ }
+
+ [Fact]
+ public void FurnitureAvailabilityGrpcContractAdapter_WhenMapped_PreservesValues()
+ {
+ var adapter = new FurnitureAvailabilityGrpcContractAdapter();
+ var request = new GetFurnitureAvailabilityRequest("FUR-002", "corr-456");
+
+ var grpcContract = adapter.ToGrpc(request);
+ var roundtrip = adapter.FromGrpc(grpcContract);
+
+ Assert.Equal("FUR-002", roundtrip.FurnitureId);
+ Assert.Equal("corr-456", roundtrip.CorrelationId);
+ }
+
+ [Fact]
+ public void FurnitureAvailabilityGrpcContractAdapter_WhenCorrelationMissing_GeneratesCorrelation()
+ {
+ var adapter = new FurnitureAvailabilityGrpcContractAdapter();
+ var grpcContract = new GetFurnitureAvailabilityGrpcContract("FUR-003", string.Empty);
+
+ var mapped = adapter.FromGrpc(grpcContract);
+
+ Assert.Equal("FUR-003", mapped.FurnitureId);
+ Assert.NotEmpty(mapped.CorrelationId);
+ }
+}