Журнал прогона и отчёты¶
Контракт журнала: 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.json—coverage_fraction_actual, сетка GSD, полигоны пробелов (runs.py:255-261).
Для демо s01 покрытие в отчёте может оставаться NOT_COMPUTED, пока слой камеры не даёт валидный actual (см. тесты fact_report).
Чтение результатов оператором¶
- Проверить код выхода
sim runилиstatusвapi_meta.json/GET /runs/{id}. - Открыть
fact_report.json— столбцы planned/actual по четырём метрикам валидатора. - При расхождении по времени — смотреть
delta_components_sуmakespan_s/total_flight_time_s. - Для траектории —
telemetry.jsonlилиGET .../telemetryсdecimate. - Для таймлайна —
events.jsonlилиGET .../events?type=....
Подробнее про стенд и пути каталогов — эксплуатация.