Aller au contenu

ADR-0030 — La livraison n'est plus un cul-de-sac : le client réceptionne ou conteste, le senior route

Statut 🟢 Accepté — 2026-06-23 ; implémenté (backend : statuts conteste/receptionnee, transitions client accepter/contester, qualification senior depuis conteste ; frontend client + senior ; notifications ; tests verts)
Portée Fin de cycle de l'étude : la réception du rapport par le client et le rejeu après contestation. Étend la machine à états workflow.py (avant : livre terminal et gelé).
Décision À la livraison, le client réceptionne explicitement : Accepter (clôture, receptionnee, valeur de décharge) ou Demander une révision (conteste, motif obligatoire + catégorie optionnelle, en modale). La contestation ramène la demande au senior, qui qualifie et route : renvoi au junior (la chaîne rejoue) ou re-livraison après explication. La nouvelle livraison est une v2 (journal append-only).
Réf. ADR-0006 — Personas staff (le senior, point de contact) ; ADR-0008 — Revue contradictoire (rejeu interne) ; ADR-0013 — Notifications ; ADR-0029 — Photo : corriger/remplacer (donnée erronée) ; ADR-0027 — Modales = tâche focalisée

🎯 À retenir

Avant, livre était un cul-de-sac total : aucune transition n'en partait, pas même pour le cabinet (renvoyer exigeait revue_senior | validee | audite). Le client recevait le PDF et ne pouvait que le subir ; le silence valait accord, sans trace. Pour une prestation actuarielle, la réception du livrable a une valeur quasi contractuelle. On ouvre donc la fin de cycle : le client accepte (décharge tracée) ou conteste (motif obligatoire). La contestation n'est pas une critique d'actuaire hypothèse par hypothèse : c'est un désaccord métier/factuel qui remonte au senior, seul point de contact, qui qualifie et route le rejeu. La chaîne d'audit existante (re-validation, re-audit) fait le reste.

Contexte

Observé en revue de fin de cycle. À la source (workflow.py) :

  • livre est terminal et gelé. STATUTS s'arrête à livre ; aucune transition n'en part. renvoyer n'accepte que revue_senior | validee | audite (l.687) — donc une étude livrée ne bouge plus, même pour le senior.
  • Le client n'a aucun levier. Toutes les transitions sont gardées SENIOR | JUNIOR | EXTERNE. Le consultant ne reçoit que l'événement livraison (visible_client=True) : une notification, pas une action.
  • Silence = accord implicite, non tracé. Ni réception, ni acceptation, ni contestation, ni rejeu côté client (vérifié : aucun mécanisme de ce type dans le backend).

Le trou : un client insatisfait n'a, dans l'app, rien. C'est le sujet de cet ADR.

Décision

  • D-RECEP-1 — Deux statuts terminaux/actifs de fin de cycle. receptionnee (terminal : le client a accepté, clôture définitive) et conteste (actif : le client conteste, atterrit chez le senior). Ajoutés à STATUTS après livre. Pas de colonne de modèle nouvelle (le statut est déjà une colonne) → pas de migration.

  • D-RECEP-2 — Le client réceptionne explicitement. Deux premières transitions ouvertes au PERSONA_CONSULTANT : POST …/accepter (livre → receptionnee, décharge journalisée reception_acceptee, visible client) et POST …/contester (livre → conteste, motif obligatoire + catégorie optionnelle, journalisé contestation_client visible client). La contestation se saisit en modale (tâche focalisée, ADR-0027). Tant que le client n'a pas tranché : « livrée, en attente de réception ».

  • D-RECEP-3 — Le senior qualifie et route depuis conteste. Deux issues, toutes deux avec commentaire obligatoire : renvoyer au junior (conteste → a_revoir ; la chaîne rejoue : re-soumission → re-validation → re-audit éventuel → re-livraison) ; re-livrer après explication (conteste → livre ; le rapport est ré-affirmé, le client peut ré-accepter ou re-contester). Une donnée RH erronée (mauvais effectif, filiale manquante) est un sous-cas du renvoi : le junior re-compose avec la bonne photo (ADR-0029). Le client ne route jamais lui-même : il motive, le senior arbitre (séparation des pouvoirs, ADR-0006/0008).

  • D-RECEP-4 — La catégorie aide, n'enferme pas. Le motif est en texte libre obligatoire ; une catégorie facultative (données RH / périmètre / méthode-chiffre / autre) oriente le senior sans forcer le client à qualifier une nature qu'il ne maîtrise pas toujours. Encodée dans le commentaire de l'événement (pas de colonne) : [Catégorie] motif.

Conséquences

  • Positif. La fin de cycle cesse d'être un cul-de-sac ; la réception est tracée (décharge ou contestation motivée) ; le rejeu réutilise la chaîne d'audit existante ; le senior reste le point de contact unique. Intégrité d'audit préservée : « approuvé = livré » vaut aussi pour la v2 (re-validation/re-audit avant re-livraison).
  • Notifications. contestation_client → seniors (le cabinet doit réagir) ; reception_acceptee → seniors (clôture). La re-livraison réutilise livraison → client.
  • Limite assumée (pré-enregistrée). Le PDF livrable est régénéré à chaque livraison (le resultat_json reflète l'état courant) ; on ne conserve pas les PDF v1…vN sur disque. Le journal garde l'historique complet des livraisons et contestations (append-only). Conserver chaque PDF livré est le déclencheur de réexamen ci-dessous.
  • Pas de boucle dure bornée en v1. Un client peut contester, le senior re-livrer, le client re-contester : tout est journalisé (pression sociale + trace d'audit bornent en pratique). Un plafond explicite pourra venir si l'usage le réclame.

Déclencheur de réexamen (pré-enregistré)

  • Exigence d'audit sur les versions livrées (si un auditeur réclame chaque PDF v1…vN) → archiver le rapport livré à chaque livraison (chemin versionné) au lieu d'écraser.
  • Allers-retours de contestation abusifs → introduire un plafond de re-contestations ou une clôture senior « définitive » opposable.