Corrige les 5 points de l'audit FIXME_M5 :
1. (Bloquant) Sépare transport HTTP et parsing : utilise requests.get()
avec timeout explicite et en-têtes conditionnels, puis transmet le
contenu à feedparser.parse() — supprime le paramètre inexistant
request_timeout qui faisait échouer toute récupération réelle.
2. Rejette les statuts HTTP 4xx/5xx via raise_for_status() avant le
parsing.
3. Préserve les validateurs de cache (etag, last_modified) d'entrée sur
les chemins d'échec (exception, bozo) au lieu de les écraser à None.
4. Sauvegarde atomique de BlogRSSState : écrit dans un .tmp puis
Path.replace() pour éviter la corruption sur interruption.
5. Déduplication normale silencieuse : les GUID déjà connus sont
ignorés sans warning ; seuls les doublons intra-flux génèrent un
avertissement.
Tests : 49 tests (32 client + 17 state) dont 11 nouveaux couvrant
transport HTTP réel, statuts 401/404/500, préservation des validateurs,
en-têtes conditionnels, doublons intra-flux et sauvegarde atomique.
Guide : §5 bis.7.1 aligné avec le nouveau pattern transport/parsing.
Co-authored-by: opencode/coder <coder@agents.invalid>
Co-authored-by: opencode/test-engineer <test-engineer@agents.invalid>
Les modes explicites (ical, pronotepy) ne basculent plus silencieusement vers
l'autre source en cas d'échec. Seul le mode auto conserve le repli iCal →
pronotepy sur exception. Conforme au contrat de TODO.md M4 et AGENTS.md.
- fallback.py : _agenda_sources() et _homework_sources() retournent
(source, None) en mode explicite ; docstrings mises à jour.
- test_fallback.py : 4 tests remplacés, 4 tests ajoutés (non-repli +
empty-list-is-success), 4 tests ajustés ; :rtype: None ajouté.
Co-authored-by: coder/coder coder@agents.invalid
Co-authored-by: test-engineer/test-engineer test-engineer@agents.invalid
Configuration (D1+D3) :
- PronoteSettings : ajout pronote_url (str | None) et account_type
(Literal student/parent, défaut parent)
Parsing iCal (Fix 4+7) :
- parse_ical : détection STATUS:CANCELLED en plus de CATEGORIES
- parse_body : list[tuple[date, str]] au lieu de dict[date, str]
pour préserver les blocs multiples à la même date
- parse_homework_blocks : adapté aux listes
Co-authored-by: opencode/coder <coder@agents.invalid>
- AgendaSource : enum StrEnum (AUTO/ICAL/PRONOTEPY)
- PronoteFetcherProtocol : Protocol consommé par le pipeline
- PronoteFetcher : unifie iCal et pronotepy avec repli automatique
- AUTO : iCal d'abord, repli pronotepy, PipelineCriticalError si
les deux échouent
- ICAL/PRONOTEPY : source explicite, erreur redactée puis
PipelineCriticalError
- Messages et informations : toujours via pronotepy
- Avertissement quand le repli pronotepy retourne un résultat vide
après échec iCal (limite du mode dégradé)
Co-authored-by: opencode/coder <coder@agents.invalid>
- PronoteClientProtocol : Protocol (get_messages, get_informations,
get_agenda_fallback) pour la logique de repli
- PronoteClient : encapsule pronotepy.Client (connexion paresseuse)
avec API réelle 2.15.7 (lessons/homework/discussions/information_and_surveys)
- Erreurs PronoteAPIError et ValueError catchées, loggées avec
redact_exception, retournent des résultats vides
- Aucune fuite de secret (get_secret_value() uniquement à la connexion)
- pre-commit : ajout de pronotepy au hook mypy
Co-authored-by: opencode/coder <coder@agents.invalid>
- Guide de développement (GUIDE_DEV_PYTHON.md) : spécification complète
- TODO.md : 15 jalons de développement (M1-M15) avec étapes et critères d'acceptation
- AGENTS.md : guide de contribution pour agents et développeurs
- pyproject.toml : configuration projet (dépendances, ruff, mypy strict, pytest)
- .gitignore : exclusion venv, bytecode, .env, caches, state files
- .env.example : template des variables d'environnement (placeholders)
- Structure du package pronote_sync/ (14 sous-packages avec __init__.py)
- tests/ avec conftest.py et fixtures/
- Environnement virtuel .venv/ (Python 3.14)