# Orchestration is contract-compiled Airflow Assets

The orchestration plane uses Airflow 3.2 Assets as the local-first control-plane
projection for data products. The authored contract schema remains the Git source
of truth: Airflow asset names, URIs, groups, freshness metadata, producer hints,
and dependency edges are compiled from contracts rather than hand-authored in DAGs.

## Decision

Compile the Airflow asset graph from the contract corpus under `ingestion/**/contracts/`
and `transform/**/contracts/`.

- Each contract produces one Airflow Asset projection with `name` equal to the
  contract `id`, `uri` under `x-datalake://<domain>/<product-path>`, `group` equal
  to the product `layer` or `source` for source contracts, and contract metadata in
  `extra`.
- `declared_lineage.upstreams[]` becomes the dependency graph. A producing task
  consumes upstream assets as inlets or asset schedules and emits its own product
  asset as an outlet.
- Contract-backed upstream refs (`kind: data_product` or `kind: source`) that are
  not present in the current corpus compile as explicit external upstream Assets
  under `x-datalake://external/...`. This keeps the Airflow graph schedulable while
  making missing contracts visible in the manifest.
- `assets[].produced_by.kind` and `assets[].produced_by.ref` select the later
  operator family: `dbt` maps to the dbt/Cosmos slice, transform/python refs map
  to Python jobs, and ingestion extract/load refs map to their own orchestration
  slices.
- DAG files stay thin registration modules. Business dependencies live in contracts
  and orchestration config, not inside hand-written DAG control flow.

The v0 orchestration compilation profile requires exactly one `assets[]` entry per
contract and a `produced_by` block on that asset. The authored contract schema may
allow broader future shapes; this compiler rejects them until the orchestration
profile is deliberately extended.

This settles the orchestration engine shape for the local v1 plane. Production
hosting and deployment topology remain separate decisions.

## Consequences

The contract compiler is pure, deterministic, side-effect-free, and warehouse-free.
Scheduler parse should read a precompiled manifest if corpus parsing becomes too
expensive; the manifest is still a projection of Git contracts, not a second source
of truth.

Removing or renaming a contract can orphan Airflow metadata. Stale-asset cleanup
must compare the current compiled asset-name set with the previously registered set
and retire missing assets deliberately. The current set includes both contracted
Assets and explicit external upstream Assets. The compiler exposes that difference;
it does not silently delete metadata during parse.

The observed-lineage event model is still deferred. OpenLineage remains a likely
event emission target for a later story, but this ADR only decides the
contract-to-Airflow asset projection.

## Scope Boundaries

This ADR does not implement dbt/Cosmos execution, transform/python execution,
ingestion operators, contract test gates, agent actions, or production deployment.
Those remain separate orchestration stories.
