# ScanSets et catalogue d'images ## Statut **IMPLEMENTED — ScanSet v1 et Image Catalog persistant v1.** Un projet contient zéro ou plusieurs acquisitions logiques appelées `ScanSet`. Un ScanSet vide est valide : il peut être créé avant la capture ou l'import. ## Modèle durable ```text Project └── ScanSet (acquisition logique) └── Capture (observation physique potentielle) ├── Image Assets source/dérivés (contenus physiques gérés) ├── Images (représentations logiques) └── zéro ou une Image sélectionnée ``` - `scanset_id` identifie durablement une acquisition, indépendamment de son nom. - `image_id` identifie durablement une observation dans un ScanSet, indépendamment du nom du fichier et de la tâche d'import. - `asset_id` identifie un contenu physique. Son SHA-256, sa taille et son chemin relatif décrivent le fichier géré par Lardon3D. - La provenance d'une image conserve son nom original, son chemin source, son instant d'import et, s'il existe, le `task_id` importeur. - Un `Capture` est une association de catalogue dans un unique ScanSet ; il ne remplace pas `image_id`. Il peut conserver par exemple les assets RAW et JPEG d'un même déclenchement, sans inférer ce lien à partir de leurs noms. - Seule une image logique explicitement sélectionnée est la représentation courante proposée au pipeline scientifique ultérieur. La sélection ne modifie ni l'image, ni son asset, ni les résultats existants. - Une dérivation asset bornée parent→enfant, versionnée par fingerprint, rend possible une future image de travail RAW ou frame vidéo sans prétendre que RAW ou vidéo sont déjà importés. Un contenu identique n'implique pas une identité logique unique. Dans un même ScanSet, le couple `(scanset_id, asset_id)` est unique : réimporter le même contenu retourne `ALREADY_PRESENT`. Dans deux ScanSets distincts, deux images logiques possèdent deux `image_id`, mais peuvent partager le même `asset_id` et le même fichier physique. Un ScanSet peut documenter un objet complet, une sous-zone ou une pièce démontée. Aucune pose ni transformation 3D entre ScanSets n'est inventée en v1. Ces trois identifiants utilisent `AUTOINCREMENT`. Un ID issu d'une transaction validée ne sera jamais réattribué, même après une future suppression physique. Cette garantie est nécessaire avant que Feature Store, Visual Index, matches et tracks ne commencent à les référencer. ## Stockage physique Les assets image sont content-addressed : ```text assets/images/<2 premiers hex>/ ``` Le hash est un SHA-256 binaire de 32 octets dans SQLite et est encodé par le programme pour construire le chemin. Le nom utilisateur ne participe jamais au chemin de stockage. Le calcul et la copie utilisent un tampon fixe de 64 Kio ; une image entière n'est jamais chargée en mémoire. La publication crée un temporaire, le synchronise, publie sans écrasement puis synchronise le répertoire. Un asset existant n'est adopté qu'après vérification complète de sa taille et de son SHA-256. La transaction SQLite vient ensuite. Un échec SQLite peut donc laisser un fichier orphelin, mais jamais une ligne `READY` créée par le chemin métier avant publication. ## Import et reprise `import.images` persiste désormais `source_path + scanset_id`. Le ScanSet est immuable pour un `task_id`. L'import parcourt le dossier en streaming et traite des lots bornés. Sa correction ne dépend pas de l'ordre de `readdir()` : la présence logique est décidée par `(scanset_id, SHA-256)` dans la base. Une source externe reste nécessaire tant que la tâche est récupérable. Après `COMPLETED`, le catalogue et l'asset géré ne dépendent plus de sa présence. Les anciennes tâches v3 sont rattachées par migration à un ScanSet explicite nommé `Imports antérieurs à ScanSet v1`. Ce rattachement exprime seulement l'absence historique de regroupement ; aucune provenance de capture n'est inventée. La migration ne transforme pas les lignes de `manifest.tsv` en images v4 : elle n'a ni hash ni transaction catalogue historique permettant de le faire sans rejouer les fichiers. Elle pose donc l'indicateur durable `legacy_image_catalog_pending=1` lorsqu'une ancienne tâche d'import existe. - Si une tâche v3 récupérable retrouve sa source, sa reprise relit les sources, publie les assets content-addressed et remplit le catalogue. Les anciennes copies sous `images/originals` ne sont ni écrasées ni supprimées. - Si sa source a disparu, la reconstruction échoue proprement et les anciennes données restent uniquement legacy ; aucune provenance ni image v4 n'est inventée. - Un import v3 déjà terminal n'est pas rejoué automatiquement. Ses images du manifeste restent accessibles par la projection legacy mais sont marquées conceptuellement **LEGACY DATA NOT YET CATALOGUED** via l'indicateur DB. L'indicateur reste conservateur en v1 et n'est pas effacé automatiquement : une future commande de migration/reconciliation devra vérifier l'intégralité des données historiques avant de le lever. ## Accès borné Les listes de ScanSets et d'images utilisent un curseur par ID et une limite de 1 à 256. Aucun `get_all_images()` persistant n'existe. Des milliers d'images ne nécessitent donc pas autant de records simultanément en mémoire. ## Transition du manifeste `images/manifest.tsv` reste pris en charge par l'ancien catalogue en mémoire et les anciennes API d'import. Le chemin production maintient une projection best-effort par hardlinks pour que la TUI existante continue d'afficher les nouvelles images sans seconde copie physique. `project.db + assets/images` reste toutefois la vérité canonique : le manifeste est legacy et diagnostique, et n'est plus une condition de reprise. Deux images de ScanSets différents qui partagent un nom ne peuvent pas toutes deux être représentées dans cette vue legacy. La migration de la TUI vers les pages SQLite reste donc nécessaire. ## Futures étapes **NOT_YET_WIRED** — sélection de ScanSet dans la TUI, migration de l'ancienne vue mémoire, vérification/scrub des assets et réconciliation globale des orphelins. **IMPLEMENTED** — Feature Store et Visual Index peuvent relier visuellement des images de ScanSets différents sans dépendre de leur nom ou ordre. **IMPLEMENTED** — paires candidates, matching, vérification géométrique et Track Model / Track Builder v1 peuvent consommer le catalogue et ses assets. Les primitives géométriques Sparse SfM Gate C et le noyau incrémental synchrone en mémoire Gate D sont **IMPLEMENTED / PASS**. **PLANNED** — BA, orchestration Sparse SfM, MVS et relations géométriques entre ScanSets. La vérification/scrub des assets et la réconciliation globale restent également NOT_YET_WIRED.