Б-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:315—energy_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.