fonzarely/regine-photos-archiverpublic Fork
⑂ main
Commits
⬇ Clone ▾
git clone https://git.rickub.com/fonzarely/regine-photos-archiver.git
git clone ssh://git@rickub.com/fonzarely/regine-photos-archiver.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
duplicates a1d9142 · on main · Fabien Champigny · Sep 22, 2026
tasks.md · 217 lines · 23.4 KBmarkdown
Blame HistoryOpen raw

description: "Task list for feature implementation"

Tasks: Importation de photos depuis une carte mémoire

Input: Design documents from /specs/001-import-photos/
Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md

Tests: Incluses — plan.md § Project Structure nomme explicitement les fichiers de test attendus, ce qui vaut demande explicite au sens des règles de génération.

Organisation: Tasks groupées par user story (spec.md) pour une implémentation et une validation indépendantes de chacune.

Dépendances inter-specs (à lire avant de commencer)

Ce module est le premier point d'intégration réel de trois autres specs déjà planifiées. Aucun code n'existe encore dans ce dépôt à ce jour.

Dépendance Fournit État
specs/004-categorisation-dossiers/tasks.md Squelette du monorepo (packages/regine-core, packages/regine-cli, packages/regine-gui, packages/regine-agent), regine_core.dossier.root.determine_root, regine_core.config.categories, regine_core.config.db tasks.md existe (27 tâches) — à exécuter avant la Phase 1 ci-dessous si ce n'est pas déjà fait
specs/002-profil-boitiers-optionnel regine_core.camera_profile.resolve_collision, regine_core.metadata.exif (lecture Model/BodySerialNumber) Pas encore de tasks.md — à générer (/speckit-tasks sur 002) et implémenter avant la Phase 5 (US3, désambiguïsation de boîtiers) ; les Phases 1 à 4 de ce fichier n'en dépendent pas
specs/005-checkout-reconciliation regine_core.archive.checkout.checkout Pas encore de tasks.md — nécessaire uniquement pour T034 (fusion vers un dossier déjà archivé) ; tout le reste de ce fichier n'en dépend pas

Phase 1: Setup

Purpose: Vérifier les prérequis inter-specs et poser le squelette propre à ce module.

  • T001 Vérifier que packages/regine-core/src/regine_core/dossier/root.py et packages/regine-core/src/regine_core/config/categories.py existent déjà (créés par specs/004-categorisation-dossiers/tasks.md) ; si absents, exécuter d'abord ce fichier de tâches avant de continuer
  • T002 [P] Créer packages/regine-core/src/regine_core/import_carte/__init__.py
  • T003 [P] Créer packages/regine-cli/src/regine_cli/import_cmd.py (squelette de la commande regine import, sans logique) — reportée à la fin de US1 (T019), une fois la logique métier disponible à orchestrer
  • T004 [P] Créer les dossiers packages/regine-core/tests/unit/ et packages/regine-core/tests/integration/ s'ils n'existent pas déjà (normalement déjà créés par specs/004) — déjà présents

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Infrastructure partagée requise par les trois user stories de cette fonctionnalité.

⚠️ CRITICAL: Aucune user story ne peut être implémentée avant la fin de cette phase.

  • T005 Créer packages/regine-core/src/regine_core/import_carte/types.py : dataclasses FichierCandidat, GroupeImport, DestinationChoisie, Renommage (cf. data-model.md)
  • T006 Étendre packages/regine-core/src/regine_core/metadata/exif.py (existant, specs/002) avec read_capture_date(chemin) -> datetime | None (tag EXIF DateTimeOriginal, cf. research.md § 2)
  • T007 Étendre packages/regine-core/src/regine_core/metadata/exif.py avec write_document_id(chemin, identifiant) -> None (écrit xmpMM:DocumentID via exiftool, idempotent, cf. research.md § 3) — read_document_id ajoutée aussi, utile pour tests/manifeste
  • T008 [P] Test unitaire de read_capture_date/write_document_id dans packages/regine-core/tests/unit/test_identifiant.py (date valide, date absente ; écriture puis relecture de l'identifiant) — validé avec de vraies opérations exiftool

Checkpoint: Fondations prêtes — les phases User Story peuvent commencer.


Phase 3: User Story 1 - Import simple d'une carte mémoire vers un nouveau dossier (Priority: P1) 🎯 MVP

Goal: Copier une carte, proposer un groupe unique, choisir titre et placement par défaut (année), renommer, attribuer un identifiant pérenne, confirmer et archiver (FR-001/002/004/005/007 [nouveau_dossier]/010/012/013/014/017/018/019).

Independent Test: Importer une carte d'une seule journée sans catégorie ; vérifier qu'un dossier correctement nommé et vérifié apparaît dans l'archive, sans dépendre d'aucune autre user story.

Tests for User Story 1

  • T009 [P] [US1] Test unitaire copie vérifiée : une seule lecture de la carte, échec de vérification signalé sans marquer la carte sûre à effacer, dans packages/regine-core/tests/unit/test_copie_checksum.py
  • T010 [P] [US1] Test unitaire découpage en groupe unique (cas simple, une seule journée) dans packages/regine-core/tests/unit/test_groupage_dates.py
  • T011 [P] [US1] Test unitaire construction du nom de dossier et détection de collision dans packages/regine-core/tests/unit/test_nommage.py
  • T012 [US1] Test d'intégration du pipeline complet (carte simple → dossier archivé, résumé confirmé) dans packages/regine-core/tests/integration/test_pipeline_import_simple.py

Implementation for User Story 1

  • T013 [US1] Implémenter copier_carte(carte, local_tmp) -> list[FichierCandidat] dans packages/regine-core/src/regine_core/import_carte/copie.py (FR-001 : une seule lecture carte, FR-004 : filtrage des fichiers déjà importés)
  • T014 [US1] Implémenter decouper_en_groupes(fichiers) -> list[GroupeImport] dans packages/regine-core/src/regine_core/import_carte/groupage.py (FR-002 lecture date, branche groupe unique par défaut de FR-005 ; le détachement multi-jours est complété en Phase 4)
  • T015 [US1] Implémenter la branche nouveau_dossier de resoudre_destination dans packages/regine-core/src/regine_core/import_carte/destination.py (FR-007 pour ce cas, appelle regine_core.dossier.root.determine_root)
  • T016 [US1] Implémenter construire_nom_dossier/renommer_fichiers dans packages/regine-core/src/regine_core/import_carte/nommage.py (FR-010/012/013/014)
  • T017 [US1] Implémenter attribuer_identifiants dans packages/regine-core/src/regine_core/import_carte/identifiant.py (FR-017, appelle write_document_id)
  • T018 [US1] Implémenter preparer_resume/archiver dans packages/regine-core/src/regine_core/import_carte/push.py (FR-018/019) — complété le 2026-09-19 par publier_copie_locale, suite à un écart avec FR-010 signalé par l'utilisateur après relecture du README (aucune copie de travail locale exploitable n'était laissée après import) ; réutilise le manifeste/verrou de specs/005 plutôt qu'un mécanisme parallèle — cf. contracts/regine-core-api.md
  • T019 [US1] Orchestrer le pipeline dans packages/regine-cli/src/regine_cli/import_cmd.py pour regine import <carte> --annee --titre TEXTE (cas nouveau_dossier uniquement) — validé en conditions réelles (python -m regine_cli.import_cmd import ...)

Checkpoint: User Story 1 fonctionnelle et testable indépendamment (MVP).


Phase 4: User Story 2 - Découpage d'un import multi-jours en plusieurs groupes (Priority: P2)

Goal: Détecter la plage de dates, exclure les dates aberrantes, mettre en avant un jour candidat au détachement, permettre à l'utilisateur de détacher et de traiter chaque groupe séparément (FR-003/005/006).

Independent Test: Importer une carte couvrant une semaine avec un pic isolé ; vérifier que ce jour est proposé comme candidat, jamais détaché automatiquement, et que le détacher produit deux dossiers distincts.

Tests for User Story 2

  • T020 [P] [US2] Test unitaire d'exclusion des dates aberrantes du calcul de plage dans packages/regine-core/tests/unit/test_groupage_dates.py
  • T021 [P] [US2] Test unitaire de mise en avant d'un jour candidat au détachement (heuristique, cf. research.md § 5) et de détachement manuel dans test_groupage_dates.py
  • T022 [US2] Test d'intégration du découpage en plusieurs groupes avec destination/titre distincts dans packages/regine-core/tests/integration/test_pipeline_multi_jours.py

Implementation for User Story 2

  • T023 [US2] Étendre decouper_en_groupes : exclusion des dates aberrantes (FR-003) et heuristique de mise en avant d'un jour candidat (FR-006, cf. research.md § 5), dans groupage.py (dépend de T014) — implémentée dès T014 (Phase 3), une seule passe d'écriture cohérente
  • T024 [US2] Ajouter le détachement manuel d'un ou plusieurs jours par l'utilisateur, produisant des GroupeImport distincts, dans groupage.py — implémentée dès T014
  • T025 [US2] Étendre packages/regine-cli/src/regine_cli/import_cmd.py pour afficher la répartition jour par jour et gérer le détachement interactif, puis demander destination/titre pour chaque groupe résultant — implémentée dès T019 (_proposer_detachement)

Checkpoint: User Stories 1 ET 2 fonctionnelles indépendamment.


Phase 5: User Story 3 - Import s'intégrant à un voyage en plusieurs étapes (Priority: P3)

Goal: Structure à deux niveaux (parent/sous-dossier), fusion locale et vers l'archive, désambiguïsation de boîtiers en cas de collision (FR-007 [nouveau_sous_dossier/nouveau_parent/fusion]/008/009/015/016).

Independent Test: Importer une première carte comme "nouveau dossier parent avec sa première étape", une seconde comme "nouveau sous-dossier", vérifier la structure à deux niveaux et l'héritage du répertoire racine.

Tests for User Story 3

  • T026 [P] [US3] Test unitaire de recherche de dossiers candidats par titre/date proche (difflib, cf. research.md § 4) dans packages/regine-core/tests/unit/test_destination_candidats.py
  • T027 [P] [US3] Test unitaire : la branche nouveau_sous_dossier réutilise le RootLocation du parent sans nouvel appel à determine_root, dans test_destination_candidats.py
  • T028 [US3] Test d'intégration voyage complet (parent + sous-dossier + fusion locale + désambiguïsation de boîtiers) dans packages/regine-core/tests/integration/test_pipeline_voyage.py
  • T029 [US3] Test d'intégration de la fusion vers un dossier déjà archivé dans test_pipeline_voyage.py — teste un vrai appel à regine_core.archive.checkout.checkout (specs/005)

Implementation for User Story 3

  • T030 [US3] Étendre resoudre_destination : branches nouveau_sous_dossier (hérite le RootLocation du parent, FR-006 de specs/004) et nouveau_parent (FR-007), dans destination.py (dépend de T015) — implémentées dès T015
  • T031 [US3] Implémenter lister_dossiers_candidats(titre_partiel, date_proche) dans destination.py (FR-008, cf. research.md § 4) — implémentée dès T015
  • T032 [US3] Implémenter la branche fusion locale de resoudre_destination (dossier cible présent dans l'espace de travail local) dans destination.py (FR-009, partie locale) — resoudre_fusion()
  • T033 [US3] Implémenter la branche fusion vers un dossier déjà archivé : appelle regine_core.archive.checkout.checkout (specs/005-checkout-reconciliation), dans destination.py — resoudre_fusion(), validé avec un vrai checkout
  • T034 [US3] Intégrer la désambiguïsation de boîtiers dans copie.py : regrouper les fichiers en collision de nom d'origine, appeler regine_core.camera_profile.resolve_collision (specs/002), gérer les groupes nécessitant un étiquetage manuel (FR-015/016) — regrouper_par_nom_origine/resoudre_collisions_boitiers ; copie anti-collision ajoutée dans copier_carte (ne jamais écraser un fichier de même nom d'origine)
  • T035 [US3] Étendre packages/regine-cli/src/regine_cli/import_cmd.py pour les 4 types de destination et la résolution interactive de collision de boîtiers — --destination nouveau|parent|sous-dossier:CHEMIN|fusion:CHEMIN (cf. contracts/cli-import.md), étiquetage manuel interactif via list_boitiers/assign_manual_source. Validation manuelle (CLI réel, pas seulement tests unitaires) a révélé et corrigé 2 bugs : (1) le sous-dossier d'étape n'était pas physiquement imbriqué sous le dossier parent réel, seulement sous la racine catégorie héritée ; (2) push.archiver écrasait silencieusement un fichier archivé de contenu différent en cas de collision de nom entre deux imports séparés — cf. CollisionNomArchiveError et contracts/regine-core-api.md

Checkpoint: User Stories 1, 2 et 3 fonctionnelles (la fusion vers un dossier déjà archivé reste conditionnée à specs/005, tout le reste est indépendant).


Phase 6: Polish & Cross-Cutting Concerns

  • T036 [P] Exécuter manuellement les 3 scénarios de specs/001-import-photos/quickstart.md et consigner le résultat — exécutés via la vraie CLI (uv run python -m regine_cli.import_cmd import ..., entrées interactives réelles pour le détachement) : scénario 1 (import simple) OK, scénario 2 (détachement du jour au pic isolé, réponse "o") OK, scénario 3 (parent + sous-dossier imbriqué + fusion avec checkout automatique + désambiguïsation de boîtiers) OK
  • T037 [P] ruff check --fix sur packages/regine-core et packages/regine-cli
  • T038 Mettre à jour contracts/cli-import.md et contracts/regine-core-api.md si l'implémentation révèle un écart avec les signatures documentées — les deux contrats réécrits pour refléter les signatures réelles (resoudre_destination/resoudre_fusion/regrouper_par_nom_origine/resoudre_collisions_boitiers, syntaxe --destination), et pour documenter CollisionNomArchiveError

Phase 7: Révision 2026-09-22 — archivage différé et classement par format

Contexte : deux écarts trouvés par test manuel de l'onglet d'import GUI (specs/006-gui-tri-consultation User Story 3) — cf. Clarifications de spec.md. (1) L'import poussait automatiquement vers l'archive NAS en fin d'opération, sans laisser au photographe l'occasion de relire/retoucher sa copie locale d'abord, et empêchait de tester l'import sans accès à un NAS réel. (2) Les fichiers n'étaient jamais classés dans un dossier de format (raw//jpeg//tiff/), contrairement à docs/archivage-photo-elements-cles.md section 10 et à l'écran de tri (specs/006) qui suppose cette structure déjà en place.

  • T039 [P] Déplacer dossier_de_format (et les ensembles d'extensions RAW/TIFF/JPEG) de regine_core.dossier.selection vers regine_core.import_carte.copie, ré-exportée depuis dossier.selection pour ne pas casser les appelants existants (specs/006) — évite une dépendance inversée entre les deux modules (Principe VI)
  • T040 Créer regine_core.import_carte.classement.classer_par_format(fichiers, racine) (FR-020) : déplace chaque fichier maître dans son dossier de format (déduit de sa propre extension, jamais celui d'un autre maître de même nom de base — cas RAW+JPEG jumeau), et chaque sidecar dans le dossier du maître RAW partageant son nom de base s'il y en a un, sinon celui de n'importe quel autre maître. Testé dans packages/regine-core/tests/unit/test_classement.py (5/5 tests, dont le cas jumeau RAW+JPEG+sidecar)
  • T041 Remplacer push.archiver/push.publier_copie_locale (écriture NAS + manifeste + verrou immédiats) par push.publier_localement (copie vérifiée vers l'espace de travail local uniquement, aucun manifeste/verrou/écriture NAS) — CollisionNomArchiveError renommée CollisionNomLocalError. Ancien fichier de test test_push_archiver.py remplacé par test_push_publier_localement.py (5/5 tests)
  • T042 Mettre à jour test_pipeline_import_simple.py (intégration) : ajoute l'étape de classement, publie vers dossier_local plutôt que dossier_archive, vérifie explicitement que l'archive n'est jamais créée
  • T043 Mettre à jour packages/regine-cli/src/regine_cli/import_cmd.py : classer_par_format avant attribuer_identifiants, publier_localement remplace archiver+publier_copie_locale, message final indiquant la commande regine reconcile à lancer plus tard pour archiver
  • T044 Mettre à jour packages/regine-gui/src/regine_gui/import_view.py : import ne bloque plus si le partage SMB n'est pas monté (seul son chemin, via chemin_local_du_partage, sert au calcul — plus resoudre_archive_locale, qui exigeait une disponibilité réelle) ; _ArchivageWorker renommé _PublicationLocaleWorker, regroupant désormais classement + identifiants + publication locale sur le thread d'arrière-plan (déplacement supplémentaire par rapport à la première version de US3, qui ne déplaçait que l'ancien archiver/publier_copie_locale) ; dialogues et journal reformulés (« Confirmer la copie de travail locale », jamais « archivage »)
  • T045 [P] ruff check --fix/ruff format sur packages/regine-core, packages/regine-cli, packages/regine-gui ; validation manuelle en mode headless (import complet sans archive configurée/montée, structure raw//jpeg/ obtenue, aucune écriture sous /Volumes/...) — 176/176 tests regine-core/regine-cli au vert
  • T046 Mettre à jour spec.md (Clarifications, User Story 1, FR-018/019, nouveau FR-020, Key Entities, Success Criteria SC-002/006/008 reformulés + nouveaux SC-009/SC-010, Assumptions), data-model.md, contracts/cli-import.md, quickstart.md, checklists/requirements.md pour refléter cette révision

Checkpoint : l'import se termine par une copie de travail locale classée par format, jamais par une écriture sur l'archive ; l'archivage réutilise regine reconcile (specs/005-checkout-reconciliation) sans aucune modification de ce dernier.


Phase 8: Révision 2026-09-22 (bis) — détection de doublons entre imports (FR-004 révisé)

Contexte : test manuel de l'utilisateur — importer deux fois la même carte vers deux dossiers différents n'affichait aucun avertissement. Cause racine trouvée : le paramètre checksums_deja_importes de copie.copier_carte (déjà en place et testé isolément depuis T009) n'était jamais renseigné par aucun appelant réel — ni regine_cli.import_cmd, ni regine_gui.import_view. La déduplication ne fonctionnait donc dans aucun cas réel, y compris le cas initialement visé par FR-004 (carte non effacée entre deux imports).

  • T047 [P] Créer regine_core.import_carte.historique (enregistrer_import, rechercher_doublons) — nouvelle table checksums_importes dans la base de contexte centralisée (regine_core.config.db, specs/003), même schéma d'implantation que camera_profile.db pour boitiers. Testé dans packages/regine-core/tests/unit/test_historique.py (4/4 tests : recherche vide, retrouve un doublon, idempotence/mise à jour du dossier, ignore les checksums inconnus)
  • T048 [US1] Étendre packages/regine-cli/src/regine_cli/import_cmd.py : conn ouvert avant copier_carte (au lieu d'après) pour permettre rechercher_doublons(conn, ...) juste après la copie ; _confirmer_malgre_doublons affiche les fichiers/dossiers concernés et demande confirmation (continue sans bloquer en mode --yes, mais reste visible sur stdout) ; enregistrer_import appelé juste après chaque publier_localement réussi
  • T049 [US3] Étendre packages/regine-gui/src/regine_gui/import_view.py : _confirmer_malgre_doublons (QMessageBox) après copier_carte dans _analyser ; _checksums_en_cours mémorisé comme _titre_en_cours/_dossier_archive_en_cours avant de lancer le worker, enregistrer_import appelé dans _sur_publication_succes (thread principal, jamais dans le worker — même précaution que pour la connexion SQLite déjà rencontrée en Phase 7)
  • T050 [P] Validé manuellement en mode headless : script import et deux fois la même carte (fake RAW+JPEG) vers deux dossiers différents (« DossierA » puis « DossierB ») — le second import affiche bien l'avertissement de doublon avec le chemin du premier dossier, avant la confirmation de copie locale. ruff check --fix/ruff format sur les trois paquets — 180/180 tests regine-core/regine-cli au vert
  • T051 Mettre à jour spec.md (Clarifications, FR-004 réécrite, Edge Case, nouvelle entité Historique des imports, SC-011, Assumptions), data-model.md, contracts/cli-import.md, contracts/regine-core-api.md pour refléter cette révision

Checkpoint : un import détecte désormais tout fichier déjà importé précédemment (même carte non effacée, ou dossier de destination différent d'un import antérieur) et en informe l'utilisateur avant de poursuivre — plus jamais une exclusion ou une inclusion silencieuse.


Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1) : dépend des tasks.md de specs/004 (packages, dossier.root, config.categories) déjà exécutées — sinon, à exécuter en premier.
  • Foundational (Phase 2) : dépend de Setup — BLOQUE toutes les user stories.
  • User Stories (Phase 3–5) : dépendent toutes de Foundational.
    • US1 (P1) : aucune dépendance sur une autre user story de ce fichier ; dépend de specs/004 (déjà disponible).
    • US2 (P2) : étend directement les fonctions de US1 (T014, T023/T024) — livrable séparément mais techniquement postérieure à US1.
    • US3 (P3) : étend destination.py de US1 (T015 → T030) ; sa branche de fusion vers l'archive (T033, specs/005) et sa désambiguïsation de boîtiers (T034, specs/002) sont désormais toutes deux activables, ces deux specs étant implémentées (2026-09-19).
  • Polish (Phase 6) : dépend des user stories livrées (au minimum US1).

Parallel Opportunities

  • T002–T004 (Phase 1) : fichiers/dossiers distincts.
  • T008 (Phase 2) : peut suivre T006/T007 en parallèle d'autres tâches de Phase 2 déjà terminées.
  • Tests marqués [P] au sein de chaque story (T009–T011, T020/T021, T026/T027) : fichiers distincts.

Parallel Example: User Story 1

# Lancer les tests de la User Story 1 ensemble :
Task: "Test unitaire copie vérifiée dans packages/regine-core/tests/unit/test_copie_checksum.py"
Task: "Test unitaire découpage groupe unique dans packages/regine-core/tests/unit/test_groupage_dates.py"
Task: "Test unitaire construction nom dossier dans packages/regine-core/tests/unit/test_nommage.py"

Implementation Strategy

MVP First (User Story 1 uniquement)

  1. Vérifier/compléter les prérequis de specs/004 (Phase 1).
  2. Compléter Phase 2 (Foundational).
  3. Compléter Phase 3 (US1) : import simple vers un nouveau dossier par défaut (année).
  4. Arrêt et validation : exécuter le Scénario 1 de quickstart.md.

Livraison incrémentale

  1. Setup + Foundational → socle prêt.
  2. US1 → import simple (MVP) → valider Scénario 1.
  3. US2 → découpage multi-jours → valider Scénario 2.
  4. US3 → voyage multi-étapes → valider Scénario 3, y compris la fusion vers un dossier déjà archivé (T033) et la désambiguïsation de boîtiers (T034), toutes deux activables (specs/005 et specs/002 implémentées le 2026-09-19).

Notes

  • [P] = fichiers différents, sans dépendance non résolue.
  • Chaque user story est livrable et testable indépendamment ; T033/T034 (US3) dépendaient de specs/005/specs/002, toutes deux implémentées (2026-09-19) — plus aucune dépendance externe non résolue dans ce fichier.
  • Committer après chaque tâche ou groupe logique de tâches.
  • Ne pas recréer le squelette monorepo ni regine_core.dossier.root/regine_core.config : ils viennent de specs/004-categorisation-dossiers/tasks.md, à étendre si besoin, jamais dupliquer.
  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
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
---

description: "Task list for feature implementation"
---

# Tasks: Importation de photos depuis une carte mémoire

**Input**: Design documents from `/specs/001-import-photos/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md

**Tests**: Incluses — `plan.md` § Project Structure nomme explicitement les fichiers de test attendus, ce qui vaut demande explicite au sens des règles de génération.

**Organisation**: Tasks groupées par user story (spec.md) pour une implémentation et une validation indépendantes de chacune.

## Dépendances inter-specs (à lire avant de commencer)

Ce module est le premier point d'intégration réel de trois autres specs déjà planifiées. Aucun code n'existe encore dans ce dépôt à ce jour.

| Dépendance | Fournit | État |
|---|---|---|
| `specs/004-categorisation-dossiers/tasks.md` | Squelette du monorepo (`packages/regine-core`, `packages/regine-cli`, `packages/regine-gui`, `packages/regine-agent`), `regine_core.dossier.root.determine_root`, `regine_core.config.categories`, `regine_core.config.db` | tasks.md existe (27 tâches) — **à exécuter avant la Phase 1 ci-dessous** si ce n'est pas déjà fait |
| `specs/002-profil-boitiers-optionnel` | `regine_core.camera_profile.resolve_collision`, `regine_core.metadata.exif` (lecture `Model`/`BodySerialNumber`) | **Pas encore de tasks.md** — à générer (`/speckit-tasks` sur 002) et implémenter avant la Phase 5 (US3, désambiguïsation de boîtiers) ; les Phases 1 à 4 de ce fichier n'en dépendent pas |
| `specs/005-checkout-reconciliation` | `regine_core.archive.checkout.checkout` | **Pas encore de tasks.md** — nécessaire uniquement pour T034 (fusion vers un dossier déjà archivé) ; tout le reste de ce fichier n'en dépend pas |

## Phase 1: Setup

**Purpose**: Vérifier les prérequis inter-specs et poser le squelette propre à ce module.

- [X] T001 Vérifier que `packages/regine-core/src/regine_core/dossier/root.py` et `packages/regine-core/src/regine_core/config/categories.py` existent déjà (créés par `specs/004-categorisation-dossiers/tasks.md`) ; si absents, exécuter d'abord ce fichier de tâches avant de continuer
- [X] T002 [P] Créer `packages/regine-core/src/regine_core/import_carte/__init__.py`
- [X] T003 [P] Créer `packages/regine-cli/src/regine_cli/import_cmd.py` (squelette de la commande `regine import`, sans logique) — reportée à la fin de US1 (T019), une fois la logique métier disponible à orchestrer
- [X] T004 [P] Créer les dossiers `packages/regine-core/tests/unit/` et `packages/regine-core/tests/integration/` s'ils n'existent pas déjà (normalement déjà créés par specs/004) — déjà présents

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Infrastructure partagée requise par les trois user stories de cette fonctionnalité.

**⚠️ CRITICAL**: Aucune user story ne peut être implémentée avant la fin de cette phase.

- [X] T005 Créer `packages/regine-core/src/regine_core/import_carte/types.py` : dataclasses `FichierCandidat`, `GroupeImport`, `DestinationChoisie`, `Renommage` (cf. `data-model.md`)
- [X] T006 Étendre `packages/regine-core/src/regine_core/metadata/exif.py` (existant, specs/002) avec `read_capture_date(chemin) -> datetime | None` (tag EXIF `DateTimeOriginal`, cf. `research.md` § 2)
- [X] T007 Étendre `packages/regine-core/src/regine_core/metadata/exif.py` avec `write_document_id(chemin, identifiant) -> None` (écrit `xmpMM:DocumentID` via exiftool, idempotent, cf. `research.md` § 3) — `read_document_id` ajoutée aussi, utile pour tests/manifeste
- [X] T008 [P] Test unitaire de `read_capture_date`/`write_document_id` dans `packages/regine-core/tests/unit/test_identifiant.py` (date valide, date absente ; écriture puis relecture de l'identifiant) — validé avec de vraies opérations exiftool

**Checkpoint**: Fondations prêtes — les phases User Story peuvent commencer.

---

## Phase 3: User Story 1 - Import simple d'une carte mémoire vers un nouveau dossier (Priority: P1) 🎯 MVP

**Goal**: Copier une carte, proposer un groupe unique, choisir titre et placement par défaut (année), renommer, attribuer un identifiant pérenne, confirmer et archiver (FR-001/002/004/005/007 [nouveau_dossier]/010/012/013/014/017/018/019).

**Independent Test**: Importer une carte d'une seule journée sans catégorie ; vérifier qu'un dossier correctement nommé et vérifié apparaît dans l'archive, sans dépendre d'aucune autre user story.

### Tests for User Story 1

- [X] T009 [P] [US1] Test unitaire copie vérifiée : une seule lecture de la carte, échec de vérification signalé sans marquer la carte sûre à effacer, dans `packages/regine-core/tests/unit/test_copie_checksum.py`
- [X] T010 [P] [US1] Test unitaire découpage en groupe unique (cas simple, une seule journée) dans `packages/regine-core/tests/unit/test_groupage_dates.py`
- [X] T011 [P] [US1] Test unitaire construction du nom de dossier et détection de collision dans `packages/regine-core/tests/unit/test_nommage.py`
- [X] T012 [US1] Test d'intégration du pipeline complet (carte simple → dossier archivé, résumé confirmé) dans `packages/regine-core/tests/integration/test_pipeline_import_simple.py`

### Implementation for User Story 1

- [X] T013 [US1] Implémenter `copier_carte(carte, local_tmp) -> list[FichierCandidat]` dans `packages/regine-core/src/regine_core/import_carte/copie.py` (FR-001 : une seule lecture carte, FR-004 : filtrage des fichiers déjà importés)
- [X] T014 [US1] Implémenter `decouper_en_groupes(fichiers) -> list[GroupeImport]` dans `packages/regine-core/src/regine_core/import_carte/groupage.py` (FR-002 lecture date, branche groupe unique par défaut de FR-005 ; le détachement multi-jours est complété en Phase 4)
- [X] T015 [US1] Implémenter la branche `nouveau_dossier` de `resoudre_destination` dans `packages/regine-core/src/regine_core/import_carte/destination.py` (FR-007 pour ce cas, appelle `regine_core.dossier.root.determine_root`)
- [X] T016 [US1] Implémenter `construire_nom_dossier`/`renommer_fichiers` dans `packages/regine-core/src/regine_core/import_carte/nommage.py` (FR-010/012/013/014)
- [X] T017 [US1] Implémenter `attribuer_identifiants` dans `packages/regine-core/src/regine_core/import_carte/identifiant.py` (FR-017, appelle `write_document_id`)
- [X] T018 [US1] Implémenter `preparer_resume`/`archiver` dans `packages/regine-core/src/regine_core/import_carte/push.py` (FR-018/019) — **complété le 2026-09-19** par `publier_copie_locale`, suite à un écart avec FR-010 signalé par l'utilisateur après relecture du README (aucune copie de travail locale exploitable n'était laissée après import) ; réutilise le manifeste/verrou de specs/005 plutôt qu'un mécanisme parallèle — cf. `contracts/regine-core-api.md`
- [X] T019 [US1] Orchestrer le pipeline dans `packages/regine-cli/src/regine_cli/import_cmd.py` pour `regine import <carte> --annee --titre TEXTE` (cas `nouveau_dossier` uniquement) — validé en conditions réelles (`python -m regine_cli.import_cmd import ...`)

**Checkpoint**: User Story 1 fonctionnelle et testable indépendamment (MVP).

---

## Phase 4: User Story 2 - Découpage d'un import multi-jours en plusieurs groupes (Priority: P2)

**Goal**: Détecter la plage de dates, exclure les dates aberrantes, mettre en avant un jour candidat au détachement, permettre à l'utilisateur de détacher et de traiter chaque groupe séparément (FR-003/005/006).

**Independent Test**: Importer une carte couvrant une semaine avec un pic isolé ; vérifier que ce jour est proposé comme candidat, jamais détaché automatiquement, et que le détacher produit deux dossiers distincts.

### Tests for User Story 2

- [X] T020 [P] [US2] Test unitaire d'exclusion des dates aberrantes du calcul de plage dans `packages/regine-core/tests/unit/test_groupage_dates.py`
- [X] T021 [P] [US2] Test unitaire de mise en avant d'un jour candidat au détachement (heuristique, cf. `research.md` § 5) et de détachement manuel dans `test_groupage_dates.py`
- [X] T022 [US2] Test d'intégration du découpage en plusieurs groupes avec destination/titre distincts dans `packages/regine-core/tests/integration/test_pipeline_multi_jours.py`

### Implementation for User Story 2

- [X] T023 [US2] Étendre `decouper_en_groupes` : exclusion des dates aberrantes (FR-003) et heuristique de mise en avant d'un jour candidat (FR-006, cf. `research.md` § 5), dans `groupage.py` (dépend de T014) — implémentée dès T014 (Phase 3), une seule passe d'écriture cohérente
- [X] T024 [US2] Ajouter le détachement manuel d'un ou plusieurs jours par l'utilisateur, produisant des `GroupeImport` distincts, dans `groupage.py` — implémentée dès T014
- [X] T025 [US2] Étendre `packages/regine-cli/src/regine_cli/import_cmd.py` pour afficher la répartition jour par jour et gérer le détachement interactif, puis demander destination/titre pour chaque groupe résultant — implémentée dès T019 (`_proposer_detachement`)

**Checkpoint**: User Stories 1 ET 2 fonctionnelles indépendamment.

---

## Phase 5: User Story 3 - Import s'intégrant à un voyage en plusieurs étapes (Priority: P3)

**Goal**: Structure à deux niveaux (parent/sous-dossier), fusion locale et vers l'archive, désambiguïsation de boîtiers en cas de collision (FR-007 [nouveau_sous_dossier/nouveau_parent/fusion]/008/009/015/016).

**Independent Test**: Importer une première carte comme "nouveau dossier parent avec sa première étape", une seconde comme "nouveau sous-dossier", vérifier la structure à deux niveaux et l'héritage du répertoire racine.

### Tests for User Story 3

- [X] T026 [P] [US3] Test unitaire de recherche de dossiers candidats par titre/date proche (`difflib`, cf. `research.md` § 4) dans `packages/regine-core/tests/unit/test_destination_candidats.py`
- [X] T027 [P] [US3] Test unitaire : la branche `nouveau_sous_dossier` réutilise le `RootLocation` du parent sans nouvel appel à `determine_root`, dans `test_destination_candidats.py`
- [X] T028 [US3] Test d'intégration voyage complet (parent + sous-dossier + fusion locale + désambiguïsation de boîtiers) dans `packages/regine-core/tests/integration/test_pipeline_voyage.py`
- [X] T029 [US3] Test d'intégration de la fusion vers un dossier **déjà archivé** dans `test_pipeline_voyage.py` — teste un vrai appel à `regine_core.archive.checkout.checkout` (specs/005)

### Implementation for User Story 3

- [X] T030 [US3] Étendre `resoudre_destination` : branches `nouveau_sous_dossier` (hérite le `RootLocation` du parent, FR-006 de specs/004) et `nouveau_parent` (FR-007), dans `destination.py` (dépend de T015) — implémentées dès T015
- [X] T031 [US3] Implémenter `lister_dossiers_candidats(titre_partiel, date_proche)` dans `destination.py` (FR-008, cf. `research.md` § 4) — implémentée dès T015
- [X] T032 [US3] Implémenter la branche `fusion` locale de `resoudre_destination` (dossier cible présent dans l'espace de travail local) dans `destination.py` (FR-009, partie locale) — `resoudre_fusion()`
- [X] T033 [US3] Implémenter la branche `fusion` vers un dossier déjà archivé : appelle `regine_core.archive.checkout.checkout` (`specs/005-checkout-reconciliation`), dans `destination.py` — `resoudre_fusion()`, validé avec un vrai checkout
- [X] T034 [US3] Intégrer la désambiguïsation de boîtiers dans `copie.py` : regrouper les fichiers en collision de nom d'origine, appeler `regine_core.camera_profile.resolve_collision` (specs/002), gérer les groupes nécessitant un étiquetage manuel (FR-015/016) — `regrouper_par_nom_origine`/`resoudre_collisions_boitiers` ; copie anti-collision ajoutée dans `copier_carte` (ne jamais écraser un fichier de même nom d'origine)
- [X] T035 [US3] Étendre `packages/regine-cli/src/regine_cli/import_cmd.py` pour les 4 types de destination et la résolution interactive de collision de boîtiers — `--destination nouveau|parent|sous-dossier:CHEMIN|fusion:CHEMIN` (cf. `contracts/cli-import.md`), étiquetage manuel interactif via `list_boitiers`/`assign_manual_source`. Validation manuelle (CLI réel, pas seulement tests unitaires) a révélé et corrigé 2 bugs : (1) le sous-dossier d'étape n'était pas physiquement imbriqué sous le dossier parent réel, seulement sous la racine catégorie héritée ; (2) `push.archiver` écrasait silencieusement un fichier archivé de contenu différent en cas de collision de nom entre deux imports séparés — cf. `CollisionNomArchiveError` et `contracts/regine-core-api.md`

**Checkpoint**: User Stories 1, 2 et 3 fonctionnelles (la fusion vers un dossier déjà archivé reste conditionnée à `specs/005`, tout le reste est indépendant).

---

## Phase 6: Polish & Cross-Cutting Concerns

- [X] T036 [P] Exécuter manuellement les 3 scénarios de `specs/001-import-photos/quickstart.md` et consigner le résultat — exécutés via la vraie CLI (`uv run python -m regine_cli.import_cmd import ...`, entrées interactives réelles pour le détachement) : scénario 1 (import simple) OK, scénario 2 (détachement du jour au pic isolé, réponse "o") OK, scénario 3 (parent + sous-dossier imbriqué + fusion avec checkout automatique + désambiguïsation de boîtiers) OK
- [X] T037 [P] `ruff check --fix` sur `packages/regine-core` et `packages/regine-cli`
- [X] T038 Mettre à jour `contracts/cli-import.md` et `contracts/regine-core-api.md` si l'implémentation révèle un écart avec les signatures documentées — les deux contrats réécrits pour refléter les signatures réelles (`resoudre_destination`/`resoudre_fusion`/`regrouper_par_nom_origine`/`resoudre_collisions_boitiers`, syntaxe `--destination`), et pour documenter `CollisionNomArchiveError`

---

## Phase 7: Révision 2026-09-22 — archivage différé et classement par format

**Contexte** : deux écarts trouvés par test manuel de l'onglet d'import GUI (`specs/006-gui-tri-consultation` User Story 3) — cf. Clarifications de `spec.md`. (1) L'import poussait automatiquement vers l'archive NAS en fin d'opération, sans laisser au photographe l'occasion de relire/retoucher sa copie locale d'abord, et empêchait de tester l'import sans accès à un NAS réel. (2) Les fichiers n'étaient jamais classés dans un dossier de format (`raw/`/`jpeg/`/`tiff/`), contrairement à `docs/archivage-photo-elements-cles.md` section 10 et à l'écran de tri (`specs/006`) qui suppose cette structure déjà en place.

- [X] T039 [P] Déplacer `dossier_de_format` (et les ensembles d'extensions RAW/TIFF/JPEG) de `regine_core.dossier.selection` vers `regine_core.import_carte.copie`, ré-exportée depuis `dossier.selection` pour ne pas casser les appelants existants (`specs/006`) — évite une dépendance inversée entre les deux modules (Principe VI)
- [X] T040 Créer `regine_core.import_carte.classement.classer_par_format(fichiers, racine)` (FR-020) : déplace chaque fichier maître dans son dossier de format (déduit de sa propre extension, jamais celui d'un autre maître de même nom de base — cas RAW+JPEG jumeau), et chaque sidecar dans le dossier du maître RAW partageant son nom de base s'il y en a un, sinon celui de n'importe quel autre maître. Testé dans `packages/regine-core/tests/unit/test_classement.py` (5/5 tests, dont le cas jumeau RAW+JPEG+sidecar)
- [X] T041 Remplacer `push.archiver`/`push.publier_copie_locale` (écriture NAS + manifeste + verrou immédiats) par `push.publier_localement` (copie vérifiée vers l'espace de travail local uniquement, aucun manifeste/verrou/écriture NAS) — `CollisionNomArchiveError` renommée `CollisionNomLocalError`. Ancien fichier de test `test_push_archiver.py` remplacé par `test_push_publier_localement.py` (5/5 tests)
- [X] T042 Mettre à jour `test_pipeline_import_simple.py` (intégration) : ajoute l'étape de classement, publie vers `dossier_local` plutôt que `dossier_archive`, vérifie explicitement que l'archive n'est jamais créée
- [X] T043 Mettre à jour `packages/regine-cli/src/regine_cli/import_cmd.py` : `classer_par_format` avant `attribuer_identifiants`, `publier_localement` remplace `archiver`+`publier_copie_locale`, message final indiquant la commande `regine reconcile` à lancer plus tard pour archiver
- [X] T044 Mettre à jour `packages/regine-gui/src/regine_gui/import_view.py` : import ne bloque plus si le partage SMB n'est pas monté (seul son chemin, via `chemin_local_du_partage`, sert au calcul — plus `resoudre_archive_locale`, qui exigeait une disponibilité réelle) ; `_ArchivageWorker` renommé `_PublicationLocaleWorker`, regroupant désormais classement + identifiants + publication locale sur le thread d'arrière-plan (déplacement supplémentaire par rapport à la première version de US3, qui ne déplaçait que l'ancien `archiver`/`publier_copie_locale`) ; dialogues et journal reformulés (« Confirmer la copie de travail locale », jamais « archivage »)
- [X] T045 [P] `ruff check --fix`/`ruff format` sur `packages/regine-core`, `packages/regine-cli`, `packages/regine-gui` ; validation manuelle en mode headless (import complet sans archive configurée/montée, structure `raw/`/`jpeg/` obtenue, aucune écriture sous `/Volumes/...`) — 176/176 tests `regine-core`/`regine-cli` au vert
- [X] T046 Mettre à jour `spec.md` (Clarifications, User Story 1, FR-018/019, nouveau FR-020, Key Entities, Success Criteria SC-002/006/008 reformulés + nouveaux SC-009/SC-010, Assumptions), `data-model.md`, `contracts/cli-import.md`, `quickstart.md`, `checklists/requirements.md` pour refléter cette révision

**Checkpoint** : l'import se termine par une copie de travail locale classée par format, jamais par une écriture sur l'archive ; l'archivage réutilise `regine reconcile` (`specs/005-checkout-reconciliation`) sans aucune modification de ce dernier.

---

## Phase 8: Révision 2026-09-22 (bis) — détection de doublons entre imports (FR-004 révisé)

**Contexte** : test manuel de l'utilisateur — importer deux fois la même carte vers deux dossiers différents n'affichait aucun avertissement. Cause racine trouvée : le paramètre `checksums_deja_importes` de `copie.copier_carte` (déjà en place et testé isolément depuis T009) n'était jamais renseigné par aucun appelant réel — ni `regine_cli.import_cmd`, ni `regine_gui.import_view`. La déduplication ne fonctionnait donc dans aucun cas réel, y compris le cas initialement visé par FR-004 (carte non effacée entre deux imports).

- [X] T047 [P] Créer `regine_core.import_carte.historique` (`enregistrer_import`, `rechercher_doublons`) — nouvelle table `checksums_importes` dans la base de contexte centralisée (`regine_core.config.db`, `specs/003`), même schéma d'implantation que `camera_profile.db` pour `boitiers`. Testé dans `packages/regine-core/tests/unit/test_historique.py` (4/4 tests : recherche vide, retrouve un doublon, idempotence/mise à jour du dossier, ignore les checksums inconnus)
- [X] T048 [US1] Étendre `packages/regine-cli/src/regine_cli/import_cmd.py` : `conn` ouvert avant `copier_carte` (au lieu d'après) pour permettre `rechercher_doublons(conn, ...)` juste après la copie ; `_confirmer_malgre_doublons` affiche les fichiers/dossiers concernés et demande confirmation (continue sans bloquer en mode `--yes`, mais reste visible sur stdout) ; `enregistrer_import` appelé juste après chaque `publier_localement` réussi
- [X] T049 [US3] Étendre `packages/regine-gui/src/regine_gui/import_view.py` : `_confirmer_malgre_doublons` (QMessageBox) après `copier_carte` dans `_analyser` ; `_checksums_en_cours` mémorisé comme `_titre_en_cours`/`_dossier_archive_en_cours` avant de lancer le worker, `enregistrer_import` appelé dans `_sur_publication_succes` (thread principal, jamais dans le worker — même précaution que pour la connexion SQLite déjà rencontrée en Phase 7)
- [X] T050 [P] Validé manuellement en mode headless : script import et deux fois la même carte (fake RAW+JPEG) vers deux dossiers différents (« DossierA » puis « DossierB ») — le second import affiche bien l'avertissement de doublon avec le chemin du premier dossier, avant la confirmation de copie locale. `ruff check --fix`/`ruff format` sur les trois paquets — 180/180 tests `regine-core`/`regine-cli` au vert
- [X] T051 Mettre à jour `spec.md` (Clarifications, FR-004 réécrite, Edge Case, nouvelle entité Historique des imports, SC-011, Assumptions), `data-model.md`, `contracts/cli-import.md`, `contracts/regine-core-api.md` pour refléter cette révision

**Checkpoint** : un import détecte désormais tout fichier déjà importé précédemment (même carte non effacée, ou dossier de destination différent d'un import antérieur) et en informe l'utilisateur avant de poursuivre — plus jamais une exclusion ou une inclusion silencieuse.

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)** : dépend des tasks.md de `specs/004` (packages, dossier.root, config.categories) déjà exécutées — sinon, à exécuter en premier.
- **Foundational (Phase 2)** : dépend de Setup — BLOQUE toutes les user stories.
- **User Stories (Phase 3–5)** : dépendent toutes de Foundational.
  - US1 (P1) : aucune dépendance sur une autre user story de ce fichier ; dépend de `specs/004` (déjà disponible).
  - US2 (P2) : étend directement les fonctions de US1 (T014, T023/T024) — livrable séparément mais techniquement postérieure à US1.
  - US3 (P3) : étend `destination.py` de US1 (T015 → T030) ; sa branche de fusion vers l'archive (T033, `specs/005`) et sa désambiguïsation de boîtiers (T034, `specs/002`) sont désormais toutes deux activables, ces deux specs étant implémentées (2026-09-19).
- **Polish (Phase 6)** : dépend des user stories livrées (au minimum US1).

### Parallel Opportunities

- T002–T004 (Phase 1) : fichiers/dossiers distincts.
- T008 (Phase 2) : peut suivre T006/T007 en parallèle d'autres tâches de Phase 2 déjà terminées.
- Tests marqués [P] au sein de chaque story (T009–T011, T020/T021, T026/T027) : fichiers distincts.

---

## Parallel Example: User Story 1

```bash
# Lancer les tests de la User Story 1 ensemble :
Task: "Test unitaire copie vérifiée dans packages/regine-core/tests/unit/test_copie_checksum.py"
Task: "Test unitaire découpage groupe unique dans packages/regine-core/tests/unit/test_groupage_dates.py"
Task: "Test unitaire construction nom dossier dans packages/regine-core/tests/unit/test_nommage.py"
```

---

## Implementation Strategy

### MVP First (User Story 1 uniquement)

1. Vérifier/compléter les prérequis de `specs/004` (Phase 1).
2. Compléter Phase 2 (Foundational).
3. Compléter Phase 3 (US1) : import simple vers un nouveau dossier par défaut (année).
4. **Arrêt et validation** : exécuter le Scénario 1 de `quickstart.md`.

### Livraison incrémentale

1. Setup + Foundational → socle prêt.
2. US1 → import simple (MVP) → valider Scénario 1.
3. US2 → découpage multi-jours → valider Scénario 2.
4. US3 → voyage multi-étapes → valider Scénario 3, y compris la fusion vers un dossier déjà archivé (T033) et la désambiguïsation de boîtiers (T034), toutes deux activables (`specs/005` et `specs/002` implémentées le 2026-09-19).

## Notes

- [P] = fichiers différents, sans dépendance non résolue.
- Chaque user story est livrable et testable indépendamment ; T033/T034 (US3) dépendaient de `specs/005`/`specs/002`, toutes deux implémentées (2026-09-19) — plus aucune dépendance externe non résolue dans ce fichier.
- Committer après chaque tâche ou groupe logique de tâches.
- Ne pas recréer le squelette monorepo ni `regine_core.dossier.root`/`regine_core.config` : ils viennent de `specs/004-categorisation-dossiers/tasks.md`, à étendre si besoin, jamais dupliquer.