Passer au contenu principal
La data platform écrit gold.decision_vector et gold.action_vector, les réplique vers Lakebase Postgres, et l’app Solya les y lit. Cette page couvre le côté app : comment ces vecteurs sont lus, filtrés, affichés, attribués et transformés en action.

Chemin de lecture — schéma analytics + services

Les tables gold sont exposées en schémas Drizzle en lecture seule sous src/server/database/analytics/schema/gold/ (decision-vector.ts, action-vector.ts), avec les constantes de colonnes dans src/constants/datasetColumns/gold/. Trois services les encapsulent :
ServiceLitSert à
decisionVectorsscores decision_vectorenrichir les articles d’alerte déclenchés au dernier snapshot
actionVectorsrecommandations action_vectorpré-remplir les articles de plan, matérialiser les tâches
decisionDistributiondecision_vector agrégéstats d’urgence au grain variante / produit / marque
La constante DecisionDomain, les clés JSONB scores et les seuils d’urgence vivent dans src/constants/decisionDistribution.ts — une source de vérité unique partagée par l’orchestrateur SQL et les helpers d’UI.

Seuils d’urgence & heatmap

URGENCY_THRESHOLDS mappe les scores bruts en drapeaux « action requise », couleurs de chips et paliers de heatmap :
URGENT:           0.5            // marque un (variante, magasin) comme nécessitant une action
CHIP_WARNING:     0.3
CHIP_ERROR:       0.6
TIER_BREAKPOINTS: [0.2, 0.4, 0.6, 0.8]   // heatmap à 5 bandes
decisionDistribution les agrège — p. ex. shopsInRestockZone compte les magasins avec restock_urgency ≥ 0.5, et le résumé marque surface un urgentCount inter-domaines.

Workflows pilotés par score

Les stratégies ADD_ITEMS_TO_PLAN des workflows routent vers la couche décision (src/types/workflows.ts) :
  • scoreDriven (quantité / matching) — le resolver de la data platform lit le vecteur de décision pour fixer la quantité ou apparier les magasins de rebalance. Aucun paramètre côté app.
  • recommended (markdown) — remise de la couche décision avec trois bornes (fallbackPercent 15, maxDiscountPct 70, marginFloorPct 0).
Voir Workflows — actions de plan pour la config complète.

CREATE_TASKS — matérialiser le vecteur d’action dans la boîte de réception

L’action de workflow CREATE_TASKS transforme les lignes action_vector en tâches PRODUCT_ACTION, scopées aux paires (variantId, shopId) matchées par le déclencheur :
{ "actionType": "CREATE_TASKS", "domains": ["restock", "markdown"], "minConfidence": 0.7 }
  • domains — un sous-ensemble non vide de ["restock", "rebalance", "markdown"].
  • minConfidence — les lignes sous ce seuil sont supprimées ; les lignes à confiance null (p. ex. restock) sont toujours conservées.

Filtrage par confiance à la lecture

getActionVectorsForItemsAction (palier riche de l’espace alertes, reco de référence en revue de plan) applique le seuil de confiance global de l’org à la lecture : une ligne dont la confiance est sous le seuil est renvoyée avec resolved: false, pour que l’UI la traite comme « pas de recommandation — saisie manuelle » plutôt que de pré-remplir une valeur peu fiable. Le hook de revue de plan usePlanReviewReferenceReco récupère des lignes action_vector (dédupliquées, plafonnées à 200 paires) uniquement pour les lignes sans snapshot stocké — afin que les écrans de revue affichent une recommandation de référence même pour les lignes ajoutées manuellement.

Lignage immuable par article

Quand un article est émis dans un plan depuis une recommandation, le decisionVectorSnapshot de la stratégie est capturé à l’émission et stocké de façon immuable sur l’article de plan (*_plan_items.decision_vector_snapshot, plus applied_rules). La forme est PlanItemDecisionVectorSnapshot (src/types/planItemLineage.ts) : capturedAt, strategyId / strategyVersion, confidence, markdownScore / agedStockFlag (markdown), et un fallback snapshot_date. Elle est en .passthrough() pour la compatibilité ascendante.
Le snapshot est immuable — il enregistre la décision originale de la stratégie. Les éditions ultérieures de quantité / remise ne doivent jamais l’écraser. Les articles ajoutés manuellement portent un snapshot NULL.

LineageBadge — recommandé vs final

LineageBadge (src/components/shared/chips/LineageBadge.tsx) surface l’écart entre ce que la stratégie a recommandé et ce qui a finalement été persisté (après contraintes OTB / budget / fournisseur). Il n’affiche rien quand il n’y a ni recommandation ni règle appliquée, ou quand la recommandation égale la valeur finale sans delta de contrainte — sinon il montre la valeur recommandée avec une infobulle des règles appliquées et l’id de stratégie.

Attribution d’audit

Chaque article recommandé est attribué dans le journal d’activité du plan. Une attribution DECISION_VECTOR porte un decisionVectorId renvoyant au snapshot ; MANUAL et WORKFLOW_FALLBACK ne portent aucune référence de snapshot (src/constants/planAuditLog.ts).

Source (app)

  • Schéma analytics : src/server/database/analytics/schema/gold/{decision-vector.ts, action-vector.ts}
  • Services : src/server/services/{decisionVectors, actionVectors, decisionDistribution}/
  • Constantes : src/constants/decisionDistribution.ts, src/constants/taskConfidence.ts, src/constants/planAuditLog.ts
  • Lignage : src/types/planItemLineage.ts, src/components/shared/chips/LineageBadge.tsx
  • Workflows : src/types/workflows.ts