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

Б-1: расхождение energy_used_frac (G3-04)

Воспроизведение до правки

cd src/backend
uv run python -m grpc_tools.protoc -I proto \
  --python_out=proto-gen/src --pyi_out=proto-gen/src --grpc_python_out=proto-gen/src \
  proto/geoscan/*.proto
uv run python -m planner run --scenario scenarios/s01-simple.json --objective makespan --out /tmp/p.json
uv run python -m validator check --scenario scenarios/s01-simple.json --plan /tmp/p.json

(Генерация proto нужна в чистом клоне: в proto-gen/src/geoscan/ лежит только __init__.py, без сгенерированных stub'ов CLI валидатора не стартует.)

Вывод validator check на s01 до правки (фрагмент с дефектом, exit=4):

FAIL  G3-04  energy     Согласованность energy_used_frac              1.000 шт
       расход заряда в плане расходится с пересчётом на 1 вылетах
         • gemini-01/s1: в плане 0.89, пересчёт 0.71
...
ВЕРДИКТ: план НЕ допущен

Отношение 0.89/0.71 ≈ 1,25 совпадает с резервом 20 %: 1 / (1 − 0,20).

Причина

Контракт и G3-04 задают energy_used_frac как долю полного запаса хода: duration_s / endurance_max_s (см. validator/checks/g3_energy.py, фикстуры validator/tests/fixtures.py, docs/task5/90-business/08-data-model.md). Ограничение «не выше 1 − reserve» обеспечивает G3-01 по бюджету endurance · (1 − reserve).

Планировщик после «фикса D-75» записывал energy_used_frac = used / budget_s, где budget_s уже без резерва. Валидатор пересчитывал от полного endurance — систематическое завышение на ~25 % при резерве 20 %. Неверна была модель планировщика; валидатор соответствует домену и контракту.

Изменения

  • src/backend/planner/planner/pipeline.py:155-156 — вынесен endurance_s, budget_s считается от него (логика отсечки вылетов без изменений).
  • src/backend/planner/planner/pipeline.py:315energy_used_frac = used / endurance_s.
  • src/backend/planner/tests/test_pipeline_defects.py:145-159 — тест test_b1_energy_used_frac_matches_validator_g3_04 вместо test_d75_energy_frac_uses_reserve_budget.

Тест

planner/tests/test_pipeline_defects.py::test_b1_energy_used_frac_matches_validator_g3_04

  • Проверяет, что energy_used_frac в плане s01 равен duration_s / endurance_max_s (как в G3-04).
  • Прогоняет validate() и требует G3-04 со статусом pass.

На старом коде падал бы на первом assert (ожидалось ~0.71, в плане было ~0.89) и на G3-04.

Прогон после правки

cd src/backend
uv run pytest planner/tests/test_pipeline_defects.py::test_b1_energy_used_frac_matches_validator_g3_04 -q
uv run python -m planner run --scenario scenarios/s01-simple.json --objective makespan --out /tmp/p.json
uv run python -m validator check --scenario scenarios/s01-simple.json --plan /tmp/p.json
.                                                                        [100%]
1 passed in 1.79s
сценарий s01-simple, критерий makespan, валидатор 0.1.0

  ok  G1-01  airspace   Заход в бесполётные зоны                      0.000 m
       бесполётных зон в сценарии нет
  ok  G1-02  airspace   Выход за разрешённое ВП                       0.000 m
       траектория внутри разрешённого ВП
  ok  G1-03  airspace   Высотный слой зоны учтён                      0.000 шт
       пролётов над зонами вне их высотного слоя нет
  ok  G1-04  airspace   Буфер безопасности от зон                     0.000 m
       буфер не задан или зон нет
warn  G1-05  airspace   Порог 150 м (разрешение на ИВП)               153.194 m
       максимальная высота 153 м выше 150 м — потребуется разрешение на ИВП (ALT_ABOVE_150M)
         • gemini-01/s1/p1: 153 м
         • gemini-01/s1/p2: 153 м
         • gemini-01/s1/p3: 153 м
         • gemini-01/s1/p4: 153 м
         • gemini-01/s1/p5: 153 м
  ok  G2-01  altitude   Потолок борта не превышен                     0.000 m
       высоты в пределах потолков задействованных бортов
  ok  G2-02  altitude   Минимальная безопасная высота                 0.000 m
       высоты не ниже минимальной безопасной
  ok  G2-03  altitude   Полёт не ниже точки старта                    0.000 m
       бортам с запретом полёта ниже старта высоты назначены корректно
warn  G2-04  altitude   Запас над рельефом                            0.000 —
       модель рельефа во входной схеме не задана — проверка не выполняется
  ok  G3-01  energy     Бюджет вылета с резервом                      0.000 s
       все вылеты укладываются в бюджет при резерве 20%
  ok  G3-02  energy     Взлёт, перелёт и посадка в бюджете            0.000 шт
       у каждого вылета есть взлёт и возврат или посадка
  ok  G3-03  energy     Оборот на площадке соблюдён                   0.000 s
       интервалы между вылетами не меньше времени оборота
  ok  G3-04  energy     Согласованность energy_used_frac              0.000 шт
       расход заряда согласован на 1 вылетах (допуск 5%)
  ok  G4-01  weather    Ветер не выше предела борта                   0.000 m/s
       ветер 0.0 м/с в пределах всех задействованных бортов
  ok  G4-02  weather    Поперечная составляющая ветра допустима       0.000 frac
       максимум |W⊥|/V_a = 0.00
  ok  G4-03  weather    Путевая скорость положительна                 
       путевая скорость положительна и согласуется с треугольником скоростей
  ok  G5-01  assignment Тип съёмки закрыт установленной нагрузкой     0.000 шт
       все галсы назначены бортам с подходящей нагрузкой
  ok  G5-02  assignment Галс проходится ровно один раз                15.000 шт
       15 галсов, повторов нет
  ok  G5-03  assignment У каждого unassigned есть причина             0.000 шт
       список unassigned пуст
  ok  G5-04  assignment Пройденные и неназначенные галсы не пересекаются 0.000 шт
       пересечений нет
  ok  G6-01  coverage   Покрытие площади заданий                      1.000 frac
       пересчитано 1.000 (1.006 из 1.006 км²), в плане 1.000
  ok  G6-02  coverage   Время посчитано с разворотами                 1699.600 s
       план 1700 с против наивных 1380 с
  ok  G6-03  coverage   Доля времени на разворотах                    0.059 frac
       пересчитано 0.059, в плане 0.059
  ok  G6-04  coverage   Согласованность makespan и налёта             1699.600 s
       makespan 1700 с, суммарный налёт 1700 с, бортов 1

нарушения: нет
метрики: makespan 0:28:20, налёт 0:28:20, покрытие 1.000, развороты 6%, галсов 15, вылетов 1
ВЕРДИКТ: план допущен

Дополнительно: на s02-nfz и s06-wind G3-04 ok; s02 по-прежнему «план НЕ допущен» из‑за G1 (блокер Б-2, вне этой задачи).

Недоделанное

Нет. Документ docs/task5/94-fixes/planner-core.md (D-75) описывает прежнюю, ошибочную семантику energy_used_frac — актуализация текста не входила в Б-1.