Interop: DataLex contracts ↔ DQL blocks¶
This document specifies how a DQL block references a DataLex contract by id, and what compilers do with that reference.
The problem¶
Without a public binding, "DQL block X uses contract Y" is a comment in prose. Tools can't verify it, AI agents can't trust it, and contracts drift from the analytics that supposedly enforce them.
The contract¶
A DQL block declares the DataLex contract it implements via a top-level
datalex_contract field that holds an opaque, stable id of the form
<domain>.<entity>.<contract_name>:
block "Monthly Active Customers" {
domain = "customer"
type = "custom"
status = "certified"
datalex_contract = "commerce.Customer.monthly_active_customers"
description = "..."
query = """ ... """
}
The matching DataLex contract:
# DataLex/commerce.model.yaml
model:
name: commerce
domain: commerce
...
entities:
- name: Customer
contracts:
- name: monthly_active_customers
id: commerce.Customer.monthly_active_customers
description: Customers who placed at least one order in the calendar month.
signature:
inputs:
- name: order_month
type: date
outputs:
- name: monthly_active_customers
type: integer
constraints: ["positive"]
version: 1
Resolution rules¶
A consuming tool — including the DQL compiler from 1.6 onward — MUST resolve the reference as follows:
- The DataLex manifest emitted by the DataLex compiler is the source of
truth. Reading the YAML directly is permitted but the manifest is
canonical (see
v1/datalex-manifest.schema.json— published athttps://datalex.duckcode.ai/manifest-spec/v1/datalex-manifest.schema.jsonfor external consumers to pin). - The DQL compiler MUST locate a contract whose
idexactly matches the block'sdatalex_contractvalue. If no contract is found, compilation MUST fail with a clear error. - The DQL compiler MUST verify that every
outputs[*].namedeclared by the contract appears in the block's SQL output (column-level lineage in the DQL manifest provides the evidence). If a column is missing, compilation MUST fail. - The DQL compiler MAY warn (not fail) when the block produces extra columns not declared in the contract.
- A block MAY declare
datalex_contractwhile itsstatusisreviewordraft. In those statuses, compilers MUST NOT block the developer; the contract reference becomes a hard requirement only whenstatusreachescertified.
Versioning¶
DataLex contracts carry an integer version. When a contract version
increments, downstream DQL blocks pin a major version like
commerce.Customer.monthly_active_customers@1. Pinning is REQUIRED once
DataLex contract versioning ships (DataLex 2.0); until then, blocks
reference unversioned ids and the producing compiler emits a warning.
Lineage events¶
Manifests at both ends emit OpenLineage events describing the binding (see
the producing repos for the event schema). A DataLex contract change with a
breaking signature SHOULD raise an OpenLineage failed event downstream so
consumers (catalogs, observability tools) can surface impact without polling
the spec repo.
Compatibility table¶
| spec version | DataLex range | DQL range | Status |
|---|---|---|---|
| v1.0.0 | 1.8.x — 1.x | 1.5.x — 1.x | current |