Skip to main content
Every Flow target executor writes a _kaireon_lineage JSONB column on every row it loads. The Lineage tab in the Flow Editor UI reads that column to show you which run + source node produced any row in the table.

What’s stored

For every loaded row, the column carries:
{
  "runId": "uuid-of-pipeline-run",
  "pipelineId": "uuid-of-pipeline",
  "sourceNodeId": "src",
  "writeOrder": 1
}
The column is added idempotently via ALTER TABLE … ADD COLUMN IF NOT EXISTS _kaireon_lineage JSONB the first time a target writes to that table. Pre-Phase-6 tables won’t have the column until you re-run the pipeline.

API

GET /api/v1/lineage?schema=public&table=ds_customer&limit=100
Tenant scoping: the (schema, table) pair must match a data_schemas row owned by the current tenant. ds_* tables only — public-but-unmanaged tables are not exposed. Response shape:
{
  "schema": { "id": "...", "name": "customer", "displayName": "Customer" },
  "table": "public.ds_customer",
  "lineageColumn": "_kaireon_lineage",
  "rows": [
    {
      "row": { "id": 1, "name": "Alice", ... },
      "lineage": { "runId": "...", "pipelineId": "...", "sourceNodeId": "src" }
    }
  ],
  "count": 50
}
When the target table has no _kaireon_lineage column (pre-6.0 table that hasn’t re-loaded), the response is 400 with a remediation message — never silently empty.

Walk-back path

Click a row in the Lineage tab → a panel expands showing the IR DAG path from the source node forward to the target, broken into pills:
[ src ] → [ t ] → [ v ] → [ tgt ]
This reads the IR for the version captured in the run’s metadata.irVersion. Older runs whose source nodes no longer exist in the current IR surface as “Source node X not found in current IR — likely an older run from a previous IR version”.

Limits

  • Default limit: 100 rows (clamp [1, 1000])
  • Ordering: ORDER BY ctid DESC (most-recent insert first)
  • Multi-input joins: the walk follows the first input only — full multi-parent visualization is a Wave 4 polish plan