Cohesive Systems logoCOHESIVE SYSTEMS

Building Blocks

Cohesive.Infra

Cohesive.Infra is the typed semantic infrastructure model for compute, runtimes, external services, capabilities, bindings, legalization, and projection targets.

Core Idea

Cohesive.Infra is the realization IR for Cohesive systems. It defines the compute, runtime, external service, network, configuration, capability, and binding model used to host a distributed application.

It is not only an IaC wrapper. It is a typed semantic infrastructure model.

The framework lets a system declare:

  • What compute exists?
  • What runtime components execute application code?
  • What external services exist?
  • What capabilities do those components provide?
  • What capabilities does the application require?
  • How are semantic constructs bound to those capabilities?
  • Which realization graph satisfies the requirements?
  • Which backend projects the result into Pulumi, Terraform, Aspire, Kubernetes, Docker, or another target?

The core invariant is:

  • Application semantics declare requirements.
  • Infrastructure/runtime components declare capabilities.
  • Bindings compose capabilities into realized behavior.
  • The legalizer verifies or rewrites the realization graph until requirements are satisfied.

Layer Model

Cohesive.Infra models a realization layer below the semantic model, then projects that realization onto concrete deployment systems.

Cohesive Semantic Model
Entities, repositories, transitions, processes, APIs, projections, and clients declare requirements.
Realization Layer
Runtime Layer
ASP.NET, Orleans, Akka, Temporal workers, Durable Task workers, EDI ingress runtimes, queue consumers, and projection workers.
External Service Layer
Cosmos DB, DynamoDB, PostgreSQL, Redis, Event Hubs, Kafka, Elastic, Azure AI Search, blob stores, Temporal, and identity providers.
Compute Layer
Raw hosts, VMs, OS processes, containers, Kubernetes workloads, App Service, Function Apps, Docker Compose services, and TestContainers.
Cohesive.Infra Projection
PulumiTerraformAspireKubernetesDocker

The compute layer provides the physical or virtual place where processes run.

The application/runtime layer receives activity, demultiplexes it, routes it, controls concurrency, and dispatches code.

The external service layer contains distributed systems accessed by runtimes through clients, drivers, protocols, or RPC.


Core Concepts

Infra System

The top-level model is an immutable graph.

public sealed record InfraSystemDefinition
{
    public InfraSystemId Id { get; init; }
    public string? Version { get; init; }
    public ImmutableArray<ComputeComponentDefinition> Compute { get; init; }
    public ImmutableArray<RuntimeComponentDefinition> Runtimes { get; init; }
    public ImmutableArray<ServiceComponentDefinition> Services { get; init; }
    public ImmutableArray<NetworkSurfaceDefinition> Network { get; init; }
    public ImmutableArray<CapabilityProviderDefinition> Providers { get; init; }
    public ImmutableArray<RequirementDefinition> Requirements { get; init; }
    public ImmutableArray<BindingDefinition> Bindings { get; init; }
    public ImmutableArray<LegalizationRuleDefinition> LegalizationRules { get; init; }
    public ImmutableArray<ConfigurationBindingDefinition> Configuration { get; init; }
    public ImmutableDictionary<AnnotationKey, AnnotationValue> Annotations { get; init; }
}

The model is not a deployment artifact. It is the source of truth for realization.

Projection adapters compile it into deployment artifacts, local development hosts, integration-test fixtures, or provider-specific IaC.


Component Kinds

Compute Components

A compute component is a place where processes or containers run.

Examples:

  • RawHostAn existing host that can run one or more local processes.
  • VirtualMachineA provisioned VM boundary with OS, CPU, memory, and network settings.
  • ContainerA single image with ports, volumes, environment, and resource limits.
  • KubernetesDeploymentA replicated Kubernetes workload for stateless services.
  • KubernetesStatefulSetA Kubernetes workload with stable identity and persistent storage.
  • AppServiceA managed web or worker host in Azure App Service.
  • FunctionAppAn event-driven serverless host for function entry points.
  • DockerComposeServiceA local or composed service declared in Docker Compose.
  • TestContainerAn ephemeral container created for integration tests.
  • EdgeRuntimeA constrained runtime close to request ingress.
  • BrowserHostA browser execution boundary for client-side components.

Typical capabilities:

  • CanRunProcessCan host an OS process.
  • CanRunContainerCan host a container image.
  • CpuAllocationExposes CPU requests, limits, or reservations.
  • MemoryAllocationExposes memory requests, limits, or reservations.
  • NetworkInterfaceProvides routable network attachment.
  • PortBindingMaps logical service ports to host or platform ports.
  • VolumeMountAttaches persistent or ephemeral storage.
  • SecretInjectionSupplies secrets through environment, files, or platform bindings.
  • ReplicaScalingControls instance count or autoscaling bounds.
  • HealthRestartRestarts unhealthy workloads.
  • NodePlacementConstrains node, pool, or host placement.
  • ZoneSpreadDistributes instances across zones or failure domains.

Example definition:

var apiCompute = infra.Compute.KubernetesDeployment("freight-api", deployment =>
{
    deployment.Image("ghcr.io/cohesive/freight-api:1.8.0");
    deployment.Replicas(min: 3, max: 20);
    deployment.Resources(cpu: Cpu.Cores(2), memory: Memory.Gibibytes(4));
    deployment.ExposePort("http", 8080);
    deployment.ProviderSettings(new KubernetesWorkloadSettings
    {
        Namespace = "freight-prod",
        TopologySpread = TopologySpread.ByZone,
        RollingUpdate = new RollingUpdateSettings(maxUnavailable: 1, maxSurge: 2)
    });
});

Runtime Components

A runtime component executes or dispatches application code inside a process or worker.

Examples:

  • DotNetProcessRuntimeRuns .NET application code inside a process.
  • AspNetRuntimeHosts HTTP APIs, middleware, routing, and request handling.
  • OrleansClusterRuntimeHosts Orleans grains and cluster membership.
  • AkkaClusterRuntimeHosts Akka actors and cluster routing.
  • TemporalWorkerRuntimeRuns Temporal workflow and activity workers.
  • DurableTaskWorkerRuntimeRuns Durable Task orchestrations and activities.
  • QueueConsumerRuntimeDispatches queue messages into application handlers.
  • ProjectionWorkerRuntimeRuns read-model or integration projections.
  • EdiIngressRuntimeHandles EDI protocol ingress and response timing.
  • BackgroundServiceRuntimeRuns long-lived background services.

Typical capabilities:

  • HttpIngressReceives HTTP traffic from a network boundary.
  • RequestReplyProduces synchronous request and response behavior.
  • RouteDispatchDispatches requests to route handlers.
  • MiddlewarePipelineOrders request middleware and filters.
  • HostLanguageRpcInvokes in-process application functions.
  • ActorIdentityProvides stable actor identity.
  • ActorMessageRoutingRoutes messages to actor instances.
  • SerializedPerIdentityExecutionSerializes work for each identity.
  • RuntimePlacementPlaces runtime instances on compatible compute.
  • DurableWorkflowExecutionPersists workflow state across awaits and restarts.
  • DurableTimerSchedules durable workflow wakeups.
  • ExternalSignalReceives external workflow signals.
  • ActivityDispatchDispatches durable activities.
  • LockGuardedCriticalSectionWraps work in a managed lock scope.
  • PartitionedConsumerExecutionProcesses partitions with stable ownership.

Runtime components are hosted on compute components.

var aspNet = infra.Runtime.AspNet("public-http", runtime =>
{
    runtime.HostedOn(apiCompute);
    runtime.Listen(Http.Public(port: 443));
    runtime.Provides(Http.RequestReply());
    runtime.Provides(Http.RouteDispatch());
    runtime.ProviderSettings(new AspNetRuntimeSettings
    {
        RequestBodyLimitBytes = 50 * 1024 * 1024,
        ForwardedHeaders = true,
        UseHttp2 = true
    });
});

External Service Components

An external service component is a runtime outside the application process, accessed through a client, driver, protocol, or RPC.

Examples:

  • CosmosAccountCosmos DB account, database, and container boundary.
  • DynamoDbTableDynamoDB table with key schema and stream settings.
  • PostgresDatabaseRelational database with transactions and locks.
  • RedisClusterRedis cache or data structure service.
  • EventHubNamespaceEvent Hubs namespace and event stream boundary.
  • KafkaClusterKafka brokers, topics, and consumer coordination.
  • ServiceBusNamespaceService Bus queues, topics, and subscriptions.
  • ElasticClusterElastic cluster for indexing and search.
  • AzureSearchServiceAzure AI Search indexes and query endpoints.
  • BlobStoreObject storage buckets or containers.
  • TemporalServiceTemporal control plane, namespace, and task queues.
  • IdentityProviderIdentity, token, and claims authority.
  • ObservabilityBackendTrace, metric, and log collection backend.

Typical capabilities:

  • DurableDocumentStoragePersists JSON-like documents by key.
  • RelationalStoragePersists relational tables and queries.
  • TransactionalWriteCommits multiple writes atomically.
  • ConditionalWriteApplies writes only when predicates hold.
  • OptimisticConcurrencyDetects conflicts with versions or ETags.
  • PessimisticLockingBlocks competing writers through database locks.
  • AdvisoryLockProvides application-scoped lock primitives.
  • ChangeFeedPublishes ordered changes from storage.
  • DurableEventStreamPersists replayable event streams.
  • ConsumerGroupTracks independent stream consumers.
  • OffsetCheckpointStores replay positions.
  • SearchIndexIndexes documents for text search.
  • VectorIndexIndexes embeddings for vector search.
  • ObjectStorageStores blobs, files, or large payloads.
  • SecretStorageStores secrets with controlled access.
  • TraceSinkReceives distributed traces.
  • MetricSinkReceives metrics and time series.

Example:

var cosmos = infra.Service.Cosmos("primary-cosmos", service =>
{
    service.Account("freight-prod-cosmos");
    service.Database("freight");
    service.Container("orders", container =>
    {
        container.PartitionKey("/tenantId");
        container.Provides(Storage.DocumentStore());
        container.Provides(Storage.OptimisticConcurrency("etag"));
        container.Provides(Storage.TransactionalBatch(scope: TransactionScope.SinglePartition));
        container.Provides(Events.ChangeFeed());
    });
 
    service.ProviderSettings(new CosmosProviderSettings
    {
        Consistency = CosmosConsistency.Session,
        DefaultTimeToLive = null,
        RegionPriority = ["westus2", "eastus2"],
        Throughput = CosmosThroughput.AutoScale(maxRuPerSecond: 50_000)
    });
});

Provider-Specific Settings

Every provider exposes its own settings without polluting the portable Cohesive capability model.

The typical split is:

Portable contract
    common component kind, common capabilities, common constraints
 
Provider settings
    product-specific options, deployment knobs, version-specific features
 
Projection settings
    target-specific artifact behavior, such as Pulumi stack names or Terraform modules

Provider settings are strongly typed when supported and extensible when not.

public abstract record ProviderSettings
{
    public string ProviderName { get; init; }
    public string? ProviderVersion { get; init; }
    public ImmutableDictionary<string, ObservationValue> Extensions { get; init; }
}

Each provider adapter maps product-specific settings to provided capabilities.

Cosmos settings
    partition key, consistency, transactional batch, change feed, RU model
        -> capabilities and constraints
 
Kubernetes settings
    replicas, probes, resources, affinity, topology spread
        -> compute capabilities and constraints
 
Orleans settings
    cluster id, silo membership, placement strategy, grain storage
        -> actor runtime capabilities and constraints

Unknown provider settings round-trip. Cohesive may not understand every product option, but it preserves them and allows adapters to consume them.


Capability Model

Capabilities are first-class typed semantic facts about resources, runtimes, and composed behavior.

A capability is not just a label. It has parameters, constraints, scope, and sometimes proof obligations.

public sealed record CapabilityDefinition
{
    public CapabilityId Id { get; init; }
    public string Name { get; init; }
    public CapabilityKind Kind { get; init; }
    public ImmutableArray<CapabilityProperty> Properties { get; init; }
    public ImmutableArray<CapabilityConstraint> Constraints { get; init; }
    public ImmutableArray<CapabilityObligation> Obligations { get; init; }
}

The capability kinds are:

public enum CapabilityKind
{
    Compute,
    Network,
    Ingress,
    Dispatch,
    ExecutionDiscipline,
    ConcurrencyControl,
    Durability,
    Storage,
    Eventing,
    Search,
    Security,
    Observability,
    Configuration,
    Composite
}

Examples:

Execution.SerializedByIdentity(scope: "OrderId")
Execution.InlineSerializedBeforeResponse(scope: "ShipmentId", response: "SynchronousHttp")
Execution.DurableWorkflowHistory()
Execution.DurableTimer()
 
Storage.DocumentStore()
Storage.TransactionalBatch(scope: TransactionScope.SinglePartition)
Storage.OptimisticConcurrency(token: "etag")
Storage.RelationalTransaction(isolation: IsolationLevel.Serializable)
 
Events.DurableStream()
Events.AtLeastOnceDelivery()
Events.OrderedWithinPartition(key: "OrderId")
Events.ConsumerGroups()
 
Search.FullTextIndex()
Search.VectorIndex(dimensions: 1536)
Search.EventuallyConsistentProjection()

Primitive vs Composed Capabilities

Cohesive.Infra distinguishes primitive resources from realized behavior.

A lock provides a primitive:

  • MutualExclusionPrimitive
  • Lease
  • FencingToken (if supported)
  • Renewal (if supported)

It does not by itself provide serialized execution.

Serialized execution is provided by a composed runtime binding:

ASP.NET route
lock key
lock acquisition
lock release/expire
LockGuardedInlineExecution

A partitioned queue provides a primitive:

  • PartitionedOrderedDelivery
  • OffsetCheckpoint
  • ConsumerGroup

It does not by itself provide serialized processing.

Serialized processing is provided by a composed consumer binding:

queue partition key mapping
one active consumer lane
checkpoint after success
retry discipline preserving order
SerializedAsyncProcessing

This distinction is mandatory. Capabilities attach to realized behavior graphs, not merely to named resources.


Requirement Model

Application and semantic layers declare requirements without hardcoding products.

public sealed record RequirementDefinition
{
    public RequirementId Id { get; init; }
    public SemanticSubjectRef Subject { get; init; }
    public RequiredCapability RequiredCapability { get; init; }
    public RequirementStrength Strength { get; init; }
    public ImmutableArray<RequirementConstraint> Constraints { get; init; }
}

Example requirements:

  • OrderRepository requires DurableDocumentStorage.
  • OrderRepository requires OptimisticConcurrency.
  • OrderTransitionRuntime requires SerializedExecution by OrderId.
  • OrderTransitionRuntime requires AtomicStateWriteAndOutboxAppend.
  • FulfillmentFlow requires DurableWorkflowExecution.
  • FulfillmentFlow requires DurableTimers and ExternalSignals.
  • PublicApi requires SynchronousHttpRequestReply.
  • DomainEvents requires DurableAtLeastOncePartitionedReplayableStream.
  • OrderSearchProjection requires FullTextSearchIndex.
  • AS2Ingress requires InlineSerializedExecution by ShipmentId before SynchronousHttpResponse.

The domain layer states what it needs. It does not need to know whether the implementation is Cosmos, PostgreSQL, Orleans, Akka, Event Hubs, Redis, Kubernetes, or Temporal.


Binding Model

A binding connects a semantic subject to a provider graph.

public sealed record BindingDefinition
{
    public BindingId Id { get; init; }
    public SemanticSubjectRef Subject { get; init; }
    public ImmutableArray<ComponentRef> Providers { get; init; }
    public ImmutableArray<CapabilityMapping> CapabilityMappings { get; init; }
    public ImmutableArray<IdentityMapping> IdentityMappings { get; init; }
    public ImmutableArray<BoundaryMapping> BoundaryMappings { get; init; }
    public ImmutableArray<ConfigurationBindingDefinition> Configuration { get; init; }
}

Common binding types:

  • RepositoryBindingConnects an entity repository to storage providers.
  • TransitionRuntimeBindingConnects state transitions to serialized execution providers.
  • ProcessRuntimeBindingConnects long-running processes to workflow or worker runtimes.
  • ApiBindingConnects API semantics to request/response runtime capabilities.
  • ProjectionBindingConnects projections to event streams and target stores.
  • ClientBindingConnects generated or typed clients to reachable service endpoints.
  • EventStreamBindingConnects logical events to durable stream providers.
  • IngressRuntimeBindingConnects inbound protocol boundaries to hosted runtimes.
  • OutboxBindingConnects transactional writes to outbox publication behavior.
  • LockGuardBindingConnects scoped work to lock acquisition, renewal, and release.
  • SearchProjectionBindingConnects search projections to indexing providers.

Repository Binding

app.Entity<Order>().Repository.BindTo(cosmos.Container("orders"), binding =>
{
    binding.Requires(Storage.DocumentStore());
    binding.Requires(Storage.OptimisticConcurrency("etag"));
    binding.MapPartitionKey(order => order.TenantId);
    binding.MapId(order => order.OrderId);
});

Transition Runtime Binding

app.Entity<Order>().Transitions.BindTo(orleans, binding =>
{
    binding.Requires(Execution.SerializedByIdentity("OrderId"));
    binding.MapIdentity("OrderId", RuntimeIdentity.GrainId);
    binding.BindState(app.Entity<Order>().Repository);
});

Process Runtime Binding

app.Flow("FulfillmentFlow").BindTo(temporal, binding =>
{
    binding.Requires(Execution.DurableWorkflowHistory());
    binding.Requires(Execution.DurableTimer());
    binding.Requires(Execution.ExternalSignal());
    binding.MapIdentity("ShipmentId", RuntimeIdentity.WorkflowId);
    binding.TaskQueue("fulfillment");
});

API Binding

app.Api("PublicFreightApi").BindTo(aspNet, binding =>
{
    binding.Requires(Http.RequestReply());
    binding.Requires(Http.RouteDispatch());
    binding.ExposeTransition<Order>("AcceptTender", route: "POST /orders/{id}/accept");
});

Lock-Guarded Transition Runtime Binding

app.Entity<Shipment>().Transitions.BindTo(aspNet, binding =>
{
    binding.Requires(Execution.InlineSerializedBeforeResponse("ShipmentId"));
 
    binding.UseLockGuard(redisLock, guard =>
    {
        guard.MapIdentity("ShipmentId", key: "shipment:{ShipmentId}");
        guard.GuardCriticalSection("ReceiveAndRespond");
        guard.RequireLeaseRenewal();
        guard.RequireFencingToken();
        guard.ReleaseAfter(Boundary.HttpResponseDecision);
    });
});

Legalization Model

Legalization is the compiler-like process that turns semantic requirements into valid runtime/infrastructure realizations.

Requirement graph
    + available providers
    + selected bindings
    + legalization rules
        -> realization graph
        -> proof / diagnostics
        -> projection artifacts

The core relation is:

ProviderGraph ⊨ RequiredCapability

But this is not a flat lookup. It may require composition.

Legalization Results

public enum LegalizationStatus
{
    SatisfiedDirectly,
    SatisfiedByComposition,
    SatisfiedAfterRewrite,
    RequiresUserChoice,
    Unsatisfied,
    Invalid
}

A result includes a proof chain.

public sealed record LegalizationResult
{
    public LegalizationStatus Status { get; init; }
    public RealizationGraph Realization { get; init; }
    public ImmutableArray<CapabilityProofStep> Proof { get; init; }
    public ImmutableArray<InfraDiagnostic> Diagnostics { get; init; }
}

Legalization Rule Examples

Actor dispatch satisfies serialized execution

Required:
    SerializedExecution(scope = X)
 
Provided:
    ActorRuntime.SerializedPerIdentity
 
Legal if:
    X maps to actor identity
    all entry points for the subject dispatch through that actor
    execution boundary is compatible with the caller's response boundary

Lock guard satisfies inline serialized execution

Required:
    InlineSerializedExecution(scope = X, boundary = BeforeHttpResponse)
 
Provided:
    HttpRuntime.RequestReply
    LockService.Lease
    RuntimeBinding.LockGuardedCriticalSection
 
Legal if:
    X maps to lock key
    lock is acquired before critical section
    critical section includes every response-relevant operation
    lock is held until response decision is complete
    lease renewal/fencing semantics satisfy configured risk policy
    all relevant entry points use the same guard

Optimistic concurrency does not satisfy serialized execution

Required:
    SerializedExecution(scope = X)
 
Provided:
    Storage.OptimisticConcurrency
 
Illegal because:
    optimistic concurrency detects conflict at commit time
    it does not prevent concurrent execution from entering the critical section

Queue partitioning satisfies only async serialization

Required:
    InlineSerializedExecution(scope = X, boundary = BeforeHttpResponse)
 
Provided:
    PartitionedQueue.OrderedWithinPartition
    ConsumerRuntime.SingleActiveHandlerPerPartition
 
Illegal because:
    serialization occurs after enqueue and outside the synchronous response boundary
 
Legal for:
    SerializedAsyncContinuation(scope = X)

Change feed to event hub rewrite preserves logical stream

Required:
    LogicalEventStream(
        durable,
        atLeastOnce,
        partitioned,
        orderedWithin = OrderId,
        replayable,
        consumerGroups)
 
Initial realization:
    CosmosChangeFeed
 
Scaled realization:
    CosmosChangeFeed -> Bridge -> EventHubs
 
Legal if:
    envelope preserved
    idempotency key preserved
    partition key mapping preserves required ordering
    consumer checkpoint semantics satisfy replay requirement
    retention is adequate

Realization Graph

The legalizer produces a realization graph. This graph is lower-level than the semantic model and higher-level than provider-specific deployment artifacts.

Example: AS2 ingress with actor serialization.

AS2IngressRuntime
    requires HTTP synchronous response
    requires inline serialized execution by ShipmentId
 
Realization:
    ASP.NET route /as2/receive
        -> Orleans grain As2ShipmentGrain(ShipmentId)
        -> durable receive store
        -> outbox append
        -> MDN response

Example: AS2 ingress with lock-guarded ASP.NET.

AS2IngressRuntime
    requires HTTP synchronous response
    requires inline serialized execution by ShipmentId
 
Realization:
    ASP.NET route /as2/receive
        -> acquire distributed lock shipment:{ShipmentId}
        -> receive critical section
        -> durable receive store
        -> outbox append
        -> MDN response decision
        -> release lock

Example: outbox stream scaling rewrite.

Application binding:
    DomainEvents logical stream
 
v1 realization:
    Cosmos outbox container
        -> Cosmos change feed consumers
 
v2 realization:
    Cosmos outbox container
        -> ChangeFeedToEventHubBridge
        -> Event Hub domain-events
        -> consumers

The semantic binding remains stable. The infra graph changes.


Configuration Integration

Cohesive.Infra integrates with Cohesive.Configuration. Infra does not store raw configuration values as untyped strings.

Each component exposes a configuration surface:

Inputs
    values required to provision or run the component
 
Outputs
    values produced by provisioning, discovery, or runtime allocation
 
Bindings
    wiring from outputs to inputs, secrets, environment variables, appsettings, files, or provider-specific mechanisms

Configuration values are typed, scoped, and provenance-aware.

public sealed record ConfigurationSlot<T>
{
    public ConfigurationKey Key { get; init; }
    public ConfigurationValueKind Kind { get; init; }
    public bool IsSecret { get; init; }
    public T? DefaultValue { get; init; }
    public ImmutableArray<ConfigurationConstraint> Constraints { get; init; }
}

Value kinds:

  • Literal
  • EnvironmentVariable
  • SecretReference
  • ProviderOutput
  • GeneratedValue
  • ComputedExpression
  • DeploymentParameter
  • TestRuntimeValue

Example:

infra.Configuration.Bind(cosmos.Outputs.ConnectionString)
    .To(apiCompute.EnvironmentVariable("ConnectionStrings__Cosmos"))
    .AsSecret();
 
infra.Configuration.Bind(eventHub.Outputs.FullyQualifiedNamespace)
    .To(worker.Configuration("Eventing:Namespace"));
 
infra.Configuration.Bind(redis.Outputs.Endpoint)
    .To(lockGuard.Configuration("Lock:Endpoint"));

Cohesive.Configuration owns:

  • Environment overlays
  • Secret provenance
  • Validation
  • Late-bound provider outputs
  • Deployment-time vs runtime-time values
  • Local/test/prod substitution
  • Typed quantities, durations, resource names, and endpoints

Cohesive.Infra consumes those semantics and attaches them to runtime/service bindings.


Projection Targets

Pulumi

Use for cloud resource provisioning and application deployment.

Projection concerns
  • Resource graph
  • Provider credentials
  • Stack outputs
  • Secret handling
  • Cloud-specific resources
  • Kubernetes deployments
  • Managed databases
  • Managed queues
  • Managed search services

A single Cohesive.Infra model may produce different projections for different environments.

  • localAspire + TestContainers
  • integration-testTestContainers
  • devDocker Compose or Aspire
  • stagingPulumi/Terraform + Kubernetes/App Service/managed services
  • prodPulumi/Terraform + Kubernetes/App Service/managed services

Semantic Binding Examples

Entity Repository to Storage Infrastructure

OrderRepository requires:

  • durable document storage
  • point lookup by OrderId
  • query by status
  • optimistic concurrency
  • transactional state write + outbox append within partition

Binding:

app.Entity<Order>().Repository.BindTo(cosmos.Container("orders"), binding =>
{
    binding.MapPartitionKey(order => order.TenantId);
    binding.MapId(order => order.OrderId);
    binding.Requires(Storage.DocumentStore());
    binding.Requires(Storage.OptimisticConcurrency("etag"));
    binding.Requires(Storage.TransactionalBatch(TransactionScope.SinglePartition));
});

Verifier diagnostics might include:

Valid:
    Cosmos container provides document storage and ETag optimistic concurrency.
 
Conditional:
    Transactional batch is valid only when Order state and Outbox event share the same partition key.

Distributed Lock Embedded into Transition Runtime

Shipment AS2 ingress transition requires:

  • synchronous HTTP response
  • serialized decision by ShipmentId before response
  • durable receive record before response

Binding:

app.Edi.As2Ingress("ShipmentAs2Receive").BindTo(aspNet, binding =>
{
    binding.Route("POST /edi/as2/shipments");
    binding.Requires(Http.SynchronousResponse());
    binding.Requires(Execution.InlineSerializedBeforeResponse("ShipmentId"));
 
    binding.UseLockGuard(redisLock, guard =>
    {
        guard.MapIdentity("ShipmentId", "shipment:{ShipmentId}");
        guard.AcquireBefore("ReceiveDecision");
        guard.ReleaseAfter(Boundary.HttpResponseDecision);
        guard.RequireFencingToken();
    });
});

The lock alone is not the provider. The provider is the composed runtime behavior:

ASP.NET runtime
distributed lock
critical section
inline serialized response-bound execution

Actor Runtime Alternative

app.Edi.As2Ingress("ShipmentAs2Receive").BindTo(aspNet, binding =>
{
    binding.Route("POST /edi/as2/shipments");
    binding.Requires(Http.SynchronousResponse());
    binding.Requires(Execution.InlineSerializedBeforeResponse("ShipmentId"));
 
    binding.DispatchTo(orleans.Grain("ShipmentAs2IngressGrain"), dispatch =>
    {
        dispatch.MapIdentity("ShipmentId", RuntimeIdentity.GrainId);
        dispatch.AwaitBeforeResponse();
    });
});

Event Stream Rewrite

Initial realization:

var domainEvents = infra.EventStream("DomainEvents", stream =>
{
    stream.Requires(Events.Durable());
    stream.Requires(Events.AtLeastOnce());
    stream.Requires(Events.OrderedWithin("AggregateId"));
    stream.Requires(Events.Replayable());
});
 
domainEvents.RealizeWith(cosmos.Container("outbox").ChangeFeed());

Scaled realization:

var eventHub = infra.Service.EventHub("domain-events", hub =>
{
    hub.PartitionBy("AggregateId");
    hub.Retention(TimeSpan.FromDays(7));
    hub.Provides(Events.DurableStream());
    hub.Provides(Events.ConsumerGroups());
});
 
infra.Pipe("outbox-to-eventhub", pipe =>
{
    pipe.From(cosmos.Container("outbox").ChangeFeed());
    pipe.To(eventHub);
    pipe.PreserveEnvelope();
    pipe.PreserveIdempotencyKey("EventId");
    pipe.PreservePartitionKey("AggregateId");
});
 
domainEvents.RealizeWith(eventHub);

Publishers and consumers remain bound to DomainEvents.


Compiler Pipeline

Cohesive.Infra behaves like a compiler backend for system realization.

  1. Parse / construct InfraSystemDefinition.
  2. Normalize provider-specific settings.
  3. Discover provided capabilities.
  4. Collect requirements from semantic models and explicit infra definitions.
  5. Build initial binding graph.
  6. Run legalization passes.
  7. Emit diagnostics and proof graph.
  8. Resolve configuration surfaces with Cohesive.Configuration.
  9. Produce RealizationGraph.
  10. Project to Pulumi, Aspire, TestContainers, Docker Compose, Terraform, etc.

Diagnostics

Diagnostics are precise and semantic.

Example:

Error cohesive.infra.execution.serialized.unsatisfied:
    AS2Ingress 'ShipmentAs2Receive' requires InlineSerializedExecution by ShipmentId before SynchronousHttpResponse.
 
Current binding:
    ASP.NET route 'POST /edi/as2/shipments'
    Kubernetes deployment replicas = 4
    Cosmos ETag optimistic concurrency
 
Problem:
    ASP.NET does not serialize requests by ShipmentId.
    Cosmos ETag detects conflicts at commit time, not before the response-bound critical section.
 
Legalization options:
    1. Dispatch to Orleans/Akka identity keyed by ShipmentId and await before response.
    2. Insert lock-guarded critical section keyed by ShipmentId with lease renewal and fencing.
    3. Restrict to single replica. Not recommended for production scale.

Environment Model

Infra definitions are environment-parameterized without duplicating semantic intent.

  • localAspire or Docker Compose + TestContainers
  • integration-testTestContainers
  • stagingPulumi/Terraform + Kubernetes/App Service/managed services
  • productionPulumi/Terraform + Kubernetes/App Service/managed services

Environments override values and provider settings, but not semantic requirements unless explicitly allowed.

infra.Environment("local", env =>
{
    env.ProjectWith(Aspire.Projector);
    env.Override(cosmos, service => service.UseEmulator());
    env.Override(eventHub, service => service.UseContainerizedKafka());
});
 
infra.Environment("prod", env =>
{
    env.ProjectWith(Pulumi.Projector);
    env.RequireNoCapabilityDowngrades();
    env.RequireSecretProvider("AzureKeyVault");
});

Design Rules

  1. Infrastructure resources are not passive; they provide typed capabilities.
  2. Capabilities may be primitive or composed.
  3. Semantic constructs bind to capabilities, not products.
  4. Provider-specific settings are allowed but isolated from the portable capability contract.
  5. Legalization preserves requirements or rejects the realization.
  6. Optimistic concurrency is not serialized execution.
  7. A queue is not serialized processing unless the consumer runtime enforces it.
  8. A lock is not serialized execution unless a runtime acquires, renews, fences, and releases it around the required critical section.
  9. Response boundaries are first-class. Some requirements are satisfied before an external response is committed.
  10. Configuration is typed, scoped, secret-aware, and integrated through Cohesive.Configuration.
  11. Projection backends are targets, not sources of semantic truth.
  12. The realization graph is inspectable and diagnosable.