gold.decision_context est le socle de la couche décision. Il matérialise une ligne par
(organization_id, variant_id, shop_id, snapshot_date), consolidant l’état du stock, la marge,
la prévision et les clés de dimension en une forme unique que chaque scorer du vecteur de
décision lit. On le construit une fois, on le score de trois façons.
| Concept | Valeur |
|---|---|
| Grain | une ligne par (organization_id, variant_id, shop_id, snapshot_date) |
| Clé primaire | ["organization_id", "variant_id", "shop_id", "snapshot_date"] |
| Mode d’écriture | MERGE sur la PK (reruns idempotents le même jour) |
| Clustering | (organization_id, snapshot_date, variant_id) |
| Rétention | 90 jours de snapshots quotidiens par position (imposée par le writer) |
| Writer | BuildDecisionContextTask (pipelines/layers/gold/tasks/build_decision_context/) |
Lignage — trois entrées gold
Le builder s’ancre surgold.stock_snapshot (une position = une ligne de stock) et y joint en
LEFT JOIN la marge et la prévision, après avoir agrégé chaque entrée sur size_taxonomy_id.
stock_snapshotest l’ancre : aucune position → rien à construire (skip_task_if_empty).sales_kpisfournitgross_margin_pct(LEFT JOIN sur la clé de position).sales_forecastsest best-effort — filtré àgranularity = 'daily', sommé sur la fenêtre des 30 prochains jours ; une prévision manquante laisse la colonne NULL.
Référence des colonnes
Les colonnes d’audit (created_at, updated_at) sont omises. aged_stock_flag est la seule
colonne hors position en NOT NULL.
État du stock
| Colonne | Type | Signification | Source / transformation |
|---|---|---|---|
current_stock | DOUBLE | Quantité en stock à snapshot_date | stock_snapshot.current_stock_qty, SUM sur les tailles |
target_stock | DOUBLE | Stock cible de la position | v1 : toujours NULL (hook Phase 2) |
days_of_cover | DOUBLE | Jours de couverture au rythme actuel | stock_snapshot.days_of_supply, MIN sur les tailles |
lead_time_days | INT | Délai d’approvisionnement | v1 : toujours NULL (arrive avec la dimension fournisseur) |
Ventes et marge
| Colonne | Type | Signification | Source / transformation |
|---|---|---|---|
gross_margin_pct | DOUBLE | Marge brute % réalisée | LEFT JOIN sales_kpis |
sell_through_7d / 30d / 90d | DOUBLE | Taux d’écoulement | v1 : toujours NULL (calcul par position en Phase 2) |
aged_stock_flag | BOOLEAN | Indicateur de stock dormant (NOT NULL) | (snapshot_date − last_sale_date) ≥ aged_stock_threshold_days (défaut 90) ; false si parse échoue |
Prévision
| Colonne | Type | Signification | Source / transformation |
|---|---|---|---|
forecast_30d | DOUBLE | Prévision de demande 30 jours | SUM sales_forecasts.quantity sur (snapshot_date, +30] |
forecast_confidence | DOUBLE | Confiance de la prévision 30 jours | AVG forecast_confidence sur la même fenêtre |
Clés de dimension (matching de périmètre des règles)
| Colonne | Type | Signification | Source |
|---|---|---|---|
brand_id | STRING | Marque (dénormalisée) | passthrough depuis la ligne stock_snapshot ancre |
category_id | STRING | Catégorie | v1 : toujours NULL |
supplier_id | STRING | Fournisseur | v1 : toujours NULL |
Slots toujours-NULL en v1
Sept colonnes sont typées et réservées mais toujours NULL en v1 —target_stock,
lead_time_days, sell_through_7d/30d/90d, category_id, supplier_id. Leur type et leur
nullabilité sont stables pour que le writer puisse les remplir plus tard sans migration DDL.
La couche de scoring traite NULL comme « ignorer ce signal pour cette position » en
ramenant chaque entrée NULL à une valeur neutre avant les calculs (documenté par domaine sur
la page suivante).
Validation
Les règles sont embarquées sur le schéma et appliquées par le writer :- Erreurs (échouent la tâche) :
decision_context_not_empty,decision_context_required_fields(organization_id,snapshot_date,aged_stock_flagnon-NULL),decision_context_pk_unique. - Avertissements : contrôles de non-négativité sur
current_stock,days_of_cover,forecast_30d.
DecisionContextHealthTask lève des brèches [freshness] (pas de snapshot récent) ou
[row-count-drift] (la tranche du jour diverge de celle de la veille) pour le triage on-call.
Source
- Schéma :
pipelines/shared/schemas/gold/decision_context.py - Writer :
pipelines/layers/gold/tasks/build_decision_context/task.py - Doc repo :
docs/gold/decision-context.md

