Hybrid of dbt Labs Option 1 (PR-to-main flow) + Option 2 (UAT environment)
Failed CI or rejected sign-off → developer pushes fixes, flow re-runs from step 2.
flowchart TB
subgraph Dev["1. Development"]
A[Create feature branch from main]
B[Open PR targeting main]
A --> B
end
subgraph CIzone["2. CI Validation"]
C{"CI Job runs
state:modified+ deferred to prod
DAG overlap skips redundant retests
Fan-out capped at +3 if needed"}
end
subgraph UATzone["3. UAT (ephemeral only, auto-deploys on CI pass)"]
D["Ephemeral schema per PR
uat.ct_test_pr_N
isolated validation vs prod baseline"]
E["On-demand combined schema
uat.ct_test_combined_N_M
only created when another open PR
has DAG overlap with this one"]
G{"UAT sign-off"}
end
subgraph Prodzone["4. Production"]
H["Merge PR to main
= prod deployment"]
J["Other open PRs auto-revalidate
only if DAG overlap with merged change"]
end
B --> C
C -->|Pass| D
C -.->|if DAG overlap with another open PR| E
D --> G
E -.-> G
G -->|Approved| H
H --> J
classDef devNode fill:#e3f2fd,stroke:#1976d2,color:#0d47a1
classDef ciNode fill:#fff8e1,stroke:#f9a825,color:#5d4037
classDef uatNode fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
classDef uatOptional fill:#fbf5fc,stroke:#7b1fa2,color:#4a148c,stroke-dasharray: 5 5
classDef prodNode fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
class A,B devNode
class C ciNode
class D,G uatNode
class E uatOptional
class H,J prodNode
state:modified+ deferred to prod builds only models the PR actually changed. Capped at +3 only on big fan-outs (e.g. conformed dims), not the full ~6000 model project.uat.ct_test_pr_N), deferred to the prod baseline. No cross-contamination between teams, no shared catalog drift, no uat branch to reset.uat catalog: Isolation is at the schema level, not the catalog level. Catalogs are heavyweight; schemas are cheap to create and tear down.