Z2 — Pipeline J0 — Error paths & timeouts
OCR failures · Timeouts · Partial processing · État cohérent en cas d'erreur
Le pipeline J0 est le point d'entrée critique. Une erreur non gérée ici peut laisser le chapitre dans un état partiellement initialisé, invisiblement corrompu pour les sessions suivantes.
Z2-AC01 — Carte de leçon partielle si OCR en cours
|
|
| Lot 0 |
P1 |
| GIVEN |
L'élève uploade 10 pages. Le traitement des pages 1–3 est terminé. Les pages 4–10 sont en cours de traitement (OCR worker en cours). |
| WHEN |
L'élève ouvre la carte de leçon. |
| THEN |
La carte affiche les items des pages 1–3. Un indicateur de progression (3/10 pages analysées) est visible. Les pages non traitées apparaissent comme placeholders. L'élève peut commencer un diagnostic sur les items disponibles. |
NOTE : La carte partielle est fonctionnelle. L'absence de pages ne bloque pas l'accès.
Z2-AC02 — Timeout OCR sur une page intermédiaire
|
|
| Lot 0 |
P2 |
| GIVEN |
Le pipeline traite 10 pages. La page 4 dépasse le timeout (10 s, après 3 retries). |
| WHEN |
Le worker abandonne la page 4. |
| THEN |
La page 4 est marquée status = FAILED avec reason = 'ocr_timeout'. Les pages 5–10 continuent leur traitement normalement. L'élève voit un badge 'Zone illisible · page 4' sur la carte. Le chapitre n'est PAS bloqué. Aucune exception non gérée n'est propagée. |
Z2-AC03 — Photo floue détectée (confidence globale < 0.3)
|
|
| Lot 0 |
P2 |
| GIVEN |
Une page uploadée a une confidence OCR globale < 0.3 sur tous ses blocs. |
| WHEN |
Le worker finalise l'analyse de cette page. |
| THEN |
Un message non-bloquant est affiché : 'Photo floue — vous pouvez reprendre cette photo pour de meilleurs résultats'. La page reste dans le chapitre avec ses blocs marqués UNCERTAIN. L'élève peut continuer sans reprendre la photo. |
Z2-AC04 — Aucun item généré sur une page (page vide ou illisible)
|
|
| Lot 0 |
P1 |
| GIVEN |
Une page OCRisée ne produit aucun Item après la phase de génération (texte vide ou uniquement des artefacts). |
| WHEN |
La génération d'items se termine pour cette page. |
| THEN |
Aucun Item n'est créé pour cette page. La page est marquée status = 'no_items_extracted'. La carte de leçon ne montre pas de section vide pour cette page. Le chapitre est valide si au moins une autre page a produit des items. |
Z2-AC05 — Échec génération Items (erreur LLM)
|
|
| Lot 0 |
P1 |
| GIVEN |
L'OCR d'une page a réussi. L'appel LLM pour la génération d'items retourne une erreur (timeout, quota, ou réponse malformée). |
| WHEN |
Le worker LLM épuise ses retries (x2 avec back-off). |
| THEN |
Les blocs de cette page sont conservés avec leur texte OCR brut. Aucun Item n'est créé pour cette page. La page est marquée status = 'items_generation_failed'. Une ValidationTask admin est créée pour re-traitement manuel. Le reste du pipeline n'est pas affecté. |
Z2-AC06 — Re-tentative pipeline après interruption (idempotence)
|
|
| Lot 0 |
P2 |
| GIVEN |
Le pipeline J0 a été interrompu après les étapes 1–4 (upload, segmentation, OCR, plan). L'élève ou le système relance le traitement du chapitre. |
| WHEN |
Le pipeline redémarre. |
| THEN |
Les étapes déjà complétées ne sont pas ré-exécutées (les résultats OCR en cache permanent sont réutilisés). Le pipeline reprend à partir de l'étape non complétée. Aucun Item en double n'est créé. |
Z2-AC07 — Diagnostic impossible si 0 items valides
|
|
| Lot 0 |
P1 |
| GIVEN |
Le pipeline J0 se termine avec 0 items produits (toutes pages échouées ou illisibles). |
| WHEN |
L'élève tente de lancer le diagnostic initial. |
| THEN |
Le bouton diagnostic est désactivé. Un message explicite est affiché : 'Aucun contenu n'a pu être extrait — vérifiez la qualité des photos et ré-uploadez.' Le chapitre reste en état PENDING_UPLOAD. |
Z2-AC08 — Bloc SCHEMA/MAP non OCRisé conservé comme Document image
|
|
| Lot 0 |
P2 |
| GIVEN |
Un bloc de type MAP ou SCHEMA a une confidence OCR < 0.5. |
| WHEN |
L'étape OCR se termine pour ce bloc. |
| THEN |
Le bloc n'est PAS OCRisé. Un Document de type correspondant est créé avec source_image_url = crop_url et tags = ['map'] ou ['schema']. Ce Document est éligible aux gabarits GEN.DOC.MAP.READ_ZONES ou GEN.DOC.IMAGE.DESCRIBE_INTERPRET. Aucun texte OCR n'est stocké. |
Z2-AC09 — File de validation non dépassée (max 8)
|
|
| Lot 0 |
P2 |
| GIVEN |
Le pipeline J0 détecte 15 items avec validation_required = true sur un chapitre. |
| WHEN |
La file de validation est constituée. |
| THEN |
Seuls les 8 items avec la priorité la plus haute (score d'impact sur la note) sont inclus dans la ValidationTask. Les 7 autres items restent avec validation_required = true mais ne sont pas soumis à l'élève. Ils peuvent être traités par l'admin en backoffice. |
Z2-AC10 — Streaming carte de leçon (première page disponible)
|
|
| Lot 0 |
P1 |
| GIVEN |
Le chapitre a 8 pages en cours de traitement. La page 1 est la première traitée. |
| WHEN |
Le traitement de la page 1 se termine (OCR + items + tags). |
| THEN |
La carte de leçon est mise à jour en temps réel via SSE avec les items de la page 1. L'élève peut interagir avec ces items avant que les pages 2–8 soient traitées. Les pages suivantes s'ajoutent progressivement sans recharger la vue. |
Z2-AC11 — Relance élève pour pages en échec de génération
|
|
| Lot 0 |
— |
| GIVEN |
Une page du chapitre est en status = 'items_generation_failed' (erreur LLM après retries). Le texte OCR brut est conservé. |
| WHEN |
L'élève consulte la carte de leçon du chapitre. |
| THEN |
Un badge 'Exercices non générés · page X' est affiché avec un bouton 'Réessayer'. Le clic déclenche un nouveau passage par l'étape 7 du pipeline (génération items) en réutilisant le texte OCR en cache. Si le retry réussit, les items sont ajoutés à la carte et le badge disparaît. Si le retry échoue à nouveau, le badge réapparaît avec le message 'Génération toujours indisponible — réessaie plus tard'. Maximum 3 retries manuels par page. Au-delà, seul l'admin peut relancer. |
NOTE : Ce mécanisme complète Z2-AC05 en offrant une action côté élève. L'admin reste le fallback ultime mais l'élève n'est plus bloqué sans recours en cas d'indisponibilité temporaire du LLM.
Z2-AC12 — Rétention crops et OCR alignée sur politique photos (RGPD)
|
|
| Lot 0 |
— |
| GIVEN |
Une page a été traitée par le pipeline. Les crops (Block.crop, Document.source_image_url) et le texte OCR brut sont stockés. La photo originale est supprimée à J+30 (politique par défaut). |
| WHEN |
Le job de nettoyage RGPD s'exécute à J+30 pour cette page. |
| THEN |
Si l'utilisateur n'a PAS opté pour la conservation : les crops d'image sont supprimés en même temps que la photo originale. Les crop_url des blocs sont remplacés par null. Les source_image_url des Documents sont remplacés par null. Le texte OCR brut est conservé (il ne contient pas l'image de l'écriture manuscrite). Les ValidationTasks en cours conservent un crop_snapshot_text (description textuelle du crop) mais pas l'image. Les gabarits de type GEN.DOC.IMAGE.* deviennent inéligibles pour les Documents dont le source_image_url est null — ces items sont restreints aux gabarits textuels. |
NOTE : Le PRD §20 Q2 mentionne la suppression des « photos originales » à J+30, mais les crops (fragments d'image) et les source_image_url des Documents n'avaient pas de politique de rétention explicite. Cela créait un trou RGPD : un parent pensait les photos supprimées alors que des fragments persistaient indéfiniment. Ce AC aligne la rétention des crops sur celle des photos originales.
Z2-AC13 — Versioning du modèle LLM pour reproductibilité et détection de drift
|
|
| Lot 0 |
— |
| GIVEN |
Le pipeline J0 (segmentation, item generation, fidelity check) et la lazy generation utilisent des appels LLM. Le modèle LLM sous-jacent peut changer (mise à jour provider, bascule de modèle, changement de prompt). |
| WHEN |
Un appel LLM est effectué à n'importe quelle étape du pipeline ou de la génération. |
| THEN |
Chaque résultat LLM (Item, Question, fidelity_score) est taggé avec llm_model_version (identifiant du modèle, e.g. gpt-4o-2024-08-06) et prompt_template_version (hash ou version sémantique du prompt utilisé). Le champ llm_model_version est indexé. Un changement de modèle ou de prompt déclenche une alerte admin LLM_VERSION_CHANGED. Un job hebdomadaire compare les métriques qualité (taux fidelity_score < 0.6, taux signalements élève) entre l'ancienne et la nouvelle version. Si le taux de dégradation dépasse 15% sur l'un des indicateurs, l'admin reçoit une alerte LLM_DRIFT_DETECTED avec détail comparatif. |
NOTE : Sans versioning LLM, un changement de modèle silencieux (ex. le provider met à jour le modèle derrière la même API) peut dégrader la qualité des items générés sans qu'on puisse identifier la cause. Le versioning permet le diagnostic (« depuis quand les fidelity_score baissent-ils ? ») et le rollback informé. C'est aussi une exigence de traçabilité pour un produit éducatif destiné à des mineurs.
Z2-AC14 — Pipeline incrémental pour ajout de pages (pas de re-traitement des pages existantes)
|
|
| Lot 0 |
— |
| GIVEN |
Le chapitre « Mouvement et vitesse » a 3 pages existantes (pipeline déjà terminé, 8 items générés). L'élève ajoute les pages 4-6 via « Ajouter des pages » (Z5-AC11). |
| WHEN |
Le pipeline J0 se déclenche pour les pages ajoutées. |
| THEN |
Le pipeline s'exécute uniquement sur les pages 4-6. Les étapes sont : (1) segmentation des pages 4-6 en blocs, (2) OCR des blocs textuels, (3) génération d'items à partir des blocs, (4) fidelity check des nouveaux items, (5) cohérence cross-page : les nouveaux items sont comparés aux items existants du chapitre pour détecter doublons (similarité cosinus keywords > 0.9) et contradictions — mais les items existants ne sont pas comparés entre eux (déjà fait lors du pipeline initial). Le statut du pipeline au niveau chapitre passe à processing_incremental (distinct de processing pour un pipeline complet). En cas d'échec sur une page ajoutée, le retry élève Z2-AC11 est disponible. Un échec sur les pages 4-6 n'affecte pas les items des pages 1-3. Les pages ajoutées héritent de revision_id = R1 (pas de nouvelle révision). L'idempotence Z2-AC06 s'applique : si le pipeline incrémental est interrompu et relancé, aucun doublon n'est créé. |
NOTE : Le pipeline incrémental est le pendant technique de Z5-AC11 (ajout de pages). Sans lui, ajouter 3 pages à un chapitre de 10 pages relancerait le pipeline complet sur 13 pages — coût OCR x4, latence x4, et risque de drift OCR sur les pages existantes. Le statut processing_incremental permet à l'UI d'afficher « Ajout de 3 pages en cours… » plutôt que « Traitement du chapitre… » (qui inquiéterait l'élève sur ses données existantes).
Z2-AC15 — Détection et préservation des zones visuelles (dual coding)
|
|
| Lot 0 |
— |
| GIVEN |
L'élève uploade des pages de cours contenant du texte et des éléments visuels (diagrammes, schémas annotés, graphiques, figures légendées, tableaux dessinés). |
| WHEN |
Le pipeline J0 segmente les pages en blocs (étape 1, PRD §6.1). |
| THEN |
Le pipeline distingue 3 types de blocs : (1) Texte (OCR standard), (2) Visuel pédagogique (diagramme, schéma, graphique, figure annotée — détecté par le modèle de segmentation), (3) Décoratif (dessin sans valeur pédagogique, marge, rature — ignoré). Les blocs visuels pédagogiques sont : (a) sauvegardés comme images recadrées (visual_block.image_url, visual_block.type = 'diagram' | 'graph' | 'table' | 'figure'), (b) associés aux items du même passage via le champ Item.visual_block_ids[], (c) les légendes/labels détectés dans le visuel sont extraits par OCR et ajoutés aux métadonnées (visual_block.labels[]). Le LLM de structuration (étape 2) reçoit les visuels en contexte et peut générer des gabarits spécifiques : « Complète les légendes de ce schéma » (image affichée avec labels retirés), « Que représente ce graphique ? » (image affichée, question ouverte), « Associe chaque élément du schéma à sa fonction » (matching). Ces gabarits visuels sont marqués template.uses_visual = true et template.visual_block_id. La carte de leçon (Z1-AC21, « Voir ma leçon ») affiche les blocs visuels associés à la Notion en cours, intercalés avec le texte. Si le modèle de segmentation ne détecte aucun visuel, le pipeline continue normalement (texte uniquement). Le tagging est conservatif : en cas de doute sur la nature pédagogique d'un visuel, il est classé « décoratif » (faux négatif préférable au faux positif). |
NOTE : La théorie du double codage (Paivio) montre que l'encodage simultané verbal + visuel améliore le rappel de façon substantielle (Butcher 2006, d=0.48 ; Mayer 2009, +89% sur le transfert). Les cahiers de collégiens sont riches en schémas (SVT : cycle de l'eau, cellule ; Physique : circuits, schémas de forces ; Géographie : cartes, graphiques). Ignorer ces visuels revient à perdre 30-50% de la valeur pédagogique du cahier. Le coût d'implémentation est concentré dans le modèle de segmentation (distinguer texte/visuel/décoratif) — le reste (association item-visuel, gabarits visuels) s'intègre dans le pipeline existant. Le tagging conservatif protège contre les faux positifs (un gribouillage classé « schéma » dégraderait l'expérience).
|
|
| Lot 0 |
— |
| GIVEN |
Le pipeline segmente une page contenant un tableau dessiné à la main (lignes horizontales/verticales formant une grille) ou un tableau imprimé collé dans le cahier. Le bloc est classé type = TABLE. |
| WHEN |
L'étape 2 (segmentation) et l'étape 3 (OCR) traitent ce bloc. |
| THEN |
Le pipeline extrait la structure du tableau en plus du texte OCR brut : (1) Détection de grille : les lignes horizontales et verticales sont détectées (Hough transform ou modèle spécialisé). Le nombre de lignes (rows) et colonnes (cols) est déterminé. (2) Extraction cellule par cellule : chaque cellule est OCRisée individuellement (meilleure précision que l'OCR global sur le bloc entier). Le résultat est stocké dans VisualBlock.table_structure = { rows: int, cols: int, headers: string[]?, cells: string[][] }. (3) Détection d'en-têtes : la première ligne (et/ou première colonne) est détectée comme en-tête si elle contient des termes différents du reste (style, taille, position). headers[] contient les en-têtes détectés. (4) Limites : si le tableau dépasse 8 colonnes ou contient des cellules fusionnées détectées (bounding boxes chevauchantes), le pipeline bascule en mode image (le bloc est reclassé SCHEMA et traité comme un visuel simple, pas comme une table structurée). Un log TABLE_FALLBACK_TO_SCHEMA est créé. (5) Gabarits spécifiques : les tableaux structurés sont éligibles aux gabarits GEN.DOC.TABLE.READ_VALUE (lire une valeur dans le tableau) et GEN.DOC.TABLE.COMPLETE_CELL (compléter une cellule masquée). Les tableaux en mode image (fallback SCHEMA) sont éligibles uniquement à GEN.DOC.IMAGE.DESCRIBE_INTERPRET. (6) Qualité : si la confidence OCR d'une cellule < 0.4, la cellule est marquée uncertain dans la structure. Si > 30% des cellules sont uncertain, le tableau entier bascule en mode image. |
NOTE : Les tableaux sont omniprésents dans les cahiers de collège : tableaux de conversion (Physique-Chimie), tableaux de données expérimentales (SVT), tableaux chronologiques (Histoire), tableaux de comparaison (Géographie). Un tableau OCRisé « en vrac » (tout le texte mélangé sans structure) perd sa valeur pédagogique — l'élève ne peut plus répondre « Quelle est la densité du fer ? » si le tableau est un blob de texte. L'extraction cellule par cellule est 2-3x plus précise que l'OCR global car chaque cellule est un bloc compact avec peu de bruit. Le fallback vers le mode image pour les tableaux complexes (≥ 8 colonnes, fusions) est pragmatique : ces tableaux sont rares dans les cahiers de collège et l'extraction structurée serait fragile.
Z2-AC17 — Qualité minimale des crops visuels (résolution, cadrage, stockage)
|
|
| Lot 0 |
— |
| GIVEN |
Le pipeline segmente un bloc visuel pédagogique (SCHEMA, MAP, GRAPH, TABLE, CIRCUIT, PHOTO) et génère un crop (image recadrée). |
| WHEN |
Le crop est généré et prêt à être stocké. |
| THEN |
Le crop respecte les contraintes de qualité suivantes : (1) Résolution minimale : 300×300 px. Si le crop brut est plus petit (schéma dans une marge, petit graphique), un upscaling bilinéaire conservatif est appliqué pour atteindre 300×300 px. Si le crop brut est < 100×100 px, le bloc est reclassé DECORATIVE (trop petit pour être un visuel pédagogique — probablement un symbole, une flèche, un numéro de page). (2) Marge de cadrage : 5% de la bounding box détectée est ajouté de chaque côté pour capturer les légendes et annotations environnantes (une légende coupée rend le schéma incompréhensible). Si la marge dépasse les bords de la page, elle est tronquée au bord. (3) Format de stockage : WebP, qualité 85 (compression ~60% vs JPEG, qualité visuelle équivalente). L'URL est stockée dans Block.crop_url et VisualBlock.image_url. (4) Thumbnail : un thumbnail 150×150 px est généré en parallèle pour l'affichage dans les listes (carte leçon, navigation rapide). Stocké dans VisualBlock.thumbnail_url. (5) Métadonnées : VisualBlock.width_px, VisualBlock.height_px sont renseignés pour permettre un layout responsive sans reflow (le client connaît les dimensions avant le chargement). (6) Rétention : VisualBlock.retention_expires_at est fixé à J+30 (aligné sur Z2-AC12 RGPD). À expiration, image_url et thumbnail_url sont remplacés par null. Les gabarits uses_visual = true liés à ce VisualBlock deviennent inéligibles (même logique que Z2-AC12 pour source_image_url). |
NOTE : Un crop de mauvaise qualité (flou, coupé, trop petit) rend les gabarits visuels inutilisables : « Complète les légendes de ce schéma » avec un schéma illisible est pire qu'aucune question visuelle. La marge de 5% est un compromis : trop large capture du bruit (texte environnant non pertinent), trop étroite coupe les légendes. Le format WebP est supporté par tous les navigateurs modernes et réduit le stockage de 60% — important pour un SaaS avec potentiellement des milliers de photos uploadées. Le threshold 100×100 px pour reclassification en DECORATIVE élimine les faux positifs les plus courants (numéros de page, puces, petites flèches détectées comme « blocs visuels »).
Z2-AC18 — Rendu des visuels pendant les sessions de révision
|
|
| Lot 0 |
— |
| GIVEN |
Une question instanciée utilise un gabarit visuel (template.uses_visual = true). La question a un visual_block_id et un rendered_visual_url (visuel transformé : légendes masquées, zones floutées, etc.) ou le VisualBlock.image_url original. |
| WHEN |
L'élève voit cette question dans une session. |
| THEN |
L'affichage suit les règles suivantes : (1) Layout : l'image est affichée au-dessus de la question texte, occupant toute la largeur disponible (max 100% container, hauteur proportionnelle). Sur mobile (< 768 px), l'image occupe la pleine largeur. Sur desktop, l'image est centrée avec max-width: 600px. (2) Zoom : un tap/clic sur l'image ouvre un viewer plein écran (pinch-to-zoom sur mobile, scroll-zoom sur desktop) pour que l'élève puisse lire les détails fins (légendes, valeurs d'axes). Un bouton « Fermer » ou swipe-down referme le viewer. (3) Chargement : l'image est lazy-loaded avec un placeholder aux dimensions exactes (width_px × height_px du VisualBlock) pour éviter le reflow. Un spinner s'affiche pendant le chargement. Si l'image ne charge pas (erreur réseau), un message s'affiche : « Image indisponible — réponds à partir du texte si possible. » La question reste répondable (le score n'est pas pénalisé si l'image est absente). (4) Visuels transformés : si la question utilise un rendered_visual_url (légendes masquées, cellules effacées), c'est cette version qui s'affiche — pas l'original. L'original est accessible via le bouton « Voir ma leçon » (Z1-AC21) pour contexte. (5) Accessibilité : le alt_text du VisualBlock est utilisé comme attribut alt de l'image. Les légendes extraites (labels[]) sont affichées sous l'image en texte pour les lecteurs d'écran. (6) Feedback post-réponse : après réponse, si la question était « complète les légendes », le feedback affiche le visuel original (avec légendes) à côté du visuel transformé (avec les légendes que l'élève a complétées) pour une comparaison directe. |
NOTE : L'affichage du visuel est critique pour l'efficacité du dual coding — un visuel mal rendu (trop petit, pas zoomable, layout cassé) annule le bénéfice pédagogique. Le zoom est indispensable sur mobile : les schémas de cahier contiennent souvent des détails fins (légendes, valeurs numériques) illisibles en taille réduite. Le placeholder aux dimensions exactes évite le « saut » de layout (CLS, Cumulative Layout Shift) qui dégrade l'expérience utilisateur et perd le focus de l'élève. La comparaison côte-à-côte dans le feedback (original vs complété) est la forme la plus efficace de correction pour les gabarits visuels — l'élève voit immédiatement où sont ses erreurs.