optional learning layer on #1365 — nothing else depends on it.
- each pipeline stage (rotate, upload, aggregate, load) emits openlineage run events (job, run, input/output datasets, row-count facets)
- instead of marquez, a small consumer writes the events into memgraph: lineage is a graph, so 'which stats are stale because an upstream job failed' is one cypher match instead of recursive sql
- attach the openlineage spark listener to ad-hoc jobs over the s3 logs for free column-level lineage
optional learning layer on #1365 — nothing else depends on it.