fix(pronote): ne pas sélectionner un jour sans cours comme date cible #30

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

Objectif

Déterminer la date cible du digest comme un prochain jour de classe réellement observable dans les données Pronote, sans choisir par défaut une journée sans cours lorsque le flux fournit déjà la reprise ou le prochain cours.

Constat local

La fonction pronote_sync.pipeline.steps.fetch.resolve_target_date() reçoit school_events, mais les supprime immédiatement avec la ligne « del school_events ».

Le comportement actuel est :

  • J+1 si au moins un cours est présent à J+1 ;
  • le prochain jour contenant un cours si aujourd'hui contient un cours ;
  • sinon J+1, même si J+1 est un week-end, un jour férié, une période de vacances ou une journée sans cours.

La docstring formalise même ce dernier comportement (« J+1 est conservé, y compris pendant les vacances »), mais le paramètre school_events et le modèle SchoolEventKind.PUBLIC_HOLIDAY montrent qu'une évolution était prévue. Il n'existe pas de test unitaire dédié à cette fonction.

Pourquoi cela affecte le parsing Pronote

Le problème n'est pas seulement l'affichage de la date : il modifie la requête des devoirs et le contenu du digest.

Scénarios à risque :

  1. exécution le vendredi sans cours le samedi : J+1 peut être choisi au lieu du prochain lundi ;
  2. exécution la veille d'un jour férié ou d'une fermeture explicitement présente dans l'iCal : le digest interroge le mauvais jour ;
  3. fin de vacances : le flux contient la reprise plus loin dans la fenêtre mais la date par défaut reste J+1 ;
  4. journée banalisée sans cours : un digest vide peut être envoyé alors que le prochain jour de classe est connu ;
  5. agenda réellement vide ou source en échec : il faut conserver la distinction entre « aucune donnée de cours » et « source indisponible », conformément au contrat de repli.

Le site de démonstration de pronote-digest décrit également un choix du prochain jour de classe basé sur les cours présents dans le flux, avec gestion des fériés et de la reprise. Sa documentation d'architecture explicite les cas « demain », « prochain jour avec cours » et « aucune reprise connue ».

Périmètre attendu

  1. Définir une règle déterministe de sélection sur la fenêtre effectivement récupérée :
    • privilégier J+1 si des cours effectifs y sont présents ;
    • sinon sélectionner le prochain jour contenant des cours effectifs ;
    • utiliser les événements vacances/jours fériés pour expliquer ou exclure les dates sans cours, sans confondre absence de cours et échec de récupération.
  2. Préciser le comportement lorsqu'aucun prochain cours n'est présent dans la fenêtre : J+1 conservé, date de reprise issue d'un événement, ou résultat « aucune journée de classe connue ».
  3. Prendre en compte les statuts annulé/déplacé et le cas où tous les cours d'une date ont été annulés.
  4. Garantir la cohérence entre les sources iCal et pronotepy.
  5. Ne pas utiliser le calendrier théorique pour inventer un calendrier Pronote réel : il peut seulement servir de source explicitement configurée si le contrat le prévoit.
  6. Conserver une journalisation opérationnelle et expurgée de la règle appliquée (date choisie, raison, présence d'événement), sans contenu personnel.

Critères d'acceptation

  • Tests directs de resolve_target_date() pour J+1 avec cours, week-end, férié, vacances, journée banalisée et reprise connue.
  • Tests des bornes SchoolEvent.from_date inclusive / to_date exclusive.
  • Tests d'une date dont tous les cours sont annulés et d'un remplacement par cours déplacé.
  • Tests distinguant liste vide valide, agenda partiel et exception critique de récupération.
  • Le chemin iCal et le chemin pronotepy produisent la même date cible à données équivalentes.
  • La règle retenue est documentée dans GUIDE_DEV_PYTHON.md et dans la docstring.
  • La suite existante reste verte avec ruff, mypy, bandit et pytest.

Conclusion opérationnelle

Traiter ce ticket après #27 et #28, ou conjointement si la normalisation des statuts et des événements est nécessaire. La priorité est d'empêcher l'envoi d'un digest « demain » alors que Pronote permet déjà d'identifier le prochain jour de classe. Si aucune reprise n'est visible dans la fenêtre, le comportement doit rester explicite et observable plutôt que de présenter une date arbitraire comme certaine.

## Objectif Déterminer la date cible du digest comme un prochain jour de classe réellement observable dans les données Pronote, sans choisir par défaut une journée sans cours lorsque le flux fournit déjà la reprise ou le prochain cours. ## Constat local La fonction pronote_sync.pipeline.steps.fetch.resolve_target_date() reçoit school_events, mais les supprime immédiatement avec la ligne « del school_events ». Le comportement actuel est : - J+1 si au moins un cours est présent à J+1 ; - le prochain jour contenant un cours si aujourd'hui contient un cours ; - sinon J+1, même si J+1 est un week-end, un jour férié, une période de vacances ou une journée sans cours. La docstring formalise même ce dernier comportement (« J+1 est conservé, y compris pendant les vacances »), mais le paramètre school_events et le modèle SchoolEventKind.PUBLIC_HOLIDAY montrent qu'une évolution était prévue. Il n'existe pas de test unitaire dédié à cette fonction. ## Pourquoi cela affecte le parsing Pronote Le problème n'est pas seulement l'affichage de la date : il modifie la requête des devoirs et le contenu du digest. Scénarios à risque : 1. exécution le vendredi sans cours le samedi : J+1 peut être choisi au lieu du prochain lundi ; 2. exécution la veille d'un jour férié ou d'une fermeture explicitement présente dans l'iCal : le digest interroge le mauvais jour ; 3. fin de vacances : le flux contient la reprise plus loin dans la fenêtre mais la date par défaut reste J+1 ; 4. journée banalisée sans cours : un digest vide peut être envoyé alors que le prochain jour de classe est connu ; 5. agenda réellement vide ou source en échec : il faut conserver la distinction entre « aucune donnée de cours » et « source indisponible », conformément au contrat de repli. Le site de démonstration de [pronote-digest](https://yoanbernabeu.github.io/pronote-digest/) décrit également un choix du prochain jour de classe basé sur les cours présents dans le flux, avec gestion des fériés et de la reprise. Sa [documentation d'architecture](https://github.com/yoanbernabeu/pronote-digest/blob/main/docs/architecture.md) explicite les cas « demain », « prochain jour avec cours » et « aucune reprise connue ». ## Périmètre attendu 1. Définir une règle déterministe de sélection sur la fenêtre effectivement récupérée : - privilégier J+1 si des cours effectifs y sont présents ; - sinon sélectionner le prochain jour contenant des cours effectifs ; - utiliser les événements vacances/jours fériés pour expliquer ou exclure les dates sans cours, sans confondre absence de cours et échec de récupération. 2. Préciser le comportement lorsqu'aucun prochain cours n'est présent dans la fenêtre : J+1 conservé, date de reprise issue d'un événement, ou résultat « aucune journée de classe connue ». 3. Prendre en compte les statuts annulé/déplacé et le cas où tous les cours d'une date ont été annulés. 4. Garantir la cohérence entre les sources iCal et pronotepy. 5. Ne pas utiliser le calendrier théorique pour inventer un calendrier Pronote réel : il peut seulement servir de source explicitement configurée si le contrat le prévoit. 6. Conserver une journalisation opérationnelle et expurgée de la règle appliquée (date choisie, raison, présence d'événement), sans contenu personnel. ## Critères d'acceptation - [ ] Tests directs de resolve_target_date() pour J+1 avec cours, week-end, férié, vacances, journée banalisée et reprise connue. - [ ] Tests des bornes SchoolEvent.from_date inclusive / to_date exclusive. - [ ] Tests d'une date dont tous les cours sont annulés et d'un remplacement par cours déplacé. - [ ] Tests distinguant liste vide valide, agenda partiel et exception critique de récupération. - [ ] Le chemin iCal et le chemin pronotepy produisent la même date cible à données équivalentes. - [ ] La règle retenue est documentée dans GUIDE_DEV_PYTHON.md et dans la docstring. - [ ] La suite existante reste verte avec ruff, mypy, bandit et pytest. ## Conclusion opérationnelle Traiter ce ticket après #27 et #28, ou conjointement si la normalisation des statuts et des événements est nécessaire. La priorité est d'empêcher l'envoi d'un digest « demain » alors que Pronote permet déjà d'identifier le prochain jour de classe. Si aucune reprise n'est visible dans la fenêtre, le comportement doit rester explicite et observable plutôt que de présenter une date arbitraire comme certaine.
Codex added the buginvestigation labels 2026-09-12 10:41:16 +02:00
Codex self-assigned this 2026-09-12 10:41:16 +02:00
Codex added the area:operationsarea:parsingarea:pronotepriority:critical labels 2026-09-12 13:14:36 +02:00
Codex closed this issue 2026-09-12 14:55:33 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: AntoineVe/college-infos#30