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

Журнал прогона и отчёты

Контракт журнала: simulate/contracts/log_schema.json (log_schema_version: 1). Валидация записей: simulate/src/geoscan_sim/journal/schema_validate.py.

Headless-прогон (run_plan_headless) создаёт каталог с манифестом, JSONL-потоками и fact_report.json (simulate/src/geoscan_sim/mission/runner.py). HTTP-прогон дополнительно пишет api_meta.json и копию plan.json в каталог run_id (simulate/src/geoscan_sim/api/run_worker.py).


Файлы в каталоге прогона

Файл Назначение Схема / код
run_manifest.json Идентичность прогона, хеши, допущения, exit definitions.run_manifest в log_schema.json:105+
telemetry.jsonl Покадровая телеметрия telemetry_record
events.jsonl Дискретные события (взлёт, смена фазы, …) event_record
fact_report.json План vs факт для валидатора definitions.fact_report
frames.jsonl Паспорта кадров съёмки генерируется камерным модулем
frames_summary.json Агрегат покрытия / GSD для GET .../coverage
world_manifest.json Снимок мира на момент прогона копия каталога миров
api_meta.json Только HTTP: status, error, метаданные очереди run_store.py
.journal_run_id Маркер run_id (защита от коллизии) writer.py:409-420

Коллизия run_id в одном каталоге → исключение RunIdCollisionError с code RUN_ID_COLLISION (writer.py:32-35, тест tests/test_journal_schema.py:55-60).


ER-диаграмма сущностей журнала

Связи логические: манифест ссылается на хеши потоков; fact_report ссылается на telemetry_sha256; события и телеметрия разделяют t_sim_s и uav_id.

erDiagram
  RUN_MANIFEST ||--o{ TELEMETRY_LINE : contains
  RUN_MANIFEST ||--o{ EVENT_LINE : contains
  RUN_MANIFEST ||--|| FACT_REPORT : summarizes
  RUN_MANIFEST {
    uuid run_id
    string plan_sha256
    string telemetry_sha256
    int seed
    string exit_status
  }
  TELEMETRY_LINE {
    float t_sim_s
    string uav_id
    float lon
    float lat
    string mode
  }
  EVENT_LINE {
    float t_sim_s
    int seq
    string type
    json payload
  }
  FACT_REPORT {
    int schema_version
    string telemetry_sha256
    json plan_vs_fact
  }
  FRAMES_LINE {
    string frame_id
    float t_sim_s
    float gsd_m
  }
  RUN_MANIFEST ||--o{ FRAMES_LINE : optional

Вывод: первичный источник времени — telemetry.jsonl; fact_report — производный артефакт для сравнения с планом, не дублирующий сырой поток.


run_manifest.json

Обязательные поля перечислены в log_schema.json:107-125 (log_schema_version, run_id, world_snapshot_id, plan_sha256, seed, dt_s, telemetry_hz, clock_mode, assumptions_used, exit_status, версии движка и погоды и др.).

assumptions_used не пустой для реального прогона (тест tests/test_journal_schema.py:91-98).

exit_status: completed | failed | aborted (log_schema.json:178).


telemetry.jsonl

Одна строка — один JSON-объект. Минимальный набор для валидатора схемы: t_sim_s, uav_id, lon, lat (тест tests/test_journal_schema.py:108-109).

Первая строка прогона s01 (CLI, 2026-09-17), сокращено:

{
  "t_sim_s": 0.0,
  "uav_id": "gemini-01",
  "lon": 37.6173,
  "lat": 55.7508,
  "alt_amsl_m": 100.0,
  "east_m": 0.0,
  "north_m": 0.0,
  "mode": "takeoff",
  "v_air_ms": 10.0,
  "v_ground_ms": 10.0,
  "energy_remaining_wh": 144.693972222,
  "link_up": true,
  "fidelity_class": "derived",
  "validation_level": "V2",
  "depends_on": ["ASSUMP-ENV-019", "ASSUMP-UAV-001", "..."]
}

Координаты: round-trip ENU ↔ WGS84 с точностью ≤ 1 см на полигоне s01 (tests/test_journal_schema.py:29-37). Запись формируется в writer.py:127-158.

Частота и шаг интегратора — в манифесте (dt_s, telemetry_hz).


events.jsonl

Обязательные поля: t_sim_s, seq, type, штампы fidelity (log_schema.json:189-191). Типы включают run_start, run_end, takeoff, transect_start, mode_change и др. (enum в log_schema.json:197+).

Пример run_start:

{
  "t_sim_s": 0.0,
  "seq": 0,
  "type": "run_start",
  "uav_id": "gemini-01",
  "payload": {"clock_mode": "headless"},
  "fidelity_class": "derived",
  "validation_level": "V2"
}

Для headless-прогона события могут приходить из симулятора (_event_lines_from_sim, writer.py:161-182) или собираться из плана (_build_events, writer.py:185+).


fact_report.json

Сборка: build_fact_report (simulate/src/geoscan_sim/mission/fact_report.py:361+). Имена метрик для валидатора geoscan:

VALIDATOR_PLAN_FACT_METRICS = (
    "makespan_s",
    "total_flight_time_s",
    "coverage_fraction",
    "energy_used_frac",
)

(fact_report.py:25-30, тест tests/test_fact_report.py:33-41).

Верхний уровень

Поле Описание
schema_version Версия отчёта
metric_names Список ключей в plan_vs_fact
plan_vs_fact Словарь метрик
telemetry_sha256 Хеш потока телеметрии
fact_report_sha256 Хеш канонического JSON отчёта
environment Температура, ветер, endurance, link
determinism Флаг stochastic: false для headless
preflight / preflight_codes Коды допуска

Схема: log_schema.json:65-104.

Структура метрики plan_vs_fact.<name>

Каждая метрика — объект plan_vs_fact_metric (log_schema.json:41-63):

  • planned, actual, delta_pct, delta_s — либо null, либо quantity с полями value, unit, fidelity_class, depends_on, validation_level;
  • для времени — delta_components_s (разложение отклонения: фазы, ветер, усечение, contingency);
  • status / status_reason — например NOT_COMPUTED для покрытия без кадров.

Сжатый живой фрагмент (sim run, /tmp/sim-doc-fact, 2026-09-17):

{
  "schema_version": 1,
  "metric_names": ["makespan_s", "total_flight_time_s", "coverage_fraction", "energy_used_frac"],
  "telemetry_sha256": "e11273715f65affb7987923aeb444d85ded8c8919264af05a2cf446cf4b62371",
  "plan_vs_fact": {
    "makespan_s": {
      "planned": {"value": 1680.0, "unit": "s"},
      "actual": {"value": 1680.0, "unit": "s"},
      "suspicious_plan_copy": true
    },
    "coverage_fraction": {
      "planned": {"value": 1.0, "unit": "1"},
      "actual": null,
      "status": "NOT_COMPUTED",
      "status_reason": "frame footprints not available (B4)"
    }
  }
}

Пример чисел для s01, seed 42 (CLI, 2026-09-17):

Метрика План Факт Примечание
makespan_s 1680 s 1680 s delta_components_s суммируется в delta_s (тест test_fact_report.py:72-79)
coverage_fraction 1.0 null status: NOT_COMPUTED — не копия плана (test_fact_report.py:46-52)
energy_used_frac ~0.42 из энергомодели actual > 0 (test_fact_report.py:56-62)

Фрагмент makespan_s в API-ответе после done:

"plan_vs_fact": {
  "makespan_s": {
    "planned": {"value": 1680.0, "unit": "s", "fidelity_class": "assumed", "validation_level": "V1"},
    "actual": {"value": 1680.0, "unit": "s", "fidelity_class": "derived", "validation_level": "V2"}
  }
}

Детерминизм

Повторный прогон с тем же планом и seed даёт идентичные telemetry_sha256 и fact_report (тест tests/test_fact_report.py:104-115).


Кадры и покрытие

  • frames.jsonl — паспорта с footprint, gsd_m, fidelity_class (раздаются через GET .../frames).
  • frames_summary.jsoncoverage_fraction_actual, сетка GSD, полигоны пробелов (runs.py:255-261).

Для демо s01 покрытие в отчёте может оставаться NOT_COMPUTED, пока слой камеры не даёт валидный actual (см. тесты fact_report).


Чтение результатов оператором

  1. Проверить код выхода sim run или status в api_meta.json / GET /runs/{id}.
  2. Открыть fact_report.json — столбцы planned/actual по четырём метрикам валидатора.
  3. При расхождении по времени — смотреть delta_components_s у makespan_s / total_flight_time_s.
  4. Для траектории — telemetry.jsonl или GET .../telemetry с decimate.
  5. Для таймлайна — events.jsonl или GET .../events?type=....

Подробнее про стенд и пути каталогов — эксплуатация.