Steph680/ormuz
SINDBAD — Système d'INformation sur le Détroit : Bulletins, Analyses et Données
Surveillance du trafic marchand et des événements sécuritaires dans le détroit d'Ormuz (en anglais : Strait INtelligence Dashboard: Bulletins, Alerts & Data). Tableau de bord bilingue FR / EN (bascule en haut à droite), derrière authentification, qui croise trafic maritime, renseignement de sécurité, imagerie satellite et analyse assistée par IA.
Ce que le tableau de bord présente
Dans l'ordre des panneaux :
- Bandeau d'alertes (affichage désactivé — `BANDEAU_ACTIF` dans `static/app.js` ; la collecte, la route et les notifications par courriel restent actives) — le 8 septembre 2026, le CGRI a sommé les équipages des navires au mouillage au Koweït et à Bahreïn de quitter leur bord. SINDBAD avait capté le message, correctement. Il a pourtant échappé à l'opérateur : les signaux critiques étaient dispersés dans douze panneaux, et rien ne venait chercher le lecteur.
Le bandeau ne mesure rien de nouveau : il rassemble ce que les autres modules détectent déjà — avertissements à la navigation, incidents des sources officielles, bascules de posture, ruptures de couverture de presse, anomalies de marché — les classe par gravité d'abord, fraîcheur ensuite, et les pose là où on ne peut pas les manquer. Un clic mène au panneau qui détaille : le bandeau signale, il ne remplace pas. Replié, il continue d'afficher les critiques — les replier le ferait échouer précisément dans le cas qui l'a fait naître.
Les alertes de niveau critique — avertissements à la navigation et incidents des sources authentifiées — sont notifiées par courriel. Deux principes opposés gouvernent cet envoi : ne rien manquer, et ne pas noyer. D'où un périmètre étroit, une carence de 3 jours par alerte, et un plafond par cycle : un déluge de courriels ne serait pas une amélioration de la vigilance, ce serait sa perte. Un échec d'envoi est enregistré comme échec et réessayé — le compter comme traité ferait taire l'alerte définitivement.
- Cartes de synthèse — dernier jour publié et moyenne 7 jours du trafic, avec un double affichage PortWatch (satellite, différé) et AIS SINDBAD (relevés temps réel) ; compteur des transits du jour en temps réel.
- Météo du détroit orientée capteurs (Open-Meteo + houle marine au point 26,5°N 56,25°E, METAR de Khasab pour visibilité/plafond observés) : état de la mer (Douglas), vent, visibilités horizontale et verticale, humidité/point de rosée, verdict d'impact optronique (EO/IR/aéroporté) et niveau de nuit 1-5 (illumination lunaire corrigée de la nébulosité). Les relevés sont archivés heure par heure (
meteo_history, historique amorcé depuis la réanalyse ERA5) pour être corrélables aux incidents.
- Trafic quotidien — comptages [IMF PortWatch](https://portwatch.imf.org) (AIS satellitaire, point « chokepoint6 », historique depuis 2019, différé de 5 à 8 jours) en barres cargos/tankers, complétés par une ligne verte des relevés AIS temps réel SINDBAD ; sélecteur de période. (Note : la série PortWatch est dégradée depuis mars 2026 — brouillage AIS régional.)
- Derniers passages détectés en temps réel — table des transits captés par la collecte AIS commerciale, avec pavillon (drapeau + nom du pays, déduit du MMSI à défaut), type, direction, voie, horodatage ; nom de navire cliquable vers sa fiche VesselFinder. Fenêtre de lecture à ascenseur.
- Flux par voie de navigation — comparaison des trois voies du couloir 56°E–57°E (nord ≥ 26°40'N, centrale, sud ≤ 26°26'N) d'après les transits temps réel ; un clic sur une bande du graphique ou une ligne du tableau détaille les navires de la voie.
- Carte des incidents (Leaflet embarqué, fond sombre) — positions des alertes officielles (UKMTO, NGA MSI) et des incidents OSINT (marqueurs cyan, cf. plus bas), marqueur pulsant sur le dernier incident cliquable pour ouvrir son rapport, période réglable (366 j par défaut).
- Imagerie satellite du détroit — dernières scènes optique (Sentinel-2) et radar (Sentinel-1) recadrées au pixel près sur la boîte du détroit (56–57°E / 26,15–26,99°N) via le service de rendu du Copernicus Data Space (Process API), en mosaïque des passages récents pour une couverture complète. Le radar met les navires en rouge sur mer sombre (utile de nuit et sous les nuages). Repli sur la dernière image en base si le catalogue ne répond pas.
Chaque vignette porte l'heure exacte de prise de vue et l'heure du prochain passage prévu, toutes deux en UTC (afficher une heure de passage satellite en heure locale prêterait à confusion). La prévision ne demande aucune éphéméride externe : un Sentinel repasse exactement au bout de son cycle orbital (10 jours pour Sentinel-2, 12 pour Sentinel-1), donc chaque acquisition du catalogue déjà interrogé annonce la suivante ; on retient le premier passage à venir, toutes traces et tous satellites confondus — ce n'est pas nécessairement la trace qui a produit l'image affichée. Les données corroborent la méthode : les acquisitions optiques observées au-dessus du détroit tombent à 06:46 les 25/08, 30/08, 04/09 et 09/09, soit exactement 10 jours d'écart. C'est une prévision : un passage peut être omis (conflit d'acquisition, maintenance) ou s'ajouter.
- Détection radar des navires — comptage et positions des navires sur le rendu Sentinel-1, indépendamment de l'AIS : le radar voit les navires qui n'émettent pas, de nuit et à travers les nuages. Particulièrement utile ici, où l'AIS est brouillé depuis mars 2026 (la série PortWatch en est dégradée).
La détection se fait sur l'image déjà en cache, dont le rendu colore les échos de navire en rouge : aucun appel supplémentaire à Copernicus, et une garantie de cohérence — ce que le détecteur compte est exactement ce que vous voyez en rouge à l'écran. Le tri entre navire et côte ne demande aucune donnée géographique : un navire forme une tache de quelques pixels (~100 m par pixel), une côte ou une île en forme des centaines ; filtrer les composantes connexes par leur taille suffit à écarter la terre.
Le seuil se calibre sur l'image elle-même, en exploitant une propriété physique : un écho de navire est bien plus brillant que le chatoiement radar ou une frange de côte. Quand on durcit le seuil, le nombre de taches s'effondre tant qu'on élimine du bruit, puis se stabilise dès qu'il ne reste que des cibles réelles. On retient ce coude, et le profil complet (seuil → nombre de taches) est conservé pour rendre le choix vérifiable.
Deux versions antérieures ont été écartées par les données : la première abandonnait la scène au-delà d'un plafond (« rendu inexploitable, 580 échos ») — privant de toute mesure ; la seconde s'arrêtait au premier seuil passant sous ce plafond, et retenait 394 échos, c'est-à-dire le chiffre rond décidait à la place de la mesure.
Deux garde-fous issus des données réelles : le type MIME n'est pas un critère (Copernicus annonce ses rendus en « application/octet-stream » — s'y fier ferait rejeter toutes les scènes), et l'aperçu de repli est lui aussi un PNG (297×159 observé en base) mais n'est pas recadré sur la boîte. Seules les dimensions exactes du rendu prouvent la géométrie, donc la validité des positions ; toute autre taille est refusée sans rien publier. Le décodage PNG est écrit sur la bibliothèque standard — aucune dépendance d'imagerie ajoutée — et validé sur un vrai PNG Copernicus, filtres Paeth/Up/Sub compris.
Confrontation à l'AIS (échos sans correspondance) — le rendu affiché est une mosaïque de neuf jours : ses échos ne sont pas simultanés, et le confronter à un relevé AIS ferait déclarer « sans AIS » des navires qui émettaient parfaitement, une semaine plus tôt. Un second rendu, borné à une seule acquisition, sert donc à la corrélation.
Trois vérifications ont précédé. Le test porte sur le polygone réel et non sur le rectangle englobant : une fauchée est un parallélogramme oblique, et s'y fier avait d'abord fait conclure à tort à une couverture complète. Deux traces couvrent la fenêtre AIS : l'ascendante de ~14:16 UTC (100 %, et 94,6 % de la boîte entière — tout sauf le coin sud-est) et la descendante de ~02:14 (99,9 %). Chacune revient tous les 6 jours, décalée de l'autre : une occasion tous les 2 à 4 jours.
Le critère de sélection est une part de surface (95 %), pas les quatre coins. Exiger les coins paraissait rigoureux ; en production cela rejetait une trace couvrant 99,8 % de la fenêtre pour un angle manquant, et la cadence observée tombait de 6 à 12 jours — la moitié des occasions perdue pour une écharde. Les échos sont de toute façon filtrés un par un sur l'emprise réelle : rien n'est jugé là où le satellite n'a pas regardé.
La prévision du prochain passage se fait trace par trace, chacune avec sa cadence propre. Les mélanger donnait une suite d'intervalles 2, 4, 2, 4… dont la médiane vaut 4 — une cadence à laquelle aucun passage n'a jamais lieu.
L'AIS ordinaire est relevé toutes les 4 heures — à 15 nœuds un navire parcourt 111 km entre deux relevés, donc aucun ne peut servir. Un instantané est programmé à l'heure du passage prévu, déduite de la cadence observée. Le rayon d'appariement n'est pas fixe : il grandit avec l'âge de la position AIS et la vitesse du navire, qui a continué d'avancer. Sans relevé simultané, la scène reste explicitement non corrélée plutôt que de produire un « tout est sans AIS » trompeur.
⚠ Ce n'est pas une liste de suspects. À ~100 m par pixel, un pétrolier de 300 m fait trois pixels : on ne le distingue pas d'un groupe de boutres. Et dans le Golfe, quantité de navires n'émettent légalement pas (pêche, servitude portuaire, bâtiments militaires — aucune obligation en dessous de 300 tonneaux). C'est un indicateur de tendance : sa variation à trafic comparable informe, sa valeur absolue non.
Lire le comptage. Un nombre brut — « 344 navires » — ne se lit pas : rien ne dit si c'est beaucoup. La carte affiche donc l'écart à la médiane des scènes précédentes. La médiane et non la moyenne : une scène aberrante (rendu trop contrasté, couverture partielle) ne doit pas déplacer la référence, et la scène courante est exclue de son propre calcul, sinon elle se justifierait elle-même. Sous trois scènes antérieures, aucune référence n'est annoncée.
Voir où ils sont. Trois cent quarante coordonnées ne s'exploitent pas à l'œil : la liste se limite aux échos les plus francs, et la lecture d'ensemble se fait sur la carte des incidents (case « échos radar »). Les échos y apparaissent en points clairs ; ceux sans correspondance AIS y sont cerclés de rouge. Leur popup rappelle leur date propre : ils viennent d'un passage unique, pas de la mosaïque, et les confondre les ferait croire simultanés.
Qualification « navire sombre » : affirmer qu'un navire a éteint son AIS exige de confronter chaque écho aux positions AIS du même instant. Le crochet existe (correler_ais) mais reste sans effet tant qu'aucun flux AIS ne tourne : aucun écho n'est déclaré sombre faute d'avoir regardé. Ce panneau remplace la détection par Global Fishing Watch, dont la licence CC BY-NC réserve l'usage au non commercial ; ici tout vient de Copernicus, dont la licence autorise l'usage commercial.
- Assistant IA (démonstrateur) — questions en langage naturel dont la réponse s'appuie exclusivement sur les données collectées par SINDBAD (événements, incidents, trafic, météo, synthèses) ; le modèle cite les dates et n'invente rien.
- Synthèse de période (INTREP) — deux dates, et un LLM rédige une synthèse de renseignement structurée (situation générale, incidents officiels, activités iranienne et américaine, trafic et impact temps réel, avis et évolution) à partir des seules données collectées, postures des acteurs, changements de posture datés et tendances de couverture de presse compris (cf. plus bas). Mise en cache par période ; le prompt étant versionné, une synthèse produite par une version antérieure est régénérée d'elle-même plutôt que de rester privée des rubriques ajoutées depuis.
- Postures & tendances — mesure des changements de posture dans les déclarations officielles. Chaque déclaration est notée sur un axe d'escalade de −3 (désescalade, ouverture) à +3 (menace, action) par un lexique pondéré FR/EN — déterministe et gratuit : l'indice ne dépend pas du LLM. Le panneau affiche, par acteur (Iran gouvernement, Iran CGRI, EAU, Arabie saoudite) : l'indice de posture (moyenne sur 7 j), l'indice de tendance (durcissement / stable / apaisement par rapport aux 7 jours précédents) et une courbe de fond ; un résumé des 15 derniers jours régénéré toutes les 24 h par le LLM, dégageant les thématiques dominantes et les nouveaux arguments (présents dans les 5 derniers jours, absents des 10 précédents) ; et les déclarations des 24 h en tête de fenêtre, les plus anciennes à l'ascenseur.
Alerte sur changement de posture : quand l'indice d'un acteur bascule d'au moins 1,0 point entre deux fenêtres, un bandeau est levé en tête de panneau — SIGNAL à partir de 1,0, ALERTE à partir de 1,5 — daté, attribué et chiffré (indice avant → après). Un délai de carence de 3 jours évite de ré-alerter sur le même virage, que la fenêtre glissante continue de voir. Ces ruptures sont historisées et versées dans l'INTREP de la période (rubrique dédiée), où le modèle doit les exploiter pour caractériser les acteurs et dans son avis final : une inflexion du discours officiel est un signal en soi, à dater et à attribuer.
Avertissements à la navigation. Une menace explicite adressée aux équipages — « quittez votre navire, au mouillage comme à quai, il sera pris pour cible » — ne représente que 3 % des déclarations : une moyenne sur sept jours la dilue entièrement. Ces messages sont donc remontés tels quels, en tête du panneau, datés et attribués, indépendamment de l'indice. Ils sont détectés sur le texte intégral : le marqueur décisif arrive après la formule d'usage, et la tête seule vaut +2 là où le message entier vaut +3. Chacun porte un résumé d'une phrase « quoi / où / qui », produit par le LLM à partir du message entier, parce que le titre brut tait presque toujours la cible : « Avertissement immédiat de la marine du CGRI en réponse à l'action lâche de l'armée américaine… » devient « Le CGRI ordonne aux équipages des pétroliers de quitter leur navire, au mouillage comme à quai, sous peine d'être pris pour cible. » Le message d'origine reste à un clic. Un résumé par avertissement, mis en cache — 3 % des déclarations, donc un coût négligeable ; sans LLM, le titre brut reste affiché.
La consigne impose une distinction que la v1 avait manquée : la partie invoquée comme victime n'est pas la cible. Le message du 08/09 cite les pétroliers iraniens en grief (« en réponse aux frappes américaines contre nos navires ») puis menace « les équipages des pétroliers qui hébergent ces terroristes et sont complices » — ce sont ces derniers qui sont visés, et le premier résumé annonçait l'inverse. Le résumé part désormais du texte dans sa langue d'origine : passer par la traduction anglaise ajoutait l'étape où le sens s'était perdu. La consigne est versionnée, donc un résumé erroné se refait au lieu de rester figé. Le signal retenu est l'avertissement, non la note maximale : 21 déclarations atteignent +3 (surtout des revendications de frappes passées) contre 8 avertissements — alerter sur la note ferait du bruit.
Deux garde-fous issus des données réelles : une déclaration qui condamne l'acte d'un adversaire (« Bahreïn condamne l'attaque iranienne ») est comptée comme fermeté et non comme menace ; les republications d'une même annonce (fréquentes sur les canaux Telegram) sont dédupliquées, et un acteur noté sur moins de 3 déclarations est signalé « échantillon faible » plutôt que d'afficher une fausse tendance. Le lexique est versionné : l'incrémenter recalcule tout l'historique pour ne jamais mélanger deux barèmes.
- Déclarations officielles — publications collectées automatiquement sur les canaux officiels lisibles par machine (IRNA, Sepah News / CGRI via son miroir Eitaa, WAM, SPA), filtrées sur la crise (maritime, frappes, arraisonnements, décisions politiques, effets économiques ancrés au détroit), traduites FR/EN, et classées par rubrique (belligérants, pays du Golfe, M3SoH, organisations internationales, autres). Ces publications alimentent aussi la presse, l'INTREP et le rapport d'incident.
Chaque publication est rendue sous la forme « quoi / qui / où », en une phrase. Un titre n'est que la tête du message : « Conférence de presse du porte-parole du ministère des Affaires étrangères » ne dit ni ce qui a été annoncé, ni à qui, ni où. La phrase est construite dans cet ordre — l'acte, l'auteur et la partie visée, le lieu — et le titre brut reste au survol. Tant que le résumé n'est pas produit, la ligne retombe sur le titre : rien ne disparaît jamais.
La production est plafonnée par cycle (quota LLM), les plus récents d'abord. Les avertissements à la navigation en sont exclus : leur résumé, centré sur la menace et sur la distinction victime/cible, est déjà produit par posture et reste prioritaire. Une consigne explicite interdit au modèle d'inventer un lieu — sans elle, il place « détroit d'Ormuz » partout.
Canaux surveillés, par rubrique : belligérants — IRNA, Sepah News (CGRI), CENTCOM, NAVCENT ; pays du Golfe — WAM (Émirats), SPA (Arabie saoudite), ONA (Oman) ; M3SoH (coalition Military Multinational Strait of Hormuz, France et Royaume-Uni) — Ministère des Armées, Royal Navy, MoD britannique ; organisations internationales — OMI, SEAE (Union européenne) ; autres — MOFA (Japon), MAE (Chine), tiers dont la dépendance au détroit rend la position diplomatique décisive.
Deux propriétés de Google News gouvernent ces requêtes. D'abord site: est une recherche classée par pertinence, pas un fil chronologique : sans borne de date, le flux CENTCOM rendait cent éléments étalés de 2019 à 2026 — vingt-deux seulement de l'année en cours — et les déclarations du jour se noyaient dans sept ans d'archives. Toutes les requêtes sont donc bornées à 30 jours. Ensuite, quand l'ancrage géographique est dans la requête, Google l'a appliqué à la page entière : re-filtrer localement sur le seul titre ne peut que retrancher — « Conférence de presse du porte-parole » ne contient aucun mot maritime et serait écartée alors que Google l'a retenue pour son contenu. Ces sources sont marquées ancre et échappent au filtre local ; IRNA et Sepah News, qui déversent tout leur fil, y restent soumises.
Deux pièges relevés en ajoutant ces sources. Sur un site militaire, « navy », « naval » ou « ship » sont le bruit de fond : la requête maritime générique y ramenait des obsèques royales et des archives du Débarquement, et Google News plafonnant à 100 éléments, saturer la fenêtre de hors-sujet aurait fait manquer la déclaration cherchée — ces sources ont donc une requête ancrée (Ormuz, golfes, IMSC/EMASOH/AGENOR). Et le filtre de moisson, entièrement anglais et persan, rejetait « Le détroit d'Ormuz, passage stratégique » avant tout examen : un lexique français a été ajouté, lui aussi ancré sur la géographie et la mission plutôt que sur « navire » ou « marine », qui ne discriminent rien chez un ministère des Armées.
- Tendances presse — mesure de l'évolution de la couverture, pendant du panneau des postures mais sur un objet différent : un article n'est pas un acte de parole, c'est un compte rendu — la presse n'a pas de posture, elle a une attention, un écho et un agenda. Tout est calculé sur les seuls articles pertinents (sur le corpus brut, l'indice suivrait le bruit de collecte).
Quatre indices, fenêtre de 7 jours contre les 7 précédentes : Attention (événements distincts par jour — ce qui se passe), Volume (articles par jour — ce qui s'écrit), Écho (organes distincts) et surtout Amplification (articles ÷ événements). Beaucoup d'articles sur peu d'événements n'est pas de l'information nouvelle : c'est une reprise massive ou une campagne. S'y ajoute l'agenda thématique — part des articles évoquant chaque thème (cinétique, militaire, économique, diplomatique, sanctions, droit de passage), en multi-étiquette : un article peut relever de plusieurs thèmes, et forcer un thème « dominant » masquerait justement la bascule que l'on cherche. La bascule d'agenda, mesurée en points de part, est le vrai changement de tendance de la presse.
Alertes aux mêmes règles que les postures (SIGNAL / ALERTE, carence de 3 jours, historisation, versement INTREP) : variations en pourcentage pour les volumes, en points pour l'agenda. Plus un croisement propre : la divergence presse / discours officiel, levée quand l'attention de la presse et la posture officielle partent en sens contraires.
Deux précautions imposées par les données : le jour en cours est partiel et se trouve exclu des fenêtres (sans quoi un effondrement serait annoncé chaque matin), et les jours passés gagnent des articles rétroactivement (rattrapage GDELT), d'où un recalcul glissant des 21 derniers jours.
- Conséquences économiques — effets mesurables d'une entrave au détroit, sept indicateurs, aucune source payante : Brent, WTI, gaz Henry Hub et stocks de brut américains (EIA, clé gratuite), l'écart Brent − WTI, les passages de pétroliers (PortWatch, déjà collectés) et la tension assurantielle.
L'indicateur décisif n'est aucun des deux prix, c'est leur écart Brent − WTI. Le Brent cote un brut maritime, le WTI un brut terrestre nord-américain ; en régime normal ils ne s'écartent que de ~4 $. Un écart qui se creuse dit que la tension est régionale et maritime — la signature même d'un problème à Ormuz — là où une hausse conjointe ne dirait qu'une tension mondiale de la demande. Il ne coûte rien : il se déduit des deux autres. C'est aussi le seul à disposer d'une référence absolue : au-delà de 8 $ il est signalé « niveau anormal » même s'il n'a pas bougé de la semaine, sans quoi l'indicateur le plus parlant du panneau s'afficherait « stable » en plein blocage. Second croisement, porté par la courbe : prix ↑ / passages ↓ caractérise un blocage effectif, là où des prix qui montent à trafic constant ne sont qu'une prime de risque.
⚠ La « tension assurantielle » n'est pas un prix. Les primes de risque de guerre sont cotées de gré à gré par les courtiers du marché de Londres et ne sont publiées par aucune source gratuite (les indices de fret Baltic sont payants). L'indicateur mesure la part des articles du corpus traitant d'assurance maritime, de surprime de guerre ou de coût du fret : un signal d'attention, étiqueté comme tel dans l'interface et dans l'invite du modèle.
S'y ajoute une analyse de deux phrases par bloc — Europe, Chine, États du Golfe, États-Unis, Iran, plus l'Inde, le Japon et la Corée du Sud, les plus dépendants d'Ormuz avec la Chine. Elle est produite par une seule requête LLM par langue (un objet JSON pour les huit blocs), régénérée toutes les 24 h et dès que les valeurs bougent. FRED coupant la connexion quand on l'interroge en rafale, les séries sont demandées une par une, espacées de 20 secondes, quatre fois par jour ; une série en échec n'en fait pas tomber d'autres et se signale série par série dans l'auto-diagnostic.
Les quatre séries de marché viennent de l'EIA, avec une clé gratuite et délivrée instantanément. Deux constats de production l'ont imposé. D'abord, FRED ne reprend aucune série de stocks pétroliers (WCESTUS1 est un code EIA, pas un identifiant FRED). Ensuite et surtout, le CSV public de FRED fonctionne depuis une connexion domestique mais échoue depuis le Space : son anti-robot ferme la porte aux adresses de centre de données — les trois prix étaient absents en production alors que le test local passait. FRED reste branché en secours, sollicité pour les seules séries que l'EIA n'a pas fournies. Sans EIA_API_KEY, le panneau tombe à trois indicateurs sur sept, et l'auto-diagnostic affiche le motif exact de chaque série manquante — pas seulement son nom.
- Nous écrire (menu ☰, en bas) — formulaire de contact : adresse de réponse et message, transmis à l'exploitant. Un Space Hugging Face gratuit n'a pas de serveur de messagerie, la fonction est donc bâtie en deux temps, et l'ordre compte : le message est d'abord écrit en base (et la sauvegarde déclenchée aussitôt — le disque du Space est éphémère), puis relayé par courriel si un service d'envoi est configuré. Un relais absent, en panne ou à quota épuisé ne fait donc jamais perdre un message : il reste en statut « en attente », lisible et renvoyable d'un clic depuis la rubrique Messages reçus de
/admin. L'inverse — n'enregistrer qu'en cas de succès — perdrait justement les messages les jours où le relais tombe.
L'adresse saisie sert de répondre-à, jamais d'expéditeur : usurper le domaine d'un tiers ferait rejeter le courriel par SPF/DMARC. Le formulaire est derrière l'authentification et limité à 5 messages par heure et par compte ; le destinataire n'est pas dans le code (le dépôt du Space est public) mais dans un secret.
- Presse & événements — suivi de la presse (Google News RSS + GDELT), articles classés (incident / déclaration Iran / USA / autres), regroupés par événement (les couvertures d'un même fait forment une ligne « +N articles ») et titres traduits FR ⇄ EN (opus-mt, original au survol). Filtres catégorie et origine (⚓ officiel / 📰 presse), fenêtre de lecture à ascenseur.
Trois garanties issues d'un manquement constaté le 08/09/2026, où sept dépêches annonçant une menace iranienne sur les pétroliers mouillant au Koweït et à Bahreïn sont restées invisibles — notées 45, cinq points sous le seuil d'affichage :
- Un seul annuaire géographique (
app/lieux.py) sert au classifieur ET au géocodeur. Les deux listes avaient divergé : les ports du Golfe étaient géocodables mais inconnus du classifieur, qui appliquait donc une base de 30 au lieu de 50 à toute menace visant un mouillage. Ajouter un lieu le rend désormais reconnu des deux côtés. - Un avertissement à la navigation ne peut pas être filtré. Tout message avertissant explicitement des équipages ou la navigation (« warns tanker crews », « avis aux navigateurs », « leave their vessel ») voit sa pertinence plancherée à 90, au-dessus de tous les seuils. Sa catégorie est préservée : un avertissement est une déclaration, pas un incident.
- Les règles sont versionnées (
classifier.REGLES_VERSION) : les incrémenter fait recalculer tout l'historique au démarrage suivant (app/reclassement.py), au lieu de laisser des verdicts périmés masquer des articles. Les alertes des sources officielles et les incidents OSINT en sont exclus — leur pertinence tient à leur provenance, pas à une analyse de texte. - Plus aucune troncature. Les messages des canaux Telegram/Eitaa étaient coupés à 280 caractères à l'ingestion, le reste jeté : la clause opérative de l'avertissement du CGRI — « quittez votre navire, au mouillage comme à quai, il sera pris pour cible » — n'entrait jamais en base. Le texte intégral est désormais conservé (
corps,corps_fr,corps_en), et c'est lui qui sert au filtre de moisson, au classement et à la traduction : le même message vaut 45 jugé sur sa tête, 90 jugé sur son texte entier. Un bouton « texte intégral » le déplie dans le panneau des déclarations. Les messages déjà amputés sont rechargés depuis leur URL d'origine puis retraduits et reclassés (stratcom_collector.reparer_tronques).
- Rapport d'incident (bouton 📄 sur la carte et les alertes) — à partir d'une alerte sûre (UKMTO, NGA, MAE Oman) ou d'un incident OSINT, l'application retrouve les articles de presse du même événement et un LLM rédige une fiche (événement, faits établis, apports de la presse, cohérences et divergences, évaluation), avec séparation stricte source/presse, en fenêtre superposée. Le rapport est régénéré automatiquement si de nouveaux articles paraissent entre deux consultations.
Sources de sécurité et OSINT
- Sources officielles (badge ⚓, toutes les 2 h) : incidents UKMTO (API de la Royal Navy, positions comprises), avertissements NAVAREA IX (marine pakistanaise, réduits aux sujets sécuritaires en zone), avis actifs NGA MSI (gouvernement américain), déclarations du MAE d'Oman (RSS). Écartés après étude : MSCIO (republie UKMTO) et le MAE iranien (géobloqué).
- Incidents OSINT (source « OSINT », marqueurs cyan) : la liste Wikipédia des navires attaqués pendant la guerre de 2026 (API MediaWiki), navires nommés géocodés (annuaire régional + Nominatim), versés à la carte et aux événements (donc à l'INTREP et au rapport). Liveuamap a été écarté (API commerciale, anti-robots). (Évolution possible : clé recherche ACLED.)
Sources de trafic AIS temps réel
Le couloir est écouté en temps réel via un fournisseur AIS commercial (Datalastic, vessel_inradius, fenêtre 056°14'E–056°46'E, ~6 relevés/jour pour rester dans le quota). Une intégration Datadocked existe en veille (couverture terrestre insuffisante dans le détroit à ce jour). L'écoute gratuite aisstream.io reste dormante (pas de station dans le Golfe).
Extrait pour analyse par IA
/admin propose un extrait JSON de la base, à déposer tel quel dans un assistant. Un vidage brut serait inutilisable — 80 000 articles et 64 Mo n'entrent dans la fenêtre d'aucun modèle, et neuf dixièmes du corpus sont du bruit de collecte. L'extrait est donc choisi, pas copié : une ligne par événement (pas par article, la reprise d'un même fait par cinquante journaux n'ajoute rien), les seuls articles pertinents, et les séries déjà agrégées plutôt que leurs composants.
Le fichier s'ouvre sur un manifeste : période, description et volume de chaque section, et surtout les pièges de lecture. C'est lui qui fait la différence entre un extrait exploitable et un tas de lignes — sans lui, un modèle prendrait la « tension assurantielle » pour une prime cotée, lirait le creux de fin de série PortWatch comme une chute de trafic alors que la publication a huit jours de retard, ou conclurait qu'un écho radar est un navire aux transpondeurs éteints.
Jamais exportés, et l'omission est documentée dans le manifeste pour qu'elle ne passe pas pour un oubli : comptes et empreintes de mots de passe, sessions, messages du formulaire de contact (ils portent des adresses personnelles), journal de fréquentation, paramètres internes. Les synthèses et rapports déjà produits par un modèle en sont également absents : les réinjecter ferait commenter une IA par une autre au lieu des données.
Configuration (secrets du Space)
Aucun secret ne figure dans le code : tout est lu dans l'environnement, et l'application démarre et reste fonctionnelle même si une clé manque (le service concerné se met alors simplement en veille).
Comptes clients et administration
La page `/admin` (réservée à l'ACCESS_KEY ou à un compte de rôle admin) gère des comptes identifiant + mot de passe : à la création, un code initial est montré une seule fois — l'utilisateur choisit son propre mot de passe à sa première connexion. Mots de passe hachés (scrypt salé), sessions à jetons révocables (TTL 30 jours glissant) ; révocation d'un compte et réinitialisation du code en un clic, sans service d'e-mail. Chaque opération de compte déclenche une sauvegarde immédiate.
La page affiche aussi : l'état du système (feux par collecteur, badge global), la fréquentation par compte et par jour, le journal des ~300 dernières lignes, et un auto-diagnostic à sondes actives (aller-retour réel en base, jeton HF, fraîcheur des collectes AIS/OSINT/STRATCOM/météo, espace disque…) exécuté toutes les 30 minutes avec un historique de 7 jours.
Fonctionnement interne
- Base SQLite sauvegardée toutes les 15 minutes vers le dataset privé et restaurée au démarrage (perte maximale ≈ 15 min). Migrations additives : grappes d'événements (
cluster_id), titres traduits (title_fr/en), pavillon des navires (vessels.country), comptes v4 (identifiant + mot de passe), historique météo (meteo_history), imagerie (imagery_cache), signature de presse des rapports (rapports.presse_sig). - Démarrage non bloquant : le port s'ouvre immédiatement (healthcheck du Space) ; toutes les collectes et le rattrapage tournent en tâches de fond.
- Recoupement des articles (
app/topics.py) : deux articles de même catégorie publiés à ±4 jours dont les titres partagent l'essentiel de leurs mots significatifs — ou un nom propre distinctif (navire, lieu, personnalité) plus un autre mot — sont rattachés au même événement. Les alertes officielles ne fusionnent jamais entre elles. - Imagerie (
app/imagery.py) : catalogue public Copernicus (OData, sans compte) pour trouver la scène la plus récente couvrant la boîte ; avec les identifiants CDSE, rendu Process API clippé et mosaïqué (évalscripts true-colour S2 et SAR VV/VH « navires en rouge ») ; sinon, vignette de la scène la mieux centrée. Rafraîchissement toutes les 6 h, repli sur la dernière image en base. - Assistant IA (
app/ask.py) : récupération ancrée (mots-clés + fraîcheur) des faits pertinents en base, puis rédaction par le LLM avec consigne stricte de s'en tenir aux données fournies. - API (sélection) :
/api/status,/api/events,/api/rapport,/api/synthese,/api/ask,/api/stratcom/articles,/api/geo,/api/meteoet/api/meteo/historique,/api/imagery,/api/transits/recent,/api/stats/daily,/api/stats/today,/api/stats/voies,/health(ouvert, pour un moniteur de disponibilité).
Limites assumées
- Publication différée du trafic : PortWatch publie à J−5/J−8, et sa série est dégradée depuis mars 2026 ; l'AIS temps réel ne couvre qu'une fenêtre resserrée à ~6 relevés/jour (contrainte de quota).
- Classification et regroupement par mots-clés : rapides et gratuits mais imparfaits — vérifier les articles. Le regroupement inter-langues fonctionne mal.
- Traduction automatique (opus-mt et LLM) : correcte mais littérale ; l'original s'affiche au survol.
- Imagerie radar : la distinction navire/terre est intensité-par-pixel — les reliefs côtiers rugueux ressortent aussi ; en pleine eau les navires restent nets.
- Produits IA (INTREP, rapports, assistant) : analyses automatiques, à recouper avant toute décision.
- Hébergement gratuit : le Space peut redémarrer ; un moniteur gratuit (ex. UptimeRobot) pinguant
/healthtoutes les 5 minutes évite la mise en sommeil.
Développement local
python3 -m venv venv && venv/bin/pip install -r requirements.txt
venv/bin/python -m pytest tests/ # 223 tests : transit, grappes, rapport, imagerie, OSINT, météo…
venv/bin/uvicorn app.main:app --port 7860 # http://localhost:7860Sans ACCESS_KEY définie, l'API est ouverte (mode développement). Sans les clés correspondantes, chaque service (LLM, AIS, imagerie recadrée, sauvegarde, traduction) se met simplement en veille sans casser le reste.
