From 51ca910e11fc15c50f2b27d874e033673e305a17 Mon Sep 17 00:00:00 2001 From: Gwadaking Date: Wed, 8 Apr 2026 02:33:31 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20l'observation=20la=20plus=20proche=20gag?= =?UTF-8?q?ne=20=E2=80=94=20=C3=A9vite=20l'=C3=A9crasement=20par=20zone=20?= =?UTF-8?q?distante?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ImpactScoreService : ne pas écraser le score si la nouvelle observation est plus loin que le score actuel (sauf après 6h de stale). Empêche Barbade d'écraser la Guadeloupe avec 367km quand des sargasses sont à 8km. SpotScoreController : horizons et bancs filtrés par proximité (<300km) du spot, plus la dernière observation globale quelle que soit sa zone. Co-Authored-By: Claude Sonnet 4.6 --- .../src/Controller/SpotScoreController.php | 10 ++++++++-- .../Service/Forecast/ImpactScoreService.php | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/backend/src/Controller/SpotScoreController.php b/backend/src/Controller/SpotScoreController.php index 70f15ae..2d240f8 100644 --- a/backend/src/Controller/SpotScoreController.php +++ b/backend/src/Controller/SpotScoreController.php @@ -107,7 +107,10 @@ class SpotScoreController extends AbstractController JOIN sargassum_observation o ON o.id = f.source_observation_id WHERE f.source_observation_id = ( SELECT o2.id FROM sargassum_observation o2 - INNER JOIN sargassum_forecast ff ON ff.source_observation_id = o2.id + INNER JOIN sargassum_forecast ff ON ff.source_observation_id = o2.id, + coastal_point cp3 + WHERE cp3.id = :spotId + AND ST_Distance(o2.geometry::geography, cp3.geometry::geography) < 300000 ORDER BY o2.detected_at DESC LIMIT 1 ) ORDER BY f.time_horizon ASC', @@ -226,7 +229,10 @@ class SpotScoreController extends AbstractController FROM sargassum_observation o WHERE o.id = ( SELECT o2.id FROM sargassum_observation o2 - INNER JOIN sargassum_forecast ff ON ff.source_observation_id = o2.id + INNER JOIN sargassum_forecast ff ON ff.source_observation_id = o2.id, + coastal_point cp3 + WHERE cp3.id = :spotId + AND ST_Distance(o2.geometry::geography, cp3.geometry::geography) < 300000 ORDER BY o2.detected_at DESC LIMIT 1 ) ) dump diff --git a/backend/src/Service/Forecast/ImpactScoreService.php b/backend/src/Service/Forecast/ImpactScoreService.php index 783d104..d6c6ee4 100644 --- a/backend/src/Service/Forecast/ImpactScoreService.php +++ b/backend/src/Service/Forecast/ImpactScoreService.php @@ -267,6 +267,25 @@ class ImpactScoreService /** @param array{score: int, level: string, distance: float|null, density: float, trend: string, etaHours: int|null} $data */ private function persistScore(CoastalPoint $spot, array $data): void { + // "L'observation la plus proche gagne" : ne pas écraser un score avec une distance + // plus grande que le score actuel, sauf si celui-ci a plus de 6h (stale). + if ($data['distance'] !== null) { + $current = $this->connection->fetchAssociative( + 'SELECT distance_to_nearest_sargassum AS dist, timestamp + FROM impact_score WHERE coastal_point_id = :id ORDER BY timestamp DESC LIMIT 1', + ['id' => (string) $spot->getId()] + ); + if ($current !== false && $current['dist'] !== null) { + $ageSeconds = (new \DateTimeImmutable())->getTimestamp() + - (new \DateTimeImmutable($current['timestamp']))->getTimestamp(); + $isStale = $ageSeconds > 21_600; // 6h + $isCloser = $data['distance'] < (float) $current['dist']; + if (!$isStale && !$isCloser) { + return; // garder le score de l'observation plus proche + } + } + } + $s = new ImpactScore(); $s->setCoastalPoint($spot); $s->setScore($data['score']);