Preserve the local graph-first investigation stack through macro V1. Include reviewed source, tests, contracts, documentation and synthetic assets. Retain the standalone financial V21 test foundation without runtime migration. Runtime remains V20; operational JobStore remains V3. Local experimental checkpoint, not a stable release.
5.8 KiB
Analyse EML persistée vers le graphe Web — lot J3
État :
CURRENTlocal, synthétique, non publié Runtime d'écriture et de lecture : V20 inchangé Contrat transport :labfy.web_graph.snapshot.v3
Ce lot exécute réellement l'analyseur natif eml_analyzer sur une preuve EML
importée par les API de production. Les observations ne sont ni préinsérées ni
reconstruites par Python ou JavaScript : le service C les calcule, les publie
dans SQLite avec leur extraction, ferme la connexion d'écriture, puis la
projection C les relit en lecture seule pour produire le snapshot Web.
EML SPECIMEN
→ EvidenceImporter → preuve originale contrôlée
→ EmlAnalysisPersistenceService::prepare
chemin relatif + anti-symlink + taille + SHA-256
eml_analyzer_analyze_file (en-têtes uniquement)
dérivé JSON versionné en mémoire
→ staging privé + rename du dérivé
→ transaction SQLite unique
preuve dérivée + extraction + observations proposed
→ fermeture / réouverture V20 read-only
→ CoreGraphProjectionService → snapshot v3
→ serveur statique loopback → graphe Web
Contrat du service
La demande fournit trois UUID distincts et une date UTC : preuve source,
identité de requête/extraction et identité de preuve dérivée. Le service
emprunte une Database ouverte et copie la racine d'enquête ; l'appelant reste
propriétaire des deux. prepare() possède son résultat jusqu'à
eml_analysis_prepared_free() et ne modifie ni SQLite ni le disque.
publish() retourne un résultat possédé, libéré avec
eml_analysis_publication_result_free().
Avant l'analyse comme avant un replay idempotent, la copie contrôlée est un
fichier régulier sous la racine, sans composant symbolique. Sa taille et son
SHA-256 doivent être identiques au EvidenceRecord. Les limites locales sont
4 Mio pour la source, 256 observations et 1 Mio pour le dérivé. Elles bornent
le travail de cette capacité sans imposer une limite scientifique globale à
l'enquête.
Le dérivé labfy.eml_analysis.derivative.v1 conserve :
- UUID et date de demande ;
- UUID, taille et SHA-256 de l'original ;
labfy.eml_analyzer, version1;- portée
headers-onlyet limites appliquées ; - pour chaque observation : type, brut, normalisé, rôle, en-tête, occurrence et nature de provenance.
Le dérivé est préparé hors transaction, écrit dans un staging privé puis renommé. La preuve dérivée, l'extraction et toutes les observations sont ensuite insérées dans une transaction SQLite unique. Un échec annule les lignes et supprime uniquement le fichier final créé par cette tentative. Les originaux ne sont jamais modifiés.
Idempotence et réanalyse
L'UUID de demande est la clé idempotente. Un replay après réouverture vérifie à nouveau l'original, le dérivé, son hash, son contrat, l'outil, les paramètres, la date et le lot exact d'observations persistées. Il retourne le même résultat sans seconde publication. Une identité réutilisée avec une source, un dérivé, une date ou des observations incompatibles produit un conflit explicite. Un dérivé orphelin ou un lot incomplet demande une récupération explicite.
Une réanalyse est une nouvelle demande, avec un nouvel UUID d'extraction et un nouvel UUID de dérivé. Elle peut donc produire un second lot proposé sans écraser le premier. Le scénario de démonstration exerce les deux cas : replay de la première demande, puis réanalyse distincte.
Persistance V20 et projection v3
Aucune migration ni DDL n'est ajouté. Le lot réutilise :
| Objet | Persistance V20 | Relation |
|---|---|---|
| original EML | preuves |
entrée de l'analyse |
| dérivé structuré | preuves |
extractions.evidence_id |
| tentative publiée | extractions |
source_kind=evidence, source_id=<original> |
| observation calculée | evidence_entity_observations |
evidence_id=<original>, extraction_id=<demande> |
Les observations restent proposed, non promues et sans entité créée. Le lot
ne fabrique pas d'osint_execution : le runtime V20 ne permet pas d'y exprimer
une sélection de type preuve, et falsifier cette exécution détruirait la
provenance.
Le snapshot v2 demeure inchangé pour le scénario J3 read-only historique. La
v3 ajoute seulement object_kind: extraction, les nœuds d'extraction et les
arêtes de provenance analysis_input, analysis_derivative et
analysis_observation. L'original, le dérivé et chaque observation conservent
leurs identités SQLite. Le navigateur reçoit ce snapshot ; il ne lit jamais la
base ou le dérivé et n'invente aucune observation.
Démonstration et validation
make -j8 eml-graph-demo
cd prototypes/web-graph
python3 run_eml_demo.py --port 8765
Le lanceur crée une racine privée temporaire, exécute un binaire fixé avec des
arguments séparés et un délai de 45 secondes, puis ne sert que le snapshot
accompagné du manifeste EML attendu. --variant alternate produit un autre EML
synthétique afin de prouver que l'affichage suit le contenu réellement analysé.
Un échec C est affiché ; aucun repli vers les fixtures J2 n'est autorisé.
Les tests C couvrent analyse, valeurs brutes/normalisées, provenance,
fermeture/réouverture, replay, conflit, altération, source absente, limite,
analyse vide, annulation, liens symboliques, rollback et intégrité SQLite. Les
tests Firefox couvrent snapshot v3, deux
extractions, deux dérivés, observations proposées, navigation de provenance,
recherche, focus/retour, drag, vue étroite, erreur sans repli et contenu HTML
inerte. Toutes les données utilisent .test, les plages IP de documentation et
des noms SPECIMEN.
Ce lot ne livre ni analyse automatique d'une enquête ouverte, ni promotion d'entité, ni mutation Web, ni serveur de production, ni action réseau OSINT.
J3_EML_ANALYSIS_TO_GRAPH = COMPLETE_LOCAL