Перейти к содержанию

Симулятор «мир БВС»: зачем он рядом с планировщиком

Этот раздел — бизнес-описание продукта simulate: что он делает, кому нужен, чем отличается от валидатора планировщика geoscan, что подаётся на вход и что получается на выходе. Пишем по коду ветки docs2/sim-business, без «бумажных» функций.

Кому читать Что взять из раздела
Заказчик / жюри §1–2, диаграмма места в экосистеме, §6 «честно о готовности»
Новый разработчик §3–4, команды с реальным выводом, ссылки на архитектуру и API (черновик)
Оператор §5 пошаговый прогон, экраны web/, что значит UNRESOLVED на вкладке «Вердикт»

Соседний продукт (планировщик): geoscan — бизнес-описание.
Дальше по симулятору: сценарии · архитектура · интерфейсы (черновик) · эксплуатация · матрица зрелости.


1. Что это за симулятор

Симулятор — отдельный сервис, который принимает уже готовое полётное задание планировщика (JSON / GeoJSON / KML после импорта) и прогоняет его в синтетическом 3D-мире с координатами WGS84: борт движется по фазам sortie, учитываются ветер, температура, связь по рельефу, часть ограничений парка Геоскан (201 / 801 / Gemini). На выходе — журнал прогона (телеметрия, события) и отчёт «план против факта» (fact_report.json), а не новый маршрут.

Краткая формулировка в корневом README продукта совпадает с кодом: симулятор не планирует галсы и не заменяет метрики качества плана — их считает валидатор (отдельный контур в geoscan и отдельный — внутри simulate для эталонов модели).

mindmap
  root((simulate))
    Вход
      План планировщика
      world_snapshot_id
      seed детерминизма
    Ядро прогона
      Preflight analyze_plan
      Интегратор engine
      Журнал telemetry events
    Выход
      fact_report план vs факт
      frames.jsonl сухая геометрия
      HTTP API и web UI
    Независимая проверка
      sim validate --reference V-1…V-14
      sim mutate мутанты
      Граница импорта validator
    Достоверность
      fidelity_class
      validation_level V1…V6
      Вердикт UNRESOLVED

Вывод с mindmap. У симулятора три слоя смысла: (1) исполнение плана во времени, (2) независимые эталоны физики и геометрии (validator/), (3) пометки доверия к каждой цифре (fidelity_class). Путать «прогон» и «эталон V-10» нельзя: парашютный снос есть в sim validate, в fact_report прогона — только то, что собирает build_fact_report (см. LIMITATIONS.md).


2. Место в общей картине: планировщик, валидатор, симулятор

Зависимость односторонняя: симулятор читает выход планировщика; планировщик о симуляторе не знает (simulate/README.md, docs/90-final/01-business-requirements.md §2).

flowchart TB
  subgraph geoscan["Планировщик geoscan"]
    SC[Сценарий: полигон, парк, ЛЗП, ветер]
    PL[План + метрики makespan coverage]
    GV[Валидатор метрик плана<br/>геометрия без «воздуха»]
    SC --> PL --> GV
  end
  subgraph simulate["Симулятор simulate"]
    PF[Preflight analyze_plan<br/>зоны, клиренс, ветер по фазам]
    RUN[sim run / POST /runs<br/>интегратор + мир]
    FR[fact_report.json<br/>план ↔ факт]
    REF[sim validate --reference<br/>V-1…V-14]
    PF --> RUN --> FR
    REF -.->|проверяет модель, не план| RUN
  end
  PL -->|файл плана| PF
  PL -->|тот же план| RUN
  GV -->|violations = 0<br/>не значит «полетит»| PF

Вывод. Планировщик отвечает на «как разложить работы оптимально». Его валидатор (docs/task5/70-plan/01-validator-first.md) пересчитывает геометрию и ограничения на бумаге: NFZ, ВП, ветер как скаляр, запас энергии, coverage_fraction по полосам захвата. Симулятор отвечает на «что произойдёт, если исполнять этот план в мире с рельефом, дискретными кадрами и потерей связи» — см. проблемы P-01…P-12 в docs/00-brief/02-vision-and-business.md.

2.1. Таблица: три способа «проверить план»

Валидатор geoscan Preflight + sim run sim validate --reference
Вопрос Допустим ли план по правилам ТЗ? Какой факт даст прогон? Верна ли модель (ТТХ, формулы)?
Вход Сценарий + план Файл плана + world_snapshot_id Нет плана; кейсы V-1…V-14
Время Секунды Секунды–минуты (s01 ≈ 100 с на машине документации) Секунды
Типичный результат violations.*, метрики плана telemetry.jsonl, fact_report.json Таблица PASS/FAIL по эталонам
Независимость Отдельный код от солвера validator/ не импортирует engine/mission статически (tests/test_validator_import_boundary.py) Oracle в validator/independent/
Чего не видит CFIT по DEM, LOS, дискретные кадры Не оптимизирует план заново Не заменяет прогон сценария s01

Preflight явно позиционирован как анализ до полного 3D-движка (../../../src/geoscan_sim/mission/preflight.py), но уже тянет мир (check_clearance_along_geometry, зоны, покрытие по геометрии).

sequenceDiagram
  participant Op as Оператор / CI
  participant GS as geoscan
  participant PF as simulate preflight
  participant EN as simulate engine
  participant FR as fact_report

  Op->>GS: Сценарий → план + метрики
  Op->>GS: validate plan (валидатор geoscan)
  GS-->>Op: violations, coverage_fraction (план)
  Op->>PF: sim run (тот же JSON)
  PF->>PF: analyze_plan
  alt fatal preflight
    PF-->>Op: structured errors, exit ≠ 0
  else ok
    PF->>EN: integrator.run по фазам
    EN-->>FR: телеметрия + RunResult
    FR-->>Op: fact_report.json, makespan delta
  end

3. Кому нужен и какие вопросы задаёт

Роль Вопрос Где ответ в продукте
Разработчик планировщика Не сломал ли я регрессию на s01? sim run, сравнение fact_report / sha256 телеметрии (determinism в отчёте)
Команда → жюри Показать 3D и числа sim serve + web/ (../../../web/) (экран «Прогон»)
Планировщик работ План A vs B по факту, не по одной модели Два прогона, таблица plan_vs_fact (../../../src/geoscan_sim/mission/fact_report.py)
Ревьюер Модель не врёт на V-10 (парашют 168 м)? sim validate --reference (../../../src/geoscan_sim/cli/__init__.py)
Оператор (в контуре команды) Есть ли NFZ / низкий клиренс до выезда? Preflight-коды + карта прогона

Роли «внешний пилот заказчика» в контуре хакатона нет — в BRD это честно отмечено (Q-BIZ-04); симулятор всё равно даёт отчёт о находках, но не выдаёт бинарный «можно лететь» (см. §6).


4. Вход и выход глазами пользователя

4.1. Вход

Что Откуда Проверка в коде
План Экспорт из UI geoscan (файл) load_and_validate_plan, validate_plan_contract в sim run (../../../src/geoscan_sim/cli/__init__.py)
Мир --world / world_snapshot_id (по умолчанию m0-synthetic-flat) Синтетика, не GLO-30 в поставке (LIMITATIONS.md)
Детерминизм --seed (default 42) fact_report.determinism.stochastic: false (../../../src/geoscan_sim/mission/fact_report.py)
Строгие зоны --strict ZONE_ALT_FRAME_REQUIRED при отсутствии altitude_frame

Погода на прогон берётся из плана/сценария (ветер, температура) и попадает в блок environment отчёта с fidelity_class: assumed для полей сценария (../../../src/geoscan_sim/mission/fact_report.py).

4.2. Выход одного sim run

После успешного прогона CLI печатает JSON-summary с путями (проверено на fixtures/plans/s01.json):

{
  "fact_report": "/tmp/sim-doc-out2/fact_report.json",
  "frames_written": 380,
  "frames_raster_count": 0,
  "manifest": "/tmp/sim-doc-out2/run_manifest.json",
  "telemetry": "/tmp/sim-doc-out2/telemetry.jsonl",
  "telemetry_sha256": "e11273715f65affb7987923aeb444d85ded8c8919264af05a2cf446cf4b62371"
}
Артефакт Смысл для человека
run_manifest.json Паспорт прогона: план, seed, ссылки, хеши
world_manifest.json Какой мир подложен, layer_completeness
telemetry.jsonl Позиция, скорости, энергия по шагу времени
events.jsonl Фазы, связь, contingency
frames.jsonl Сухая геометрия кадров (без JPEG/TIFF)
fact_report.json План против факта + окружение

4.3. Отчёт «план против факта»

Файл fact_report.json строится функцией build_fact_report (../../../src/geoscan_sim/mission/fact_report.py). Сверяемые с валидатором планировщика имена метрик зафиксированы:

```25:30:simulate/src/geoscan_sim/mission/fact_report.py VALIDATOR_PLAN_FACT_METRICS: tuple[str, ...] = ( "makespan_s", "total_flight_time_s", "coverage_fraction", "energy_used_frac", )

Для каждой метрики в `plan_vs_fact`:

- **planned** — из `plan.metrics` (класс `assumed`, `validation_level: V1`);
- **actual** — из прогона (`derived`, обычно `V2`, если метрика посчитана);
- **delta_pct** — относительное отклонение;
- для времени — **delta_components_s**: ветер, фазы, усечение, contingency (`../../../src/geoscan_sim/mission/fact_report.py`).

**Важно по честности (проверено на s01, seed 42).**

1. **`makespan_s.actual`** сейчас передаётся как сумма плановых длительностей sortie (`runner.py:323-324`), а не как независимый интегральный замер — в отчёте стоит флаг `suspicious_plan_copy: true` при совпадении с планом (`../../../src/geoscan_sim/mission/fact_report.py`). Это согласуется с [`LIMITATIONS.md`](../../extras/simulate/LIMITATIONS.md) (дефект Б-3 по makespan).
2. **`coverage_fraction`** в том же прогоне: `status: NOT_COMPUTED`, причина `frame footprints not available (B4)` — отчёт собирается **до** материализации кадров в `run_plan_headless` (`../../../src/geoscan_sim/mission/runner.py`), хотя `frames_written` в summary может быть > 0.
3. **Энергия** (`energy_used_frac`) считается по телеметрии двухякорной модели — на s01 дельта к плану может быть большой (это сигнал расхождения моделей, а не «ошибка UI»).

Пример структуры (фрагмент мока UI): `../../../web/src/fixtures/mocks/s01/fact_report.json`.

---

## 5. Оператор: прогон и чтение результата

### 5.1. CLI (минимальный сценарий)

Из каталога `simulate/` (нужен `.venv` после `uv sync`):

```bash
.venv/bin/sim run fixtures/plans/s01.json --seed 42 --output ./out-s01 --world m0-synthetic-flat

Коды выхода и preflight описаны в ../../../src/geoscan_sim/cli/exit_codes.py. Подкоманды на момент документации: run, serve, validate, mutate, identitiesbatch нет:

Error: No such command 'batch'.

(проверено: .venv/bin/sim batch --help).

Эталоны модели:

.venv/bin/sim validate --reference

Фрагмент реального вывода (все 14 строк PASS):

V-10   Parachute drift W=12 H=70 Vdesc=5             168          168           +0          ±2% PASS
V-14   Determinism 10× identical sha256                0            0           +0  exact match PASS

5.2. HTTP + веб-интерфейс

  • API: sim serve (../../../src/geoscan_sim/cli/__init__.py) — см. HTTP API (черновик).
  • UI: четыре маршрута — «Прогон», «Покрытие», «Эталоны», «Вердикт» (../../../web/src/App.tsx).

На экране «Вердикт» оператор видит строку UNRESOLVED и список blockers — это не сбой, а задуманное состояние до закрытия полноты данных (../../../src/geoscan_sim/api/verdict.py).

stateDiagram-v2
  [*] --> PlanLoaded: файл плана
  PlanLoaded --> PreflightFailed: analyze_plan fatal
  PlanLoaded --> Running: sim run / POST /runs
  PreflightFailed --> [*]: exit FATAL
  Running --> ArtifactsReady: telemetry + fact_report
  ArtifactsReady --> Viewing: web / скачать JSON
  ArtifactsReady --> VerdictUnresolved: GET .../verdict
  VerdictUnresolved --> [*]: verdict = UNRESOLVED\nblockers fidelity / V3

6. fidelity_class: зачем и как читать

BRD требует пять полей на каждой выходной величине: value, unit, fidelity_class, depends_on, validation_level (SIM-BIZ-04, §7.2 BRD).

6.1. Три класса происхождения числа

Допустимые значения заданы в коде (../../../src/geoscan_sim/fidelity/quantity.py):

fidelity_class Смысл Пример в fact_report
measured Измерено (в поставке почти нет — нет реальных логов)
derived Вычислено из модели и журнала energy_used_frac.actual
assumed Взято из допущения / сценария / плана wind_speed_ms, planned метрики

Правило BRD §7.2: величина с assumed или с validation_level ≤ V2 не может быть основанием для вердикта NO-GO — она только объясняет отчёт и попадает в перечень ограничений.

6.2. Связка с пирамидой V1…V6

Пирамида валидации описана в docs/00-brief/02-vision-and-business.md и сводная таблица «класс величин → макс. V» — в BRD §7.2. Практически:

  • эталоны sim validate --reference закрывают V1–V2 (и частично V4 по РЭ);
  • прогон + независимый validator/import boundary — задел под V3 для геометрии;
  • V6 (сверка с реальным полётом) недостижим — телеметрии нет.

Проверка полноты пометок на артефактах одного прогона (инструмент из репозитория):

.venv/bin/python tools/audit_fidelity_coverage.py /tmp/sim-doc-out2

Пример вывода:

ИТОГО                          194071           0     0.00%
Отчётные артефакты: 0 из 119 без класса — 0.00%

Тест приёмки A-12: tests/test_fidelity_class.py (полный прогон s01 в pytest — долгий; аудит по каталогу — быстрый суррогат).


7. Честно: что готово, что нет

7.1. Вердикт приёмки 96-acceptance

Каталог simulate/docs/96-acceptance/ в этой ветке отсутствует (файл 00-verdict.md не найден). Опираемся на:

  • LIMITATIONS.md — шестой артефакт ТЗ с доказательствами по коду;
  • docs/93-audit/00-CHECKLIST.md — корзина B/C;
  • текущее поведение API вердикта.

7.2. Сводка «можно показывать / нельзя обещать»

Область Статус Доказательство
Одиночный прогон sim run + артефакты Работает Команда в §5, runner.run_plan_headless
Эталоны V-1…V-14 Работает sim validate --reference, все PASS в сессии документации
fidelity_class на выходе Работает на прогоне s01 audit_fidelity_coverage.py → 0 % без класса
Preflight (NFZ, клиренс, …) Частично tests/test_preflight_detection.py, не все слои ВП
Покрытие в fact_report Частично / баг порядка NOT_COMPUTED (B4) при наличии frames.jsonl
Makespan «факт» Частично suspicious_plan_copy, плановая сумма длительностей
Реальный рельеф GLO-30 Не реализовано fixtures/mirror/manifest.jsonblocked
sim batch, docker-стенд Не реализовано sim batch → No such command
Трёхзначный вердикт NO-GO / NO-FINDINGS Не реализовано Всегда UNRESOLVED + blockers (../../../src/geoscan_sim/api/verdict.py)
Гроза / снег / полный contingency Не реализовано LIMITATIONS.md, grep по src/geoscan_sim

Детальная матрица по подсистемам — в 02-readiness-matrix.md.

7.3. Что говорить на защите (из BRD §7.4)

Формулировка без завышения достоверности:

Модель сверена с руководством по эксплуатации и с независимой геометрией; с реальным полётом не сверялась. Числа с допущениями помечены fidelity_class и перечислены в LIMITATIONS.md. Автоматический вердикт «план годен / не годен» сейчас намеренно UNRESOLVED.


8. Связанные документы

Тема Путь
Головной BRD симулятора docs/90-final/01-business-requirements.md
Известные ограничения (ТЗ п.5) LIMITATIONS.md
Метод «валидатор первым» (geoscan) docs/task5/70-plan/01-validator-first.md
Глоссарий (ПАФС, ЛАФС, галс, GSD) docs/task5/00-brief/03-glossary.md