InfrastructureDefinitionDocument
- Owns
- Portable workloads, resources, requirements, bindings, readiness dependencies, and lifecycle intent.
- Does not own
- Provider resources, deployment handles, or observed state.
Building Blocks
Cohesive.Infra defines portable infrastructure requirements, proves how a coherent target satisfies them, and records exact physical realization and lifecycle ownership.
Cohesive.Infra is the semantic boundary between application meaning and infrastructure lifecycle mechanisms. An application declares workloads, logical resources, required capabilities, bindings, and readiness dependencies. Target adapters contribute attributable evidence about the construction families they can provide. Shared compilers select a coherent target, prove capability coverage, and produce an exact realization.
Provider SDKs and deployment tools remain replaceable interpretations. They do not become the source of application or infrastructure meaning.
Infra keeps desired semantics, target evidence, physical realization, and observed state separate. Each artifact answers a different question and carries an exact fingerprint or reference to the inputs it interprets.
This is the infrastructure form of system language and realization: stable intent stays distinct from the tools that construct or observe it.
The canonical graph has two node families:
Bindings and readiness dependencies connect those nodes. Requirements attach provider-neutral capability identities to the node that demands them.
InfrastructureCapabilityId https = new("network/https");
InfrastructureCapabilityId documentAuthority = new("storage/document-authority");
InfrastructureCapabilityId changeFeed = new("storage/change-feed");
InfrastructureBindingContractId repositoryReadWrite = new("storage/repository-read-write");
var document = Infrastructure.Define(
id: new("shipping"),
revision: new("1"),
configure: infra =>
{
var api = infra.Workload(new("workload/api"))
.Requires(https);
var state = infra.Resource(new("resource/state"))
.Persistent()
.Requires(documentAuthority)
.Requires(changeFeed);
api.RequiresReady(state);
infra.Bind(new("binding/api-state"), api)
.To(state)
.As(repositoryReadWrite);
});Infrastructure.Define returns an immutable, normalized, serializable, fingerprinted InfrastructureDefinitionDocument. Collection order and builder objects are not semantic. Equivalent direct IR, generated manifests, imports, and fluent authoring normalize to the same document.
A resource declaration says that a role exists. A binding says how one node may rely on another and names the provider-neutral contract that must survive realization.
Binding elaboration profiles map exact contract identities to capability and assurance obligations. Those obligations may cover service discovery, configuration injection, identity grants, network policy, secret transport, telemetry, replacement order, or other properties of the path. Zero matching rules is unavailable; several matching rules are ambiguous. The compiler does not guess.
RequiresReady(...) carries a different meaning. It declares that one canonical node cannot be admitted as ready until another is ready. The realization compiler later lowers that semantic edge through exact workload placements and resource lifecycle bindings into a physical readiness obligation.
From semantic dependency to physical readiness
Declare the canonical readiness edge, then canonical intent, Select target facilities, then selected facilities, Place exact physical resources, then exact placement, Lower the readiness obligation
This prevents an application host, Compose file, or deployment program from becoming a second application topology.
A target adapter declares its selectable physical construction families with InfrastructureTargetFacilities.Define. A facility owns exact leaf capability evidence; the capability profile remains the authority for composition rules and operating boundaries.
var facilities = InfrastructureTargetFacilities.Define(
id: new("azure-pulumi/facilities/v1"),
profileId: new("azure-pulumi/capabilities/v1"),
target: new("pulumi-azure-native/3.16.0"),
variant: new("development"),
supportedDefinitionSchemaVersions:
[InfrastructureDefinitionDocument.CurrentSchemaVersion],
configure: target =>
{
target.Workload(new("azure/app-service"))
.Provides(AppServiceEvidence.Https);
target.Resource(new("azure/blob-storage"))
.Provides(BlobEvidence.ObjectStorage);
});
var plan = InfrastructureTargetCompiler.Compile(
document,
facilities,
ShippingBindings.Profile);The shared compiler selects one facility per logical node, resolves attributable conventions, elaborates binding obligations, and proves capability closure. A convention can choose among semantically valid alternatives or supply stable naming policy; it cannot invent requirements or weaken a guarantee.
Target variants such as local-aspire, azure-pulumi, or another adapter-defined environment are coherent alternatives. Compilation cannot cherry-pick individually convenient evidence from mutually incompatible variants.
Requirements and supplied capabilities use the same identity vocabulary. Every demand receives one inspectable disposition:
Evidence closes requirements
Application service facility capability HTTPS ingress maps to requirement API requires HTTPS as native support. Object storage facility capability Object authority maps to requirement State requires document authority as native support. Object storage facility capability Change feed maps to requirement State requires change feed as native support. Application service facility capability Workload identity maps to requirement Binding requires authenticated read/write as composed support: identity side. Object storage facility capability Object authority maps to requirement Binding requires authenticated read/write as composed support: resource side.
Composed proofs retain every intermediate and auxiliary evidence identity. Equally preferred valid proofs are ambiguous until policy selects one. Constrained evidence remains residual until an exact, demand-scoped boundary-acceptance policy supplies a rationale and attributable sources.
The result is capability closure, not a lowest-common-denominator feature check. The proof records why this exact target preserves this exact requirement.
Facility planning chooses construction families. InfrastructureTargetDeploymentManifest supplies the exact physical identities and environment participation needed to turn that plan into a realization.
InfrastructureLifecycleAuthorityId pulumiState =
new("pulumi/shipping/development");
var targetEvidence = InfrastructureSourceReferences.Target(
facilities.Profile.Target);
var deployment = InfrastructureTargetDeployments.Define(
id: new("shipping/azure-pulumi/development/v1"),
definition: document,
targetFacilities: facilities,
configure: physical =>
{
physical.Workload(
ShippingNodes.Api,
AzureFacilities.AppService,
AzureResources.AppService("shipping-api"),
[targetEvidence]);
physical.Resource(
ShippingNodes.State,
AzureFacilities.BlobStorage,
AzureResources.Container("shipping", "state"),
pulumiState,
[InfrastructureSourceReferences.LifecycleAuthority(pulumiState)]);
});
var deploymentPlan = InfrastructureTargetDeploymentCompiler.Compile(
ShippingInfrastructure.Current,
deployment);
var realization = deploymentPlan.Realization;Every canonical workload must be placed or explicitly declared non-participating with a rationale and sources. Silent omission fails. A binding or readiness edge from a participating node into a non-participating workload also fails because the declared physical environment cannot preserve the canonical path.
Placements do more than assign names. They construct demand-scoped capability witnesses, associate logical nodes with exact physical resources, and fence the realization to the definition, facility manifest, capability profile, binding profile, target, and variant that produced it.
Canonical resources declare one of three lifecycle intents:
One physical resource has one lifecycle authority. Another interpreter may consume that resource by declaring ReferencedResource(...) and naming both the manager and authority. The shared compiler then retains a managed binding for the owner and a referenced binding for the consumer.
physical.ReferencedResource(
ShippingNodes.State,
AspireFacilities.Postgres,
LocalResources.Postgres("shipping"),
dockerComposeTarget,
dockerComposeAuthority,
[InfrastructureSourceReferences.LifecycleAuthority(dockerComposeAuthority)]);Conflicting managers, ownership claims on canonical external resources, or aliases that disagree about lifecycle authority are structured errors. This makes ownership explicit across infrastructure interpreters instead of leaving it in deployment convention.
A successful realization proves semantic coverage and compiles exact readiness obligations. It does not prove that anything was deployed or is healthy.
Adapters normalize current backend evidence into InfrastructureResourceObservation values. The pure evaluator compares those attributable observations with one exact realization:
var assessment = InfrastructureReadinessEvaluator.Assess(
realization,
observations);The assessment returns one fingerprinted decision per physicalized logical node. Missing or unknown evidence fails closed. An unhealthy dependency blocks its subject even when that subject exposes an endpoint, and favorable runtime health cannot repair an incomplete capability realization.
Observation collection remains adapter work. The evaluator performs no I/O and does not deploy, mutate, restart, or reconcile resources.
InfrastructureLocalRealizationDocument is the shared input boundary for local lifecycle adapters. It combines an exact infrastructure realization with a versioned environment policy, resolved conventions, and a target-neutral construction topology.
The local topology can describe:
var topology = InfrastructureLocal.Define(local => local
.ProjectService(
ShippingNodes.Api,
LocalResources.Api,
new InfrastructureLocalProjectSource(
new("shipping-api"),
new("src/Shipping.Api/Shipping.Api.csproj")),
api => api
.Endpoint(
ShippingEndpoints.Http,
"http",
8080,
InfrastructureLocalEndpointExposure.HostLoopback,
InfrastructureLocalEndpointRole.Data,
ShippingConfiguration.ApiPort))
.ContainerService(
ShippingNodes.State,
LocalResources.Postgres,
"postgres:18.0@sha256:...",
postgres => postgres
.CommandHealth("pg_isready")
.HealthTiming(
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(1),
retries: 30)));
var localRealization = InfrastructureLocalRealizationCompiler.Compile(
realization,
ShippingEnvironments.Local,
topology,
[ShippingConventions.Local]);The compiler checks that local services agree with physical placements and lifecycle bindings, project sources attach only to workloads, images are pinned, referenced values exist, ports are valid, secrets remain external, health policies are complete, and destructive operations stay inside their named lifecycle authority.
Interactive and isolated-test profiles make data retention, project naming, maximum lifetime, and destructive authority visible. A local startup preference may remain an explicit compatibility override, but it is diagnosed when it has no matching canonical readiness dependency.
Cohesive.Infra is a zero-third-party-dependency semantic core. It does not reference Terraform, Pulumi, Aspire, Azure, AWS, GCP, Kubernetes, Docker, or their SDKs.
Dedicated adapters may:
They do not reimplement facility selection, capability closure, binding elaboration, lifecycle ownership, or readiness meaning. Current adapter packages include Docker Compose and Aspire projections, Aspire deployment integration for Pulumi, and an Azure Pulumi facility adapter.
Infrastructure compilation
Normalize the definition, then definition fingerprint, Select and prove the target, then facility plan, Compile the physical realization, then realization fingerprint, Assess attributable observations
Diagnostics are part of the programming model. Capability gaps, ambiguous proofs, unaccepted boundaries, binding gaps, participation conflicts, convention conflicts, lifecycle conflicts, missing witnesses, and unknown observations return stable diagnostic codes with semantic locations, source references, expected and observed states, and repair options.
Those structured artifacts can feed CLI text, JSON, SARIF, CI annotations, editors, tests, dashboards, or agent explanations without parsing rendered log messages.
Together these rules preserve the boundary between a portable semantic system graph and the compute, network, and storage systems chosen to realize it.