fix(gps): убран слой детекции LBS по stale re-send (помечал ~100% точек); is_lbs только по протокольному флагу valid=false + физика

This commit is contained in:
2026-08-31 17:02:56 +03:00
parent cbb659aed7
commit 0ad9bb8715
17 changed files with 208 additions and 94 deletions

View File

@@ -414,14 +414,9 @@ function medianAnchor(window: Array<{ lat: number; lng: number }>): { lat: numbe
// восстанавливается из last_* объекта в БД)
const assetWalkers = new Map<number, JumpFilterWalker>();
// Время (server time, ms) последнего stale-verdict'а по объекту.
// Идущие stale re-send'ы — сигнал потери GPS: свежие точки в течение
// STALE_LBS_WINDOW_MS после последнего stale считаются LBS (координаты
// сотовой вышки) — сохраняются и показываются, но не участвуют в геозонах.
const assetLastStaleAt = new Map<number, number>();
// Окно после последнего stale re-send'а, в котором свежие точки считаются LBS
const STALE_LBS_WINDOW_MS = 10 * 60 * 1000;
// РЕШЕНО (2026-08-31): слой «stale re-send => LBS-режим» убран — он помечал
// ~100% точек (любая ретрансляция пакета открывала 10-мин окно LBS).
// Источник истины: протокольный флаг valid=false (Traccar) + физика фильтров.
// Таймаут запроса к OSRM Nearest API (фильтр «далеко от дороги»)
const OSRM_NEAREST_TIMEOUT_MS = 2000;
@@ -490,9 +485,6 @@ export async function processPosition(
// Гидратация in-memory состояния после рестарта: если в БД объект помечен
// «потерян GPS», а lastStaleAt пуст — считаем, что stale был только что
// (осторожный режим до свежих событий)
if (asset.gpsLost && !assetLastStaleAt.has(assetId)) {
assetLastStaleAt.set(assetId, Date.now());
}
const settings = await gpsStorage.getSettings(organizationId);
@@ -506,7 +498,6 @@ export async function processPosition(
// Сохраняем как примерную (is_lbs), маркер двигаем, но walker/геозоны/пробег
// не трогаем. Заодно это сигнал потери GPS — как stale re-send.
if (input.forceLbs) {
assetLastStaleAt.set(assetId, Date.now());
if (!asset.gpsLost) {
await gpsStorage.setGpsLost(assetId, true);
console.log(`[GPS] gps_lost ON: asset=${assetId} (valid=false от протокола)`);
@@ -555,13 +546,6 @@ export async function processPosition(
// Stale re-send = трекер сам сообщает, когда в последний раз видел спутники
// (замороженный fixTime). Фиксируем как «время последнего GPS-фикса».
await gpsStorage.updateAssetGpsFix(assetId, recordedAt);
// Идущие stale re-send'ы — сигнал потери GPS: запоминаем время последнего
// stale и включаем режим «потерян GPS» у объекта
assetLastStaleAt.set(assetId, Date.now());
if (!asset.gpsLost) {
await gpsStorage.setGpsLost(assetId, true);
console.log(`[GPS] gps_lost ON: asset=${assetId} (stale re-send)`);
}
console.log(
`[GPS] skipped stale: asset=${assetId} recordedAt=${recordedAt.toISOString()} <= lastRecordedAt=${prev?.recordedAt.toISOString()}`
);
@@ -589,8 +573,9 @@ export async function processPosition(
// свежая точка — это координаты сотовой вышки (LBS), а не GPS-фикс.
// Такие точки сохраняем и показываем (пунктир на карте), но в логику
// геозон не пускаем. jump/echo/джиттер-отбросы режим не переключают.
const lastStaleAt = assetLastStaleAt.get(assetId);
const isLbs = lastStaleAt !== undefined && Date.now() - lastStaleAt < STALE_LBS_WINDOW_MS;
// Сюда доходят только точки без протокольного признака LBS
// (forceLbs-точки обработаны и вышли выше) — значит, обычная GPS-точка
const isLbs = false;
// Фильтр «далеко от дороги» — ТОЛЬКО в режиме потери GPS (LBS-точки):
// координаты сотовых вышек обычно >100 м от ближайшей дороги, настоящий