# Динамические тесты — архитектура > v0.49.0-dev, 7 июня 2026 > Ветка: `dynamic-tests` ## Концепция Два теста: **на месте** и **в движении**. Разница — только в подсказке юзеру. Физически оба делают одно: опрашивают 12 PID каждые 250мс, копят в памяти. ## Алгоритм работы (user flow) ``` 1. Ошибки → scanDtc() — считывание DTC 2. Диагностика → обычный скрипт L0/L1/L2 на сервер → LLM 3. LLM сказал сделать тест на месте → ⏱ На месте → СТАРТ → ... → СТОП → данные в памяти 4. Диагностика → обычный скрипт + динамические данные → LLM 5. LLM сказал сделать тест в движении → 🚗 В движении → СТАРТ → ... → СТОП → данные в памяти 6. Диагностика → обычный скрипт + динамические данные → LLM (финал) ``` ## Android → Сервер При нажатии **Диагностика**: 1. Выполняется обычный скрипт (AT-команды, PID'ы) 2. Если есть `dynamicSamples` (данные теста) — прикрепляются к тому же запросу 3. POST `/api/v1/session/upload` с полем `dynamic_samples` 4. Сервер по наличию `dynamic_samples` понимает, что пришёл динамический тест 5. Выбирает промпт: `DYNAMIC_PROMPT` если только динамика, или `SYSTEM_PROMPT + DYNAMIC_PROMPT` если и то и то ## Что надо сделать ### Уже сделано (написан код, не проверен) - [x] Сервер: `build_dynamic_script()` — скрипт 12 PID 250мс - [x] Сервер: `?mode=dynamic` в routes.py - [x] Сервер: `DYNAMIC_PROMPT` в prompts.py - [x] Android: кнопки «⏱ На месте» / «🚗 В движении» (layout) - [x] Android: `DynamicCollector.kt` — сбор 12 PID 250мс - [x] Android: `ElmChecker.kt` — добавлены методы для работы с DynamicCollector - [x] Android: MainActivity — СТАРТ/СТОП, данные в памяти - [x] Android: общий таймер `tv_timer` ### Надо доделать - [ ] Android: при старте Диагностики — прикрепить `dynamicSamples` к upload - [ ] Сервер: принимать `dynamic_samples` в upload_session, выбирать промпт - [ ] Отладка на реальной машине ### До отправки — в памяти ```kotlin data class DynamicSample( val ts: Long, // System.currentTimeMillis() val responses: List // 12 ответов ELM ) val samples = mutableListOf() // в памяти, быстро ``` ### После СТОП — попытка отправки ```kotlin 1. Собираем все samples в JSON 2. POST /api/v1/session/upload 3. Если 200 → ОК, забыли 4. Если ошибка → пишем ВСЁ в SessionDb ``` ### Локальное хранение — через SessionDb (уже есть) ```sql -- Таблица sessions (уже существует) session_type = "dynamic" -- отличаем от обычных -- Таблица responses (уже существует) -- Каждый сэмпл = одна запись в responses: -- session_id, step_id = "sample_N", cmd = "batch", -- raw = JSON всего опроса, decoded = "запись №N" ``` **Плюсы**: не надо новой таблицы, `SessionDb` уже умеет `createSession`/`addResponse`/`getResponses`. **Объём**: 30 секунд × 4 опроса/с × 12 PID = 1440 записей ≈ ~100KB — норм. ### Ретрай непосланных сессий При старте приложения: `db.getUnuploadedSessions()` → отправить → пометить `uploaded=1`. ## Промпт для LLM (сервер) Отдельный `DYNAMIC_PROMPT` в `brain/prompts.py`: ``` Ты — эксперт по диагностике. Получены временные ряды 12 параметров с интервалом 250мс. Проанализируй: 1. Отклик дросселя — есть ли задержка/провалы 2. STFT/LTFT — богатая или бедная смесь под нагрузкой и при сбросе 3. RPM — плавность роста/падения, пропуски 4. MAP — соответствует ли оборотам 5. Зажигание — есть ли коррекция, детонация 6. Аномалии — резкие скачки, выбросы Отвечай кратко: 2-3 предложения вывода, затем по пунктам что не так. ``` ## Что НЕ делаем - GPS / акселерометр — не сейчас - Автодетект фаз (разгон/сброс) — ручной СТАРТ/СТОП - Отправка пачками в реальном времени — копим всё до СТОП