<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Priorité Au Hors-Ligne on Boris Dupoux</title><link>https://borisdupoux.com/fr/tags/priorit%C3%A9-au-hors-ligne/</link><description>Recent content in Priorité Au Hors-Ligne on Boris Dupoux</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Fri, 12 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://borisdupoux.com/fr/tags/priorit%C3%A9-au-hors-ligne/index.xml" rel="self" type="application/rss+xml"/><item><title>Identification sur le terrain des véhicules concernés par un rappel</title><link>https://borisdupoux.com/fr/research/fleet-management/</link><pubDate>Fri, 12 Jun 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/fleet-management/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les campagnes de rappel de sécurité supposent d&amp;rsquo;atteindre chaque véhicule concerné, mais
courriers et appels téléphoniques laissent une population résiduelle de propriétaires qui
ne répondent jamais. Dans les territoires insulaires et ultramarins, le problème est plus
aigu : la couverture réseau est inégale, la logistique de terrain s&amp;rsquo;étend sur plusieurs
territoires et le registre de qui conduit quoi est incomplet. La question pratique devient
alors une question de gestion de flotte : &lt;em&gt;quels véhicules du parc en circulation sont
encore concernés, où sont-ils aperçus, et où en est chacun d&amp;rsquo;eux sur le chemin de la
réparation ?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Liste de rappel&lt;br/&gt;(récupération planifiée du fichier ou CSV manuel)"] --&gt; B["Serveur central&lt;br/&gt;import · versionnage · décodage des noms de modèles"]
 B --&gt;|"diff incrémental"| C["Unités de terrain (ordinateurs portables dans les véhicules des agents)&lt;br/&gt;copie locale de la liste de rappel"]
 D["Flux caméra"] --&gt; E["Détection de plaques + OCR&lt;br/&gt;(sur l'appareil, hors ligne)"]
 E --&gt; F["Correction tenant compte du format&lt;br/&gt;+ confirmation par double lecture"]
 F --&gt; G{"Correspondance avec&lt;br/&gt;la liste de rappel locale ?"}
 G --&gt;|"non"| H["Non transmise — absente de la base des détections"]
 G --&gt;|"oui"| I["Alerte à l'agent&lt;br/&gt;+ file d'attente locale"]
 I --&gt;|"synchronisation au retour du réseau"| B
 B --&gt; J["Tableau de bord&lt;br/&gt;unités · tournées · détections · incidents"]
 J --&gt; K["Processus de contact des propriétaires&lt;br/&gt;identifié → approché → engagé → réparé"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Ingestion et versionnage des données.&lt;/strong&gt; La liste de rappel est récupérée automatiquement
selon un calendrier ou importée manuellement. Chaque import est comparé au précédent à
l&amp;rsquo;aide d&amp;rsquo;identifiants stables, versionné par empreinte, et seul le delta est envoyé aux
unités de terrain. Les codes de type constructeur sont traduits en noms de modèles lisibles
lors de l&amp;rsquo;import.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correspondance malgré le bruit de l&amp;rsquo;OCR.&lt;/strong&gt; La détection des plaques et la reconnaissance
des caractères s&amp;rsquo;exécutent sur l&amp;rsquo;ordinateur portable de terrain avec des modèles ONNX, sans
dépendance au réseau. Deux garde-fous réduisent les fausses correspondances : (i) une étape
de &lt;em&gt;correction positionnelle&lt;/em&gt; exploite la structure connue des formats de plaques
nationaux (actuel et ancien) pour lever les confusions classiques de l&amp;rsquo;OCR (O/0, I/1, S/5,
B/8, Z/2, G/6), en rejetant toute lecture ambiguë ; (ii) une &lt;em&gt;confirmation par double
lecture&lt;/em&gt; ne comptabilise une plaque que si elle est lue deux fois dans une courte fenêtre
de temps. Une page web pour smartphone offre une solution de secours manuelle (photo ou
saisie de la plaque, avec validation de la clé de contrôle du VIN).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synchronisation pensée pour le hors-ligne.&lt;/strong&gt; Les correspondances sont mises en file d&amp;rsquo;attente
localement et transmises au serveur central à la connexion suivante, de sorte que les
détections survivent à des coupures de plusieurs jours. Les unités envoient un signal de
vie (version du logiciel, version de la liste de rappel, compteurs de lectures).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Opérations de terrain.&lt;/strong&gt; Les superviseurs planifient des tournées sous forme de points de
contrôle ordonnés et géolocalisés sur une carte, les attribuent aux équipes et aux unités,
réutilisent des modèles et suivent l&amp;rsquo;avancement. Les agents signalent les incidents avec un
niveau de gravité. Un processus de contact consigne le résultat de chaque démarche auprès
d&amp;rsquo;un propriétaire, et le tableau de bord en déduit un entonnoir de conversion (identifié →
approché → engagé → réparé) avec les tendances hebdomadaires, le délai médian jusqu&amp;rsquo;à la
réparation et une ventilation par territoire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protection des données dès la conception.&lt;/strong&gt; Les plaques sans correspondance ne sont
jamais transmises ni enregistrées dans la base des détections ; un journal local de
diagnostic des lectures OCR brutes (rotation à 2 Mo) reste sur le poste. Les
enregistrements conservés ont des durées de conservation fixes avec purge automatique ;
les actions sont consignées dans un journal d&amp;rsquo;audit ; l&amp;rsquo;accès au tableau de bord repose
sur des rôles, y compris des comptes en lecture seule ; les données du serveur sont
chiffrées au repos (LUKS2) ; une procédure de chiffrement intégral du disque a été
spécifiée pour les portables de terrain. Un registre des traitements a été rédigé
parallèlement au code.&lt;/p&gt;
&lt;h2 id="déploiement--exploitation-devops"&gt;&lt;a href="#d%c3%a9ploiement--exploitation-devops" class="header-anchor"&gt;&lt;/a&gt;Déploiement &amp;amp; exploitation (DevOps)
&lt;/h2&gt;&lt;p&gt;Le système tourne sur deux types de machines très différents : des ordinateurs
portables Windows dans les véhicules des agents, qui peuvent rester hors ligne
plusieurs jours, et un serveur par instance. Après les premières semaines de
terrain, l&amp;rsquo;essentiel du travail d&amp;rsquo;ingénierie a consisté à rendre les deux côtés
faciles à déployer, à superviser et à remettre en service, par une seule
personne, sans interrompre le travail de terrain.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 subgraph ADM["Poste d'administration"]
 GIT["Dépôt Git&lt;br/&gt;arbre commité uniquement"]
 PROV["Script de provisionnement&lt;br/&gt;un fichier de configuration par unité"]
 BLD["Build terrain&lt;br/&gt;paquet PyInstaller + modèles ONNX"]
 end
 subgraph SRV["Serveur (VPS Ubuntu LTS)"]
 CAD["Caddy&lt;br/&gt;TLS · HSTS · sans journal d'accès"]
 APP["Conteneur Docker&lt;br/&gt;API FastAPI + tableau de bord&lt;br/&gt;port en boucle locale uniquement"]
 VOL[("Volume LUKS2&lt;br/&gt;SQLite · photos · archives")]
 TIM["Timers systemd&lt;br/&gt;supervision · sauvegarde · nettoyage"]
 end
 FLD["Portables de terrain&lt;br/&gt;SQLite local · boucle de synchronisation"]
 OBJ[("Stockage objet externe&lt;br/&gt;sauvegardes chiffrées age")]
 CHAT["Alertes messagerie&lt;br/&gt;changements d'état + bilans quotidiens"]
 GIT --&gt;|"git archive via SSH → script de déploiement"| APP
 PROV --&gt;|"API d'administration"| APP
 PROV --&gt;|"fichier de configuration + LISEZMOI"| FLD
 BLD --&gt;|"archive + installateur en un clic"| FLD
 FLD &lt;--&gt;|"HTTPS : signal de vie · envois · diff des rappels"| CAD
 CAD --&gt; APP
 APP --- VOL
 TIM --&gt; VOL
 TIM --&gt;|"copie chiffrée"| OBJ
 TIM --&gt; CHAT&lt;/pre&gt;&lt;h3 id="portables-de-terrain--empaquetage-installation-et-mises-à-jour"&gt;&lt;a href="#portables-de-terrain--empaquetage-installation-et-mises-%c3%a0-jour" class="header-anchor"&gt;&lt;/a&gt;Portables de terrain : empaquetage, installation et mises à jour
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Empaquetage.&lt;/strong&gt; L&amp;rsquo;application de terrain (backend Python, interface React)
est figée avec PyInstaller en un exécutable Windows « un dossier » qui embarque
les modèles ONNX et la configuration de l&amp;rsquo;OCR : une unité n&amp;rsquo;a besoin ni d&amp;rsquo;une
installation Python ni du réseau pour lire les plaques. Des modes intégrés
&lt;code&gt;--diag&lt;/code&gt; et &lt;code&gt;--selftest&lt;/code&gt; vérifient l&amp;rsquo;environnement d&amp;rsquo;exécution embarqué et
lisent une image de test sans lancer l&amp;rsquo;interface, ce qui a permis de
diagnostiquer les échecs de démarrage directement sur la machine de terrain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installateur en un clic.&lt;/strong&gt; Le build est livré sous forme d&amp;rsquo;archive avec un
&lt;code&gt;INSTALLER.bat&lt;/code&gt; à lancer d&amp;rsquo;un double-clic. Il s&amp;rsquo;élève lui-même en
administrateur et exécute un script PowerShell qui retire des fichiers la
marque « téléchargé depuis Internet » (sans quoi l&amp;rsquo;environnement embarqué ne
se charge pas), désactive la mise en veille USB pour que le dongle GPS ne soit
pas suspendu, et installe le fichier de configuration de l&amp;rsquo;unité là où
l&amp;rsquo;exécutable le lit. Le script refuse de deviner : si plusieurs fichiers de
configuration &lt;em&gt;différents&lt;/em&gt; sont présents, il les liste et demande lequel est
le nouveau. Une réinitialisation optionnelle efface la base locale lorsqu&amp;rsquo;une
unité change de serveur ; elle affiche le serveur cible avant de demander
confirmation et avertit que les détections non synchronisées seraient perdues.
Le jeton d&amp;rsquo;accès de l&amp;rsquo;unité n&amp;rsquo;est jamais affiché. Une mise à jour suit le même
chemin : nouveau build, nouvelle exécution de l&amp;rsquo;installateur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Provisionnement.&lt;/strong&gt; Un script Python qui n&amp;rsquo;utilise que la bibliothèque
standard, et tourne donc sur un Windows nu, crée les unités à partir d&amp;rsquo;un
fichier CSV via l&amp;rsquo;API d&amp;rsquo;administration du serveur et génère, pour chacune, son
fichier de configuration (adresse du serveur, code de l&amp;rsquo;unité, nom affiché,
jeton) et un LISEZMOI à remettre avec le portable. La clé d&amp;rsquo;administration est
lue dans une variable d&amp;rsquo;environnement ou saisie de manière masquée, jamais
passée en argument de ligne de commande.&lt;/p&gt;
&lt;h3 id="versionnage--logiciel-et-liste-de-rappel"&gt;&lt;a href="#versionnage--logiciel-et-liste-de-rappel" class="header-anchor"&gt;&lt;/a&gt;Versionnage : logiciel et liste de rappel
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Version du logiciel.&lt;/strong&gt; Chaque unité indique la version de son application
dans son signal de vie. Le tableau de bord la compare à la version attendue et
signale les unités qui restent à mettre à jour.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version de la liste de rappel.&lt;/strong&gt; La liste de rappel est versionnée par
empreinte. À chaque cycle, une unité compare son empreinte locale à celle du
serveur : identique, rien à faire ; pas de copie locale, téléchargement
complet ; sinon, le serveur ne renvoie que les lignes ajoutées et retirées
depuis cette empreinte (et l&amp;rsquo;unité se rabat sur un téléchargement complet si
le serveur ne connaît plus sa version). La modification est appliquée en une
seule transaction, et l&amp;rsquo;empreinte locale n&amp;rsquo;avance que si tout a été appliqué.&lt;/p&gt;
&lt;p&gt;Cette dernière règle vient d&amp;rsquo;un incident de terrain. Une contrainte de la base
de données faisait échouer le diff sur une unité, l&amp;rsquo;erreur était absorbée par
la boucle de synchronisation, et l&amp;rsquo;unité continuait d&amp;rsquo;envoyer ses signaux de
vie alors que sa liste de rappel restait figée pendant 17 jours : elle
alertait donc sur des véhicules déjà réparés. La version 1.4.1 a corrigé
la cause, ajouté un retour arrière explicite et livré une migration de schéma
qui conserve les données existantes. Elle a été testée par une série de 62
tests (code de test non versionné), qui reproduisait le bug et migrait une
base à l&amp;rsquo;ancien schéma. La
supervision lève désormais une alerte « synchronisation des rappels figée »
lorsqu&amp;rsquo;une unité n&amp;rsquo;a pas reçu une liste publiée au-delà d&amp;rsquo;un délai de grâce.&lt;/p&gt;
&lt;h3 id="synchronisation-incrémentale-et-résiliente"&gt;&lt;a href="#synchronisation-incr%c3%a9mentale-et-r%c3%a9siliente" class="header-anchor"&gt;&lt;/a&gt;Synchronisation incrémentale et résiliente
&lt;/h3&gt;&lt;p&gt;Toutes les cinq minutes, ou à la demande, une unité exécute un cycle de
synchronisation composé d&amp;rsquo;étapes indépendantes : signal de vie, envoi des
détections (par lots), trace GPS, incidents, mises à jour des points de
contrôle, puis récupération de la liste de rappel et des tournées. Les envois
passent avant les récupérations, de sorte que les données de terrain partent
en premier. Une étape en échec ne bloque plus les autres : dans une version
antérieure, le cycle était monolithique, et un signal de vie en échec a un
jour retardé les détections de 22 minutes. Les requêtes utilisent des délais
d&amp;rsquo;attente courts, les téléchargements des délais plus longs. Le signal de vie
transmet la version du logiciel, la version de la liste de rappel, le nombre
de détections en attente et les compteurs de lectures, sur lesquels reposent
le tableau de bord et la supervision.&lt;/p&gt;
&lt;h3 id="déploiement-du-serveur"&gt;&lt;a href="#d%c3%a9ploiement-du-serveur" class="header-anchor"&gt;&lt;/a&gt;Déploiement du serveur
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Kit d&amp;rsquo;instance.&lt;/strong&gt; Chaque déploiement est une instance indépendante, décrite
par un court identifiant, sur un serveur virtuel Ubuntu LTS. Un script
d&amp;rsquo;amorçage, interactif et relançable sans risque, installe les paquets
système, Docker et Caddy depuis leurs dépôts officiels. Il active les mises à
jour de sécurité automatiques sans redémarrage automatique, restreint SSH à
l&amp;rsquo;authentification par clé, active un pare-feu en refus par défaut et une
protection contre la force brute, et vérifie que l&amp;rsquo;enregistrement DNS pointe
vers le serveur avant d&amp;rsquo;appliquer la configuration TLS. Les secrets résident
dans des fichiers de configuration réservés à root sur le serveur, jamais dans
le dépôt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conteneur et proxy inverse.&lt;/strong&gt; Un Dockerfile multi-étapes construit le
tableau de bord React avec Node, puis exécute le serveur FastAPI sur une image
Python allégée, sous un utilisateur non privilégié. Son contrôle de santé
prévoit une période de démarrage de trois minutes, car les modèles de plaques
et d&amp;rsquo;OCR sont chargés avant que le serveur n&amp;rsquo;écoute. Le conteneur n&amp;rsquo;est publié
que sur l&amp;rsquo;interface de boucle locale. Caddy est le seul point d&amp;rsquo;entrée public :
certificat Let&amp;rsquo;s Encrypt automatique, HSTS explicite et aucun journal
d&amp;rsquo;accès, car les URL de scan contiennent des plaques. Le journal d&amp;rsquo;accès de
l&amp;rsquo;application elle-même est désactivé pour la même raison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Déploiement et retour arrière.&lt;/strong&gt; Le code ne quitte le poste
d&amp;rsquo;administration que sous la forme d&amp;rsquo;un &lt;code&gt;git archive&lt;/code&gt; d&amp;rsquo;un arbre commité : les
modifications non commitées sont listées et ne partent pas, et les fins de
ligne sont forcées en LF. Sur le serveur, le nouvel arbre est extrait à côté
de l&amp;rsquo;actuel puis permuté, le précédent est conservé, et le commit déployé est
consigné. Le script de déploiement se détache ensuite de la session SSH : une
connexion coupée n&amp;rsquo;interrompt ni le déploiement ni un retour arrière. Un
verrou empêche les déploiements concurrents. Le script construit l&amp;rsquo;image
(étiquetée avec son commit), conserve l&amp;rsquo;image précédente comme &lt;code&gt;rollback&lt;/code&gt;,
recrée le conteneur et attend qu&amp;rsquo;il se déclare en bonne santé. Il abandonne
au bout de cinq minutes, ou dès que le conteneur a redémarré deux fois. En
cas d&amp;rsquo;échec, il revient automatiquement à l&amp;rsquo;image et à l&amp;rsquo;arbre source
précédents, met de côté le code en échec et envoie une alerte. Revenir à
n&amp;rsquo;importe quelle version antérieure revient à redéployer ce commit. Un retour
arrière d&amp;rsquo;image ne défait pas une migration de schéma : la procédure
documentée consiste donc à faire une sauvegarde avant tout déploiement qui
modifie le schéma.&lt;/p&gt;
&lt;h3 id="volume-chiffré-et-redémarrages-sûrs"&gt;&lt;a href="#volume-chiffr%c3%a9-et-red%c3%a9marrages-s%c3%bbrs" class="header-anchor"&gt;&lt;/a&gt;Volume chiffré et redémarrages sûrs
&lt;/h3&gt;&lt;p&gt;Les données du serveur (base, photos de contact, archives des listes de
rappel) résident dans un conteneur de fichier LUKS2 monté avec des options
restrictives. Sa phrase de passe n&amp;rsquo;est jamais stockée sur la machine : après
un redémarrage, une personne déverrouille le volume. Le conteneur redémarre de
lui-même, mais le serveur refuse de démarrer tant qu&amp;rsquo;un fichier sentinelle
&lt;em&gt;situé sur le volume chiffré&lt;/em&gt; est absent. Sans lui, un redémarrage aurait
laissé un dossier vide à la place du volume, et l&amp;rsquo;application y aurait créé
une base neuve, non chiffrée, et accepté les données de terrain. Cette
protection a été vérifiée dans les deux sens sur un conteneur jetable. Un
script distinct agrandit le volume pendant qu&amp;rsquo;il est monté.&lt;/p&gt;
&lt;h3 id="sauvegardes-et-reprise"&gt;&lt;a href="#sauvegardes-et-reprise" class="header-anchor"&gt;&lt;/a&gt;Sauvegardes et reprise
&lt;/h3&gt;&lt;p&gt;Un timer systemd quotidien prend un instantané cohérent de la base SQLite via
son API de sauvegarde, l&amp;rsquo;archive avec les photos et les archives de rappel, et
chiffre le résultat avec &lt;code&gt;age&lt;/code&gt; vers une clé publique. La clé privée n&amp;rsquo;est
affichée qu&amp;rsquo;une fois, à sa création, et conservée hors du serveur. Les
sauvegardes sont gardées localement et, en option, copiées vers un stockage
objet compatible S3 avec &lt;code&gt;rclone&lt;/code&gt;, configuré uniquement par variables
d&amp;rsquo;environnement. Un mode de &lt;em&gt;test&lt;/em&gt; de restauration déchiffre une sauvegarde
dans un dossier temporaire sur le volume chiffré, lance un contrôle
d&amp;rsquo;intégrité, compte les lignes par table, puis efface tout. Le mode
d&amp;rsquo;&lt;em&gt;application&lt;/em&gt; déplace l&amp;rsquo;état courant de côté au lieu de le supprimer. La
documentation comprend une reconstruction pas à pas après perte totale du
serveur. Le plan de continuité vise un délai de reprise de 4 heures et une
perte de données maximale de 24 heures.&lt;/p&gt;
&lt;h3 id="supervision"&gt;&lt;a href="#supervision" class="header-anchor"&gt;&lt;/a&gt;Supervision
&lt;/h3&gt;&lt;p&gt;Un chien de garde s&amp;rsquo;exécute toutes les 15 minutes et ne publie sur un webhook
de messagerie que lorsqu&amp;rsquo;un état change (problème, puis « rétabli »). Un bilan
plus complet est envoyé deux fois par jour, calé sur les horaires de terrain.
Il vérifie que le volume chiffré est monté, le point de santé de l&amp;rsquo;API (avec
plusieurs essais, car l&amp;rsquo;import quotidien peut le bloquer environ une minute),
l&amp;rsquo;état de santé du conteneur, la lisibilité de la base, l&amp;rsquo;occupation du disque
système et du volume chiffré, la taille du journal d&amp;rsquo;écriture anticipée de
SQLite, l&amp;rsquo;expiration du certificat TLS, l&amp;rsquo;âge et la taille de la dernière
sauvegarde, les unités silencieuses depuis plus de 48 heures (et non 24, car
les unités sont éteintes le week-end) et les unités dont la liste de rappel
est figée. Un guetteur distinct alerte lorsqu&amp;rsquo;aucun import de liste de rappel
n&amp;rsquo;a eu lieu depuis plus de 30 heures. Plusieurs de ces contrôles ont été
ajoutés après des incidents réels : le volume chiffré a un jour atteint 90 %
sans aucune alerte, car seul le disque système était surveillé. Un timer
hebdomadaire nettoie les caches de construction Docker et ne conserve que les
images courante et de &lt;code&gt;rollback&lt;/code&gt;. Un script dédié tronque le journal SQLite
avec une attente de verrou courte, afin que les écritures du terrain ne
soient jamais bloquées longtemps.&lt;/p&gt;
&lt;h3 id="résilience-hors-ligne"&gt;&lt;a href="#r%c3%a9silience-hors-ligne" class="header-anchor"&gt;&lt;/a&gt;Résilience hors ligne
&lt;/h3&gt;&lt;p&gt;Le côté terrain est conçu pour continuer à fonctionner pendant une panne du
serveur : lecture des plaques, correspondance avec la copie locale de la liste
de rappel, alertes, tournées déjà téléchargées et onglet de statistiques local
fonctionnent sans réseau, et la file d&amp;rsquo;attente se vide à la connexion
suivante. Seuls le tableau de bord (et la page pour
smartphone hébergée sur le serveur) sont indisponibles tant que le serveur
est arrêté.&lt;/p&gt;
&lt;h3 id="tests"&gt;&lt;a href="#tests" class="header-anchor"&gt;&lt;/a&gt;Tests
&lt;/h3&gt;&lt;p&gt;Le dépôt ne comporte pas de chaîne d&amp;rsquo;intégration continue. Les versions sont
vérifiées par des séries de tests ponctuelles consignées dans les messages de
commit (12/12 et 6/6 pour les étapes de correction des plaques et de
confirmation, 62 tests pour la version 1.4.1) ; le code de test n&amp;rsquo;est pas
versionné. Les comportements qui ne se prêtent pas aux
tests unitaires, comme la protection du volume ou un déploiement réel, ont été
vérifiés sur des conteneurs jetables et sur le point de santé de la
production.&lt;/p&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Lors des premières opérations de terrain, les agents ont marqué &lt;strong&gt;32 %&lt;/strong&gt; des alertes de
rappel comme erreurs de lecture sur neuf jours (4–12 août 2026 ; le nombre d&amp;rsquo;alertes
n&amp;rsquo;a pas été consigné). Cette mesure a motivé les étapes de correction positionnelle et
de confirmation par double lecture. Les détections marquées comme faux positifs étaient
déjà exclues des statistiques du tableau de bord (3 août).&lt;/li&gt;
&lt;li&gt;Les nouvelles étapes ont été vérifiées par des séries de tests ponctuelles consignées
dans les messages de commit (12/12 pour la correction des plaques, 6/6 pour la
confirmation, les réglages et le journal des lectures) ; le code de test n&amp;rsquo;est pas
versionné.&lt;/li&gt;
&lt;li&gt;Une liste de rappel figée silencieusement pendant &lt;strong&gt;17 jours&lt;/strong&gt; sur une unité a été
détectée puis corrigée dans la version 1.4.1 (voir plus haut).&lt;/li&gt;
&lt;li&gt;Après l&amp;rsquo;extension de la table de correspondance des noms de modèles, &lt;strong&gt;une seule&lt;/strong&gt; ligne
de la liste de rappel de production, sur environ 1,08 million, restait sans nom de
modèle décodé.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aucun taux de reconnaissance de bout en bout n&amp;rsquo;a encore été mesuré.&lt;/p&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;La précision de la reconnaissance n&amp;rsquo;a pas été mesurée sur un banc d&amp;rsquo;essai avec vérité
terrain. Les objectifs du cahier des charges (taux de lecture, latence) sont des
objectifs de conception, non des résultats.&lt;/li&gt;
&lt;li&gt;Aucune lecture de plaque à l&amp;rsquo;ancien format n&amp;rsquo;a été observée au départ. Un compteur dédié
suit désormais ces lectures de bout en bout, mais le correctif doit encore être vérifié
sur le terrain.&lt;/li&gt;
&lt;li&gt;Une fausse correspondance avec une liste volumineuse coûte toujours du temps aux agents.
L&amp;rsquo;étape suivante consiste à calibrer le seuil de confiance et la fenêtre de confirmation
sur des vidéos de terrain annotées.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;FastAPI&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;ONNX Runtime&lt;/code&gt; · &lt;code&gt;fast-alpr&lt;/code&gt; (détecteur de plaques YOLOv9 + OCR) · &lt;code&gt;OpenCV&lt;/code&gt; · &lt;code&gt;PaddleOCR&lt;/code&gt; · &lt;code&gt;React&lt;/code&gt; · &lt;code&gt;TypeScript&lt;/code&gt; · &lt;code&gt;Vite&lt;/code&gt; · &lt;code&gt;Leaflet&lt;/code&gt; · &lt;code&gt;Docker&lt;/code&gt; · &lt;code&gt;Caddy&lt;/code&gt; · &lt;code&gt;LUKS&lt;/code&gt; · &lt;code&gt;systemd&lt;/code&gt; · &lt;code&gt;age&lt;/code&gt; · &lt;code&gt;rclone&lt;/code&gt; · &lt;code&gt;PyInstaller&lt;/code&gt; · &lt;code&gt;PowerShell&lt;/code&gt;&lt;/p&gt;</description></item></channel></rss>