fix(pronote): préserver les cours déplacés et les changements de salle #27

Closed
opened 2026-09-12 10:35:35 +02:00 by Codex · 0 comments
Collaborator

Objectif

Faire parvenir au modèle interne et à la synchronisation une représentation fidèle des cours Pronote annulés, déplacés et changés de salle, sans doublon ni disparition silencieuse.

Constat local

  • LessonStatus.MOVED existe déjà dans pronote_sync.models.agenda, mais le chemin PronoteClient.get_lessons() ne produit actuellement que NORMAL ou CANCELLED à partir de lesson.canceled.
  • Le champ lesson.status fourni par pronotepy n'est pas exploité.
  • Le flux iCal reconnaît seulement certaines catégories textuelles et ne garantit pas la parité avec le chemin pronotepy.
  • La synchronisation et les messages savent déjà présenter un statut ; le défaut est donc principalement dans la perte d'information au parsing.

Preuve externe

L'issue upstream bain3/pronotepy#311 documente le cas Pronote « Changement de salle » :

  • le cours historique est renvoyé avec estAnnule=true, Statut="Cours annulé" et G=3 ;
  • le cours effectif est renvoyé avec estAnnule=false, Statut="Changement de salle" et G=2 ;
  • une annulation réelle utilise G=0.

Le seul booléen canceled ne suffit donc pas à distinguer une annulation réelle de l'ancien exemplaire d'un changement de salle. Le protocole iCal expose aussi des catégories « Cours - Cours annulé » et « Cours - Cours déplacé » (référence du protocole Pronote).

Risques actuels

  • afficher simultanément l'ancien cours annulé et le cours dans la nouvelle salle ;
  • annoncer une annulation alors que le cours a seulement changé de salle ;
  • ne jamais produire LessonStatus.MOVED via pronotepy malgré son existence dans le modèle ;
  • créer des différences CalDAV artificielles ou des notifications trompeuses.

Périmètre attendu

  1. Définir une règle de priorité documentée entre identifiant, statut, indicateur d'annulation et métadonnée de changement de salle.
  2. Préserver l'information disponible depuis iCal et depuis pronotepy, avec un comportement explicite lorsque la version de pronotepy ne remonte pas le champ brut G.
  3. Éviter l'émission de l'ancien exemplaire d'un changement de salle lorsque la paire ancien/nouveau peut être identifiée.
  4. Conserver les annulations réelles comme CANCELLED.
  5. Produire MOVED pour un cours effectivement déplacé et rendre ce statut visible dans le digest, le diff et la sérialisation.
  6. Ne pas modifier les UIDs de manière non déterministe ; vérifier le comportement lors d'une mise à jour de salle.

Critères d'acceptation

  • Test de non-régression : annulation réelle → un cours CANCELLED.
  • Test de non-régression : changement de salle → pas de doublon historique, cours effectif MOVED avec la nouvelle salle.
  • Test iCal : les variantes de catégories annulé/déplacé sont traitées sans dépendre d'une égalité trop stricte.
  • Test de parité : un même scénario produit le même statut métier depuis iCal et pronotepy, ou documente explicitement la limite.
  • Validation du diff CalDAV et des notifications sur une paire ancien/nouveau.
  • Fixtures anonymisées uniquement ; aucun flux ou jeton réel dans le dépôt.
  • Documentation du contrat de statut et de la limite éventuelle de pronotepy.

Conclusion opérationnelle

Traiter ce ticket avant toute amélioration cosmétique du rendu : une annulation ou un changement de salle mal parsé rend directement le planning faux. Ne pas supprimer globalement les cours CANCELLED ; distinguer d'abord l'annulation réelle de l'ancien exemplaire d'un cours déplacé, puis synchroniser uniquement le cours effectif.

## Objectif Faire parvenir au modèle interne et à la synchronisation une représentation fidèle des cours Pronote annulés, déplacés et changés de salle, sans doublon ni disparition silencieuse. ## Constat local - `LessonStatus.MOVED` existe déjà dans `pronote_sync.models.agenda`, mais le chemin `PronoteClient.get_lessons()` ne produit actuellement que `NORMAL` ou `CANCELLED` à partir de `lesson.canceled`. - Le champ `lesson.status` fourni par `pronotepy` n'est pas exploité. - Le flux iCal reconnaît seulement certaines catégories textuelles et ne garantit pas la parité avec le chemin `pronotepy`. - La synchronisation et les messages savent déjà présenter un statut ; le défaut est donc principalement dans la perte d'information au parsing. ## Preuve externe L'issue upstream [bain3/pronotepy#311](https://github.com/bain3/pronotepy/issues/311) documente le cas Pronote « Changement de salle » : - le cours historique est renvoyé avec `estAnnule=true`, `Statut="Cours annulé"` et `G=3` ; - le cours effectif est renvoyé avec `estAnnule=false`, `Statut="Changement de salle"` et `G=2` ; - une annulation réelle utilise `G=0`. Le seul booléen `canceled` ne suffit donc pas à distinguer une annulation réelle de l'ancien exemplaire d'un changement de salle. Le protocole iCal expose aussi des catégories « Cours - Cours annulé » et « Cours - Cours déplacé » ([référence du protocole Pronote](https://github.com/bain3/pronotepy/blob/master/PRONOTE%20protocol.md)). ## Risques actuels - afficher simultanément l'ancien cours annulé et le cours dans la nouvelle salle ; - annoncer une annulation alors que le cours a seulement changé de salle ; - ne jamais produire `LessonStatus.MOVED` via `pronotepy` malgré son existence dans le modèle ; - créer des différences CalDAV artificielles ou des notifications trompeuses. ## Périmètre attendu 1. Définir une règle de priorité documentée entre identifiant, statut, indicateur d'annulation et métadonnée de changement de salle. 2. Préserver l'information disponible depuis iCal et depuis `pronotepy`, avec un comportement explicite lorsque la version de `pronotepy` ne remonte pas le champ brut `G`. 3. Éviter l'émission de l'ancien exemplaire d'un changement de salle lorsque la paire ancien/nouveau peut être identifiée. 4. Conserver les annulations réelles comme `CANCELLED`. 5. Produire `MOVED` pour un cours effectivement déplacé et rendre ce statut visible dans le digest, le diff et la sérialisation. 6. Ne pas modifier les UIDs de manière non déterministe ; vérifier le comportement lors d'une mise à jour de salle. ## Critères d'acceptation - [ ] Test de non-régression : annulation réelle → un cours `CANCELLED`. - [ ] Test de non-régression : changement de salle → pas de doublon historique, cours effectif `MOVED` avec la nouvelle salle. - [ ] Test iCal : les variantes de catégories annulé/déplacé sont traitées sans dépendre d'une égalité trop stricte. - [ ] Test de parité : un même scénario produit le même statut métier depuis iCal et `pronotepy`, ou documente explicitement la limite. - [ ] Validation du diff CalDAV et des notifications sur une paire ancien/nouveau. - [ ] Fixtures anonymisées uniquement ; aucun flux ou jeton réel dans le dépôt. - [ ] Documentation du contrat de statut et de la limite éventuelle de `pronotepy`. ## Conclusion opérationnelle Traiter ce ticket avant toute amélioration cosmétique du rendu : une annulation ou un changement de salle mal parsé rend directement le planning faux. Ne pas supprimer globalement les cours `CANCELLED` ; distinguer d'abord l'annulation réelle de l'ancien exemplaire d'un cours déplacé, puis synchroniser uniquement le cours effectif.
Codex added the investigationbug labels 2026-09-12 10:35:35 +02:00
Codex self-assigned this 2026-09-12 10:35:36 +02:00
Codex added the area:caldavarea:parsingarea:pronotepriority:critical labels 2026-09-12 13:14:35 +02:00
Codex closed this issue 2026-09-12 14:55:22 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: AntoineVe/college-infos#27