Traçabilité au niveau des colonnes¶
Provisa assure le suivi de la traçabilité des données au niveau des colonnes de façon statique — calculée à partir des définitions SQL et des contrats de commande, sans exécution requise. Deux vues sont disponibles : un DAG par instruction et un graphe de provenance à l'échelle de la fédération couvrant toutes les vues et vues matérialisées (MV) enregistrées.
L'explorateur de traçabilité¶
Accédez à Lineage dans l'interface (/lineage). Collez une instruction SQL et cliquez sur Build statement graph pour voir son DAG au niveau des colonnes. Cliquez sur Federation graph pour charger le graphe de provenance sur chaque MV du registre. [tool-verified: LineagePage.tsx:28-119]
DAG au niveau de l'instruction (REQ-1160)¶
Chaque colonne de sortie nommée dans votre SQL devient un nœud. Le générateur la retrace à travers chaque CTE, sous-requête, jointure et appel de commande en ligne jusqu'à ses colonnes source, en construisant un graphe orienté depuis les entrées source jusqu'aux sorties finales.
Exemple détaillé¶
SELECT o.id, e.embedding, upper(e.geo) AS geo_u
FROM orders o
JOIN enrich_grpc_set('main.public.orders') e ON o.id = e.id
Cette instruction produit trois colonnes de sortie. Le graphe pour geo_u se présente ainsi :
orders.geo ──[enrich_grpc_set(...)]──► e.geo ──[UPPER]──► geo_u
orders.id ─╮ (taint closure)
orders.region ─╯
orders.id,orders.regionetorders.geosont des nœuds source (le contrat d'entrée étroit deenrich_grpc_setdéclareidetregion; la clôture de propagation (taint closure) complète relie toutes les entrées déclarées à toutes les sorties). [tool-verified:_splice_commandsen graph.py:223-242]e.embeddingete.geosont des nœuds command — la frontière deenrich_grpc_set.geo_uest un nœud derived produit par la fonction SQLUPPER.
La frontière de la commande n'est pas opaque. Comme enrich_grpc_set déclare ses colonnes d'entrée (id, region) et ses colonnes de sortie (id, embedding, geo), le moteur de traçabilité relie la clôture de propagation de façon continue depuis les colonnes déclarées de la relation source jusqu'à chaque sortie. [tool-verified: _splice_commands et _input_relation en graph.py:245-271]
Types de nœuds et repères visuels¶
[tool-verified: LineageDag.tsx:25-29, KIND_COLOR constants; LineagePage.tsx:21-26 LEGEND]
| Type de nœud | Couleur | Signification |
|---|---|---|
source |
Vert | Une colonne d'une table de base |
derived |
Bleu | Produite par une expression SQL (fonction, opérateur, CTE) |
command |
Violet | Une colonne de sortie d'une commande enregistrée |
Anneaux supplémentaires sur un nœud :
- Anneau orange — une colonne de sortie finale de l'instruction.
- Bordure double — la relation de la colonne est une vue matérialisée (instantané MV/CTAS).
- Anneau rouge — membre d'un cycle classé comme erreur.
- Anneau jaune — membre d'un cycle classé comme boucle de rétroaction.
[tool-verified: LineageDag.tsx:88-103 Cytoscape style selectors]
Transformations nommées sur les arêtes¶
Chaque arête porte l'expression SQL brute qui produit la colonne cible, ainsi qu'une liste d'opérations nommées : fonctions SQL (sql_function), opérateurs arithmétiques/logiques (operator), commandes enregistrées (command), références de colonne simples (identity) et littéraux (constant). [tool-verified: TransformOp and name_transform en graph.py:36-145]
Une arête issue d'un appel de commande est représentée par une ligne violette en pointillés dans l'interface. [tool-verified: LineageDag.tsx:122-124]
Graphe à l'échelle de la fédération (REQ-1161)¶
Le graphe de fédération fusionne la traçabilité par instruction de chaque MV enregistrée en un seul graphe de provenance. L'identité du nœud est relation.column — la colonne de sortie d'une vue et la référence d'entrée d'une autre vue vers la même colonne fusionnent en un seul nœud. Le résultat est un DAG unique allant des colonnes source de base jusqu'à chaque jeu de données dérivé de la plateforme. [tool-verified: build_federation_graph en merge.py:205-229 et qualify_outputs en graph.py:275-299]
Utilisez focus, direction et depth pour restreindre la vue à l'échelle de la fédération sans recalculer le graphe. [tool-verified: slice_graph en merge.py:160-189]
Cycles (REQ-1161)¶
Les cycles sont décrits, non rejetés. Le moteur de traçabilité détecte chaque cycle orienté et le classe. [tool-verified: Cycle.classification property en merge.py:43-46]
| Classification | Couleur de bordure | Signification |
|---|---|---|
feedback |
Jaune | Le cycle traverse un nœud matérialisé — une boucle de rétroaction légitime et décalée dans le temps. L'instantané de la MV constitue la limite de version qui la rend bien définie. |
error |
Rouge | Aucune limite de matérialisation sur la boucle — une définition circulaire sans ordre d'évaluation stable. Probablement une erreur de conception. |
[tool-verified: LineagePage.tsx:83-98 cycle alert rendering; merge.py:38-48]
Un cycle feedback n'est pas un échec. Une MV d'enrichissement qui réinjecte une colonne dérivée dans sa propre relation source est un schéma valide, à condition qu'un nœud de la boucle soit matérialisé — l'instantané isole les deux moitiés dans le temps. Un cycle error exige le jugement d'un opérateur : cela signifie généralement que deux vues se référencent mutuellement sans instantané intermédiaire.
API¶
Les deux points de terminaison sont statiques — ils lisent des définitions et des contrats, pas des données.
POST /admin/lineage/graph¶
Renvoie le DAG au niveau des colonnes pour une seule instruction SQL.
POST /admin/lineage/graph
Content-Type: application/json
{
"sql": "SELECT o.id, e.embedding FROM orders o JOIN enrich_grpc_set('main.public.orders') e ON o.id = e.id",
"dialect": "postgres"
}
[tool-verified: lineage_graph endpoint at lineage_router.py:45-54, LineageGraphRequest model at
lineage_router.py:29-31]
Forme de la réponse [tool-verified: LineageGraph.to_dict en graph.py:82-105] :
{
"nodes": [
{"id": "orders.id", "column": "id", "relation": "orders", "kind": "source", "materialized": false}
],
"edges": [
{
"source": "orders.id",
"target": "e.id",
"transform": "enrich_grpc_set(...)",
"ops": [{"name": "enrich_grpc_set", "kind": "command"}]
}
],
"outputs": ["id", "embedding"]
}
Renvoie HTTP 422 lorsque le SQL ne peut pas être analysé (parsé). [tool-verified: lineage_router.py:51-54]
GET /admin/lineage/federation¶
Renvoie le graphe de provenance fusionné sur toutes les MV du registre.
GET /admin/lineage/federation
GET /admin/lineage/federation?focus=orders.id&direction=downstream&depth=3
[tool-verified: federation_graph endpoint at lineage_router.py:73-98]
Paramètres de requête [tool-verified: function signature at lineage_router.py:73-76] :
| Paramètre | Valeurs | Par défaut | Effet |
|---|---|---|---|
focus |
Un id de nœud | — | Restreint la réponse au sous-graphe autour de ce nœud |
direction |
upstream | downstream | both |
both |
Direction de parcours à partir de focus |
depth |
entier | illimité | Distance maximale de sauts depuis focus |
La réponse a la même forme que le graphe d'instruction, avec un champ cycles ajouté
[tool-verified: MergedGraph.to_dict en merge.py:60-64] :
{
"nodes": [...],
"edges": [...],
"outputs": [...],
"cycles": [
{
"nodes": ["orders.region", "enriched_orders.region"],
"has_materialization_boundary": true,
"classification": "feedback"
}
]
}
Utiliser la traçabilité pour gouverner les contrats de commande¶
Comme la clôture de propagation relie chaque colonne d'entrée déclarée à chaque colonne de sortie déclarée, l'ampleur de cette clôture dépend entièrement de ce que vous déclarez.
Prenons une commande qui reçoit une table orders complète (id, region, amount, customer_id, discount, notes, ...) et renvoie un embedding. Si le contrat d'entrée énumère toutes ces colonnes, chaque colonne en aval qui utilise l'embedding affichera une traçabilité issue de toutes ces colonnes. C'est exact mais peu utile — il devient difficile de déterminer ce qui a réellement compté.
En déclarant uniquement id et text (les colonnes que le modèle d'embedding lit réellement), le cône de traçabilité se resserre sur ces deux colonnes source. La dérivation est alors à la fois rigoureuse et précise.
Consultez Commands pour connaître la mécanique de déclaration d'un contrat d'entrée étroit.