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
specs 6ad5e0a · on main · Fabien Champigny · Sep 19, 2026
plan.md · 108 lines · 10.5 KBmarkdown
Blame HistoryOpen raw

Implementation Plan: Checkout et réconciliation d'un dossier de l'archive

Branch: 005-checkout-reconciliation | Date: 2026-09-18 | Spec: spec.md

Input: Feature specification from /specs/005-checkout-reconciliation/spec.md

Summary

Implémente le cycle complet checkout → édition libre → réconciliation → réarchivage pour un dossier déjà présent dans l'archive : copie vérifiée vers un espace de travail local avec enregistrement d'un état de référence persistant, verrouillage côté archive, comparaison par empreinte de contenu classant chaque changement (normal, anomalie sur fichier maître, renommage/déplacement, suppression, nouveau fichier), présentation d'un « point avant archive » et écriture confirmée uniquement. Approche technique : deux nouveaux modules de la bibliothèque centrale déjà nommés dans l'architecture du projet — regine_core.integrity (hash à deux niveaux, décision anomalie/pas-anomalie) et regine_core.archive (manifeste persistant par dossier, verrouillage, checkout, réconciliation) — consommés par une nouvelle façade CLI (regine checkout, regine reconcile). Débloque le sous-scénario FR-009 de specs/001-import-photos et la User Story 4 de specs/004-categorisation-dossiers, tous deux documentés comme bloqués en attendant ce plan.

Technical Context

Language/Version: Python 3.11+ (cohérent avec regine-core, cf. specs/002/003/004)

Primary Dependencies: exiftool (déjà acté par specs/002-profil-boitiers-optionnel, étendu ici pour le calcul de ImageDataHash sur DNG/TIFF/JPEG) ; bibliothèque standard uniquement sinon (hashlib pour l'empreinte fichier entier SHA-256, sqlite3 pour le manifeste persistant, pathlib/shutil pour les copies vérifiées)

Storage: SQLite — un fichier de manifeste par dossier principal (parent + tous ses sous-dossiers), à sa racine sur l'archive, selon les conventions déjà actées par la constitution (PRAGMA user_version/application_id, écriture transactionnelle) ; le verrou de dossier vit dans la même base (table dédiée), pas un fichier séparé (cf. research.md § 2)

Testing: pytest ; tests unitaires sur la classification de réconciliation (les 5 catégories de changement), sur la décision anomalie/pas-anomalie par format, sur le versionnement de schéma ; tests d'intégration sur le cycle complet checkout→édition simulée→réconciliation→réarchivage en répertoires temporaires (archive et local simulés par le système de fichiers)

Target Platform: poste de bureau, identique aux autres modules ; l'archive est accédée comme un partage réseau monté (cf. specs/003-config-contexte-travail), aucune primitive de verrouillage réseau spécifique supposée disponible (cf. research.md § 3, limitation documentée)

Project Type: Monorepo existant — deux nouveaux modules regine_core/integrity/ et regine_core/archive/ (derniers modules de la bibliothèque centrale nommés dans docs/interface-cli-gui-architecture.md mais pas encore construits), plus une nouvelle commande CLI

Performance Goals: la réconciliation d'un dossier de quelques centaines à quelques milliers de fichiers DOIT rester praticable (minutes, pas heures) ; pas de cible chiffrée au-delà, cohérent avec l'absence de cible chiffrée dans la spec elle-même

Constraints: aucune primitive de verrouillage distribué fiable n'est supposée disponible sur un partage SMB ordinaire — le verrouillage reste une protection applicative de bonne foi (toutes les instances de Régine le respectent), pas une garantie absolue contre une écriture concurrente hors de Régine (cf. research.md § 3, limitation déjà acceptée par la constitution : « protections filesystem... en filet de sécurité complémentaire ») ; le travail à plusieurs avec verrouillage fin reste hors périmètre (Assumptions de la spec)

Scale/Scope: dossier archivé typique de quelques dizaines à quelques milliers de fichiers ; usage mono-utilisateur avec protection best-effort contre une seconde instance

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principe / contrainte Évaluation Justification
I. Fichier maître intouchable PASS C'est l'implémentation directe de ce principe : FR-007/FR-008 appliquent exactement le mécanisme de hash à deux niveaux déjà décrit par le Principe I (empreinte fichier entier pour RAW propriétaires, empreinte image-only pour DNG/TIFF/JPEG), et ne réarchivent jamais silencieusement une anomalie.
II. Confirmation explicite avant toute action à risque PASS FR-013 : aucune écriture sur l'archive sans confirmation explicite du « point avant archive » ; FR-011 : aucune suppression propagée automatiquement.
III. Identité par contenu, jamais par nom de fichier seul PASS C'est également une implémentation directe : FR-009/FR-010 détectent tout renommage/déplacement par empreinte de contenu, jamais par chemin ou nom.
IV. Métadonnées ouvertes et embarquées N/A Ce module ne touche pas aux métadonnées descriptives/de droits (légende, mots-clés, etc.) ; il lit l'identifiant pérenne déjà embarqué (specs/001) sans le redéfinir.
V. L'utilisateur décide, Régine suggère PASS FR-012 : tout fichier sans correspondance reste une décision explicite de l'utilisateur, jamais un défaut imposé (cf. spec.md Assumptions, tranché sur ce principe précisément).
VI. Bibliothèque centrale, façades minces PASS regine_core.integrity et regine_core.archive portent toute la logique ; la façade CLI n'orchestre que l'appel et l'affichage du récapitulatif.
CLI-first PASS regine checkout/regine reconcile sont les premières façades construites pour ce mécanisme.
Exécution sans démon PASS Chaque commande est un processus isolé ; le verrou est un état persistant en base, pas un service actif.
Vérification d'intégrité systématique PASS FR-015 : toute copie (checkout et réarchivage) vérifiée par empreinte de contenu.
Vérification périodique indépendante (scrub) N/A (hors périmètre) Explicitement exclu par les Assumptions de la spec ; ce plan ne le construit pas, mais regine_core.integrity (hash à deux niveaux) est conçu pour être réutilisé par un futur scrub sans redéfinition.
Formats ouverts et documentés PASS SQLite, déjà retenu par la constitution pour ce besoin précis (manifeste persistant).

Aucune violation identifiée ; la section Complexity Tracking reste vide.

Re-check post Phase 1 (après génération de data-model.md, contracts/, quickstart.md) : le schéma du manifeste (une table par dossier principal, versionnée) et les contrats CLI/API interne (classification en 5 catégories exposée comme objets structurés, jamais de texte à parser) confirment chaque évaluation PASS ci-dessus. Aucune violation nouvelle.

Project Structure

Documentation (this feature)

specs/005-checkout-reconciliation/
├── plan.md              # This file (/speckit-plan command output)
├── research.md          # Phase 0 output (/speckit-plan command)
├── data-model.md         # Phase 1 output (/speckit-plan command)
├── quickstart.md        # Phase 1 output (/speckit-plan command)
├── contracts/           # Phase 1 output (/speckit-plan command)
│   ├── cli-checkout-reconcile.md
│   └── regine-core-api.md
└── tasks.md             # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)

Source Code (repository root) — extension du monorepo posé par specs/002/003/004

packages/regine-core/
├── src/regine_core/
│   ├── metadata/
│   │   └── exif.py                    # (existant, specs/002) étendu : read_image_data_hash() pour DNG/TIFF/JPEG
│   │
│   ├── integrity/                     # NOUVEAU module (dernier module nommé dans l'architecture, pas encore construit)
│   │   ├── __init__.py
│   │   ├── hash.py                    # hash_fichier_entier() [SHA-256 stdlib], hash_image_only() [délègue à metadata.exif]
│   │   └── anomalie.py                # est_maitre_modifie(format, ref, actuel) -> bool (FR-007/FR-008, Principe I)
│   │
│   └── archive/                       # NOUVEAU module
│       ├── __init__.py
│       ├── manifest.py                # ouverture/initialisation SQLite par dossier principal, PRAGMA user_version/application_id (FR-002/017/018)
│       ├── verrou.py                  # pose/vérifie/lève le verrou dans la même base (FR-003/004/016)
│       ├── checkout.py                # checkout(dossier, dest_locale, formats=None) -> ManifestSnapshot (FR-001/019/020)
│       └── reconciliation.py          # comparer() -> RapportReconciliation (FR-006/009/010/011/012/014), archiver() (FR-013/015/016)
│
└── tests/
    ├── unit/
    │   ├── test_hash_deux_niveaux.py      # RAW propriétaire vs DNG/TIFF/JPEG, anomalie vs édition légitime
    │   ├── test_manifest_versioning.py    # PRAGMA user_version, refus sur évolution structurelle, tolérance additive
    │   ├── test_verrou.py                 # pose, refus de double checkout, levée après réconciliation
    │   └── test_reconciliation_classification.py  # les 5 catégories, y compris déplacement de dossier entier (specs/004)
    └── integration/
        ├── test_cycle_checkout_reconciliation.py   # US1+US2 : checkout → édition simulée → réconciliation → réarchivage
        └── test_checkout_partiel.py               # US6 : formats exclus jamais signalés comme anormaux

packages/regine-cli/
└── src/regine_cli/
    └── archive_cmd.py                 # NOUVEAU : commandes `regine checkout <dossier>` / `regine reconcile <dossier>`

Structure Decision: Extension du monorepo existant — deux modules qui achèvent la liste des modules de bibliothèque centrale déjà documentée (docs/interface-cli-gui-architecture.md : metadata, archive, import, dossier, integrity, camera_profile — seuls archive et integrity manquaient encore). regine_core.metadata.exif (specs/002) est étendu plutôt que dupliqué pour le calcul ImageDataHash. Ce plan complète aussi les points d'intégration laissés en attente par specs/001-import-photos (FR-009) et specs/004-categorisation-dossiers (User Story 4).

Complexity Tracking

Aucune violation de gate à justifier — section laissée vide intentionnellement.

  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
# Implementation Plan: Checkout et réconciliation d'un dossier de l'archive

**Branch**: `005-checkout-reconciliation` | **Date**: 2026-09-18 | **Spec**: [spec.md](./spec.md)

**Input**: Feature specification from `/specs/005-checkout-reconciliation/spec.md`

## Summary

Implémente le cycle complet checkout → édition libre → réconciliation → réarchivage pour un dossier déjà présent dans l'archive : copie vérifiée vers un espace de travail local avec enregistrement d'un état de référence persistant, verrouillage côté archive, comparaison par empreinte de contenu classant chaque changement (normal, anomalie sur fichier maître, renommage/déplacement, suppression, nouveau fichier), présentation d'un « point avant archive » et écriture confirmée uniquement. Approche technique : deux nouveaux modules de la bibliothèque centrale déjà nommés dans l'architecture du projet — `regine_core.integrity` (hash à deux niveaux, décision anomalie/pas-anomalie) et `regine_core.archive` (manifeste persistant par dossier, verrouillage, checkout, réconciliation) — consommés par une nouvelle façade CLI (`regine checkout`, `regine reconcile`). Débloque le sous-scénario FR-009 de `specs/001-import-photos` et la User Story 4 de `specs/004-categorisation-dossiers`, tous deux documentés comme bloqués en attendant ce plan.

## Technical Context

**Language/Version**: Python 3.11+ (cohérent avec `regine-core`, cf. `specs/002/003/004`)

**Primary Dependencies**: `exiftool` (déjà acté par `specs/002-profil-boitiers-optionnel`, étendu ici pour le calcul de `ImageDataHash` sur DNG/TIFF/JPEG) ; bibliothèque standard uniquement sinon (`hashlib` pour l'empreinte fichier entier SHA-256, `sqlite3` pour le manifeste persistant, `pathlib`/`shutil` pour les copies vérifiées)

**Storage**: SQLite — un fichier de manifeste par dossier principal (parent + tous ses sous-dossiers), à sa racine sur l'archive, selon les conventions déjà actées par la constitution (`PRAGMA user_version`/`application_id`, écriture transactionnelle) ; le verrou de dossier vit dans la même base (table dédiée), pas un fichier séparé (cf. research.md § 2)

**Testing**: pytest ; tests unitaires sur la classification de réconciliation (les 5 catégories de changement), sur la décision anomalie/pas-anomalie par format, sur le versionnement de schéma ; tests d'intégration sur le cycle complet checkout→édition simulée→réconciliation→réarchivage en répertoires temporaires (archive et local simulés par le système de fichiers)

**Target Platform**: poste de bureau, identique aux autres modules ; l'archive est accédée comme un partage réseau monté (cf. `specs/003-config-contexte-travail`), aucune primitive de verrouillage réseau spécifique supposée disponible (cf. research.md § 3, limitation documentée)

**Project Type**: Monorepo existant — deux nouveaux modules `regine_core/integrity/` et `regine_core/archive/` (derniers modules de la bibliothèque centrale nommés dans `docs/interface-cli-gui-architecture.md` mais pas encore construits), plus une nouvelle commande CLI

**Performance Goals**: la réconciliation d'un dossier de quelques centaines à quelques milliers de fichiers DOIT rester praticable (minutes, pas heures) ; pas de cible chiffrée au-delà, cohérent avec l'absence de cible chiffrée dans la spec elle-même

**Constraints**: aucune primitive de verrouillage distribué fiable n'est supposée disponible sur un partage SMB ordinaire — le verrouillage reste une protection applicative de bonne foi (toutes les instances de Régine le respectent), pas une garantie absolue contre une écriture concurrente hors de Régine (cf. research.md § 3, limitation déjà acceptée par la constitution : « protections filesystem... en filet de sécurité complémentaire ») ; le travail à plusieurs avec verrouillage fin reste hors périmètre (Assumptions de la spec)

**Scale/Scope**: dossier archivé typique de quelques dizaines à quelques milliers de fichiers ; usage mono-utilisateur avec protection best-effort contre une seconde instance

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

| Principe / contrainte | Évaluation | Justification |
|---|---|---|
| I. Fichier maître intouchable | PASS | C'est l'implémentation directe de ce principe : FR-007/FR-008 appliquent exactement le mécanisme de hash à deux niveaux déjà décrit par le Principe I (empreinte fichier entier pour RAW propriétaires, empreinte image-only pour DNG/TIFF/JPEG), et ne réarchivent jamais silencieusement une anomalie. |
| II. Confirmation explicite avant toute action à risque | PASS | FR-013 : aucune écriture sur l'archive sans confirmation explicite du « point avant archive » ; FR-011 : aucune suppression propagée automatiquement. |
| III. Identité par contenu, jamais par nom de fichier seul | PASS | C'est également une implémentation directe : FR-009/FR-010 détectent tout renommage/déplacement par empreinte de contenu, jamais par chemin ou nom. |
| IV. Métadonnées ouvertes et embarquées | N/A | Ce module ne touche pas aux métadonnées descriptives/de droits (légende, mots-clés, etc.) ; il lit l'identifiant pérenne déjà embarqué (specs/001) sans le redéfinir. |
| V. L'utilisateur décide, Régine suggère | PASS | FR-012 : tout fichier sans correspondance reste une décision explicite de l'utilisateur, jamais un défaut imposé (cf. spec.md Assumptions, tranché sur ce principe précisément). |
| VI. Bibliothèque centrale, façades minces | PASS | `regine_core.integrity` et `regine_core.archive` portent toute la logique ; la façade CLI n'orchestre que l'appel et l'affichage du récapitulatif. |
| CLI-first | PASS | `regine checkout`/`regine reconcile` sont les premières façades construites pour ce mécanisme. |
| Exécution sans démon | PASS | Chaque commande est un processus isolé ; le verrou est un état persistant en base, pas un service actif. |
| Vérification d'intégrité systématique | PASS | FR-015 : toute copie (checkout et réarchivage) vérifiée par empreinte de contenu. |
| Vérification périodique indépendante (scrub) | N/A (hors périmètre) | Explicitement exclu par les Assumptions de la spec ; ce plan ne le construit pas, mais `regine_core.integrity` (hash à deux niveaux) est conçu pour être réutilisé par un futur scrub sans redéfinition. |
| Formats ouverts et documentés | PASS | SQLite, déjà retenu par la constitution pour ce besoin précis (manifeste persistant). |

Aucune violation identifiée ; la section Complexity Tracking reste vide.

**Re-check post Phase 1** (après génération de `data-model.md`, `contracts/`, `quickstart.md`) : le schéma du manifeste (une table par dossier principal, versionnée) et les contrats CLI/API interne (classification en 5 catégories exposée comme objets structurés, jamais de texte à parser) confirment chaque évaluation PASS ci-dessus. Aucune violation nouvelle.

## Project Structure

### Documentation (this feature)

```text
specs/005-checkout-reconciliation/
├── plan.md              # This file (/speckit-plan command output)
├── research.md          # Phase 0 output (/speckit-plan command)
├── data-model.md         # Phase 1 output (/speckit-plan command)
├── quickstart.md        # Phase 1 output (/speckit-plan command)
├── contracts/           # Phase 1 output (/speckit-plan command)
│   ├── cli-checkout-reconcile.md
│   └── regine-core-api.md
└── tasks.md             # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
```

### Source Code (repository root) — extension du monorepo posé par specs/002/003/004

```text
packages/regine-core/
├── src/regine_core/
│   ├── metadata/
│   │   └── exif.py                    # (existant, specs/002) étendu : read_image_data_hash() pour DNG/TIFF/JPEG
│   │
│   ├── integrity/                     # NOUVEAU module (dernier module nommé dans l'architecture, pas encore construit)
│   │   ├── __init__.py
│   │   ├── hash.py                    # hash_fichier_entier() [SHA-256 stdlib], hash_image_only() [délègue à metadata.exif]
│   │   └── anomalie.py                # est_maitre_modifie(format, ref, actuel) -> bool (FR-007/FR-008, Principe I)
│   │
│   └── archive/                       # NOUVEAU module
│       ├── __init__.py
│       ├── manifest.py                # ouverture/initialisation SQLite par dossier principal, PRAGMA user_version/application_id (FR-002/017/018)
│       ├── verrou.py                  # pose/vérifie/lève le verrou dans la même base (FR-003/004/016)
│       ├── checkout.py                # checkout(dossier, dest_locale, formats=None) -> ManifestSnapshot (FR-001/019/020)
│       └── reconciliation.py          # comparer() -> RapportReconciliation (FR-006/009/010/011/012/014), archiver() (FR-013/015/016)
│
└── tests/
    ├── unit/
    │   ├── test_hash_deux_niveaux.py      # RAW propriétaire vs DNG/TIFF/JPEG, anomalie vs édition légitime
    │   ├── test_manifest_versioning.py    # PRAGMA user_version, refus sur évolution structurelle, tolérance additive
    │   ├── test_verrou.py                 # pose, refus de double checkout, levée après réconciliation
    │   └── test_reconciliation_classification.py  # les 5 catégories, y compris déplacement de dossier entier (specs/004)
    └── integration/
        ├── test_cycle_checkout_reconciliation.py   # US1+US2 : checkout → édition simulée → réconciliation → réarchivage
        └── test_checkout_partiel.py               # US6 : formats exclus jamais signalés comme anormaux

packages/regine-cli/
└── src/regine_cli/
    └── archive_cmd.py                 # NOUVEAU : commandes `regine checkout <dossier>` / `regine reconcile <dossier>`
```

**Structure Decision**: Extension du monorepo existant — deux modules qui achèvent la liste des modules de bibliothèque centrale déjà documentée (`docs/interface-cli-gui-architecture.md` : `metadata`, `archive`, `import`, `dossier`, `integrity`, `camera_profile` — seuls `archive` et `integrity` manquaient encore). `regine_core.metadata.exif` (specs/002) est étendu plutôt que dupliqué pour le calcul `ImageDataHash`. Ce plan complète aussi les points d'intégration laissés en attente par `specs/001-import-photos` (FR-009) et `specs/004-categorisation-dossiers` (User Story 4).

## Complexity Tracking

*Aucune violation de gate à justifier — section laissée vide intentionnellement.*