feat(lineage): new CLL experience with impact-aware column annotations#1278
feat(lineage): new CLL experience with impact-aware column annotations#1278
Conversation
Codecov Report❌ Patch coverage is
... and 4 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Add visual verification stories for the new CLL amber highlight: - Node Comparison: side-by-side impacted vs non-impacted nodes in light and dark mode for color tuning - Full Lineage Canvas: jaffle-shop-expand impacted subgraph layout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
- Pass newCllExperience/isImpacted through LineageNodeData for ReactFlow - Build mock CLL data with realistic column-level impact scenarios - Run each node through computeIsImpacted (same code path as production) - Limit to ~25 nodes with mix of impacted/not-impacted/unrelated - Export computeIsImpacted from @datarecce/ui/advanced - Fix cll undefined→null coercion in GraphNodeOss Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Pass newCllExperience flag from useRecceServerFlag to both toReactFlow call sites. When the flag is on, always capture existing node positions so nodes never jump when CLL data changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
- Replace `as any` with proper ColumnLineageData cast in story - Remove invalid `index` property from test column data - Biome auto-formatting fixes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
computeIsImpacted now also checks cllNode.columns (not just the flat cll.current.columns dict) for change_status. This catches the case where a downstream node like 'orders' has impacted columns stored on the node object rather than in the flat columns dict. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Rolling back toReactFlow newCllExperience option and LineageViewOss position locking. Focusing on correctness of impact computation first — columns and position stability will come after column-level impact propagation is working. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Replace node.impacted flag and direct change_status checks with computeImpactedColumns parent_map walk. A node is impacted if any of its columns trace upstream to a changed column. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Columns that trace upstream to a changed column via CLL parent_map now get an amber background in the schema sidebar. This helps users predict which columns would show differences in a profile diff. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
When newCllExperience is on: - toReactFlow skips column node creation (no columns on lineage map) - LineageViewOss always preserves existing node positions - Node height stays at base 60px (no column expansion) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
…ting Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
…CLL modes Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
539e715 to
dd07950
Compare
Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
There was a problem hiding this comment.
Pull request overview
Adds a new flagged column-level lineage (CLL) UX that overlays column ancestry/impact annotations on top of the existing impact-radius view, plus the supporting impact/ancestry computations and UI styling.
Changes:
- Introduces
--new-cll-experience/new_cll_experienceserver flag wiring (CLI →/api/flagconsumption). - Adds impacted node/column detection + column-ancestry annotation rendering (ReactFlow) for the new CLL experience.
- Updates schema sidebar + lineage node/column styling and extends tests/storybook coverage for the new behavior.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| recce/cli.py | Adds --new-cll-experience flag and includes new_cll_experience in server flag dict. |
| js/src/components/lineage/tests/LineageView.component.test.tsx | Updates mocks for new server-flag usage in lineage view tests. |
| js/src/components/lineage/tests/GraphNode.test.tsx | Extends contexts mock to include useRecceServerFlag. |
| js/packages/ui/src/lib/dataGrid/generators/toSchemaDataGrid.ts | Adds isImpacted to schema rows and marks impacted columns for styling. |
| js/packages/ui/src/contexts/lineage/types.ts | Extends lineage context/types with new CLL experience + impacted sets. |
| js/packages/ui/src/components/ui/dataGrid/dataGridFactory.tsx | Minor refactor to pass typed schema options into generator. |
| js/packages/ui/src/components/schema/style.css | Adds impacted-row background variables and classes for schema sidebar. |
| js/packages/ui/src/components/schema/SchemaView.tsx | Reads server flag and highlights impacted columns using frozen impacted set. |
| js/packages/ui/src/components/lineage/styles.tsx | Adds getStyleForImpacted amber background helper. |
| js/packages/ui/src/components/lineage/nodes/LineageNode.tsx | Supports new CLL props and impacted background; disables dimming in new mode. |
| js/packages/ui/src/components/lineage/LineageViewOss.tsx | Implements new CLL overlay flow: impacted sets, ancestry computation, layout preservation, cache patch helper. |
| js/packages/ui/src/components/lineage/lineage.ts | Updates toReactFlow for new experience and adds ancestry annotation node/edge generation. |
| js/packages/ui/src/components/lineage/GraphNodeOss.tsx | Passes newCllExperience and isImpacted down to node renderer. |
| js/packages/ui/src/components/lineage/GraphColumnNodeOss.tsx | Threads isImpacted through column-node data. |
| js/packages/ui/src/components/lineage/computeIsImpacted.ts | New helper to determine impacted nodes from changeStatus, node flag, and impacted columns. |
| js/packages/ui/src/components/lineage/computeImpactedColumns.ts | New memoized DFS to derive impacted columns from parent_map + change_status. |
| js/packages/ui/src/components/lineage/computeColumnAncestry.ts | New ancestry tracer for selected column producing per-model column annotations. |
| js/packages/ui/src/components/lineage/columns/LineageColumnNode.tsx | Applies impacted background styling for annotated column nodes. |
| js/packages/ui/src/components/lineage/tests/styles.test.ts | Adds unit tests for getStyleForImpacted. |
| js/packages/ui/src/components/lineage/tests/LineageNode.test.tsx | Adds tests for “no dimming” + impacted background behavior. |
| js/packages/ui/src/components/lineage/tests/lineage.test.ts | Adds test ensuring classic column nodes are skipped in new CLL experience. |
| js/packages/ui/src/components/lineage/tests/isImpacted.test.ts | New tests for computeIsImpacted. |
| js/packages/ui/src/components/lineage/tests/computeImpactedColumns.test.ts | New tests for computeImpactedColumns (chains, cycles, empties). |
| js/packages/ui/src/api/flag.ts | Extends RecceServerFlags with new_cll_experience. |
| js/packages/ui/src/advanced.ts | Exports new CLL helpers/types via @datarecce/ui/advanced. |
| js/packages/storybook/stories/lineage/CllExperience.stories.tsx | Adds storybook fixtures/demos for new CLL impacted/ancestry visuals. |
Comments suppressed due to low confidence (1)
js/src/components/lineage/tests/LineageView.component.test.tsx:141
- The mocked module object defines
useRecceServerFlagtwice; in an object literal the later key silently overrides the earlier one, which can mask issues and make the test setup misleading. Remove the duplicate and return a single consistent shape fordata(e.g. includenew_cll_experiencewhen needed).
vi.mock("@datarecce/ui/contexts", async () => {
const React = await vi.importActual<typeof import("react")>("react");
return {
useRouteConfig: vi.fn(() => ({ basePath: "" })),
useRecceServerFlag: vi.fn(() => ({ data: undefined })),
useLineageGraphContext: vi.fn(() => mockLineageGraphContext),
useRecceInstanceContext: vi.fn(() => mockRecceInstanceContext),
useRecceServerFlag: vi.fn(() => ({ data: {} })),
useRecceActionContext: vi.fn(() => ({
| /** | ||
| * Compute impacted node IDs and column IDs in a single pass over the CLL data. | ||
| * | ||
| * The expensive part is `computeImpactedColumns` (DFS over parent_map), so we | ||
| * run it once and thread the result into per-node checks. | ||
| */ | ||
| function computeImpactedSets( | ||
| lineageGraph: LineageGraph, | ||
| cll: ColumnLineageData, | ||
| ): { nodeIds: Set<string>; columnIds: Set<string> } { | ||
| const columnIds = computeImpactedColumns(cll); | ||
| const nodeIds = new Set<string>(); | ||
| for (const nodeId of Object.keys(lineageGraph.nodes)) { | ||
| const node = lineageGraph.nodes[nodeId]; | ||
| if ( | ||
| computeIsImpacted( | ||
| nodeId, | ||
| cll, | ||
| node.data.changeStatus as NodeChangeStatus, | ||
| columnIds, | ||
| ) | ||
| ) { | ||
| nodeIds.add(nodeId); | ||
| } | ||
| } | ||
| return { nodeIds, columnIds }; | ||
| } |
There was a problem hiding this comment.
computeImpactedSets calls computeIsImpacted for every node, and computeIsImpacted linearly scans the full impactedColumns set (via startsWith). This makes the overall computation O(numNodes × numImpactedColumns) and can get expensive on large graphs. Consider deriving nodeIds directly while computing impacted columns (e.g. parse the nodeId prefix from impacted column IDs) or maintaining a nodeId→impacted lookup map.
There was a problem hiding this comment.
keep as-is as this can be further perf enhancement.
| // Expand model node to fit its ancestry columns | ||
| if (annotations.length > 0) { | ||
| const modelNode = nodes.find( | ||
| (n) => n.id === modelId && n.type === "lineageGraphNode", | ||
| ); | ||
| if (modelNode) { | ||
| modelNode.height = 60 + 20 + annotations.length * COLUMN_HEIGHT; | ||
| } | ||
| } |
There was a problem hiding this comment.
Inside addColumnAncestryNodes, expanding each model node uses nodes.find(...) inside the loop over columnAncestry, which becomes O(n²) as the node list grows. Consider building an id -> node map once (or tracking model nodes as you create them) and updating heights via that map.
There was a problem hiding this comment.
keep as-is as this can be further perf enhancement.
|
This simplification is correct — |
Review Fixes Summary
|
- Add missing impactedColumnIdsRef snapshot in refreshLayout - Remove duplicate useRecceServerFlag() hook call - Fix docstring to match computeIsImpacted semantics (truthy, not !== false) - Remove duplicate useRecceServerFlag mock key that broke type-check - Revert drive-by iconColor simplification to keep PR focused Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Wei-Chun, Chang <wcchang@infuseai.io>
PR checklist
What type of PR is this?
Feature (behind
--new-cll-experienceflag)What this PR does / why we need it:
Adds a new column-level lineage (CLL) experience that treats column lineage as an annotation overlay on the impact radius view, rather than a separate mode. Behind the
--new-cll-experienceCLI flag.Specifically:
Here's a brief table of how the previous model and the new CLL use the three API calls:
If you run with both
--new-cli-experienceand--impact-at-startupthen you get layers 1&2 together immediatelyKey behaviors:
What's new:
--new-cll-experienceCLI flag +new_cll_experienceserver flagcomputeIsImpacted— three-signal impact detection (changeStatus, CLL node flag, parent_map walk)computeImpactedColumns— memoized DFS walk of parent_map for column-level impactcomputeColumnAncestry— traces selected column's upstream ancestry chaingetStyleForImpacted— amber highlight style for impacted nodes/columnsimpactedNodeIds/impactedColumnIdsrefs for cross-mode stabilitySpecial notes for your reviewer:
All behind
--new-cll-experienceflag — zero impact on existing behavior. Userecce server --new-cll-experience --impact-at-startupto test.TODO noted in code: move
isImpactedto per-model state on node data instead of a lookup set.UX Nites:
Open question:
Does this PR introduce a user-facing change?:
New
--new-cll-experienceflag for recce server that enables an improved column-level lineage visualization with impact-aware column annotations.Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com