Research: Profil de boîtiers optionnel, déclaré à la demande
1. Lecture des tags EXIF Model et BodySerialNumber
Decision: Lire ces tags via le binaire externe exiftool, en processus persistant (exiftool -stay_open) plutôt qu'un lancement par fichier, à travers un wrapper léger regine_core/metadata/exif.py.
Rationale: Les notes de conception du projet (docs/archivage-photo-elements-cles.md sections 11 et 13) utilisent déjà exiftool pour toute lecture EXIF avancée sur ce projet (RawDataUniqueID, ImageDataHash, DocumentID/OriginalDocumentID) en raison de son support fiable des RAW propriétaires, que peu de bibliothèques Python pures gèrent correctement. Réutiliser le même outil pour Model/BodySerialNumber évite d'introduire un second mécanisme de lecture EXIF avec un comportement potentiellement différent selon le format. Le mode -stay_open évite le coût de démarrage d'un nouveau processus par fichier sur un import de plusieurs centaines de photos.
Alternatives considered:
- Bibliothèque Python pure (
piexif,exifread,Pillow.ExifTags) — rejeté : support inconsistant des formats RAW propriétaires (RAF, CR2, NEF, ARW...), alors queexiftoolest déjà le choix retenu ailleurs dans le projet pour cette même raison. - Appel
exiftoolponctuel par fichier (sans-stay_open) — rejeté : coût de démarrage du processus non négligeable multiplié par le nombre de fichiers d'un import typique.
2. Emplacement de la table boitiers et de la logique de résolution
Decision: Nouveau module regine_core/camera_profile/, propriétaire de la table boitiers (dans la base de contexte centralisée déjà actée par specs/003-config-contexte-travail) et de l'algorithme de résolution. Corrige un placement provisoire : specs/003-config-contexte-travail/plan.md avait prévu regine_core/config/cameras.py pour cette logique ; ce plan établit camera_profile comme propriétaire, config ne conservant que son écran de nommage proactif (User Story 3 de specs/003), qui appelle camera_profile plutôt que de posséder sa propre logique.
Rationale: docs/interface-cli-gui-architecture.md liste déjà camera_profile comme module de premier niveau distinct de la configuration des chemins de travail. Laisser deux specs (002 et 003) définir chacune leur propre table boitiers contredirait le Principe VI de la constitution (bibliothèque centrale, pas de logique métier dupliquée) et risquerait une divergence de schéma entre les deux.
Alternatives considered:
- Conserver la table sous
regine_core/config/comme provisoirement planifié en specs/003 — rejeté pour la raison ci-dessus ;specs/003-config-contexte-travail/plan.mdest corrigé en conséquence dans la foulée de ce plan.
3. Conception de l'algorithme de résolution
Decision: Fonction pure resolve_collision(files: list[FileWithTags]) -> CollisionResolution, qui prend en entrée un groupe de fichiers déjà identifié en collision (même nom d'origine, sommes de contrôle différentes — détection hors périmètre de ce module, fournie par l'appelant), et qui :
- Regroupe les fichiers par tag
Model. - Au sein d'un groupe de même modèle, tente de les distinguer par
BodySerialNumber(quand présent et exploitable). - Retourne, pour les fichiers encore indistincts après ces deux étapes, un groupe nécessitant un étiquetage manuel (FR-005), plutôt que de choisir arbitrairement.
Rationale: Séparer la détection de collision (par somme de contrôle, module import/integrity) de la désambiguïsation de source (par métadonnées, ce module) garde chaque responsabilité testable indépendamment — cohérent avec la découpe en fonctions pures déjà retenue pour specs/004-categorisation-dossiers.
Alternatives considered:
- Fusionner détection de collision et résolution de source dans une seule fonction — rejeté : mélangerait deux responsabilités relevant de modules différents (checksum vs métadonnées EXIF).
Résumé
Tous les points du Technical Context sont résolus. Aucune dépendance tierce Python nouvelle ; exiftool est une dépendance externe déjà implicite du projet, pas une addition. Une correction de placement de module est propagée vers specs/003-config-contexte-travail/plan.md.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|