Cohesive Systems logoCOHESIVE SYSTEMS

Search Cohesive Systems

Ready

Search Cohesive Systems

Find product pages, building blocks, technical articles, and graph definitions.

Capability Closure, Not Lowest Common Denominator

By Leo GorodinskiPublished Jun 18, 2026Updated Aug 5, 2026

A common critique of any cross-provider abstraction is that it must flatten every target into the lowest common denominator.

The critique is valid when the abstraction is only a thin uniform wrapper. If PostgreSQL, Cosmos DB, Kafka, Elasticsearch, Temporal, Orleans, and cloud infrastructure are all hidden behind a single generic facade, the facade can only expose what all targets already share. Everything distinctive becomes unreachable or has to leak through undocumented side channels.

Cohesive is designed against that failure mode. It does not treat provider differences as details to erase. It treats them as capabilities to model, compose, diagnose, and project from a semantic definition.

Capability closure is the design objective of modeling supported target capabilities as first-class, versioned claims, then relating semantic requirements to native mappings, composed strategies, diagnostics, overrides, and direct provider access when needed.

The goal is not the intersection of all backends. The goal is to decouple semantic structure from interpretation, then bind stable semantic constructs to the capability closure of modeled providers. Some mappings are native, some are composed from supporting facilities, some are unavailable and become diagnostics, and some require an intentional escape hatch into target-specific code. A reported match also carries assurance, because derived support, test-backed support, and a provider declaration are different kinds of evidence.

The Lowest Common Denominator Trap

Lowest-common-denominator abstractions usually start with a reasonable goal: make application code portable across targets.

The problem is the definition of portability. If portability means "only use the features every target has in exactly the same way," the abstraction becomes smaller than every real target beneath it.

For databases, that usually means hiding indexes, partition keys, constraints, change feeds, transactional guarantees, query planners, native operators, consistency levels, and execution diagnostics behind a generic repository API.

For workflow and runtime targets, it means hiding durable timers, replay rules, activity retry policies, actor placement, message ordering, leases, queues, streams, supervision, and compensation behavior behind generic "background job" or "process" vocabulary.

For infrastructure, it means hiding regions, identity boundaries, deployment topology, network policy, scaling behavior, secrets, managed resources, and provider-specific service limits behind a flat deployment model.

That kind of abstraction reduces the developer's precision. It makes easy cases look tidy, but it gives the system no language for explaining why a target is a good fit, a partial fit, or a bad fit.

Cohesive takes the opposite stance: provider differences matter because they are part of the system's operational semantics.

Capabilities, Not Facades

Cohesive models backend targets through capabilities rather than through a single facade. A capability is a statement about what a target can do and under which conditions. A requirement is a statement about what the semantic model needs from a target.

PostgreSQL can do relational joins; a query that traverses a relation has a requirement for that capability. Cosmos DB cannot do relational joins natively, but Cohesive can compose the same result through an in-memory join over multiple Cosmos queries or through a change-feed projection that denormalizes the data ahead of time. That difference is not erased — it is modeled.

Matching requirements against capabilities makes the abstraction larger, not smaller. It can express the semantic need, native support, composed strategies, constrained support, target-specific extension points, and cases where the selected backend cannot satisfy the requirement without additional runtime support.

This analysis is strongest inside a restricted kernel whose constructs and composition rules are known to the compiler. Outside it, a result may depend on configuration, tests, an adapter declaration, or an assumption the analyzer cannot discharge. Cohesive should distinguish:

  • a verified or statically derived match;
  • a match that holds under stated conditions;
  • a test-backed capability claim;
  • a capability declared by an adapter or provider;
  • an unsupported requirement;
  • an unknown result where the analyzer lacks enough information.

Capability results are versioned dependencies, not permanent facts. A provider upgrade, compiler change, configuration change, or escape-hatch revision can invalidate an earlier result and require affected projections to be analyzed again.

That is the sense in which Cohesive aims for capability closure. It is not "PostgreSQL and Cosmos both have feature X, therefore Cohesive exposes X." It is "the model requires behavior R; target A provides it natively, target B can realize it through strategy S plus constraint C, target C cannot realize it without an explicit extension."

Escape Hatches Are Part of the Model

Cohesive's bottom-up posture matters here. A Cohesive model is not meant to lock the developer away from PostgreSQL, Cosmos DB, Kafka, Elasticsearch, Temporal, Durable Task, Orleans, a cloud SDK, or a generated codebase.

Cohesive should first give developers normal extension points: capability declarations, compiler hooks, generated artifact overrides, target-specific options, and diagnostics. Those are not escape hatches. They are part of the abstraction's ordinary extension model.

The escape hatch is more basic: when the semantic model, compiler, and override surface are not enough, the underlying target client remains reachable through an explicit semantic boundary.

A query compiler may cover the common and composed cases. It may allow a backend-specific operator, index hint, analyzer choice, scoring override, projection binding, or runtime option. But a developer should still be able to drop to the PostgreSQL connection, Cosmos container, Elasticsearch client, Azure SDK, Temporal client, or infrastructure provider API and work with the target directly.

That last-resort path should be intentional, visible, and reviewable. It declares the semantic requirements it assumes, the capabilities and effects it introduces, the identities it realizes, and the evidence supporting those claims. A mechanically checked adapter may carry verified assurance. Generated or integration tests may justify test-backed assurance. A human assertion remains declared, and an uninspectable provider operation remains opaque.

Recording only that a generated path was replaced is not enough. The graph must also show which meaning now depends on that replacement and what Cohesive can no longer verify. This keeps target-specific code available without allowing it to become an invisible second source of semantics.

Escape-hatch frequency is also language-design evidence. A recurring shape may indicate a missing semantic concept or a compiler deficiency. Whether the language absorbs those patterns faster than new ones appear is an empirical question, so usage and assurance should be measured over time.

Diagnostics Over Silent Degradation

The worst abstraction does not merely hide a capability. It silently degrades semantics.

A query that needs stable ordering should not quietly become an unordered scan. A transition that needs atomic uniqueness should not become a best-effort check. A workflow that needs durable recovery should not become an in-memory callback. A tenant isolation requirement should not become a naming convention.

Cohesive makes these mismatches diagnostic:

Cross-entity atomic transition

Possible Diagnostic
Selected target supports atomic writes only within one partition.
Resolution Path
Choose a different target, revise the partition model, or compile to a process with compensation.

Relational query with filtered joins

Possible Diagnostic
Document target cannot realize this shape without a projection or denormalized read model.
Resolution Path
Generate a projection, change the query shape, or route this query to a relational target.

Reliable external effect

Possible Diagnostic
Transition writes state and emits an integration message without a shared durability boundary.
Resolution Path
Compile an outbox, use a change feed, or bind the effect to a durable workflow.

History-sensitive entity behavior

Possible Diagnostic
Current-state persistence loses information required by the invariant.
Resolution Path
Emit durable events, use event sourcing, or persist the required historical observation explicitly.

Low-latency search over mutable data

Possible Diagnostic
Authoritative store can answer the query but does not satisfy latency or indexing requirements.
Resolution Path
Project to a search target and make read-model freshness part of the contract.

A useful abstraction should enable precision. It is not vague convenience. It gives the system a vocabulary for saying exactly what is required, exactly what is available, and exactly where a proof obligation has not been discharged.

Compiler and HAL Tactics

Cohesive is closer to a compiler or an operating-system hardware abstraction layer (HAL) than to a conventional library facade.

A compiler does not pretend every CPU architecture is identical. It has an intermediate representation, a target description, optimization passes, calling conventions, intrinsic functions, feature flags, and diagnostics. When a target has a native instruction, the compiler may use it. When it does not, the compiler may lower the operation into a sequence of simpler operations. When the target cannot support the required semantics, compilation fails or asks for a runtime helper.

An OS HAL follows a similar pattern. Hardware differences are not erased. They are organized behind contracts, capability discovery, driver hooks, interrupt models, memory models, and fallback paths. The kernel can target many devices because it has a disciplined way to separate portable semantics from target-specific control.

Cohesive can use the same tactics:

Intermediate representation

Compiler / HAL Analogy
IR separates source language from machine code.
Cohesive Interpretation
The semantic system graph separates domain requirements from concrete storage, runtime, API, and infrastructure targets.

Target descriptions

Compiler / HAL Analogy
Backends declare registers, instructions, memory rules, and calling conventions.
Cohesive Interpretation
Providers declare transaction scope, query operators, partition behavior, consistency, indexing, workflow durability, and deployment limits.

Lowering

Compiler / HAL Analogy
High-level operations become target-specific instruction sequences.
Cohesive Interpretation
A relation, transition, or effect becomes SQL, document queries, projections, outbox entries, workflow steps, actor messages, or generated API code.

Intrinsics

Compiler / HAL Analogy
Source code can request a target-native operation intentionally.
Cohesive Interpretation
A model or generated artifact can bind to PostgreSQL extensions, Cosmos change feed, provider SDKs, or target-specific runtime hooks.

Optimization

Compiler / HAL Analogy
The same program can be optimized differently per architecture.
Cohesive Interpretation
The same query or projection can choose indexes, denormalization, batching, caching, or materialization strategies per backend.

Diagnostics

Compiler / HAL Analogy
Unsupported instructions, unsafe casts, and ABI mismatches are compile-time errors.
Cohesive Interpretation
Capability mismatches become model diagnostics rather than runtime surprises.

The abstraction is therefore not a ceiling. It is an analysis and realization-planning layer between semantic requirements and target-specific mechanisms.

SQL as a Precedent

SQL is a useful precedent because it is both portable and target-specific.

The relational model gives developers a shared language for selecting, joining, filtering, grouping, constraining, and updating data. That shared language did not prevent PostgreSQL, SQL Server, Oracle, MySQL, SQLite, and other engines from building distinct planners, indexes, isolation behavior, extensions, execution strategies, and operational profiles.

The strongest SQL systems are not successful because they expose only the features common to every engine. They are successful because the common relational core is valuable, the optimizer has target-specific freedom, and providers expose extensions when the standard vocabulary is not enough.

Cohesive adopts the same lesson:

  • Define precise shared semantics for the parts of the domain that carry operational meaning.
  • Let each target optimize, specialize, or override how those semantics are realized.
  • Model target-specific capabilities explicitly through first-class capability declarations and diagnostics.
  • Keep generated artifacts inspectable and extensible.

This provides semantic portability, not uniform operational equivalence. A requirement may preserve its identity across targets while its realization changes latency, cost, staleness, failure modes, coordination needs, or capacity. Those differences belong in the result rather than behind the abstraction.

That is a higher bar than a generic repository or universal adapter. It also preserves more power.

Example: Search Query Migration

Consider a migration from Azure Search to Elasticsearch.

In practice, such a migration often means rewriting every query, filter, sort, facet, and aggregation against the Elasticsearch client. Azure Search and Elasticsearch both support search, but their query surfaces are not the same: Azure Search combines OData filters, Lucene-style search syntax, facets, and scoring profiles; Elasticsearch exposes a richer query DSL, aggregation model, and analyzer configuration.

A lowest-common-denominator abstraction would expose only the operations both targets share in the same way. That is not enough for a non-trivial scenario.

A Cohesive.Relations query can keep query requirements explicit. A query definition can represent text search, field predicates, ordering, field selection, aggregations, pagination, and scoring intent without committing up front to either backend. The Azure Search compiler can lower structured predicates to OData filters and text search to Lucene-style clauses. The Elasticsearch compiler can lower the same semantic query to the Elasticsearch SDK. Capability checks decide which parts are native, which parts are composed, which parts need an override, and which parts should fail with a diagnostic.

The tabs below show this capability-requirement pattern applied to search queries, database queries, and database updates.

Search query requirements mapped to target capabilities

Azure Search capability OData filters + Lucene query syntax maps to requirement Full-text search as native support. Azure Search capability Sorting + continuation maps to requirement Sorting & pagination as constrained support: No PIT or hierarchical sort. Azure Search capability Facets maps to requirement Aggregations as constrained support: Facets only. Elasticsearch capability Elasticsearch query DSL maps to requirement Full-text search as native support. Elasticsearch capability PIT search + hierarchical sorting maps to requirement Sorting & pagination as native support. Elasticsearch capability Rich aggregations DSL maps to requirement Aggregations as native support.

Native

Directly supplied by the target.

Composed

Compiled strategy assembled from target facilities.

Constrained

Supported only inside a declared target boundary.

A fuller Cohesive.Relations example can extend this same pattern to the source-data queries that populate the index.

Practical Design Implications

The practical proposal is to make capability modeling part of the product surface, not an internal implementation detail.

  • Capability graph per target. A developer can ask: what does this target support natively, what does Cohesive synthesize, what requires an auxiliary runtime, and what remains unavailable?

  • Generated artifacts carry provenance. A SQL query, document projection, API route, workflow, actor, index, or infrastructure resource points back to the semantic requirement that produced it.

  • Capability results carry assurance and dependency fingerprints. A result states whether it was derived, conditional, test-backed, declared, unsupported, or unknown, and which compiler, provider, configuration, and evidence revisions it depends on.

  • Overrides are explicit and local. If a developer replaces a generated query with target-specific SQL, the model knows that this projection has a native override rather than treating the change as a forked artifact outside governance.

  • Target selection is explainable. Cohesive can say why PostgreSQL is a better realization for one relation, why Cosmos is a better realization for one entity family, why Elasticsearch is a projection rather than an authoritative store, or why a transition needs a durable workflow instead of a simple request handler.

  • Failure is precise. The right answer is sometimes "this model cannot be shown to be realizable on this target with these guarantees and the available evidence." That separates a known mismatch from an analyzer that does not yet know enough.

That is not lowest common denominator. It is the pursuit of capability closure: semantic requirements compared with explicit target capabilities through native mappings, composition, diagnostics, overrides, and direct target access, with the limits and assurance of each result kept visible.