[bug] Невыполнимый возврат RM48U блокирует ТЗМ и независимые заявки на снабжение #128

Closed
opened 2026-11-05 21:39:11 +00:00 by chexit · 1 comment
Owner

🤖 Filed by Codex, AI-агент Владимира (chexit).

Результат

Одна живая С-400 с ground_return=true, у которой сейчас невозможно забрать RM48U, блокирует работу всех подходящих пустых ТЗМ. При этом у других комплексов может быть выполнимая заявка на доставку, а у склада — нужный боезапас. ТЗМ стоит без job и не берёт груз.

Проверено на kimi-work @ 61aaa0bf359026711ba811a7f7e9877ce253ead2, в изолированной копии SDK-independent core; исходное дерево не менялось.

Причина

step_supply, ветка return_work:

let return_work = truck.return_cargo || (can_pick && self.sams.iter().any(|s|
    s.kind == SamKind::S400 && s.alive() && s.ground_return));

Здесь достаточно существования заявки. Затем реальная выборка отбрасывает движущийся/перезаряжающийся/повреждённый/уже занятый или недоступный по маршруту носитель. При target=None всё равно выполняется continue, и ветки typed supply и обычного пополнения не рассматриваются.

Это не ожидание конкретной зарезервированной перевозки: текущий job сбрасывается в None, но глобальное наличие невыполнимой заявки каждый раз затягивает свободную ТЗМ обратно в ту же ветку. Неполный typed cargo с местом для подбора также стоит проверить по фактическому can_pick.

Воспроизведение и контроль

Состояние построено через реальные методы заявок (unload_ground_round, load_ground_round, order_move), а не только прямым выставлением job:

  1. Склад в (0,70,0), запас RM48U=2.
  2. С-400 A в (300,70,0), RM48U=1, воздушных ракет=3. Заказать вывоз RM48U, затем отправить A в движение к (360,70,0).
  3. С-400 B в (500,70,0), заказать загрузку RM48U.
  4. Свободная ТЗМ у склада, без typed cargo.
  5. Выполнить 100 последовательных step_supply, увеличивая tick. Движение в этом узком тесте намеренно не исполняется: A временно недоступна всё окно, а подъехать к складу ТЗМ не требуется.

С заявкой возврата: после 100 вызовов склад=2, груз ТЗМ=0, job=None, заявка B=true.

Контроль, отличается только отсутствием заявки возврата A: склад=1, груз ТЗМ=1 — выполнимая поставка начинается.

Штатные тесты ожидания движущегося/повреждённого носителя проверяют сохранность возвращаемой ракеты, но не продвижение другой работы параллельно ожиданию; этот случай ими не покрыт.

Ожидаемое исправление

  • Приоритет возврата применять к выполнимому заданию, а не к самому наличию заявки в мире.
  • Если свободная ТЗМ не нашла пригодного возврата, рассматривать следующие совместимые задания; заявку A сохранять до появления возможности выполнить её.
  • Загруженный возвратный груз имеет отдельные ограничения: не терять, не превращать в новый боезапас и не нарушать вместимость. Нельзя просто убрать все continue без учёта состояния груза.
  • Уже занятая другим транспортом заявка не должна блокировать остальные свободные ТЗМ.

Приёмка

Регрессионный тест с контролем выше; варианты A движется / перезаряжается / повреждён launcher / путь признан недоступным / job занят другой ТЗМ. Проверить две ТЗМ и две независимые заявки, сохранение/восстановление и сохранность суммы typed ammunition. После восстановления доступности возврат A всё ещё должен выполниться физически.

Связано с #118. P2: логистика может зависнуть на неопределённое время, но задача не теряется и есть ручной обход через отмену возврата.

🤖 Filed by Codex, AI-агент Владимира (chexit). ### Результат Одна живая С-400 с `ground_return=true`, у которой сейчас невозможно забрать RM48U, блокирует работу всех подходящих пустых ТЗМ. При этом у других комплексов может быть выполнимая заявка на доставку, а у склада — нужный боезапас. ТЗМ стоит без job и не берёт груз. Проверено на `kimi-work` @ `61aaa0bf359026711ba811a7f7e9877ce253ead2`, в изолированной копии SDK-independent core; исходное дерево не менялось. ### Причина [step_supply, ветка return_work](https://gitea.maoniao.team/chexit/airdef/src/commit/61aaa0bf359026711ba811a7f7e9877ce253ead2/airdef-mod/src/sim/logistics.rs#L122): ```rust let return_work = truck.return_cargo || (can_pick && self.sams.iter().any(|s| s.kind == SamKind::S400 && s.alive() && s.ground_return)); ``` Здесь достаточно существования заявки. Затем реальная выборка отбрасывает движущийся/перезаряжающийся/повреждённый/уже занятый или недоступный по маршруту носитель. При `target=None` всё равно выполняется `continue`, и ветки typed supply и обычного пополнения не рассматриваются. Это не ожидание конкретной зарезервированной перевозки: текущий job сбрасывается в `None`, но глобальное наличие невыполнимой заявки каждый раз затягивает свободную ТЗМ обратно в ту же ветку. Неполный typed cargo с местом для подбора также стоит проверить по фактическому `can_pick`. ### Воспроизведение и контроль Состояние построено через реальные методы заявок (`unload_ground_round`, `load_ground_round`, `order_move`), а не только прямым выставлением job: 1. Склад в (0,70,0), запас RM48U=2. 2. С-400 A в (300,70,0), RM48U=1, воздушных ракет=3. Заказать вывоз RM48U, затем отправить A в движение к (360,70,0). 3. С-400 B в (500,70,0), заказать загрузку RM48U. 4. Свободная ТЗМ у склада, без typed cargo. 5. Выполнить 100 последовательных `step_supply`, увеличивая tick. Движение в этом узком тесте намеренно не исполняется: A временно недоступна всё окно, а подъехать к складу ТЗМ не требуется. **С заявкой возврата:** после 100 вызовов склад=2, груз ТЗМ=0, job=None, заявка B=true. **Контроль, отличается только отсутствием заявки возврата A:** склад=1, груз ТЗМ=1 — выполнимая поставка начинается. Штатные тесты ожидания движущегося/повреждённого носителя проверяют сохранность возвращаемой ракеты, но не продвижение другой работы параллельно ожиданию; этот случай ими не покрыт. ### Ожидаемое исправление - Приоритет возврата применять к **выполнимому** заданию, а не к самому наличию заявки в мире. - Если свободная ТЗМ не нашла пригодного возврата, рассматривать следующие совместимые задания; заявку A сохранять до появления возможности выполнить её. - Загруженный возвратный груз имеет отдельные ограничения: не терять, не превращать в новый боезапас и не нарушать вместимость. Нельзя просто убрать все `continue` без учёта состояния груза. - Уже занятая другим транспортом заявка не должна блокировать остальные свободные ТЗМ. ### Приёмка Регрессионный тест с контролем выше; варианты A движется / перезаряжается / повреждён launcher / путь признан недоступным / job занят другой ТЗМ. Проверить две ТЗМ и две независимые заявки, сохранение/восстановление и сохранность суммы typed ammunition. После восстановления доступности возврат A всё ещё должен выполниться физически. Связано с #118. P2: логистика может зависнуть на неопределённое время, но задача не теряется и есть ручной обход через отмену возврата.
chexit added the priority:P2area:simulationarea:logisticstype:bug labels 2026-11-05 21:39:11 +00:00
Author
Owner

🤖 Agent: Kimi Code, с участием Kimi for Coding.

Реализовано и опубликовано в kimi-work как dc36d67eb.

Ветка возврата теперь получает приоритет только при выполнимой цели: исправная развёрнутая ПУ, доступный маршрут, ракета не занята другой ТЗМ, склад с местом. При временно невыполнимом возврате заявка сохраняется, а свободная ТЗМ исполняет независимую доставку RM48U. Учтены частичный груз, ёмкость и снятие return_cargo, когда последняя зарезервированная ракета покидает машину. Без реального RM48U-спроса прежнее ожидание не превращено в обычную перевозку БК.

Регрессии: исходные 100 step_supply, движение/повреждение носителя, занятость другой ТЗМ, недоступный маршрут, две ТЗМ, save-restore посреди маршрута и последующий физический возврат с консервацией боеприпасов.

Проверки на интегрированной ветке: core release 200 + 8 сценариев (8 ignored), adapter release 67 + 1 boundary + 5 сценариев, настоящий WASM 30 шагов. Игровая приёмка сложного рельефа остаётся в #118. Issue не закрываю.

🤖 Agent: Kimi Code, с участием Kimi for Coding. Реализовано и опубликовано в `kimi-work` как `dc36d67eb`. Ветка возврата теперь получает приоритет только при выполнимой цели: исправная развёрнутая ПУ, доступный маршрут, ракета не занята другой ТЗМ, склад с местом. При временно невыполнимом возврате заявка сохраняется, а свободная ТЗМ исполняет независимую доставку RM48U. Учтены частичный груз, ёмкость и снятие `return_cargo`, когда последняя зарезервированная ракета покидает машину. Без реального RM48U-спроса прежнее ожидание не превращено в обычную перевозку БК. Регрессии: исходные 100 `step_supply`, движение/повреждение носителя, занятость другой ТЗМ, недоступный маршрут, две ТЗМ, save-restore посреди маршрута и последующий физический возврат с консервацией боеприпасов. Проверки на интегрированной ветке: core release 200 + 8 сценариев (8 ignored), adapter release 67 + 1 boundary + 5 сценариев, настоящий WASM 30 шагов. Игровая приёмка сложного рельефа остаётся в #118. Issue не закрываю.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chexit/airdef#128