> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solya.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Couche décision — vue d'ensemble

> Comment Solya transforme l'état brut de l'inventaire en recommandations classées : le pipeline decision_context → decision_vector → action_vector et sa consommation par l'app.

La **couche décision** est le moteur de recommandation de Solya. Elle s'exécute
quotidiennement sur la data platform (Databricks) et transforme l'état brut de l'inventaire en
**recommandations classées et explicables** — combien d'unités réassortir, quelle remise
appliquer, quoi transférer entre magasins — que l'app surface dans les alertes, les plans, les
tâches et les workflows.

C'est un **pipeline en trois étapes**. Chaque étape est une table de la couche gold, calculée
dans l'ordre :

1. **`gold.decision_context`** — une ligne de snapshot consolidée par position (stock, marge,
   prévision, clés de dimension).
2. **`gold.decision_vector`** — des **scores de risque/urgence** par domaine dérivés du
   contexte (urgence de réassort, risque de rupture, surplus/déficit, urgence de transfert…).
3. **`gold.action_vector`** — la **recommandation résolue** (une quantité ou une remise) plus
   un snapshot enrichi du « pourquoi », dérivés des scores.

L'app lit l'`action_vector` précalculé (et les scores `decision_vector` sous-jacents) via
Postgres et les utilise pour pré-remplir les plans, matérialiser les tâches, piloter les
stratégies de workflow par score, et attribuer chaque article recommandé à sa source.

```mermaid theme={null}
flowchart TD
  subgraph DP["Data platform (Databricks · quotidien)"]
    SS[gold.stock_snapshot]
    SK[gold.sales_kpis]
    SF[gold.sales_forecasts]
    DC[gold.decision_context<br/>1 ligne / variante×magasin / jour]
    DVr[decision_vector · restock]
    DVb[decision_vector · rebalance]
    DVm[decision_vector · markdown]
    DV[gold.decision_vector<br/>scores + actions autorisées/interdites]
    AV[gold.action_vector<br/>qté / remise recommandée + pourquoi]

    SS --> DC
    SK --> DC
    SF --> DC
    DC --> DVr
    DC --> DVb
    DC --> DVm
    DVr --> DV
    DVb --> DV
    DVm --> DV
    DV --> AV
  end

  AV -->|sync CDC Lakebase| LB[(gold_lakebase.*<br/>Postgres)]
  DV -->|sync CDC Lakebase| LB
  LB --> APP["App Solya<br/>alertes · plans · tâches · workflows"]
```

## Les deux vecteurs, en une phrase

* Un **vecteur de décision** répond à *« à quel point cette position est-elle risquée /
  urgente ? »* — des scores bruts dans `[0, 1]`, sans unité.
* Un **vecteur d'action** répond à *« que faut-il donc faire ? »* — une quantité ou un
  pourcentage de remise concrets, avec une confiance et une explication.

Le vecteur de décision est **en amont** ; le vecteur d'action est la forme **résolue** sur
laquelle l'app agit. La résolution est faite par des « cœurs de résolution » partagés que le
batch quotidien et la simulation à la demande de l'app appellent tous deux — garantissant que
les valeurs précalculées correspondent à ce qu'une simulation interactive produirait.

## Grain — variante × magasin, sans axe taille

Chaque étape est clé sur `(organization_id, variant_id, shop_id, snapshot_date)` — et, à partir
du vecteur de décision, un axe `domain`. Il n'y a **délibérément pas d'axe `size`** :
`decision_context` agrège chaque entrée de scoring sur `size_taxonomy_id`, donc les
recommandations sont au niveau variante et l'app agrège les tailles pour l'affichage. (Le
dimensionnement par taille — p. ex. la répartition par courbe de tailles du réassort — se fait
plus tard, dans l'app, à l'ajout des articles au plan.)

## Snapshots quotidiens et idempotence

Chaque table est un **snapshot quotidien**. Les writers utilisent `MERGE` sur la clé primaire,
donc :

* relancer un build le même jour calendaire met à jour les lignes en place (un no-op à
  l'octet près si les entrées sont inchangées — le scoring est déterministe) ;
* différents domaines pour le même `(variant, shop, snapshot_date)` coexistent (valeurs de
  `domain` distinctes) ;
* les tranches quotidiennes antérieures sont préservées (`decision_context` conserve une
  fenêtre de rétention de 90 jours).

Les tables de la couche décision sont répliquées vers Lakebase Postgres
(`<env>.gold_lakebase.*`) via une sync CDC déclenchée, donc l'app les lit en Postgres à faible
latence au grain variante / produit / marque.

## Les trois domaines de décision

| Domaine     | Question                                  | Scores du vecteur                                                                      | Action recommandée                      |
| ----------- | ----------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------- |
| `restock`   | Allons-nous être en rupture ?             | `restock_urgency`, `stockout_risk`, `overstock_risk`                                   | `recommended_qty` (unités à réassortir) |
| `rebalance` | Le stock est-il dans le mauvais magasin ? | `surplus_score`, `deficit_score`, `transfer_urgency`, `surplus_units`, `deficit_units` | `recommended_qty` (unités à transférer) |
| `markdown`  | Faut-il démarquer ?                       | `markdown_score` + fraction de remise (réutilise les slots restock)                    | `recommended_discount_pct`              |

<Note>
  Les valeurs de domaine sont **en minuscules** partout dans la couche gold (`"restock"`,
  `"rebalance"`, `"markdown"`). L'app les reflète dans la constante `DecisionDomain`.
</Note>

## À lire ensuite

<CardGroup cols={2}>
  <Card title="Contexte de décision" icon="database" href="/fr/developers/decision-layer/decision-context">
    La table d'entrée fondatrice — ses sources, ses colonnes, et les slots toujours-NULL en v1.
  </Card>

  <Card title="Vecteur de décision" icon="gauge-high" href="/fr/developers/decision-layer/decision-vector">
    La couche de scoring — formules par domaine, pondérations, et la porte des actions.
  </Card>

  <Card title="Vecteur d'action" icon="bullseye-arrow" href="/fr/developers/decision-layer/action-vector">
    La couche de résolution — comment les scores deviennent quantités et remises, avec confiance.
  </Card>

  <Card title="Consommation par l'app" icon="display" href="/fr/developers/decision-layer/app-consumption">
    Comment l'app Next.js lit, filtre, attribue et agit sur les vecteurs.
  </Card>
</CardGroup>
