HTTP API симулятора¶
Базовый URL: /api/v1. Ops-эндпоинты без префикса. Формат JSON, snake_case, ошибки {code, severity, path, message} (реестр simulate/contracts/error_codes.yaml).
Запуск¶
cd simulate
.venv/bin/pip install -e .
# Ключ: переменная SIMULATE_API_KEY, флаг --api-key или автогенерация при старте
export SIMULATE_API_KEY='dev-local-key'
.venv/bin/sim serve --host 127.0.0.1 --port 8080
# Локальная разработка без ключа (в лог — WARN):
# .venv/bin/sim serve --host 127.0.0.1 --port 8080 --no-auth
Статика фронта (simulate/web/dist) монтируется на /, если каталог существует. Для live SPA против защищённого API задайте при сборке VITE_SIM_API_KEY (см. simulate/web/src/config/runtime.ts).
Аутентификация¶
Защищены все пути /api/v1/*. Публичны без ключа: /healthz, /readyz, /metrics (Prometheus).
Передайте ключ одним из способов:
- заголовок
Authorization: Bearer <key>; - заголовок
X-Api-Key: <key>.
Источник ключа на сервере: SIMULATE_API_KEY, опция sim serve --api-key, либо ключ, напечатанный при автогенерации на старте. Режим --no-auth отключает проверку (только dev).
| Ситуация | HTTP | code |
|---|---|---|
Сервер без ключа и без --no-auth (явный create_app в тестах) |
503 | API_KEY_REQUIRED |
| Запрос без ключа / неверный ключ | 401 | API_KEY_INVALID |
Ops¶
| Метод | Путь | Ответ |
|---|---|---|
| GET | /healthz |
{"status":"ok","version":"<engine_version>"} |
| GET | /readyz |
{"status":"ok"} |
| GET | /metrics |
Prometheus text |
Во всех ответах заголовок X-Request-Id.
Каталог¶
GET /api/v1/fleet¶
Каталог бортов и нагрузок из fleet.yaml / payloads.yaml.
curl -sS -H "Authorization: Bearer ${SIMULATE_API_KEY}" \
http://127.0.0.1:8080/api/v1/fleet | jq '.fleet.uav | keys[:3]'
GET /api/v1/worlds¶
Список синтетических миров: world_id, kind, bbox, resolution_m, sha256.
GET /api/v1/worlds/{world_id}¶
world_manifest.json: слои, CRS, layer_completeness, layers.
Прогоны¶
POST /api/v1/runs → 202¶
Тело: {plan, scenario?, world_id, seed, options?, run_id?} или {plan_ref, world_id?, seed?, run_id?} (s01 / fixtures/plans/s01.json). Опциональный run_id (UUID) — идемпотентность каталога; повтор с тем же id → 409 RUN_ID_COLLISION.
curl -sS -D - -X POST http://127.0.0.1:8080/api/v1/runs \
-H "Authorization: Bearer ${SIMULATE_API_KEY}" \
-H 'Content-Type: application/json' \
-d @- <<'EOF'
{"plan_ref":"s01","world_id":"plane_seed_42","seed":42}
EOF
Ответ: {"run_id":"…","status":"queued"}, заголовок Location: /api/v1/runs/{run_id}.
Коды: 400 — мир/вход; 422 — план; 429 — RUN_QUEUE_FULL; 409 — коллизия run_id (журнал).
GET /api/v1/runs¶
Список: run_id, status, created_at, world_id, plan_sha256.
GET /api/v1/runs/{run_id}¶
status ∈ queued|running|done|failed, manifest, fact_report, preflight_codes, exit_status.
GET /api/v1/runs/{run_id}/telemetry¶
Параметры: from, to, decimate, uav_id. По умолчанию ≤ 20 000 точек, равномерное прореживание.
GET /api/v1/runs/{run_id}/events¶
Параметр type — фильтр по полю type.
GET /api/v1/runs/{run_id}/frames¶
Паспорта кадров; decimate (по умолчанию ≤ 5000). Если кадры не материализованы — status: NOT_COMPUTED, пустой список.
GET /api/v1/runs/{run_id}/coverage¶
coverage_fraction_actual, сетка GSD, полигоны пропусков (из frames_summary.json, если есть).
GET /api/v1/runs/{run_id}/verdict¶
Трёхзначный вердикт. По чеклисту §7.2 сейчас всегда UNRESOLVED + blockers.
Валидация и эталоны¶
POST /api/v1/validate¶
{plan, scenario} → reference (V-1…V-14) и mutants (матрица base).
GET /api/v1/reference¶
14 строк: id, metric, reference, actual, delta, tolerance, status, source.
OpenAPI¶
Схема: GET /api/v1/openapi.json. Снимок в репозитории: simulate/contracts/openapi.snapshot.json.
Коды ошибок (выборка)¶
| HTTP | code | Смысл |
|---|---|---|
| 404 | RUN_NOT_FOUND |
Нет прогона |
| 422 | PLAN_SCHEMA_VERSION_UNSUPPORTED |
План не проходит импорт/контракт |
| 429 | RUN_QUEUE_FULL |
Очередь прогонов |
| 401 | API_KEY_INVALID |
Нет или неверный ключ |
| 503 | API_KEY_REQUIRED |
Сервер без настроенного ключа |
| 500 | INTERNAL_ERROR |
Внутренняя ошибка |