Lineage model¶
ZLens's lineage graph answers three questions:
- What depends on this? (impact analysis — downstream)
- Where did this come from? (trust chain — upstream)
- What's shared across teams? (cross-domain detection)
Node types¶
| Kind | Source |
|---|---|
source |
dbt source or warehouse table |
model |
dbt model |
term |
DQL business vocabulary term |
block |
DQL block |
business_view |
DQL business composition view |
notebook |
DQL notebook |
dashboard |
DQL dashboard |
metric / dimension |
Semantic layer object |
Edge types¶
| Kind | Meaning |
|---|---|
reads |
A queries from B |
defines |
A business term defines the meaning of a block or business view |
composes |
A block or business view is composed into a higher-level business view |
contains |
A embeds B (e.g. notebook contains block) |
materializes_to |
A is compiled into B (e.g. block → dashboard section) |
Extraction¶
SQL-level refs are extracted with node-sql-parser (not regex), which
correctly handles CTEs, subqueries, lateral joins, QUALIFY, and dialect
quirks. Semantic refs (@metric, @block, @table) are extracted from
the DQL AST directly.
Business terms are extracted from term declarations and terms = [...]
references on blocks and business views. Business composition refs are
extracted from business_view declarations:
term -> DQL block -> business_view -> dashboard/App
dbt source -> dbt model -> DQL block -> business_view -> dashboard/App
This separates technical data dependencies from business lineage. The technical lineage answers "what source/model/query produced this block?" Business lineage answers "what term does this implement, where was it composed, and where is it consumed by dashboards, Apps, or notebooks?"
Storage¶
Lineage is persisted in .dql/cache/manifest.sqlite and rebuilt
incrementally — only touched subgraphs are recomputed on a file change.
Warm rebuild on a 4,000-model project is under 2s.
CLI surface¶
zlens lineage summary
zlens lineage --term Customer # term -> block/view impact
zlens lineage --business-360 Customer # definition, composition, sources, consumers, gaps
zlens lineage --business "Customer 360" # business composition and technical backing
zlens lineage impact customers # downstream of `customers`
zlens lineage trust-chain revenue_q4 # upstream of a block
zlens lineage cross-domain # edges that cross domain boundaries
Business 360¶
zlens lineage --business-360 <node> builds a business-first snapshot from the
same local graph. It works for terms, blocks, business views, dashboards, Apps,
and notebooks.
For a term, ZLens first follows outgoing defines edges to the blocks and
business views that implement the term. It then traces upstream to source
tables, dbt sources, and dbt models, and traces downstream to dashboards, Apps,
notebooks, nested business views, and blocks.
For a business_view, ZLens shows the included blocks or nested views, then
uses those included artifacts to find technical sources and consumption. This
keeps the answer useful even when a dashboard consumes the composed block
directly rather than the view node itself.
The result also includes gaps, such as terms that do not define any artifact, views with no composition, missing upstream sources, or no downstream consumers. These are local graph gaps only; org-wide catalog search and cross-repo lineage stay outside the OSS local lineage surface unless that metadata is present in the project manifest.
For block-centric views, Business 360 also emits reusable block contracts: pattern, grain, declared outputs, allowed filters, parameter policies, filter bindings, source systems, and replacement references. This is how reviewers can distinguish a reusable parameterized block from static duplicate SQL created for one set of filter values.
Column-level lineage¶
Table-level lineage is fully open-source. Column-level lineage is a commercial feature in the DuckCode Cloud build — see the OSS/Cloud boundary. The manifest output is identical in both builds; column-level is gated at the surface, not in the graph.