Relix

Problem solving

Why is this row here, where did it come from

Grain: one row per result (after WHY), then one per contributing source tuple (after μ) · Class: Explanation · Signals: why, where from, which inputs, how derived, trace back, provenance, justify · Operators: WHY (ω), μ

The problem

"This result row looks wrong — which source rows produced it, and how did they combine? I want to trace a surprising result back to the exact inputs behind it."

How to recognise it

The question is about a result you already have, not a new one — why is this here, where did this come from, which inputs does it depend on, justify this number. It is a debugging and audit question, and the answer is the row's lineage: the source tuples that produced it and the way they combined. WHY reifies that lineage as an ordinary nested column, so the rest of the algebra can slice it like any other data.

The tell that you want WHY and not a rerun: you are not trying to change the result, you are trying to account for it.

The data

Orders := [
| oid | cid | region | amount |
|-----|-----|--------|--------|
| 100 | 7   | west   | 40     |
| 101 | 7   | west   | 25     |
| 102 | 9   | east   | 10     |
];

Customers := [
| cid | name  |
|-----|-------|
| 7   | Ada   |
| 9   | Grace |
];

Recipe: reify lineage, then read it (WHY, μ)

WHY (R) emits every result row of R unchanged, plus one provenance column recording which source rows produced it. Wrap the query whose results you want to explain:

Query
Aug := { WHY (π region, amount (Orders ⨝ Orders.cid = Customers.cid Customers)) };
query { Aug };
Result
 region  amount  provenance
 ──────  ──────  ──────────────────────────────
 west        40  [{coefficient: 1, variables: …
 west        25  [{coefficient: 1, variables: …
 east        10  [{coefficient: 1, variables: …
(3 rows)

provenance is ordinary nested data — an array of derivations (the ways the row could arise), each an array of the source tuples that combined. So the ordinary operators read it: μ explodes a derivation array, and dotted paths read its fields. To name the exact source rows behind every west result, flatten one level to the derivations, lift the variables out, flatten again, and select:

Query
PerDeriv := { μ provenance (Aug) };
Lifted   := { π region, amount, provenance.variables → variables (PerDeriv) };
PerVar   := { μ variables (Lifted) };
query {
    π region, amount, variables.relation → source, variables.ordinal → ordinal
        (σ region = "west" (PerVar))
};
Result
 region  amount  source     ordinal
 ──────  ──────  ─────────  ───────
 west        40  Customers        1
 west        40  Orders           1
 west        25  Customers        1
 west        25  Orders           2
(4 rows)

Each result names the two tuples that combined to produce it, because a join is a joint derivation — one derivation, several variables. A result reachable two ways (a union of a duplicated value) would instead show two derivations. Nothing in that query is special to provenance: π, μ and σ do to provenance exactly what they do to any nested column, which is the whole point of reifying lineage as data.

Variations

Pitfalls

Check it