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:
2026-09-07 12:24:22 +02:00
parent b4b0247919
commit a1bae41be8
14 changed files with 735 additions and 298 deletions

View File

@@ -21,6 +21,7 @@ from icalendar import Calendar, Component, Event, vDate, vDatetime
from pronote_sync.models.agenda import Lesson, LessonStatus, SchoolEvent
from pronote_sync.models.homework import Homework
from pronote_sync.utils.uid import normalize_datetime_to_utc
#: Propriété iCalendar marquant un événement géré par ``pronote-sync``.
MANAGED_PROPERTY = "X-PRONOTE-SYNC-MANAGED"
@@ -175,7 +176,10 @@ def component_to_signature(component: Component) -> str:
continue
value = getattr(raw, "dt", raw)
if hasattr(value, "isoformat"):
rendered = value.isoformat()
if isinstance(value, datetime):
rendered = normalize_datetime_to_utc(value).isoformat()
else:
rendered = value.isoformat()
else:
rendered = str(value).strip().lower()
props.append(f"{key.lower()}={rendered}")