⚡ Swarm Architecture

Design — Produits complémentaires v2 (ancrage taxonomie famille)

# Design — Produits complémentaires v2 (ancrage taxonomie famille)

Date : 2026-06-08 Auteur : Pierre Samson + Claude Périmètre : refonte de la brique « Compléments IA » suite au rejet métier de la v1 Statut : méthode validée en Q&R (Pierre, 2026-06-08), spec à relire

---

1. Contexte & pourquoi une v2

La v1 (exports/complements_ia_FR_2026-06-04_d90.xlsx) typait chaque produit par IA depuis le titre SAP abrégé, puis croisait avec les ventes. Rejetée par le métier : liens faux (« dérouleur scotch ⇄ papier toilette »). Cause racine : un titre cryptique (LYRECO MINI TAPE DISPENSER 19MMX33) mal typé (« dérouleur bobine ») → lien plausible mais faux. L'IA devinait la catégorie.

Découverte clé qui débloque la v2 : les produits se joignent à 100 % à ecom_products (postgres :5433), qui est bien plus riche que le titre du CSV :

  • hiérarchie catégorie authoritative : `section_code → family_code →
category_code → subcategory_code + world (via section_taxonomy`) ;
  • descriptions riches : web_title, web_description, key_selling_point1/2/3,
key_words, product_group_description ;
  • identité fournisseur : brand, manufacturer, supplier_product_reference,
product_type_code, lyreco_brand.

⇒ On n'infère plus la catégorie : elle est donnée par le warehouse. C'est le levier qui fiabilise les liens.

Volumétrie taxonomie : 206 familles, 21 sections. Gérable pour un raisonnement IA au niveau famille.

---

2. Décisions verrouillées (Q&R 2026-06-08)

| Décision | Choix | |---|---| | Nature des liens | C = A + B (A consommables/nécessaires + B compléments larges) | | Fiabilité A | brand + manufacturer + supplier_product_reference + product_type_code (+ GTIN du CSV Marie) → compatibilité exacte | | Fiabilité B | famille ↔ famille (hiérarchie warehouse) dans un même univers d'usage ; l'IA raisonne sur la catégorie réelle, jamais sur le titre | | Règles famille↔famille | proposées par l'IA, relues par Pierre/Marie sur les 20 lignes, puis étendues | | Profondeur | 1 saut validé d'abord ; multi-saut (café→filtre→détartrant→poubelle) en v2 | | Sorties | 3 onglets A — consommables · B — compléments larges · Mix (A+B) + README | | Validation | 20 premiers produits ancres du fichier source (= CAFETERIA : cafés + biscuits) | | Statut des compléments proposés | uniquement actifs (status ≠ Delisted/New Product Delisted) | | Format | large : 1 ligne / ancre, jusqu'à 20 blocs [Consumable Web · Local SAP Description · Local Status Current Year · Display Sequence] |

---

3. Données

3.1 Fichier source (associations existantes = baseline)

imports/lucas/20260608_094900_Produits_comple_mentaires_20260526_1.xlsx
  • Importé en table postgres product_complements par
scripts/import_product_complements.py : 10 665 paires · 5 458 ancres, ~2 compléments/ancre (max 20), statuts Continued 9036 / New 1235 / Delisted 151 / vide 240.
  • Layout : col0 = ancre SAP, col1 = description, puis 20 blocs de 4
[code complément, description, statut, display_sequence].
  • Sert de baseline (associations actuelles du site) pour comparer notre
proposition. C'est le format de sortie cible.

3.2 Catalogue enrichi

ecom_products (FR) — clé product_reference (18 digits zéro-paddés ; les codes SAP du fichier sont paddés via zfill(18), déjà fait à l'import). Fournit catégorie, descriptions riches, marque/fabricant, status_code, flags not_salable_flag / not_visible_flag.

3.3 Libellés de famille (à dériver — pas de libellé propre)

product_group_description n'est PAS un libellé de famille (c'est la description d'un produit). Il faut dériver un libellé lisible par famille depuis un échantillon de produits (web_title + descriptions), une fois, caché.

---

4. Méthode (1 saut, offline, validation 20 ancres)

Phase 1 — Anchors & enrichissement

Lire les 20 premières ancres du fichier source (ordre du fichier). Pour chacune : récupérer dans ecom_products sa famille, son world, sa marque, son fabricant, ses descriptions riches.

Phase 2 — Profils de famille (IA, caché)

Pour chaque famille impliquée (familles des 20 ancres + familles candidates voisines dans le même world), construire un profil : échantillon de ~12 produits (web_title/product_description) → l'IA renvoie un libellé court + une phrase « ce que contient cette famille ». Caché par family_code.

Phase 3 — Graphe de compléments famille → familles (IA, relu)

Pour la famille de chaque ancre, l'IA propose les familles complémentaires (choisies dans la liste réelle des 206 familles, profils fournis), chacune classée :
  • A (relation consommable-de / recharge-de / accessoire-de) =
nécessaire pour utiliser/consommer l'ancre (ex. café → filtres, gobelets) ;
  • B (relation complément-usage / même-contexte) = acheté dans le même
contexte sans être nécessaire (ex. café → biscuits, nettoyage cafétéria) ; avec force (0-1) et justification. Relu par Pierre/Marie sur les 20 lignes. > Resserrage A par compatibilité exacte : quand l'ancre est un durable > (imprimante, étiqueteuse…), un lien A n'est retenu que si un produit de la > famille candidate partage manufacturer/brand compatible (+ GTIN si dispo). > Pour les ancres « consommables » (café/biscuits) A reste sémantique (filtres…).

Phase 4 — Expansion famille → SKU

Pour chaque arête famille retenue, choisir les SKU concrets à afficher : produits actifs de la famille complément (statut Continued/New, non not_salable/not_visible), classés par ventes (réutiliser le compteur de co-achat / volume des paniers FR), top-N pour remplir jusqu'à 20.

Phase 5 — Assemblage des 3 vues + Display Sequence

  • A : seulement les arêtes classées A, dépliées en SKU.
  • B : seulement les arêtes classées B.
  • Mix : A puis B, display_sequence = 1..20 (A en tête, puis B par force ×
ventes décroissantes), plafonné à 20 compléments/ancre.

Phase 6 — Sorties

XLSX exports/product_complements_v2_FR_.xlsx :
  • README (méthode + lecture), A — consommables, B — compléments larges,
Mix (A+B) — chacun au format large (col0 SAP ancre, col1 description, puis 20 blocs `[Consumable Web = code SAP complément · Local SAP Description · Local Status Current Year · Display Sequence]`).
  • Une feuille Baseline (site actuel) optionnelle : les compléments existants
de product_complements pour ces 20 ancres, pour comparaison.
  • Snapshot JSON associé.

---

5. Architecture & isolation

  • core/complement_families.py — fonctions pures : dérivation profil famille
(assemblage de l'échantillon), classification A/B des arêtes, expansion famille→SKU (tri ventes + filtre statut), assemblage Display Sequence, construction du format large. Testables (TDD), aucun I/O.
  • Réutiliser core/ai_typing.py (backend injectable get_llm_backend,
cache incrémental, modèle Haiku/Sonnet) pour les appels IA (profils + graphe famille). Aucun appel réseau en test (llm_call stubbé).
  • scripts/refresh_product_complements_v2.py — orchestration : lecture 20 ancres
→ enrichissement (postgres) → profils familles (IA) → graphe famille (IA) → expansion SKU → 3 vues → XLSX. CLI `--n-anchors 20 --model sonnet --llm-backend cli|api --depth 1`.
  • tests/test_complement_families.py — TDD, IA stubbée.

---

6. Risques & garde-fous

  • Qualité des liens B = enjeu n°1. Mitigations : ancrage famille (pas titre),
profils famille relus, l'IA choisit dans la liste réelle des familles, et Pierre/Marie relisent les 20 lignes avant extension.
  • A peut être clairsemé pour des ancres « consommables » (un sachet de café
n'a pas de consommable propre) — c'est attendu et ça valide la séparation A/B. A est riche surtout pour les durables.
  • Libellés de famille dérivés (pas natifs) : risque d'imprécision sur une
famille fourre-tout → on échantillonne assez de produits + on relit.
  • Statut : ne jamais proposer un complément Delisted (filtre dur).
  • Multi-saut hors périmètre v1 (chaînage A) — prévu v2.
  • Ne casse pas la table product_complements (baseline en lecture seule) ni
la v1.

---

7. Hors périmètre (v1 de cette refonte)

  • Multi-saut / chaînage transitif (café→filtre→détartrant→poubelle).
  • Génération sur tout le catalogue (on valide 20 ancres d'abord).
  • Écriture en base / branchement panel — snapshot XLSX/JSON seulement.
  • GB.