fix(M7): corrections d'audit FIXME_M7 — sécurité, fenêtre, UID, timezone
Corrige les 5 constats de l'audit FIXME_M7 : #1 (Bloquant) — Protection des événements non marqués : - upsert_event() vérifie le marqueur X-PRONOTE-SYNC-MANAGED avant modification ; lève PronoteSyncError en cas de collision avec un événement non géré (aucune écriture) - delete_event() vérifie le marqueur ; no-op avec warning si non géré - Méthode privée _is_managed_event() factorisant le contrôle #2 (Bloquant) — Fenêtre de synchronisation : - Calcul en journées entières (minuit à minuit exclusif) - Filtrage des données locales (lessons, homeworks, school_events) avant passage au planner - Paramètre now injectable pour les tests #3 (Bloquant) — UID canonique vs brut : - list_managed_events() retourne (raw_uid, canonical_uid, vevent) - compute_plan() matche par UID canonique, route les raw UID vers *_to_remove, retourne le mapping remote_raw_by_canonical - executor.execute() utilise le raw UID pour les mises à jour (pas de doublon) - Pas de migration destructive des UID distants existants #4 (Correction) — Normalisation temporelle UTC : - normalize_datetime_to_utc() dans utils/uid.py : naïve → Europe/Paris → UTC ; consciente → UTC - Utilisée par generate_deterministic_uid() et component_to_signature() - Deux représentations du même instant → même UID et même signature #5 (Compatibilité) — date_search déprécié : - Remplacement par calendar.search(start, end, event=True, expand=True) Documentation : - GUIDE_DEV_PYTHON.md : suppression des références obsolètes à sync/state.py et état SQLite/JSON ; mise à jour de l'API CalDAV (search au lieu de date_search, upsert par UID) - TODO.md : M7 décoché (corrections en cours de validation) Tests : 390 passés, couverture 95.61% Co-authored-by: opencode/coder <coder@agents.invalid> Co-authored-by: opencode/test-engineer <test-engineer@agents.invalid> Co-authored-by: opencode/tech-writer <tech-writer@agents.invalid>
This commit is contained in:
16
TODO.md
16
TODO.md
@@ -131,20 +131,20 @@ Lire l'agenda théorique (JSON) via une interface de provider extensible, avec g
|
||||
- Une configuration incomplète (ancre de parité manquante alors que des leçons `even`/`odd` existent) produit une erreur explicite.
|
||||
|
||||
---
|
||||
|
||||
## M7. Synchronisation CalDAV — Priorité : Haute
|
||||
|
||||
Synchroniser différentiellement les événements Pronote vers le calendrier CalDAV, de façon idempotente.
|
||||
|
||||
- [x] Créer `sync/caldav.py` : passerelle CalDAV isolant la bibliothèque `caldav>=1.3.0` (connexion via `DAVClient`, résolution du calendrier via `calendar_path`, récupération/ajout/MAJ/suppression des événements, marqueur `X-PRONOTE-SYNC-MANAGED: v1`).
|
||||
- [x] Calculer le `CalDAVSyncPlan` (to_add / to_update / to_remove) par UID stable, explicitement avant l'exécution de la sync.
|
||||
- [x] Implémenter l'exécution du plan : ajout, mise à jour (si modifié), suppression (si absent). En mode `dry_run`, loguer le plan sans écrire.
|
||||
- [x] Vérifier sur fixture anonymisée que le même cours provenant d'iCal et de `pronotepy` possède le même identifiant canonique ; corriger la normalisation des UID dans `sources/pronote/client.py` à la frontière des sources si nécessaire.
|
||||
- [x] Implémenter la sync différentielle : conserver les cours annulés (`STATUS:CANCELLED`), ne pas supprimer.
|
||||
- [x] Garantir l'idempotence (2 exécutions identiques → même `CalDAVSyncResult`), sans état local persistant (scan du calendrier distant).
|
||||
- [x] Ne jamais modifier ou supprimer les événements non marqués `X-PRONOTE-SYNC-MANAGED`.
|
||||
- [ ] Créer `sync/caldav.py` : passerelle CalDAV isolant la bibliothèque `caldav>=1.3.0` (connexion via `DAVClient`, résolution du calendrier via `calendar_path`, récupération/ajout/MAJ/suppression des événements, marqueur `X-PRONOTE-SYNC-MANAGED: v1`).
|
||||
- [ ] Calculer le `CalDAVSyncPlan` (to_add / to_update / to_remove) par UID stable, explicitement avant l'exécution de la sync.
|
||||
- [ ] Implémenter l'exécution du plan : ajout, mise à jour (si modifié), suppression (si absent). En mode `dry_run`, loguer le plan sans écrire.
|
||||
- [ ] Vérifier sur fixture anonymisée que le même cours provenant d'iCal et de `pronotepy` possède le même identifiant canonique ; corriger la normalisation des UID dans `sources/pronote/client.py` à la frontière des sources si nécessaire.
|
||||
- [ ] Implémenter la sync différentielle : conserver les cours annulés (`STATUS:CANCELLED`), ne pas supprimer.
|
||||
- [ ] Garantir l'idempotence (2 exécutions identiques → même `CalDAVSyncResult`), sans état local persistant (scan du calendrier distant).
|
||||
- [ ] Ne jamais modifier ou supprimer les événements non marqués `X-PRONOTE-SYNC-MANAGED`.
|
||||
|
||||
### Critères d'acceptation
|
||||
|
||||
- Le plan de sync est correctement calculé (données Pronote vs événements distants gérés).
|
||||
- Un changement de source iCal ↔ `pronotepy` ne crée ni doublon ni suppression/ajout artificiel pour un cours équivalent.
|
||||
- Un run dry-run n'écrit rien ; deux runs identiques donnent un résultat identique.
|
||||
|
||||
Reference in New Issue
Block a user