Compose a native workspace and independent workloads¶
For data and platform engineers, release composition publishes one immutable release containing a complete native multi-project dbt workspace and a separate ordinary workload catalog. It verifies both source inventories before publication. Use this guide when the ordinary transfers are independently owned, rather than transfers generated by a dbt project's publishing policy.
Composition prepares delivery artifacts. It does not execute SQL, activate a deployment, or certify a live route. See the contract reference for supported inputs and operations guide for recovery, delivery, and upgrades.
Prepare the workspace and toolchain¶
Use compatible composition-aware core, Airflow provider, and runtime packages. Older readers reject release-set.v3. Keep the exact producer version recorded in the resulting release; changing the producer version can change the release ID.
Start in your repository root with a complete workspace configured through workspace authoring. That guide covers project publishing policies, the pinned dbt toolchain, and local manifest preparation. The compact workspace delivery guide explains the native input required here. Use distinct DAG IDs, workload IDs, artifact paths, and logical target relations across the workspace and ordinary workloads.
Set XCOM_SIDECAR_IMAGE to your approved digest-pinned sidecar reference before
running the following commands. Native compilation and ordinary inventory do not
pull images; actual runtime images and connection bindings require separate
platform preparation.
mkdir -p reports
dpone dbt workspace compile \
--root workspace --output-dir compiled-native --format json \
> reports/native-compile.json
dpone gitops airflow release-materialize \
--pack-root compiled-native --cache-root native-cache \
--xcom-sidecar-image "$XCOM_SIDECAR_IMAGE" --format json \
> reports/native-materialize.json
Check each command's exit status before continuing. The second report must have
passed: true; retain its release_id and release_dir. This compact native
release is the input to composition. Preserve its entire tree, including
release-set.json, source snapshot, integrity subject, schemas, and runtime
payloads. Do not copy selected dbt packs into a legacy _dags root.
Build an ordinary catalog through public producers¶
The following files describe one synthetic PostgreSQL transfer. source and
target are logical connection references; no credentials are embedded. The
image below is a synthetic digest-shaped reference for offline preparation;
replace it with your platform's approved immutable runtime image before delivery.
Create ordinary/manifests/orders.yaml:
name: ordinary_orders
source:
type: postgres
connection_ref: source
query: SELECT 1 AS id
sink:
type: postgres
connection_ref: target
table:
schema: public
name: ordinary_orders
strategy:
mode: full_refresh
Create ordinary/gitops.yaml:
gitops:
version: 1
defaults:
image: example.invalid/dpone@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
image_digest: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
environments:
dev:
namespace: airflow-example
runner_policy: advisory
includes:
- path: domains/*.yaml
Create ordinary/domains/sample.yaml:
domain: sample
workloads:
ordinary_orders:
manifest: ../manifests/orders.yaml
dags:
ordinary_daily:
schedule: null
start_date: "2026-01-01"
workloads: [ordinary_orders]
The ordinary composition capability admits a plain single-transfer manifest per workload, with optional referenced SQL files. It does not admit batch or authoring manifests, recipe expansion, hooks, transforms, custom runner assets, or dbt execution. Leave connection projection unconfigured: the final deployment owns runtime connection delivery. A secret-volume or Airflow environment bridge is not an interchangeable input to this procedure.
Inspect and compile the catalog:
dpone gitops workloads list --workload-set ordinary/gitops.yaml --env dev
dpone gitops airflow pack \
--workload ordinary_orders --workload-set ordinary/gitops.yaml --env dev \
--output-path .dpone/ordinary-preview/ordinary_orders/airflow-pack.json \
--format json > reports/ordinary-pack.json
dpone gitops airflow reconcile \
--workload-set ordinary/gitops.yaml --all-workloads --env dev \
--output-dir .dpone/ordinary-build --format json \
> reports/ordinary-reconcile.json
The single-pack command is an inspection step. Use the full reconcile output for
composition. Its pack root is .dpone/ordinary-build/airflow, containing
_dags/ordinary_daily.dag-spec.json and
ordinary_orders/airflow-pack.json. Keep reports outside that root. Use a fresh
reconcile destination when changing the catalog so stale workload directories do
not become orphan artifacts. The catalog guide and
reconcile runbook describe these producers.
Capture source identity and compose¶
dpone gitops airflow release-inventory \
--pack-root .dpone/ordinary-build/airflow \
--xcom-sidecar-image "$XCOM_SIDECAR_IMAGE" --format json \
> reports/ordinary-inventory.json
Exit 0 means the reader verified the DAGs, original pack fingerprints, detached
runtime archives, dependency closure, and supported producer reconstruction.
Retain inventory_sha256. Inventory does not publish or rewrite its source root.
The sidecar is validated here, but its choice is not part of the source inventory
digest.
Generate composition.yaml from the actual reports, rather than copying example
digests. Run this from the repository root, after verifying the inventory command
succeeded:
import json
import os
from pathlib import Path
import yaml
native = json.loads(Path("reports/native-materialize.json").read_text())
ordinary = json.loads(Path("reports/ordinary-inventory.json").read_text())
assert native["passed"] and ordinary["passed"]
manifest = {
"schema": "dpone.release-composition.v1",
"native_workspace": {
"root": str(Path(native["release_dir"]).absolute()),
"expected_release_id": native["release_id"],
},
"standalone": {
"root": ".dpone/ordinary-build/airflow",
"expected_inventory_sha256": ordinary["inventory_sha256"],
},
"transport": {
"profile": "compact_v2_runtime_connection_context",
"xcom_sidecar_image": os.environ["XCOM_SIDECAR_IMAGE"],
},
}
Path("composition.yaml").write_text(yaml.safe_dump(manifest, sort_keys=False))
dpone gitops airflow release-compose \
--manifest composition.yaml --output-dir composed-release --format json \
> reports/composition.json
--output-dir is the exact immutable destination, not a cache root. Relative
input roots are resolved from composition.yaml; the output path is resolved
from the command's working directory. All three roots must be disjoint. The
manifest and reports belong outside the immutable destination.
On exit 0, the report has passed: true, status: passed, the parent
release_id, the native source_release_id, and the ordinary inventory_sha256.
composed-release/release-set.json contains the explicit v3 envelope. Its
dags/, packs/, native runtime payloads, _composition/ source artifacts, and
release-subjects.sha256 form one immutable tree. No illustrative output here
substitutes for inspecting your own report.
Use the same service from Python¶
The Python entrypoint uses the same verifiers and publication semantics as CLI:
from pathlib import Path
from dpone.app.release_composition import build_release_composition_service
from dpone.manifest.release_composition_request import read_release_composition_request
service = build_release_composition_service()
request = read_release_composition_request(
Path("composition.yaml"), output_dir=Path("composed-release")
)
report = service.compose(request)
if not report.passed:
raise RuntimeError(report.to_dict())
print(report.release_id)
An identical retry verifies the same immutable destination. Never treat
durability_uncertain as success. Follow delivery and recovery
to install the complete parent into a cache and prepare its deployment projection.