[bug] P1: кэш exact-ray переиспользует ответ для другой траектории и изменённого блока #73

Closed
opened 2026-10-30 09:55:01 +00:00 by chexit · 1 comment
Owner

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

Ревью 76f680eba64b64eb28435e71ce9f22a84b0e5da1 (после 6f3fc64). Регрессия narrow phase из исправления #63: ответ точного луча кэшируется по (flight_id, block), хотя он относится к конкретному отрезку и версии геометрии. В результате ранее открытый проход превращается в разрешение пролетать через заполненную часть блока.

Подтверждено

airdef-mod/src/sim/world.rs::WorldCache::narrow берёт запись self.rays.entries[(key,block)], не сверяя a/b. Для Exact::Clear сразу возвращает Sweep::Clear. Для Hit проецирует старый point на новый отрезок и может вернуть старую точку, даже если она сбоку от новой траектории. Ни changed_rev, ни columns_changed, ни touched не инвалидируют rays.entries/by_id; смена epoch тоже не очищает RayDesk. Очистка по возрасту делается лишь раз в 128 тиков и держит запись до 600 тиков.

Выполненное нативное воспроизведение

Стенд на копии исходного мода, реальные Ground::trace и WorldCache::serve с shapes provider:

  1. Нижняя полуплита (10,70,0), flight key=7. Отрезок (9.5,70.75,0.5)→(11.5,70.75,0.5) после ответа точного луча законно даёт Clear.
  2. Тот же flight key и блок, но Y=70.25 (через плиту): Clear без нового запроса.
  3. Секция инвалидируется, плита заменяется полным кубом, occupancy обновляется. Старый верхний отрезок также даёт Clear, поскольку ray cache остался прежним.
cached upper-half Clear reused through slab lower-half: Clear
cached Clear after slab replaced with full cube: Clear

Это не прежнее отсутствие narrow phase: здесь старый точный ответ разрешает физически другой, уже неверный шаг. На развороте, повторном заходе или после изменения мира аппарат может проходить сквозь препятствие.

Нужно

Привязать exact reply к world epoch/revision, поколению запроса и конкретному неподтверждённому шагу. При смене отрезка/shape запросить заново либо применять только доказуемо переиспользуемую геометрию, а не старый бинарный Clear. Инвалидировать RayDesk вместе с геометрией; не применять поздний ответ к новому миру. Для Hit проверять реальное пересечение текущего отрезка, не только проекцию старой точки.

Приёмка

Один аппарат повторно пересекает разные половины плиты, меняет курс у того же voxel; block replacement, chunk reload, epoch change и запоздалый ответ. Тёплый кэш не меняет результат по сравнению со свежим точным raycast. Стоимость и память остаются ограниченными.

🤖 Filed by Codex, AI-агент Владимира (chexit). Ревью `76f680eba64b64eb28435e71ce9f22a84b0e5da1` (после `6f3fc64`). Регрессия narrow phase из исправления #63: ответ точного луча кэшируется по `(flight_id, block)`, хотя он относится к конкретному отрезку и версии геометрии. В результате ранее открытый проход превращается в разрешение пролетать через заполненную часть блока. ### Подтверждено `airdef-mod/src/sim/world.rs::WorldCache::narrow` берёт запись `self.rays.entries[(key,block)]`, не сверяя `a/b`. Для `Exact::Clear` сразу возвращает `Sweep::Clear`. Для Hit проецирует старый point на новый отрезок и может вернуть старую точку, даже если она сбоку от новой траектории. Ни `changed_rev`, ни `columns_changed`, ни `touched` не инвалидируют `rays.entries/by_id`; смена epoch тоже не очищает RayDesk. Очистка по возрасту делается лишь раз в 128 тиков и держит запись до 600 тиков. ### Выполненное нативное воспроизведение Стенд на копии исходного мода, реальные `Ground::trace` и `WorldCache::serve` с shapes provider: 1. Нижняя полуплита `(10,70,0)`, flight key=7. Отрезок `(9.5,70.75,0.5)→(11.5,70.75,0.5)` после ответа точного луча законно даёт Clear. 2. Тот же flight key и блок, но Y=70.25 (через плиту): **Clear без нового запроса**. 3. Секция инвалидируется, плита заменяется полным кубом, occupancy обновляется. Старый верхний отрезок также даёт **Clear**, поскольку ray cache остался прежним. ```text cached upper-half Clear reused through slab lower-half: Clear cached Clear after slab replaced with full cube: Clear ``` Это не прежнее отсутствие narrow phase: здесь старый точный ответ разрешает физически другой, уже неверный шаг. На развороте, повторном заходе или после изменения мира аппарат может проходить сквозь препятствие. ### Нужно Привязать exact reply к world epoch/revision, поколению запроса и конкретному неподтверждённому шагу. При смене отрезка/shape запросить заново либо применять только доказуемо переиспользуемую геометрию, а не старый бинарный Clear. Инвалидировать RayDesk вместе с геометрией; не применять поздний ответ к новому миру. Для Hit проверять реальное пересечение текущего отрезка, не только проекцию старой точки. ### Приёмка Один аппарат повторно пересекает разные половины плиты, меняет курс у того же voxel; block replacement, chunk reload, epoch change и запоздалый ответ. Тёплый кэш не меняет результат по сравнению со свежим точным raycast. Стоимость и память остаются ограниченными.
chexit added the type:bugpriority:P1area:simulation labels 2026-10-30 09:55:01 +00:00
Author
Owner

🤖 Agent: сделано в b43d471706 (запушено в main). Проверено нативными тестами, в игре не запускалось.

🤖 Agent: сделано в https://gitea.maoniao.team/chexit/airdef/commit/b43d47170626e5a403d4c210246cce8fd4b763bc (запушено в main). Проверено нативными тестами, в игре не запускалось.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chexit/airdef#73